package org.andork.collect; import java.lang.ref.WeakReference; import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; /** * A {@link Collection} that weakly references its elements; they will cease to * belong to the collection once the garbage collector determines that there are * no more strong references to its elements. Iterators are guaranteed to return * the elements in the order they were added. * * @author Andy * * @param <E> * the element type */ public class WeakOrderedCollection<E> extends AbstractCollection<E> { private class ExpungingIterator implements Iterator<E> { Iterator<WeakReference<E>> refIter = refs.iterator(); E lastReturned; E nextElement; @Override public boolean hasNext() { while (nextElement == null) { if (!refIter.hasNext()) { return false; } nextElement = refIter.next().get(); if (nextElement == null) { refIter.remove(); } } return true; } @Override public E next() { if (nextElement == null && !hasNext()) { throw new NoSuchElementException(); } lastReturned = nextElement; nextElement = null; return lastReturned; } @Override public void remove() { if (lastReturned == null) { throw new IllegalStateException(); } refIter.remove(); lastReturned = null; } } public static <E> WeakOrderedCollection<E> newArrayCollection() { return new WeakOrderedCollection<>(new ArrayList<>()); } public static <E> WeakOrderedCollection<E> newLinkedCollection() { return new WeakOrderedCollection<>(new LinkedList<>()); } private List<WeakReference<E>> refs; /** * @param refs * the backing {@link List}. It should be empty, modifiable, and * not be modified by anything by this * {@code WeakOrderedCollection}. */ public WeakOrderedCollection(List<WeakReference<E>> refs) { this.refs = refs; } @Override public boolean add(E e) { return refs.add(new WeakReference<E>(e)); } private void expungeStaleElements() { // the iterator will take care of expungement for (@SuppressWarnings("unused") Object o : this) { ; } } @Override public Iterator<E> iterator() { return new ExpungingIterator(); } @Override public int size() { expungeStaleElements(); return refs.size(); } }