package au.id.zancanaro.javacheck; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.function.Function; import java.util.function.Predicate; public final class Iterators { private Iterators() { } public static RangeIterator rangeIterator(int countTo, Function fn) { return new RangeIterator<>(countTo, fn); } private static class RangeIterator implements Iterator { private final Function action; private final int countTo; private int index = 0; public RangeIterator(int countTo, Function action) { this.countTo = countTo; this.action = action; } @Override public boolean hasNext() { return index < countTo; } @Override public T next() { return action.apply(index++); } } public static FlattenIterator flatten(Iterator> iterators) { return new FlattenIterator<>(iterators); } public static class FlattenIterator implements Iterator { private final Iterator> iterators; private Iterator current; public FlattenIterator(Iterator> iterators) { this.current = Iterators.emptyIterator(); this.iterators = iterators; } private Iterator getCurrent() { while (!current.hasNext() && iterators.hasNext()) { current = iterators.next(); } return current; } @Override public boolean hasNext() { return getCurrent().hasNext(); } @Override public T next() { return getCurrent().next(); } } public static ConcatIterator concat(Iterator left, Iterator right) { return new ConcatIterator<>(left, right); } public static class ConcatIterator implements Iterator { private final Iterator left; private final Iterator right; public ConcatIterator(Iterator left, Iterator right) { this.left = left; this.right = right; } @Override public boolean hasNext() { return left.hasNext() || right.hasNext(); } @Override public T next() { if (left.hasNext()) { return left.next(); } else { return right.next(); } } } @SuppressWarnings("WeakerAccess") public static EmptyIterator emptyIterator() { return new EmptyIterator<>(); } public static class EmptyIterator implements Iterator { @Override public boolean hasNext() { return false; } @Override public T next() { throw new NoSuchElementException("Empty iterators contain no elements"); } } public static MappingIterator mappingIterator(Function f, Iterator iterator) { return new MappingIterator<>(f, iterator); } private static class MappingIterator implements Iterator { private final Function mapping; private final Iterator iterator; public MappingIterator(Function mapping, Iterator iterator) { this.mapping = mapping; this.iterator = iterator; } @Override public boolean hasNext() { return iterator.hasNext(); } @Override public R next() { return mapping.apply(iterator.next()); } } public static FilteringIterator filteringIterator(Predicate predicate, Iterator iterator) { return new FilteringIterator<>(predicate, iterator); } private static class FilteringIterator implements Iterator { private final Predicate predicate; private final Iterator iterator; private List nextValue; public FilteringIterator(Predicate predicate, Iterator iterator) { this.predicate = predicate; this.iterator = iterator; this.nextValue = null; } private void populateNext() { while (nextValue == null && iterator.hasNext()) { T value = iterator.next(); if (predicate.test(value)) { nextValue = Collections.singletonList(value); } else { nextValue = null; } } } @Override public boolean hasNext() { populateNext(); return nextValue != null; } @Override public T next() { populateNext(); T result = nextValue.get(0); nextValue = null; return result; } } }