package ch.akuhn.foreach; import static ch.akuhn.foreach.State.NULL; import static ch.akuhn.foreach.State.VOID; import static ch.akuhn.foreach.State.YIELD; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; public class CollectAs<E,R> implements Iterable<EachAs<E,R>> { public static <E,R> CollectAs<E,R> from(Class<R> returnType, E... elements) { return new CollectAs<E,R>(Arrays.asList(elements), returnType); } public static <E,R> CollectAs<E,R> from(Class<R> returnType, Iterable<E> elements) { return new CollectAs<E,R>(elements, returnType); } private Class<?> type; private Iter iter; private CollectAs(Iterable<E> elements, Class<R> type) { this.iter = new Iter(elements.iterator()); this.type = type; } public List<R> getResult() { return iter.getResult(); } @SuppressWarnings("unchecked") public R[] getResultArray() { List<R> result = getResult(); return result.toArray((R[]) Array.newInstance(type, result.size())); } public Iterator<EachAs<E,R>> iterator() { return iter.start(); } private class Iter implements Iterator<EachAs<E,R>> { private EachAs<E,R> each; private Iterator<E> elements; private int index = 0; private List<R> result; private State state; private Iter(Iterator<E> elements) { state = NULL; this.elements = elements; } private List<R> getResult() { if (state == YIELD) hasNext(); return result; } public boolean hasNext() { if (state == YIELD) { result.add(each.yield); state = VOID; } if (elements.hasNext()) return true; elements = null; return false; } public EachAs<E,R> next() { if (!hasNext()) throw new NoSuchElementException(); each.value = elements.next(); each.yield = null; each.index = index++; state = YIELD; return each; } public void remove() { throw new UnsupportedOperationException(); } private Iter start() { if (state != NULL) throw new IllegalStateException("Cannot run query twice!"); state = VOID; each = new EachAs<E,R>(); result = new ArrayList<R>(); index = 0; return this; } } }