/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jena.atlas.iterator ; import java.io.PrintStream ; import java.util.* ; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream ; import java.util.stream.StreamSupport ; import org.apache.jena.atlas.lib.Closeable ; import org.apache.jena.atlas.lib.Sink ; /** * Iter provides general utilities for working with {@link Iterator}s. * This class provides functionality similar to {@code Stream} * except for iterators (and hence single threaded). * <p> * Style 1: functional style using statics. * * <pre> * import static org.apache.jena.atlas.iterator.Iter.* ; * * filter(map(iterator, <i>function></i>), <i>predicate</i>) * </pre> * * Style 2: Stream-like: The class {@code Iter} provides methods to call on an iterator. * * <pre> * import static org.apache.jena.atlas.iterator.Iter.iter ; * * iter(iterator).map(...).filter(...)} * </pre> * * @param <T> the type of element over which an instance of Iter iterates, */ public class Iter<T> implements Iterator<T> { // IteratorSlotted needed? IteratorPeek // IteratorSlotted.inspect public static <T> Stream<T> asStream(Iterator<T> iterator) { return asStream(iterator, false); } public static <T> Stream<T> asStream(Iterator<T> iterator, boolean parallel) { // Why isn't there a JDK operation for Iterator -> (sequential) stream? int characteristics = 0 ; //Spliterator.IMMUTABLE; return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, characteristics), parallel); } // ---- Special iterators. public static <T> Iterator<T> singleton(T item) { // Theer is a single iterator in Co0llections but it is not public. return new SingletonIterator<>(item) ; } public static <T> Iterator<T> nullIterator() { // Java7 caught up. return Collections.emptyIterator(); } // ---- Collectors. /** Collect an iterator into a set. */ public static <T> Set<T> toSet(Iterator<? extends T> stream) { Set<T> acc = new HashSet<>() ; collect(acc, stream) ; return acc ; } /** Collect an iterator into a list. */ public static <T> List<T> toList(Iterator<? extends T> stream) { List<T> acc = new ArrayList<>() ; collect(acc, stream) ; return acc ; } /** Collect an iterator. */ private static <T> void collect(Collection<T> acc, Iterator<? extends T> stream) { stream.forEachRemaining((x)->acc.add(x)) ; } /** * Create another iterator without risk of concurrent modification * exceptions. This materializes the input iterator. */ public static <T> Iterator<T> iterator(Iterator<? extends T> iterator) { List<T> x = Iter.toList(iterator) ; return x.iterator() ; } // -- Operations on iterators. public interface Folder<X, Y> { Y eval(Y acc, X arg) ; } public static <T, R> R foldLeft(Iterable<? extends T> stream, Folder<T, R> function, R value) { return foldLeft(stream.iterator(), function, value) ; } public static <T, R> R foldLeft(Iterator<? extends T> stream, Folder<T, R> function, R value) { // Tail recursion, unwound for (; stream.hasNext();) { T item = stream.next() ; value = function.eval(value, item) ; } return value ; } public static <T, R> R foldRight(Iterable<? extends T> stream, Folder<T, R> function, R value) { return foldRight(stream.iterator(), function, value) ; } public static <T, R> R foldRight(Iterator<? extends T> stream, Folder<T, R> function, R value) { // Recursive. if ( !stream.hasNext() ) return value ; T item = stream.next() ; return function.eval(foldRight(stream, function, value), item) ; } // Note fold-left and fold-right // http://en.wikipedia.org/wiki/Fold_%28higher-order_function%29 // This reduce is fold-left (take first element, apply to rest of list) // which copes with infinite lists. // Fold-left starts by combining the first element, then moves on. /** Reduce by aggregator. * This reduce is fold-left (take first element, apply to rest of list) */ public static <T, R> R reduce(Iterable<? extends T> stream, Accumulate<T, R> aggregator) { return reduce(stream.iterator(), aggregator) ; } /** Reduce by aggregator. * This reduce is fold-left (take first element, apply to rest of list) */ public static <T, R> R reduce(Iterator<? extends T> stream, Accumulate<T, R> aggregator) { aggregator.start() ; for (; stream.hasNext();) { T item = stream.next() ; aggregator.accumulate(item) ; } aggregator.finish() ; return aggregator.get() ; } /** Act on elements of an iterator. * @see #map(Iterator, Function) */ public static <T> void apply(Iterator<? extends T> stream, Consumer<T> action) { for (; stream.hasNext();) { T item = stream.next() ; action.accept(item) ; } } // ---- Filter public static <T> Iterator<T> filter(final Iterator<? extends T> stream, final Predicate<T> filter) { final Iterator<T> iter = new Iterator<T>() { boolean finished = false ; boolean slotOccupied = false ; T slot ; @Override public boolean hasNext() { if ( finished ) return false ; while (!slotOccupied) { if ( !stream.hasNext() ) { finished = true ; break ; } T nextItem = stream.next() ; if ( filter.test(nextItem) ) { slot = nextItem ; slotOccupied = true ; break ; } } return slotOccupied ; } @Override public T next() { if ( hasNext() ) { slotOccupied = false ; return slot ; } throw new NoSuchElementException("filter.next") ; } @Override public void remove() { throw new UnsupportedOperationException("filter.remove") ; } } ; return iter ; } public static <T> Iterator<T> notFilter(final Iterator<? extends T> stream, final Predicate<T> filter) { return filter(stream, filter.negate()) ; } // Filter-related /** * Return true if every element of stream passes the filter (reads the * stream until the first element not passing the filter) */ public static <T> boolean every(Iterator<? extends T> stream, Predicate<T> filter) { while ( stream.hasNext() ) { T item = stream.next() ; if ( !filter.test(item) ) return false ; } return true ; } /** * Return true if one or more elements of stream passes the filter (reads * the stream to first element passing the filter) */ public static <T> boolean some(Iterator<? extends T> stream, Predicate<T> filter) { while ( stream.hasNext() ) { T item = stream.next() ; if ( filter.test(item) ) return true ; } return false ; } // ---- Map /** Apply a function to every element of an iterator, transforming it * from a {@code T} to an {@code R}. */ public static <T, R> Iterator<R> map(Iterator<? extends T> stream, Function<T, R> converter) { final Iterator<R> iter = new Iterator<R>() { @Override public boolean hasNext() { return stream.hasNext() ; } @Override public R next() { return converter.apply(stream.next()) ; } @Override public void remove() { throw new UnsupportedOperationException("map.remove") ; } } ; return iter ; } /** Transform a list of elements to a new list of the function applied to each element. * Using a stream is often better. This operation preseves the order of the list. * @deprecated Use Java8 Streams */ @Deprecated public static <T, R> List<R> map(List<? extends T> list, Function<T, R> converter) { return toList(map(list.iterator(), converter)) ; } /** * Apply an action to everything in stream, yielding a stream of the * same items. */ public static <T> Iterator<T> operate(final Iterator<? extends T> stream, final Consumer<T> action) { final Iterator<T> iter = new Iterator<T>() { @Override public boolean hasNext() { return stream.hasNext() ; } @Override public T next() { T t = stream.next() ; action.accept(t) ; return t ; } @Override public void remove() { throw new UnsupportedOperationException("operate.remove") ; } } ; return iter ; } /** Print an iterator as it gets used - this adds a printing wrapper */ public static <T> Iterator<T> printWrapper(final Iterator<? extends T> stream) { return Iter.printWrapper(System.out, stream) ; } /** Print an iterator as it gets used - this adds a printing wrapper */ public static <T> Iterator<T> printWrapper(final PrintStream out, final Iterator<? extends T> stream) { return Iter.operate(stream, out::println) ; } /** Join two iterators. * If there, potentially, going to be many iterators, it is better to * create an {@link IteratorConcat} explicitly and add each iterator. */ public static <T> Iterator<T> append(Iterator<? extends T> iter1, Iterator<? extends T> iter2) { return IteratorCons.create(iter1, iter2) ; } /** Return an iterator that will see each element of the underlying iterator only once. * Note that this need working memory to remember the elements alreadey seen. */ public static <T> Iterator<T> distinct(Iterator<T> iter) { return filter(iter, new FilterUnique<T>()) ; } /** Remove adjacent duplicates. This operation does not need * working memory to remember the all elements already seen, * just a slot for the last element seen. */ public static <T> Iterator<T> distinctAdjacent(Iterator<T> iter) { return filter(iter, new FilterDistinctAdjacent<T>()) ; } /** Remove nulls from an iterator */ public static <T> Iterator<T> removeNulls(Iterator<T> iter) { return filter(iter, Objects::nonNull) ; } /** Take the first N elements of an iterator - stop early if too few */ public static <T> List<T> take(Iterator<T> iter, int N) { iter = new IteratorN<>(iter, N) ; List<T> x = new ArrayList<>(N) ; while ( iter.hasNext() ) x.add(iter.next()) ; return x ; } /** Create an iterator such that it yields elements while a predicate test on * the elements is true, end the iteration. * @see Iter#filter(Iterator, Predicate) */ public static <T> Iterator<T> takeWhile(Iterator<T> iter, Predicate<T> predicate) { return new IteratorTruncate<>(iter, predicate) ; } /** * Create an iterator such that it yields elements until a predicate test on * the elements becomes true, end the iteration. * * @see Iter#filter(Iterator, Predicate) */ public static <T> Iterator<T> takeUntil(Iterator<T> iter, Predicate<T> predicate) { return new IteratorTruncate<>(iter, predicate.negate()) ; } /** Create an iterator such that elements from the front while * a predicate test become true are dropped then return all remaining elements * are iterated over. * The first element where the predicte becomes true is the first element of the * returned iterator. */ public static <T> Iterator<T> dropWhile(Iterator<T> iter, Predicate<T> predicate) { PeekIterator<T> iter2 = new PeekIterator<>(iter) ; for(;;) { T elt = iter2.peek() ; if ( elt == null ) return Iter.nullIterator() ; if ( ! predicate.test(elt) ) break ; } return iter2 ; } /** Create an iterator such that elements from the front until * a predicate test become true are dropped then return all remaining elements * are iterated over. * The first element where the predicate becomes true is the first element of the * returned iterator. */ public static <T> Iterator<T> dropUntil(Iterator<T> iter, Predicate<T> predicate) { return dropWhile(iter, predicate.negate()) ; } /** Iterator that only returns upto N items */ static class IteratorN<T> implements Iterator<T> { private final Iterator<T> iter ; private final int N ; private int count ; IteratorN(Iterator<T> iter, int N) { this.iter = iter ; this.N = N ; this.count = 0 ; } @Override public boolean hasNext() { if ( count >= N ) return false ; return iter.hasNext() ; } @Override public T next() { if ( count >= N ) throw new NoSuchElementException() ; T x = iter.next() ; count++ ; return x ; } @Override public void remove() { // But leave the count as-is. iter.remove() ; } } /** Count the iterator (this is destructive on the iterator) */ public static <T> long count(Iterator<T> iterator) { long x = 0 ; while (iterator.hasNext()) { iterator.next() ; x++ ; } return x ; } /** Consume the iterator */ public static <T> void consume(Iterator<T> iterator) { count(iterator) ; } // ---- String related helpers // Java8 has StringJoin public static <T> String asString(Iterable<T> stream) { return asString(stream, new AccString<T>()) ; } public static <T> String asString(Iterator<T> stream) { return asString(stream, new AccString<T>()) ; } public static <T> String asString(Iterable<T> stream, String sep) { return asString(stream, new AccString<T>(sep)) ; } public static <T> String asString(Iterator<T> stream, String sep) { return asString(stream, new AccString<T>(sep)) ; } public static <T> String asString(Iterable<T> stream, AccString<T> formatter) { return asString(stream.iterator(), formatter) ; } public static <T> String asString(Iterator<T> stream, AccString<T> formatter) { return reduce(stream, formatter) ; } // ---- public static <T> void close(Iterator<T> iter) { if ( iter instanceof Closeable ) ((Closeable)iter).close() ; } /** * Print an iterator to stdout, return a copy of the iterator. Printing * occurs now. See {@link #debug} for an operation to print as the * iterator is used. */ public static <T> Iterator<T> log(Iterator<T> stream) { return log(System.out, stream) ; } /** * Print an iterator to stdout, return a copy of the iterator. Printing * occurs now. See {@link #debug} for an operation to print as the * iterator is used. */ public static <T> Iterator<T> log(final PrintStream out, Iterator<T> stream) { Iterator<T> iter = debug(out, stream) ; // And force it to run. return Iter.toList(iter).iterator(); } /** * Print an iterator to stdout, return a copy of the iterator. Printing * occurs when the iterator is used. See {@link #log} for * an operation to print now. */ public static <T> Iterator<T> debug(Iterator<T> stream) { return debug(System.out, stream) ; } /** * Print an iterator, return a copy of the iterator. Printing * occurs as the returned iterator is used. */ public static <T> Iterator<T> debug(final PrintStream out, Iterator<T> stream) { try { return map(stream, item -> {out.println(item); return item;}) ; } finally { out.flush() ; } } /** Print an iterator (destructive) */ public static <T> void print(Iterator<T> stream) { print(System.out, stream) ; } /** Print an iterator (destructive) */ public static <T> void print(final PrintStream out, Iterator<T> stream) { apply(stream, out::println) ; } /** Send the elements of the iterator to a sink - consumes the iterator */ public static <T> void sendToSink(Iterator<T> iter, Sink<T> sink) { while ( iter.hasNext() ) { T thing = iter.next() ; sink.send(thing) ; } sink.close() ; } /** Send the elements of the iterable to a sink */ public static <T> void sendToSink(Iterable<T> stream, Sink<T> sink) { sendToSink(stream.iterator(), sink) ; } // ---- // Iter class part : factories public static <T> Iter<T> iter(Iter<T> iter) { return iter ; } public static <T> Iter<T> iter(Collection<T> collection) { return iter(collection.iterator()) ; } public static <T> Iter<T> iter(Iterator<T> iterator) { if ( iterator instanceof Iter<? > ) return (Iter<T>)iterator ; return new Iter<>(iterator) ; } public static <T> Iter<T> singletonIter(T item) { return iter(new SingletonIterator<>(item)) ; } public static <T> Iter<T> nullIter() { return iter(new NullIterator<T>()) ; } /** * Materialize an iterator, that is, force it to run now - useful in * debugging or when iteration may modify underlying datastructures. */ public static <T> Iterator<T> materialize(Iterator<T> iter) { return toList(iter).iterator() ; } /** An {@code Iter} of 2 {@code Iter}'s */ public static <T> Iter<T> concat(Iter<T> iter1, Iter<T> iter2) { if ( iter1 == null ) return iter2 ; if ( iter2 == null ) return iter1 ; return iter1.append(iter2) ; } /** An {@code Iterator} of 2 {@code Iterator}'s. * See also {@link IteratorConcat}. */ public static <T> Iterator<T> concat(Iterator<T> iter1, Iterator<T> iter2) { if ( iter1 == null ) return iter2 ; if ( iter2 == null ) return iter1 ; return iter(iter1).append(iter(iter2)) ; } /** Return the first element of an iterator or null if no such element. * @param iter * @return An item or null. */ public static <T> T first(Iterator<T> iter) { return first(iter, (x)-> true ) ; } /** Skip to the first element meeting a condition and return that element. */ public static <T> T first(Iterator<T> iter, Predicate<T> filter) { while (iter.hasNext()) { T t = iter.next() ; if ( filter.test(t) ) return t ; } return null ; } /** @deprecated Use Java8 Streams */ @Deprecated public static <T> T first(Collection<T> collection, Predicate<T> filter) { return collection.stream().filter(filter).findFirst().orElse(null); } /** Skip to the first element meeting a condition and return that element's index (zero-based). */ public static <T> int firstIndex(Iterator<T> iter, Predicate<T> filter) { for (int idx = 0; iter.hasNext(); idx++) { T t = iter.next() ; if ( filter.test(t) ) return idx ; } return -1 ; } /** @deprecated Use Java8 Streams */ @Deprecated public static <T> int firstIndex(Collection<T> collection, Predicate<T> filter) { return firstIndex(collection.iterator(), filter) ; } /** Return the last element or null, if no elements. This operation consumes the iterator. */ public static <T> T last(Iterator<T> iter) { return last(iter, (x)->true) ; } /** Return the last element satisfying a predicate. This operation consumes the whole iterator. */ public static <T> T last(Iterator<T> iter, Predicate<T> filter) { T thing = null ; while (iter.hasNext()) { T t = iter.next() ; if ( filter.test(t) ) thing = t ; } return thing ; } /** @deprecated Use Java8 Streams */ @Deprecated public static <T> T last(Collection<T> collection, Predicate<T> filter) { return last(collection.iterator(), filter) ; } /** Return the index of the last element satisfying a predicate (zero-based). */ public static <T> int lastIndex(Iterator<T> iter, Predicate<T> filter) { int location = -1 ; for (int idx = 0; iter.hasNext(); idx++) { T t = iter.next() ; if ( filter.test(t) ) location = idx ; } return location ; } /** @deprecated Use Java8 Streams */ @Deprecated public static <T> int lastIndex(Collection<T> collection, Predicate<T> filter) { return lastIndex(collection.iterator(), filter) ; } // ------------------------------------------------------ // The class. private Iterator<T> iterator ; private Iter(Iterator<T> iterator) { this.iterator = iterator ; } /** Consume the {@code Iter} and produce a {@code Set} */ public Set<T> toSet() { return toSet(iterator) ; } /** Consume the {@code Iter} and produce a {@code List} */ public List<T> toList() { return toList(iterator) ; } public void sendToSink(Sink<T> sink) { sendToSink(iterator, sink) ; } public T first() { return first(iterator) ; } public T last() { return last(iterator) ; } /** Skip to the first element meeting a condition and return that element. */ public T first(Predicate<T> filter) { return first(iterator, filter) ; } /** Skip to the first element meeting a condition and return that element's index (zero-based). */ public int firstIndex(Predicate<T> filter) { return firstIndex(iterator, filter) ; } /** Return the last element satisfying a predicate. This operation destroys the whole iterator. */ public T last(Predicate<T> filter) { return last(iterator, filter) ; } /** Return the index of the last element satisfying a predicate (zero-based). */ public int lastIndex(Predicate<T> filter) { return lastIndex(iterator, filter) ; } /** Filter by predicate */ public Iter<T> filter(Predicate<T> filter) { return iter(filter(iterator, filter)) ; } /** Return true if every element satisfies a predicate */ public boolean every(Predicate<T> predciate) { return every(iterator, predciate) ; } /** Return true if some element satisfies a predicate */ public boolean some(Predicate<T> filter) { return some(iterator, filter) ; } /** Remove nulls */ public Iter<T> removeNulls() { return iter(removeNulls(this)) ; } /** Map each element using given function */ public <R> Iter<R> map(Function<T, R> converter) { return iter(map(iterator, converter)) ; } /** * Apply an action to everything in the stream, yielding a stream of the * original items. */ public Iter<T> operate(Consumer<T> action) { return iter(operate(iterator, action)) ; } /** Reduce by aggregator. * This reduce is fold-left (take first element, apply to rest of list) */ public <R> R reduce(Accumulate<T, R> aggregator) { return reduce(iterator, aggregator) ; } /** Apply an action to every element of an iterator */ public void apply(Consumer<T> action) { apply(iterator, action) ; } /** Join on an {@code Iterator}.. * If there are going to be many iterators, uit is better to create an {@link IteratorConcat} * and <tt>.add</tt> each iterator. The overheads are much lower. */ public Iter<T> append(Iterator<T> iter) { return iter(IteratorCons.create(iterator, iter)) ; } /** Return an Iter that yields at most the first N items */ public Iter<T> take(int N) { return iter(take(iterator, N)) ; } /** Create an {@code Iter} such that it yields elements while a predicate test on * the elements is true, end the iteration. * @see Iter#filter(Predicate) */ public Iter<T> takeWhile(Predicate<T> predicate) { return iter(takeWhile(iterator, predicate)) ; } /** * Create an {@code Iter} such that it yields elements until a predicate test on * the elements becomes true, end the iteration. * * @see Iter#filter(Predicate) */ public Iter<T> takeUntil(Predicate<T> predicate) { return iter(takeUntil(iterator, predicate)) ; } /** Create an {@code Iter} such that elements from the front while * a predicate test become true are dropped then return all remaining elements * are iterated over. * The first element where the predicte becomes true is the first element of the * returned iterator. */ public Iter<T> dropWhile(Predicate<T> predicate) { return iter(dropWhile(iterator, predicate)) ; } /** Create an {@code Iter} such that elements from the front until * a predicate test become true are dropped then return all remaining elements * are iterated over. * The first element where the predicate becomes true is the first element of the * returned iterator. */ public Iter<T> dropUntil(Predicate<T> predicate) { return iter(dropWhile(iterator, predicate.negate())) ; } /** Count the iterator (this is destructive on the iterator) */ public long count() { ActionCount<T> action = new ActionCount<>() ; apply(action) ; return action.getCount() ; } public String asString() { return asString(iterator) ; } public String asString(String sep) { return asString(iterator, sep) ; } /** Return an {:@code Iter} that will see each element of the underlying iterator only once. * Note that this need working memory to remember the elements alreadey seen. */ public Iter<T> distinct() { return iter((distinct(iterator))) ; } /** Remove adjacent duplicates. This operation does not need * working memory to remember the all elements already seen, * just a slot for the last element seen. */ public Iter<T> distinctAdjacent() { return iter(distinctAdjacent(iterator)) ; } // ---- Iterator @Override public boolean hasNext() { return iterator.hasNext() ; } @Override public T next() { return iterator.next() ; } @Override public void remove() { iterator.remove() ; } }