package denominator.common;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* adapted from guava's {@code com.google.common.collect.AbstractIterator}.
*/
public abstract class PeekingIterator<T> implements Iterator<T> {
private PeekingIterator.State state = State.NOT_READY;
private T next;
/**
* Constructor for use by subclasses.
*/
protected PeekingIterator() {
}
protected abstract T computeNext();
protected final T endOfData() {
state = State.DONE;
return null;
}
@Override
public final boolean hasNext() {
switch (state) {
case DONE:
return false;
case READY:
return true;
default:
}
return tryToComputeNext();
}
private boolean tryToComputeNext() {
next = computeNext();
if (state != State.DONE) {
state = State.READY;
return true;
}
return false;
}
@Override
public final T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
state = State.NOT_READY;
return next;
}
public T peek() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return next;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
private enum State {
/**
* We have computed the next element and haven't returned it yet.
*/
READY,
/**
* We haven't yet computed or have already returned the element.
*/
NOT_READY,
/**
* We have reached the end of the data and are finished.
*/
DONE,
}
}