package ch.akuhn.util; import java.util.AbstractList; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; public class IteratorAsList<E> extends AbstractList<E> { private class Iter implements ListIterator<E> { private ListIterator<E> delegate; public Iter(int index) { delegate = list.listIterator(upTo(index)); } public void add(E e) { delegate.add(e); } public boolean hasNext() { return delegate.hasNext() || iter.hasNext(); } public boolean hasPrevious() { return delegate.hasPrevious(); } public E next() { if (delegate.hasNext()) return delegate.next(); E next = iter.next(); delegate.add(next); // step back and forth to enable subsequent #remove delegate.previous(); return delegate.next(); } public int nextIndex() { return delegate.nextIndex(); } public E previous() { return delegate.previous(); } public int previousIndex() { return delegate.previousIndex(); } public void remove() { delegate.remove(); } public void set(E e) { delegate.set(e); } } @SuppressWarnings("unchecked") private static final Iterator NULL = new Iterator() { public boolean hasNext() { return false; } public Object next() { throw new NoSuchElementException(); } public void remove() { throw new IllegalStateException(); } }; private Iterator<E> iter; private ArrayList<E> list; public IteratorAsList(Iterable<E> iter) { this(iter.iterator()); } public IteratorAsList(Iterator<E> iter) { this.iter = iter; this.list = new ArrayList<E>(); } @SuppressWarnings("unchecked") public void clear() { list.clear(); iter = (Iterator<E>) NULL; } public E get(int index) { return list.get(upTo(index)); } public boolean isEmpty() { return list.size() == 0 && !iter.hasNext(); } public Iterator<E> iterator() { return listIterator(); } public ListIterator<E> listIterator() { return listIterator(0); } public ListIterator<E> listIterator(int index) { upTo(index == 0 ? 0 : index - 1); return iter.hasNext() ? new Iter(index) : super.listIterator(index); } public E remove(int index) { return list.remove(upTo(index)); } public E set(int index, E element) { return list.set(upTo(index), element); } /** Return the number of elements read so far from the backing iterator. * * @return the number of elements read so far from the backing iterator. * @see #upTo(int) * @see #upToEnd() */ public int size() { return list.size(); } public List<E> subList(int fromIndex, int toIndex) { if (fromIndex > toIndex) throw new IllegalArgumentException(); return super.subList(upTo(fromIndex), upTo(toIndex - 1) + 1); } /** Read elements from the backing iterator, up to and including the specified position. * * @param index of the specified position * @return the specified position * @throws IndexOutOfBoundsException if the index is out of range * (<tt>index < 0 || index >= upToEnd()</tt>) * @see #size() * @see #upToEnd() */ public int upTo(int index) { if (index < 0) throw new IndexOutOfBoundsException(); if (index < list.size()) return index; while (list.size() <= index) { if (!iter.hasNext()) throw new IndexOutOfBoundsException(); list.add(iter.next()); } return index; }; /** Read all remaining elements from the backing iterator. * * @return the total number of elements in this list. * @see #size() * @see #upTo(int) */ public int upToEnd() { while (iter.hasNext()) list.add(iter.next()); return size(); } @Override public int lastIndexOf(Object o) { upToEnd(); // super uses #size, must not stay lazy! return super.lastIndexOf(o); } @Override public String toString() { if (isEmpty()) return "[]"; upTo(0); String str = list.toString(); if (iter.hasNext()) str = str.substring(0, str.length() - 1) + ", ...]"; return str; } }