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;
/**
* Loops over each element of a collection, returning a new collection
* containing the values yielded by the loop body. In the loop body, read
* <em>each.value</em> to access the current elements, and write
* <em>each.yield</em> to yield elements.
*<P>
* Example:
*
* <PRE>
* Collect<String> query = Collect.from(words);
* for (Each<String> each : query) {
* each.yield = each.value.toUppercase();
* }
* result = query.resultAsList();
*</PRE>
*
* Or use the short form:
*
* <PRE>
* for (Each<String> each : Query.collect(words)) {
* each.yield = each.value.toUppercase();
* }
* result = Query.resultAsList();
*</PRE>
*
*
* @author akuhn
*
* @param <E>
*/
public class Collect<E> implements Iterable<Each<E>> {
public static <E> Collect<E> from(E... elements) {
return new Collect<E>(Arrays.asList(elements), elements.getClass().getComponentType());
}
public static <E> Collect<E> from(Iterable<E> elements) {
return new Collect<E>(elements, null);
}
private Class<?> type;
private Iter iter;
private Collect(Iterable<E> elements, Class<?> type) {
this.iter = new Iter(elements.iterator());
this.type = type;
}
public List<E> getResult() {
return iter.getResult();
}
@SuppressWarnings("unchecked")
public E[] getResultArray() {
List<E> result = getResult();
if (type == null) type = result.iterator().next().getClass();
return result.toArray((E[]) Array.newInstance(type, result.size()));
}
@SuppressWarnings("unchecked")
public E[] getResultArray(Class<? extends E> type) {
List<E> result = getResult();
return result.toArray((E[]) Array.newInstance(type, result.size()));
}
public Iterator<Each<E>> iterator() {
return iter.start();
}
private class Iter implements Iterator<Each<E>> {
private Each<E> each;
private Iterator<E> elements;
private int index = 0;
private List<E> result;
private State state;
private Iter(Iterator<E> elements) {
state = NULL;
this.elements = elements;
}
private List<E> 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 Each<E> next() {
if (!hasNext()) throw new NoSuchElementException();
each.yield = each.value = elements.next();
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 Each<E>();
result = new ArrayList<E>();
index = 0;
return this;
}
}
}