strangedb/src/main/java/org/warp/jcwdb/ann/DBList.java

172 lines
4.1 KiB
Java

package org.warp.jcwdb.ann;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import java.io.IOError;
import java.io.IOException;
import java.util.LinkedList;
import java.util.StringJoiner;
public abstract class DBList<T> extends DBObject {
@DBField(id = 0, type = DBDataType.INTEGER)
private int maxLoadedItems;
@DBField(id = 1, type = DBDataType.UID_LIST)
private LongArrayList itemIndices;
public DBList(JCWDatabase db, int maxLoadedItems) {
super(db);
this.maxLoadedItems = maxLoadedItems;
this.itemIndices = new LongArrayList();
}
public DBList(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException {
super(database, objectInfo);
}
public int getMaxLoadedItems() {
return maxLoadedItems;
}
public void add(T obj) {
try {
itemIndices.add(saveObjectToDatabase(database.allocateNullValue(), obj));
} catch (IOException e) {
throw new IOError(e);
}
}
public int size() {
return this.itemIndices.size();
}
private T loadObjectAt(int i) throws IOException {
return loadObjectFromDatabase(itemIndices.getLong(i));
}
protected abstract T loadObjectFromDatabase(long uid) throws IOException;
protected abstract long saveObjectToDatabase(long uid, T value) throws IOException;
public DBListIterator<T> iterator() {
return new DBListIterator<>() {
private int position = itemIndices.size();
private LinkedList<T> cachedItems;
private int objectToSavePosition;
private T objectToSave;
@Override
public boolean hasNext() {
if (position > 0) {
return true;
} else {
try {
saveObservedObject();
} catch (IOException e) {
throw new IOError(e);
}
return false;
}
}
@Override
public T next() {
position--;
if (position < 0) {
throw new NullPointerException("Position < 0");
}
if (cachedItems == null || cachedItems.size() == 0) {
try {
cachedItems = fillCache(position);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
try {
return switchObservedObject(position, cachedItems.removeFirst());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void remove() {
try {
saveObservedObject();
} catch (IOException e) {
throw new RuntimeException(e);
}
itemIndices.removeLong(position);
}
@Override
public void insert(T obj) {
try {
itemIndices.add(position, saveObjectToDatabase(database.allocateNullValue(), obj));
} catch (IOException e) {
throw new IOError(e);
}
}
@Override
public void set(T obj) {
try {
itemIndices.set(position, saveObjectToDatabase(database.allocateNullValue(), obj));
} catch (IOException e) {
throw new IOError(e);
}
}
private LinkedList<T> fillCache(int position) throws IOException {
LinkedList<T> cachedItems = new LinkedList<>();
int firstObjectIndex = position;
int lastObjectIndex = firstObjectIndex - maxLoadedItems;
if (lastObjectIndex < 0) {
lastObjectIndex = 0;
}
for (int i = firstObjectIndex; i >= lastObjectIndex; i--) {
cachedItems.addLast(loadObjectAt(i));
}
return cachedItems;
}
private void saveObservedObject() throws IOException {
if (objectToSave != null) {
itemIndices.set(objectToSavePosition, saveObjectToDatabase(database.allocateNullValue(), objectToSave));
objectToSave = null;
objectToSavePosition = 0;
}
}
private T switchObservedObject(int position, T obj) throws IOException {
saveObservedObject();
objectToSave = obj;
objectToSavePosition = position;
return obj;
}
};
}
public interface DBListIterator<T> {
boolean hasNext();
T next();
void remove();
void insert(T obj);
void set(T obj);
}
@Override
public String toString() {
return new StringJoiner(", ", DBList.class.getSimpleName() + "[", "]")
.add("size=" + size())
.add("maxLoadedItems=" + maxLoadedItems)
.add("itemIndices=" + (itemIndices.size() < 100 ? itemIndices : "["+itemIndices.size()+" items]"))
.toString();
}
}