blob: 866cf9fd2600ef8b5a0ec00e21a5c42ead6236c0 [file] [log] [blame]
/*
* 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.tinkerpop.gremlin.util.iterator;
import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
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;
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
*/
public final class IteratorUtils {
private IteratorUtils() {
}
public static final <S> Iterator<S> of(final S a) {
return new SingleIterator<>(a);
}
public static final <S> Iterator<S> of(final S a, S b) {
return new DoubleIterator<>(a, b);
}
///////////////
public static final <S extends Collection<T>, T> S fill(final Iterator<T> iterator, final S collection) {
while (iterator.hasNext()) {
collection.add(iterator.next());
}
return collection;
}
public static void iterate(final Iterator iterator) {
while (iterator.hasNext()) {
iterator.next();
}
}
public static final long count(final Iterator iterator) {
long ix = 0;
for (; iterator.hasNext(); ++ix) iterator.next();
return ix;
}
public static final long count(final Iterable iterable) {
return IteratorUtils.count(iterable.iterator());
}
public static <S> List<S> list(final Iterator<S> iterator) {
return fill(iterator, new ArrayList<>());
}
public static <S> List<S> list(final Iterator<S> iterator, final Comparator comparator) {
final List<S> l = list(iterator);
Collections.sort(l, comparator);
return l;
}
public static <S> Set<S> set(final Iterator<S> iterator) {
return fill(iterator, new HashSet<>());
}
public static <S> Iterator<S> limit(final Iterator<S> iterator, final int limit) {
return new Iterator<S>() {
private int count = 0;
@Override
public boolean hasNext() {
return iterator.hasNext() && this.count < limit;
}
@Override
public void remove() {
iterator.remove();
}
@Override
public S next() {
if (this.count++ >= limit)
throw FastNoSuchElementException.instance();
return iterator.next();
}
};
}
///////////////////
public static <T> boolean allMatch(final Iterator<T> iterator, final Predicate<T> predicate) {
while (iterator.hasNext()) {
if (!predicate.test(iterator.next())) {
return false;
}
}
return true;
}
public static <T> boolean anyMatch(final Iterator<T> iterator, final Predicate<T> predicate) {
while (iterator.hasNext()) {
if (predicate.test(iterator.next())) {
return true;
}
}
return false;
}
public static <T> boolean noneMatch(final Iterator<T> iterator, final Predicate<T> predicate) {
while (iterator.hasNext()) {
if (predicate.test(iterator.next())) {
return false;
}
}
return true;
}
///////////////////
public static <K, S> Map<K, S> collectMap(final Iterator<S> iterator, final Function<S, K> key) {
return collectMap(iterator, key, Function.identity());
}
public static <K, S, V> Map<K, V> collectMap(final Iterator<S> iterator, final Function<S, K> key, final Function<S, V> value) {
final Map<K, V> map = new HashMap<>();
while (iterator.hasNext()) {
final S obj = iterator.next();
map.put(key.apply(obj), value.apply(obj));
}
return map;
}
public static <K, S> Map<K, List<S>> groupBy(final Iterator<S> iterator, final Function<S, K> groupBy) {
final Map<K, List<S>> map = new HashMap<>();
while (iterator.hasNext()) {
final S obj = iterator.next();
map.computeIfAbsent(groupBy.apply(obj), k -> new ArrayList<>()).add(obj);
}
return map;
}
public static <S> S reduce(final Iterator<S> iterator, final S identity, final BinaryOperator<S> accumulator) {
S result = identity;
while (iterator.hasNext()) {
result = accumulator.apply(result, iterator.next());
}
return result;
}
public static <S> S reduce(final Iterable<S> iterable, final S identity, final BinaryOperator<S> accumulator) {
return reduce(iterable.iterator(), identity, accumulator);
}
public static <S, E> E reduce(final Iterator<S> iterator, final E identity, final BiFunction<E, S, E> accumulator) {
E result = identity;
while (iterator.hasNext()) {
result = accumulator.apply(result, iterator.next());
}
return result;
}
public static <S, E> E reduce(final Iterable<S> iterable, final E identity, final BiFunction<E, S, E> accumulator) {
return reduce(iterable.iterator(), identity, accumulator);
}
///////////////
public static final <S> Iterator<S> consume(final Iterator<S> iterator, final Consumer<S> consumer) {
return new Iterator<S>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public void remove() {
iterator.remove();
}
@Override
public S next() {
final S s = iterator.next();
consumer.accept(s);
return s;
}
};
}
public static final <S> Iterable<S> consume(final Iterable<S> iterable, final Consumer<S> consumer) {
return () -> IteratorUtils.consume(iterable.iterator(), consumer);
}
///////////////
public static final <S, E> Iterator<E> map(final Iterator<S> iterator, final Function<S, E> function) {
return new Iterator<E>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public void remove() {
iterator.remove();
}
@Override
public E next() {
return function.apply(iterator.next());
}
};
}
public static final <S, E> Iterable<E> map(final Iterable<S> iterable, final Function<S, E> function) {
return () -> IteratorUtils.map(iterable.iterator(), function);
}
///////////////
public static final <S> Iterator<S> filter(final Iterator<S> iterator, final Predicate<S> predicate) {
return new Iterator<S>() {
S nextResult = null;
@Override
public boolean hasNext() {
if (null != this.nextResult) {
return true;
} else {
advance();
return null != this.nextResult;
}
}
@Override
public void remove() {
iterator.remove();
}
@Override
public S next() {
try {
if (null != this.nextResult) {
return this.nextResult;
} else {
advance();
if (null != this.nextResult)
return this.nextResult;
else
throw FastNoSuchElementException.instance();
}
} finally {
this.nextResult = null;
}
}
private final void advance() {
this.nextResult = null;
while (iterator.hasNext()) {
final S s = iterator.next();
if (predicate.test(s)) {
this.nextResult = s;
return;
}
}
}
};
}
public static final <S> Iterable<S> filter(final Iterable<S> iterable, final Predicate<S> predicate) {
return () -> IteratorUtils.filter(iterable.iterator(), predicate);
}
///////////////////
public static final <S, E> Iterator<E> flatMap(final Iterator<S> iterator, final Function<S, Iterator<E>> function) {
return new Iterator<E>() {
private Iterator<E> currentIterator = Collections.emptyIterator();
@Override
public boolean hasNext() {
if (this.currentIterator.hasNext())
return true;
else {
while (iterator.hasNext()) {
this.currentIterator = function.apply(iterator.next());
if (this.currentIterator.hasNext())
return true;
}
}
return false;
}
@Override
public void remove() {
iterator.remove();
}
@Override
public E next() {
if (this.hasNext())
return this.currentIterator.next();
else
throw FastNoSuchElementException.instance();
}
};
}
///////////////////
public static final <S> Iterator<S> concat(final Iterator<S>... iterators) {
final MultiIterator<S> iterator = new MultiIterator<>();
for (final Iterator<S> itty : iterators) {
iterator.addIterator(itty);
}
return iterator;
}
///////////////////
public static Iterator asIterator(final Object o) {
final Iterator itty;
if (o instanceof Iterable)
itty = ((Iterable) o).iterator();
else if (o instanceof Iterator)
itty = (Iterator) o;
else if (o instanceof Object[])
itty = new ArrayIterator<>((Object[]) o);
else if (o instanceof Stream)
itty = ((Stream) o).iterator();
else if (o instanceof Map)
itty = ((Map) o).entrySet().iterator();
else if (o instanceof Throwable)
itty = of(((Throwable) o).getMessage());
else
itty = of(o);
return itty;
}
public static List asList(final Object o) {
return list(asIterator(o));
}
/**
* Construct a {@link Stream} from an {@link Iterator}.
*/
public static <T> Stream<T> stream(final Iterator<T> iterator) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.IMMUTABLE | Spliterator.SIZED), false);
}
public static <T> Stream<T> stream(final Iterable<T> iterable) {
return IteratorUtils.stream(iterable.iterator());
}
public static <T> Iterator<T> noRemove(final Iterator<T> iterator) {
return new Iterator<T>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public void remove() {
// do nothing
}
@Override
public T next() {
return iterator.next();
}
};
}
public static <T> Iterator<T> removeOnNext(final Iterator<T> iterator) {
return new Iterator<T>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public void remove() {
iterator.remove();
}
@Override
public T next() {
final T object = iterator.next();
iterator.remove();
return object;
}
};
}
}