package org.warp.jcwdb; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.io.IOException; import java.util.*; import java.util.function.Consumer; import java.util.function.Predicate; public class LightArrayList implements LightList { 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 ref = null; try { ref = db.get(element); if (o.equals(ref.getValueReadOnly())) { return true; } } catch (IOException e) { e.printStackTrace(); } } } return false; } /** * Use iteratorReferences() */ @Deprecated @SuppressWarnings("unchecked") @Override public Iterator iterator() { System.out.println("WARNING! YOU ARE USING iterator()! PLEASE USE ITERATORREFERENCES TO AVOID OUTOFMEMORY!"); final ArrayList elements = new ArrayList<>(); for (long element : internalList) { try { elements.add((T) db.get(element).getValueReadOnly()); } catch (IOException e) { e.printStackTrace(); } } return elements.iterator(); } @SuppressWarnings("unchecked") @Override public Iterator> iteratorReferences() { final ArrayList> 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 action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } @Override public void forEachReference(Consumer> action) { Objects.requireNonNull(action); for (long index : this.internalList) { try { action.accept(db.get(index)); } catch (IOException e) { throw (RuntimeException) new RuntimeException().initCause(e); } } } @SuppressWarnings("unchecked") @Override public T[] toArray() { final T[] elements = (T[]) new Objects[internalList.size()]; for (int i = 0; i < elements.length; i++) { try { elements[i] = (T) db.get(internalList.getLong(i)).getValueReadOnly(); } catch (IOException e) { e.printStackTrace(); } } return elements; } @SuppressWarnings("unchecked") @Override public T1[] toArray(T1[] a) { final T1[] elements = (T1[]) new Objects[internalList.size()]; for (int i = 0; i < elements.length; i++) { try { elements[i] = (T1) db.get(internalList.getLong(i)).getValueReadOnly(); } catch (IOException e) { e.printStackTrace(); } } return elements; } @Override public boolean add(T o) { EntryReference ref = addEntry(o); return ref != null; } @Override public EntryReference addEntry(T o) { EntryReference 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 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 c) { boolean result = false; for (Object o : c) { result |= add((T) o); } return result; } @SuppressWarnings("unchecked") @Override public boolean addAll(int index, Collection 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 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 { return (T) db.get(internalList.getLong(index)).getValueReadOnly(); } catch (IOException e) { e.printStackTrace(); return null; } } @Override public EntryReference 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 ref = addToDatabase(element); long oldIndex = internalList.set(index, ref.getIndex()); try { ref.close(); return ((EntryReference) (db.get(oldIndex))).getValueReadOnly(); } catch (IOException e) { throw (NullPointerException) new NullPointerException().initCause(e); } } @Override public void add(int index, T element) { EntryReference ref = addToDatabase(element); internalList.add(index, ref.getIndex()); } @SuppressWarnings("unchecked") @Override public T remove(int index) { long oldIndex = internalList.removeLong(index); try { return ((EntryReference) (db.get(oldIndex))).getValueReadOnly(); } 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 ref) { for (int i = 0; i < internalList.size(); i++) { long index = internalList.getLong(i); try { EntryReference ref2 = db.get(index); if (ref.getValueReadOnly().equals(ref2.getValueReadOnly())) { 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 ref = addToDatabase(o).cast(); return lastIndexOfEntry(ref); } @Override public int lastIndexOfEntry(EntryReference 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()) { if (ref.getValueReadOnly().equals(ref2.getValueReadOnly())) { lastValue = i; } } } catch (IOException e) { throw (NullPointerException) new NullPointerException().initCause(e); } } return lastValue; } @Deprecated @Override public ListIterator listIterator() { // TODO: implement throw new RuntimeException("Not implemented!"); } @Deprecated @Override public ListIterator listIterator(int index) { // TODO: implement throw new RuntimeException("Not implemented!"); } @Deprecated @Override public List subList(int fromIndex, int toIndex) { // TODO: implement throw new RuntimeException("Not implemented!"); } private EntryReference addToDatabase(U obj) { EntryReference 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 filter) { Objects.requireNonNull(filter); boolean removed = false; for (int i = 0; i < internalList.size(); ) { T obj; try { obj = ((EntryReference) (db.get(internalList.getLong(i)).cast())).getValueReadOnly(); } catch (IOException e) { throw (NullPointerException) new NullPointerException().initCause(e); } if (filter.test(obj)) { internalList.removeLong(i); removed = true; } else { i++; } } return removed; } }