package org.zwobble.couscous.util; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; import com.google.common.collect.PeekingIterator; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; import java.util.stream.StreamSupport; import static org.zwobble.couscous.util.ExtraLists.list; public class ExtraIterables { private ExtraIterables() {} public static void forEach(Iterable first, Iterable second, Action2 action) { Iterator firstIterator = first.iterator(); Iterator secondIterator = second.iterator(); while (firstIterator.hasNext()) { action.run(firstIterator.next(), secondIterator.next()); } if (secondIterator.hasNext()) { throw new RuntimeException("Iterables not of same length"); } } public static Iterable lazyMap(Iterable iterable1, Iterable iterable2, BiFunction function) { return new Iterable() { @Override public Iterator iterator() { Iterator iterator1 = iterable1.iterator(); Iterator iterator2 = iterable2.iterator(); return map(iterator1, iterator2, function); } }; } private static Iterator map(Iterator iterator1, Iterator iterator2, BiFunction function) { return new Iterator() { @Override public boolean hasNext() { return iterator1.hasNext() && iterator2.hasNext(); } @Override public R next() { return function.apply(iterator1.next(), iterator2.next()); } }; } public static Iterable cast(Class type, Iterable iterable) { return new Iterable() { @Override public Iterator iterator() { return cast(type, iterable.iterator()); } }; } private static Iterator cast(Class type, Iterator iterator) { return new Iterator() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public T next() { Object next = iterator.next(); if (type.isInstance(next)) { return (T) next; } else { throw new ClassCastException(); } } }; } public static Iterable lazyAppend(Iterable head, T tail) { return Iterables.concat(head, list(tail)); } public static Iterable lazyCons(T head, Iterable tails) { return Iterables.concat(list(head), tails); } public static Iterable lazyFilter(Iterable iterable, java.util.function.Predicate predicate) { return new Iterable() { @Override public Iterator iterator() { return stream(iterable).filter(predicate).iterator(); } }; } public static Optional find(Iterable iterable, Predicate predicate) { for (T element : iterable) { if (predicate.test(element)) { return Optional.of(element); } } return Optional.empty(); } public static Iterable lazyMap(Iterable iterable, Function function) { return new Iterable() { @Override public Iterator iterator() { return map(iterable.iterator(), function); } }; } private static Iterator map(Iterator iterator, Function function) { return new Iterator() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public R next() { return function.apply(iterator.next()); } }; } public static Iterable lazyFlatMap(Iterable iterable, Function> function) { return iterable(() -> stream(iterable).flatMap(element -> stream(function.apply(element)))); } public static Stream stream(Iterable iterable) { return StreamSupport.stream(iterable.spliterator(), false); } public static Iterable iterable(Supplier> stream) { return new Iterable() { @Override public Iterator iterator() { return stream.get().iterator(); } }; } public static Iterable empty() { return ImmutableList.of(); } public static Iterable of(T e1) { return ImmutableList.of(e1); } public static Iterable of(T e1, T e2) { return ImmutableList.of(e1, e2); } public static Iterable of(T e1, T e2, T e3) { return ImmutableList.of(e1, e2, e3); } public static Iterable iterable(Optional optional) { if (optional.isPresent()) { return of(optional.get()); } else { return empty(); } } public static Iterable takeUntil(Iterable iterable, Predicate predicate) { return new Iterable() { @Override public Iterator iterator() { return takeUntil(iterable.iterator(), predicate); } }; } public static Iterator takeUntil(Iterator iterator, Predicate predicate) { PeekingIterator peekingIterator = Iterators.peekingIterator(iterator); return new Iterator() { @Override public boolean hasNext() { return peekingIterator.hasNext() && !predicate.test(peekingIterator.peek()); } @Override public T next() { if (hasNext()) { return peekingIterator.next(); } else { throw new NoSuchElementException(); } } }; } public static T only(Iterable iterable) { Iterator iterator = iterable.iterator(); T value = iterator.next(); if (iterator.hasNext()) { throw new RuntimeException("iterable had more than one element"); } else { return value; } } public static T only(Iterable iterable, Supplier orElse) { Iterator iterator = iterable.iterator(); T value = iterator.next(); if (iterator.hasNext()) { throw orElse.get(); } else { return value; } } }