package com.googlecode.totallylazy;
import com.googlecode.totallylazy.collections.PersistentList;
import com.googlecode.totallylazy.functions.Callables;
import com.googlecode.totallylazy.functions.Curried2;
import com.googlecode.totallylazy.functions.Function1;
import com.googlecode.totallylazy.functions.Function2;
import com.googlecode.totallylazy.iterators.*;
import com.googlecode.totallylazy.predicates.LogicalPredicate;
import com.googlecode.totallylazy.predicates.Predicate;
import com.googlecode.totallylazy.predicates.Predicates;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.concurrent.Callable;
import static com.googlecode.totallylazy.Appendables.append;
import static com.googlecode.totallylazy.functions.Callables.nullGuard;
import static com.googlecode.totallylazy.functions.Callables.returns;
import static com.googlecode.totallylazy.Callers.call;
import static com.googlecode.totallylazy.functions.Functions.function;
import static com.googlecode.totallylazy.Option.none;
import static com.googlecode.totallylazy.Option.some;
import static com.googlecode.totallylazy.Pair.pair;
import static com.googlecode.totallylazy.predicates.Predicates.in;
import static com.googlecode.totallylazy.predicates.Predicates.instanceOf;
import static com.googlecode.totallylazy.predicates.Predicates.is;
import static com.googlecode.totallylazy.predicates.Predicates.not;
import static com.googlecode.totallylazy.predicates.Predicates.onlyOnce;
import static com.googlecode.totallylazy.predicates.Predicates.whileTrue;
import static com.googlecode.totallylazy.Sequences.one;
import static com.googlecode.totallylazy.Sequences.sequence;
import static com.googlecode.totallylazy.Unchecked.cast;
import static com.googlecode.totallylazy.numbers.Numbers.increment;
public class Iterators {
public static boolean equalsTo(Iterator<?> a, Iterator<?> b) {
while (a.hasNext() && b.hasNext()) {
Object aValue = a.next();
Object bValue = b.next();
if (aValue == bValue) {
continue;
}
if (aValue == null || !aValue.equals(bValue)) {
return false;
}
}
return !(a.hasNext() || b.hasNext());
}
public static <T> boolean equalsTo(Iterator<? extends T> a, Iterator<? extends T> b, Predicate<? super Pair<T, T>> predicate) {
while (a.hasNext() && b.hasNext()) {
if (!predicate.matches(pair(a.next(), b.next()))) return false;
}
return !(a.hasNext() || b.hasNext());
}
public static <T> void each(final Iterator<? extends T> iterator, final Function1<? super T, ?> runnable) {
while (iterator.hasNext()) {
Callers.call(runnable, iterator.next());
}
}
public static <T, S> Iterator<S> map(final Iterator<? extends T> iterator, final Function1<? super T, ? extends S> callable) {
return new MapIterator<T, S>(iterator, callable);
}
public static <T, S> Iterator<S> flatMap(final Iterator<? extends T> iterator, final Function1<? super T, ? extends Iterable<? extends S>> callable) {
return flattenIterable(map(iterator, callable));
}
public static <T> Iterator<T> filter(final Iterator<? extends T> iterator, final Predicate<? super T> predicate) {
return new FilterIterator<T>(iterator, predicate);
}
public static <T> Iterator<T> reject(final Iterator<? extends T> iterator, final Predicate<? super T> predicate) {
return filter(iterator, not(predicate));
}
public static <T> Iterator<T> iterate(final Function1<? super T, ? extends T> callable, final T t) {
return new IterateIterator<T>(nullGuard(callable), t);
}
public static <T> T head(final Iterator<? extends T> iterator) {
if (iterator.hasNext()) {
return iterator.next();
}
throw new NoSuchElementException();
}
public static <T> Option<T> headOption(final Iterator<? extends T> iterator) {
return iterator.hasNext() ? some(iterator.next()) : Option.<T>none();
}
public static <T> T last(final Iterator<? extends T> iterator) {
return head(reverse(iterator));
}
public static <T> Option<T> lastOption(final Iterator<? extends T> iterator) {
return headOption(reverse(iterator));
}
public static <T> Iterator<T> tail(final Iterator<? extends T> iterator) {
if (iterator.hasNext()) {
iterator.next();
return new PeekingIterator<T>(iterator);
}
throw new NoSuchElementException();
}
public static <T> Iterator<T> init(final Iterator<? extends T> iterator) {
return new InitIterator<T>(iterator);
}
public static <T, S> S fold(final Iterator<? extends T> iterator, final S seed, final Function2<? super S, ? super T, ? extends S> callable) {
return foldLeft(iterator, seed, callable);
}
public static <T, S> S foldLeft(final Iterator<? extends T> iterator, final S seed, final Function2<? super S, ? super T, ? extends S> callable) {
S accumulator = seed;
while (iterator.hasNext()) {
accumulator = call(callable, accumulator, iterator.next());
}
return accumulator;
}
public static <T, S> Iterator<S> scanLeft(final Iterator<? extends T> iterator, final S seed, final Function2<? super S, ? super T, ? extends S> callable) {
return new StatefulIterator<S>() {{push(seed);}
@Override
protected S getNext() throws Exception {
if(iterator.hasNext()){
return callable.call(current, iterator.next());
}
return finished();
}
};
}
public static <T, S> S foldRight(final Iterator<? extends T> iterator, final S seed, final Function2<? super T, ? super S, ? extends S> callable) {
Iterator<T> reversed = reverse(iterator);
S accumilator = seed;
while (reversed.hasNext()) {
accumilator = call(callable, reversed.next(), accumilator);
}
return accumilator;
}
public static <T> Iterator<T> reverse(Iterator<? extends T> iterator) {
return PersistentList.constructors.reverse(iterator).iterator();
}
public static <T, S> S foldRight(final Iterator<? extends T> iterator, final S seed, final Function1<? super Pair<T, S>, ? extends S> callable) {
if (!iterator.hasNext()) return seed;
return Callers.call(callable, pair(returns(head(iterator)), () -> {
S next = foldRight(iterator, seed, callable);
return next;
}));
}
public static <T, S> S reduce(final Iterator<? extends T> iterator, final Function2<? super S, ? super T, ? extends S> callable) {
return reduceLeft(iterator, callable);
}
public static <T, S> S reduceLeft(final Iterator<? extends T> iterator, final Function2<? super S, ? super T, ? extends S> callable) {
return foldLeft(iterator, seed(iterator, callable), callable);
}
private static <T, S> S seed(Iterator<? extends T> iterator, Object callable) {
if (callable instanceof Identity) return Unchecked.<Identity<S>>cast(callable).identity();
return Unchecked.<S>cast(iterator.next());
}
public static <T, S> S reduceRight(final Iterator<? extends T> iterator, final Function2<? super T, ? super S, ? extends S> callable) {
Iterator<T> reversed = reverse(iterator);
S accumulator = seed(reversed, callable);
while (reversed.hasNext()) {
accumulator = Callers.call(callable, reversed.next(), accumulator);
}
return accumulator;
}
public static <T, S> S reduceRight(final Iterator<? extends T> raw, final Function1<? super Pair<T, S>, ? extends S> callable){
Iterator<? extends T> iterator = addSeed(raw, callable);
return internalReduceRight(iterator, callable);
}
public static <T, S> S internalReduceRight(final Iterator<? extends T> iterator, final Function1<? super Pair<T, S>, ? extends S> callable) {
T head = iterator.next();
if(!iterator.hasNext()) return cast(head);
return Callers.call(callable, pair(() -> head, () -> internalReduceRight(iterator, callable)));
}
private static <T> Iterator<T> addSeed(Iterator<T> iterator, final Object callable) {
if(callable instanceof Identity) return add(iterator, Unchecked.<Identity<T>>cast(callable).identity());
return iterator;
}
public static String toString(final Iterator<?> iterator, final String separator) {
return toString(iterator, "", separator, "");
}
public static String toString(final Iterator<?> iterator, final String start, final String separator, final String end) {
return appendTo(iterator, new StringBuilder(), start, separator, end).toString();
}
public static <A extends Appendable> A appendTo(Iterator<?> iterator, A appendable) {
return appendTo(iterator, appendable, ",");
}
public static <A extends Appendable> A appendTo(Iterator<?> iterator, A appendable, String separator) {
return appendTo(iterator, appendable, "", separator, "");
}
public static <A extends Appendable> A appendTo(Iterator<?> iterator, A appendable, String start, String separator, String end) {
append(start, appendable);
if (iterator.hasNext()) append(String.valueOf(iterator.next()), appendable);
while (iterator.hasNext()) {
append(separator, appendable); // Do not single line as causes weird BUG with StringBuilder
append(String.valueOf(iterator.next()), appendable);
}
return append(end, appendable);
}
public static <T> List<T> toList(final Iterator<? extends T> iterator) {
final List<T> result = new ArrayList<T>();
while (iterator.hasNext()) {
result.add(iterator.next());
}
return result;
}
public static <T> Deque<T> toDeque(final Iterator<? extends T> iterator) {
final Deque<T> result = new ArrayDeque<T>();
while (iterator.hasNext()) {
result.add(iterator.next());
}
return result;
}
public static <T> Iterator<T> repeat(final Callable<? extends T> callable) {
return new RepeatIterator<T>(callable);
}
public static <T> Iterator<T> repeat(final T item) {
return new RepeatIterator<T>(returns(item));
}
public static Iterator<Number> range(final Number start) {
return iterate(increment, start);
}
public static Iterator<Number> range(final Number start, final Number end) {
return new RangerIterator(start, end);
}
public static Iterator<Number> range(final Number start, final Number end, final Number step) {
return new RangerIterator(start, end, step);
}
public static <T> Iterator<T> remove(final Iterator<? extends T> iterator, final T t) {
return filter(iterator, not(onlyOnce(is(t))));
}
public static <T> Iterator<T> removeAll(final Iterator<? extends T> iterator, final Iterable<? extends T> remove) {
return filter(iterator, not(in(remove)));
}
public static <T> Iterator<T> take(final Iterator<? extends T> iterator, final int count) {
return new TakeIterator<>(iterator, count);
}
public static <T> Iterator<T> takeWhile(final Iterator<? extends T> iterator, final Predicate<? super T> predicate) {
return new TakeWhileIterator<T>(iterator, predicate);
}
public static <T> Iterator<T> drop(final Iterator<? extends T> iterator, final int count) {
return dropWhile(iterator, Predicates.countTo(count));
}
public static <T> Iterator<T> dropWhile(final Iterator<? extends T> iterator, final Predicate<? super T> predicate) {
return filter(iterator, not(whileTrue(predicate)));
}
public static <T> boolean forAll(final Iterator<? extends T> iterator, final Predicate<? super T> predicate) {
while (iterator.hasNext()) {
if (!predicate.matches(iterator.next())) {
return false;
}
}
return true;
}
public static <T> boolean contains(final Iterator<? extends T> iterator, final T t) {
return exists(iterator, is(t));
}
public static <T> boolean exists(final Iterator<? extends T> iterator, final Predicate<? super T> predicate) {
while (iterator.hasNext()) {
boolean result = predicate.matches(iterator.next());
if (result) {
return true;
}
}
return false;
}
public static <T> Option<T> find(final Iterator<? extends T> iterator, final Predicate<? super T> predicate) {
while (iterator.hasNext()) {
T item = iterator.next();
boolean result = predicate.matches(item);
if (result) {
return some(item);
}
}
return none();
}
public static <T, S> Option<S> tryPick(final Iterator<? extends T> iterator, final Function1<? super T, ? extends Option<? extends S>> callable) {
while (iterator.hasNext()) {
T item = iterator.next();
Option<S> result = Unchecked.cast(call(callable, item));
if (!result.isEmpty()) {
return result;
}
}
return none();
}
public static <T, S> S pick(final Iterator<? extends T> iterator, final Function1<? super T, ? extends Option<? extends S>> callable) {
return tryPick(iterator, callable).get();
}
public static <T> Iterator<T> add(final Iterator<? extends T> iterator, final T t) {
return join(iterator, one(t).iterator());
}
public static <T> Iterator<T> join(final Iterator<? extends T> first, final Iterator<? extends T> second) {
return join(sequence(first, second));
}
public static <T> Iterator<T> join(final Iterator<? extends T> first, final Iterator<? extends T> second, final Iterator<? extends T> third) {
return join(sequence(first, second, third));
}
public static <T> Iterator<T> join(final Iterator<? extends T> first, final Iterator<? extends T> second, final Iterator<? extends T> third, final Iterator<? extends T> fourth) {
return join(sequence(first, second, third, fourth));
}
public static <T> Iterator<T> join(final Iterator<? extends T> first, final Iterator<? extends T> second, final Iterator<? extends T> third, final Iterator<? extends T> fourth, final Iterator<? extends T> fifth) {
return join(sequence(first, second, third, fourth, fifth));
}
@SafeVarargs
public static <T> Iterator<T> join(final Iterator<? extends T>... iterators) {
return join(sequence(iterators));
}
public static <T> Iterator<T> join(final Iterable<? extends Iterator<? extends T>> iterable) {
return flatten(iterable.iterator());
}
public static <T> Iterator<T> cons(final T t, final Iterator<? extends T> iterator) {
return join(one(t).iterator(), iterator);
}
public static <T, S> Iterator<S> safeCast(final Iterator<? extends T> iterator, final Class<? extends S> aClass) {
return map(filter(iterator, instanceOf(aClass)), Callables.cast(aClass));
}
public static <T, S> Iterator<S> unsafeCast(final Iterator<? extends T> iterator) {
return map(iterator, Callables.<T, S>cast());
}
public static <T> int size(final Iterator<? extends T> iterator) {
int count = 0;
while (iterator.hasNext()) {
iterator.next();
count++;
}
return count;
}
public static <T> Number number(final Iterator<? extends T> iterator) {
Number count = 0;
while (iterator.hasNext()) {
iterator.next();
count = increment(count);
}
return count;
}
public static <T> Pair<Sequence<T>, Sequence<T>> partition(final Iterator<? extends T> iterator, final Predicate<? super T> predicate) {
final Queue<T> matchedQueue = new ArrayDeque<T>();
final Queue<T> unmatchedUnmatched = new ArrayDeque<T>();
return pair(Sequences.memorise(new PartitionIterator<T>(iterator, predicate, matchedQueue, unmatchedUnmatched)),
Sequences.memorise(new PartitionIterator<T>(iterator, Predicates.<T>not(predicate), unmatchedUnmatched, matchedQueue)));
}
public static <T> Pair<Sequence<T>, Sequence<T>> splitAt(final Iterator<? extends T> iterator, final Number index) {
return partition(iterator, Predicates.countTo(index));
}
public static <T> Pair<Sequence<T>, Sequence<T>> splitWhen(final Iterator<? extends T> iterator, final Predicate<? super T> predicate) {
Pair<Sequence<T>, Sequence<T>> partition = breakOn(iterator, predicate);
return pair(partition.first(), partition.second().isEmpty() ? Sequences.<T>empty() : partition.second().tail());
}
public static <T> Pair<Sequence<T>, Sequence<T>> splitOn(final Iterator<? extends T> iterator, final T instance) {
return splitWhen(iterator, is(instance));
}
public static <T> Pair<Sequence<T>, Sequence<T>> span(final Iterator<? extends T> iterator, final Predicate<? super T> predicate) {
return partition(iterator, whileTrue(predicate));
}
public static <T> Pair<Sequence<T>, Sequence<T>> breakOn(final Iterator<? extends T> iterator, final Predicate<? super T> predicate) {
return partition(iterator, whileTrue(Predicates.<T>not(predicate)));
}
public static <T, Key> Sequence<Group<Key, T>> groupBy(final Iterator<? extends T> iterator, final Function1<? super T, ? extends Key> callable) {
return Maps.entries(Maps.multiMap(iterator, callable)).map(entry -> new Group<Key, T>(entry.getKey(), entry.getValue()));
}
public static <T> Iterator<Sequence<T>> windowed(final Iterator<? extends T> iterator, final int size) {
return new WindowedIterator<T>(iterator, size);
}
public static <T> Iterator<Sequence<T>> windowed(final Iterator<? extends T> iterator, final int step, final int size) {
return new WindowedIterator<T>(iterator, step, size);
}
public static <T> LogicalPredicate<Iterator<T>> hasNext() {
return new LogicalPredicate<Iterator<T>>() {
public boolean matches(Iterator<T> iterator) {
return iterator.hasNext();
}
};
}
public static <T> Function1<Iterator<T>, T> next() {
return Iterator::next;
}
public static <T> Iterator<T> flatten(final Iterator<? extends Iterator<? extends T>> iterator) {
return new FlattenIterator<T>(iterator);
}
public static <T> Iterator<T> flattenIterable(final Iterator<? extends Iterable<? extends T>> iterator) {
Iterator<Iterable<T>> noWildCards = unsafeCast(iterator);
return flatten(map(noWildCards, Callables.<T>asIterator()));
}
public static <T> Iterator<T> interruptable(final Iterator<? extends T> iterator) {
return map(iterator, Callables.<T>returnArgument().interruptable());
}
public static <A, B> Iterator<A> unfoldRight(Function1<? super B, ? extends Option<? extends Pair<? extends A, ? extends B>>> callable, B seed) {
return new UnfoldRightIterator<A, B>(callable, seed);
}
public static <T, C extends Segment<T>> C joinTo(Iterator<? extends T> iterator, C rest) {
while (iterator.hasNext()) {
rest = cast(rest.cons(iterator.next()));
}
return rest;
}
public static <T> T index(Iterator<? extends T> iterator, int index) {
for (int i = 0; iterator.hasNext(); i++) {
T next = iterator.next();
if (i == index) return next;
}
throw new IndexOutOfBoundsException();
}
public static <T> int indexOf(Iterator<? extends T> iterator, T instance) {
for (int i = 0; iterator.hasNext(); i++) {
T next = iterator.next();
if (instance.equals(next)) return i;
}
return -1;
}
public static <T> Iterator<T> tap(final Iterator<? extends T> iterator, final Function1<? super T, ?> callable) {
return new ReadOnlyIterator<T>(){
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public T next() {
T next = iterator.next();
call(callable, next);
return next;
}
};
}
public static class functions {
public static <T> Curried2<Iterable<? extends T>, Iterable<? extends T>, Iterable<T>> join() {
return (a, b) -> new Sequence<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.join(a.iterator(), b.iterator());
}
};
}
}
}