2018-12-20 00:16:16 +01:00
|
|
|
package org.warp.jcwdb;
|
|
|
|
|
|
|
|
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
|
|
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
|
|
|
2019-01-06 00:31:52 +01:00
|
|
|
import java.io.IOError;
|
2018-12-20 00:16:16 +01:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.*;
|
|
|
|
import java.util.function.Consumer;
|
|
|
|
import java.util.function.Predicate;
|
|
|
|
|
|
|
|
public class LightArrayList<T> implements LightList<T> {
|
|
|
|
|
|
|
|
public final LongArrayList internalList;
|
|
|
|
private final transient JCWDatabase db;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param db Database reference
|
|
|
|
*/
|
|
|
|
public LightArrayList(JCWDatabase db) {
|
|
|
|
this.db = db;
|
|
|
|
this.internalList = new LongArrayList();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param db Database reference
|
|
|
|
* @param elements Elements to add
|
|
|
|
*/
|
|
|
|
public LightArrayList(JCWDatabase db, LongArrayList elements) {
|
|
|
|
this.db = db;
|
|
|
|
this.internalList = new LongArrayList(elements);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int size() {
|
|
|
|
return internalList.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isEmpty() {
|
|
|
|
return internalList.isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean contains(Object o) {
|
|
|
|
if (o != null) {
|
|
|
|
for (long element : internalList) {
|
|
|
|
EntryReference<T> ref = null;
|
|
|
|
try {
|
|
|
|
ref = db.get(element);
|
2019-01-09 19:05:41 +01:00
|
|
|
if (o.equals(ref.getValueReadOnlyUnsafe())) {
|
2018-12-20 00:16:16 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Use iteratorReferences()
|
|
|
|
*/
|
|
|
|
@Deprecated
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
@Override
|
|
|
|
public Iterator<T> iterator() {
|
|
|
|
System.out.println("WARNING! YOU ARE USING iterator()! PLEASE USE ITERATORREFERENCES TO AVOID OUTOFMEMORY!");
|
|
|
|
final ArrayList<T> elements = new ArrayList<>();
|
|
|
|
for (long element : internalList) {
|
|
|
|
try {
|
2019-01-09 19:05:41 +01:00
|
|
|
elements.add((T) db.get(element).getValueReadOnlyUnsafe());
|
2018-12-20 00:16:16 +01:00
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return elements.iterator();
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
@Override
|
|
|
|
public Iterator<EntryReference<T>> iteratorReferences() {
|
|
|
|
final ArrayList<EntryReference<T>> elements = new ArrayList<>();
|
|
|
|
for (long element : internalList) {
|
|
|
|
try {
|
|
|
|
elements.add(db.get(element));
|
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return elements.iterator();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* USE forEachReference INSTEAD, TO AVOID OUTOFMEMORY
|
|
|
|
*
|
|
|
|
* @param action
|
|
|
|
*/
|
|
|
|
@Deprecated
|
|
|
|
@Override
|
|
|
|
public void forEach(Consumer<? super T> action) {
|
|
|
|
Objects.requireNonNull(action);
|
|
|
|
for (T t : this) {
|
|
|
|
action.accept(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void forEachReference(Consumer<? super EntryReference<T>> action) {
|
|
|
|
Objects.requireNonNull(action);
|
|
|
|
for (long index : this.internalList) {
|
|
|
|
try {
|
|
|
|
action.accept(db.get(index));
|
|
|
|
} catch (IOException e) {
|
2019-01-06 00:31:52 +01:00
|
|
|
throw new IOError(e);
|
2018-12-20 00:16:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
@Override
|
|
|
|
public T[] toArray() {
|
2018-12-21 10:03:30 +01:00
|
|
|
final T[] elements = (T[]) new Object[internalList.size()];
|
2018-12-20 00:16:16 +01:00
|
|
|
for (int i = 0; i < elements.length; i++) {
|
|
|
|
try {
|
2019-01-09 19:05:41 +01:00
|
|
|
T element = (T) db.get(internalList.getLong(i)).getValueReadOnlyUnsafe();
|
2018-12-21 10:03:30 +01:00
|
|
|
elements[i] = element;
|
2018-12-20 00:16:16 +01:00
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return elements;
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
@Override
|
|
|
|
public <T1> T1[] toArray(T1[] a) {
|
|
|
|
final T1[] elements = (T1[]) new Objects[internalList.size()];
|
|
|
|
for (int i = 0; i < elements.length; i++) {
|
|
|
|
try {
|
2019-01-09 19:05:41 +01:00
|
|
|
elements[i] = (T1) db.get(internalList.getLong(i)).getValueReadOnlyUnsafe();
|
2018-12-20 00:16:16 +01:00
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return elements;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean add(T o) {
|
|
|
|
EntryReference<T> ref = addEntry(o);
|
|
|
|
return ref != null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public EntryReference<T> addEntry(T o) {
|
|
|
|
EntryReference<T> ref = addToDatabase(o);
|
|
|
|
if (internalList.add(ref.getIndex())) {
|
|
|
|
return ref;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean remove(Object o) {
|
|
|
|
int removeIndex = indexOf(o);
|
|
|
|
if (removeIndex >= 0) {
|
|
|
|
internalList.removeLong(removeIndex);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean remove(EntryReference<T> ref) {
|
|
|
|
int removeIndex = indexOfEntry(ref);
|
|
|
|
if (removeIndex >= 0) {
|
|
|
|
internalList.removeLong(removeIndex);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean containsAll(Collection<?> c) {
|
|
|
|
for (Object o : c) {
|
|
|
|
int objIndex = indexOf(o);
|
|
|
|
if (objIndex < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
@Override
|
|
|
|
public boolean addAll(Collection<? extends T> c) {
|
|
|
|
boolean result = false;
|
|
|
|
for (Object o : c) {
|
|
|
|
result |= add((T) o);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
@Override
|
|
|
|
public boolean addAll(int index, Collection<? extends T> c) {
|
|
|
|
boolean result = false;
|
|
|
|
int delta = 0;
|
|
|
|
for (Object o : c) {
|
|
|
|
add(index + delta, (T) o);
|
|
|
|
result = true;
|
|
|
|
delta++;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
@Override
|
|
|
|
public boolean removeAll(Collection<?> c) {
|
|
|
|
boolean result = false;
|
|
|
|
for (Object o : c) {
|
|
|
|
result |= remove((T) o);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean retainAll(Collection<?> c) {
|
|
|
|
boolean result = false;
|
|
|
|
LongArrayList collectionHashes = new LongArrayList();
|
|
|
|
ObjectArrayList<Object> collection = new ObjectArrayList<>();
|
|
|
|
collection.addAll(c);
|
|
|
|
for (Object o : c) {
|
|
|
|
collectionHashes.add(db.calculateHash(o));
|
|
|
|
}
|
|
|
|
for (int i = 0; i < internalList.size(); i++) {
|
|
|
|
long hash = internalList.getLong(i);
|
|
|
|
int positionInCollection = collectionHashes.indexOf(hash);
|
|
|
|
if (positionInCollection == -1) {
|
|
|
|
remove(collection.get(positionInCollection));
|
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void clear() {
|
|
|
|
internalList.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Use getReference or getReadOnlyValue
|
|
|
|
*/
|
|
|
|
@Deprecated
|
|
|
|
@Override
|
|
|
|
public T get(int index) {
|
|
|
|
return getReadOnlyValue(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
public T getReadOnlyValue(int index) {
|
|
|
|
try {
|
2019-01-09 19:05:41 +01:00
|
|
|
return (T) db.get(internalList.getLong(index)).getValueReadOnlyUnsafe();
|
2018-12-20 00:16:16 +01:00
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public EntryReference<T> getReference(int index) {
|
|
|
|
try {
|
|
|
|
return db.get(internalList.getLong(index)).cast();
|
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
@Override
|
|
|
|
public T set(int index, T element) {
|
|
|
|
EntryReference<T> ref = addToDatabase(element);
|
|
|
|
long oldIndex = internalList.set(index, ref.getIndex());
|
|
|
|
try {
|
|
|
|
ref.close();
|
2019-01-09 19:05:41 +01:00
|
|
|
return ((EntryReference<T>) (db.get(oldIndex))).getValueReadOnlyUnsafe();
|
2018-12-20 00:16:16 +01:00
|
|
|
} catch (IOException e) {
|
|
|
|
throw (NullPointerException) new NullPointerException().initCause(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void add(int index, T element) {
|
|
|
|
EntryReference<T> ref = addToDatabase(element);
|
|
|
|
internalList.add(index, ref.getIndex());
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
@Override
|
|
|
|
public T remove(int index) {
|
|
|
|
long oldIndex = internalList.removeLong(index);
|
|
|
|
try {
|
2019-01-09 19:05:41 +01:00
|
|
|
return ((EntryReference<T>) (db.get(oldIndex))).getValueReadOnlyUnsafe();
|
2018-12-20 00:16:16 +01:00
|
|
|
} catch (IOException e) {
|
|
|
|
throw (NullPointerException) new NullPointerException().initCause(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int indexOf(Object o) {
|
|
|
|
EntryReference<?> ref = addToDatabase(o);
|
|
|
|
long objToRemoveHash = ref.calculateHash();
|
|
|
|
LongArrayList hashes = new LongArrayList();
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < hashes.size(); i++) {
|
|
|
|
long hash = hashes.getLong(i);
|
|
|
|
if (objToRemoveHash == hash) {
|
|
|
|
try {
|
|
|
|
if (ref.equals(db.get(internalList.getLong(i)))) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw (NullPointerException) new NullPointerException().initCause(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int indexOfEntry(EntryReference<T> ref) {
|
|
|
|
for (int i = 0; i < internalList.size(); i++) {
|
|
|
|
long index = internalList.getLong(i);
|
|
|
|
try {
|
|
|
|
EntryReference<?> ref2 = db.get(index);
|
2019-01-09 19:05:41 +01:00
|
|
|
if (ref.getValueReadOnlyUnsafe().equals(ref2.getValueReadOnlyUnsafe())) {
|
2018-12-20 00:16:16 +01:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw (NullPointerException) new NullPointerException().initCause(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void appendIndex(long elementIndex) {
|
|
|
|
internalList.add(elementIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int lastIndexOf(Object o) {
|
|
|
|
EntryReference<T> ref = addToDatabase(o).cast();
|
|
|
|
return lastIndexOfEntry(ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int lastIndexOfEntry(EntryReference<T> ref) {
|
|
|
|
long objToRemoveHash = ref.calculateHash();
|
|
|
|
|
|
|
|
int lastValue = -1;
|
|
|
|
|
|
|
|
for (int i = 0; i < internalList.size(); i++) {
|
|
|
|
long index2 = internalList.getLong(i);
|
|
|
|
try {
|
|
|
|
EntryReference<?> ref2 = db.get(index2);
|
|
|
|
if (objToRemoveHash == ref2.calculateHash()) {
|
2019-01-09 19:05:41 +01:00
|
|
|
if (ref.getValueReadOnlyUnsafe().equals(ref2.getValueReadOnlyUnsafe())) {
|
2018-12-20 00:16:16 +01:00
|
|
|
lastValue = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw (NullPointerException) new NullPointerException().initCause(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lastValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
@Override
|
|
|
|
public ListIterator<T> listIterator() {
|
|
|
|
// TODO: implement
|
|
|
|
throw new RuntimeException("Not implemented!");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
@Override
|
|
|
|
public ListIterator<T> listIterator(int index) {
|
|
|
|
// TODO: implement
|
|
|
|
throw new RuntimeException("Not implemented!");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
@Override
|
|
|
|
public List<T> subList(int fromIndex, int toIndex) {
|
|
|
|
// TODO: implement
|
|
|
|
throw new RuntimeException("Not implemented!");
|
|
|
|
}
|
|
|
|
|
|
|
|
private <U> EntryReference<U> addToDatabase(U obj) {
|
|
|
|
EntryReference<U> ref;
|
|
|
|
try {
|
|
|
|
ref = db.add(obj);
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw (NullPointerException) new NullPointerException().initCause(e);
|
|
|
|
}
|
|
|
|
return ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
|
|
|
final int prime = 31;
|
|
|
|
int result = 1;
|
|
|
|
result = prime * result + ((internalList == null) ? 0 : internalList.hashCode());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
@Override
|
|
|
|
public boolean removeIf(Predicate<? super T> filter) {
|
|
|
|
Objects.requireNonNull(filter);
|
|
|
|
boolean removed = false;
|
|
|
|
for (int i = 0; i < internalList.size(); ) {
|
|
|
|
T obj;
|
|
|
|
try {
|
2019-01-09 19:05:41 +01:00
|
|
|
obj = ((EntryReference<T>) (db.get(internalList.getLong(i)).cast())).getValueReadOnlyUnsafe();
|
2018-12-20 00:16:16 +01:00
|
|
|
} catch (IOException e) {
|
|
|
|
throw (NullPointerException) new NullPointerException().initCause(e);
|
|
|
|
}
|
|
|
|
if (filter.test(obj)) {
|
|
|
|
internalList.removeLong(i);
|
|
|
|
removed = true;
|
|
|
|
} else {
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return removed;
|
|
|
|
}
|
2018-12-21 10:03:30 +01:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "LightArrayList{" +
|
|
|
|
"internalList=" + internalList +
|
|
|
|
", db=" + db +
|
|
|
|
'}';
|
|
|
|
}
|
2018-12-20 00:16:16 +01:00
|
|
|
}
|