package org.zwobble.mammoth.internal.util; import java.util.Iterator; import java.util.Optional; import java.util.OptionalInt; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; import java.util.stream.StreamSupport; public class Iterables { public static Optional tryFind(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); } }; } public static Iterable lazyMapWithIndex(Iterable iterable, BiFunction function) { return new Iterable() { @Override public Iterator iterator() { return map(iterable.iterator(), function); } }; } public static Optional getFirst(Iterable iterable) { Iterator iterator = iterable.iterator(); if (iterator.hasNext()) { return Optional.of(iterator.next()); } else { return Optional.empty(); } } public static T getFirst(Iterable iterable, T defaultValue) { Iterator iterator = iterable.iterator(); if (iterator.hasNext()) { return iterator.next(); } else { return defaultValue; } } public static Optional tryGetLast(Iterable iterable) { Iterator iterator = iterable.iterator(); if (!iterator.hasNext()) { return Optional.empty(); } while (true) { T last = iterator.next(); if (!iterator.hasNext()) { return Optional.of(last); } } } public static Iterable lazyFlatMap(Iterable iterable, Function> function) { return lazyFlatten(lazyMap(iterable, function)); } public static Iterable lazyConcat(Iterable iterable1, Iterable iterable2) { return new Iterable() { @Override public Iterator iterator() { return Stream.concat(stream(iterable1), stream(iterable2)).iterator(); } }; } public static Iterable lazyFlatten(Iterable> iterables) { return new Iterable() { @Override public Iterator iterator() { return stream(iterables) .flatMap(iterable -> stream(iterable)) .iterator(); } }; } public static Iterable lazyFilter(Iterable iterables, Predicate predicate) { return new Iterable() { @Override public Iterator iterator() { return stream(iterables) .filter(predicate) .iterator(); } }; } public static Iterable lazyFilter(Iterable iterables, Class clazz) { return new Iterable() { @Override @SuppressWarnings("unchecked") public Iterator iterator() { return (Iterator) stream(iterables) .filter(clazz::isInstance) .iterator(); } }; } 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()); } }; } private static Iterator map(Iterator iterator, BiFunction function) { return new Iterator() { private int nextIndex = 0; @Override public boolean hasNext() { return iterator.hasNext(); } @Override public R next() { return function.apply(nextIndex++, iterator.next()); } }; } public static boolean any(Iterable iterable, Predicate predicate) { return stream(iterable).anyMatch(predicate); } public static Stream stream(Iterable iterable) { return StreamSupport.stream(iterable.spliterator(), false); } public static OptionalInt findIndex(Iterable iterable, Predicate predicate) { int index = 0; for (T element : iterable) { if (predicate.test(element)) { return OptionalInt.of(index); } index++; } return OptionalInt.empty(); } public static Iterable intRange(int start, int end) { return new Iterable() { @Override public Iterator iterator() { return new Iterator() { private int next = start; @Override public boolean hasNext() { return next < end; } @Override public Integer next() { return next++; } }; } }; } }