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