package xapi.util.impl;
import xapi.util.api.ProvidesValue;
import java.util.Iterator;
/**
* @author James X. Nelson (james@wetheinter.net)
* Created on 2/6/16.
*/
public class ReverseIterator <T> implements Iterator<T> {
private static final ProvidesValue END/* http://goo.gl/W2Slg6 */ = () -> {
assert false : "You should never attempt to get a value from the end provider";
return null;
};
private ProvidesValue<T> supplier;
private Iterable<T> iterable;
private final Iterator<T> original;
public ReverseIterator(Iterator<T> forward) {
this.original = forward;
supplier = consume(END, forward, 0);
}
public ReverseIterator(Iterable<T> forward) {
this(forward.iterator());
this.iterable = forward;
}
private ProvidesValue<T> consume(final ProvidesValue<T> before, Iterator<T> forward, int count) {
// yes, we are using recursion to form our stack (using call stack instead of stack object).
assert count < 1024 * 1024 * 2 : "You are using a ReverseIterator on an iterable containing 2^21 objects; this iterator, " + forward + " either never runs out, " +
"or you are using very large collections recklessly.";
if (forward.hasNext()) {
final T value = forward.next();
final ProvidesValue<T> here = () ->{
supplier = before;
return value;
};
return consume(here, forward, count+1); // will return the deepest node
} else {
// terminal; this deepest node should be the first provided value.
// our before value is the last item in the iterator, and will be the first one we supply
return before;
}
}
@Override
public boolean hasNext() {
return supplier != END;
}
@Override
public T next() {
return supplier.get();
}
public Iterator<T> getOriginal() {
return original;
}
public Iterable<T> getIterable() {
return iterable;
}
}