/*
* 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() ;
}
}