| /* |
| * Copyright 2016 Google Inc. |
| * |
| * Licensed 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 java.util.stream; |
| |
| import static javaemul.internal.InternalPreconditions.checkNotNull; |
| import static javaemul.internal.InternalPreconditions.checkState; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Optional; |
| import java.util.Spliterator; |
| import java.util.Spliterators; |
| import java.util.Spliterators.AbstractDoubleSpliterator; |
| import java.util.Spliterators.AbstractIntSpliterator; |
| import java.util.Spliterators.AbstractLongSpliterator; |
| import java.util.Spliterators.AbstractSpliterator; |
| import java.util.function.BiConsumer; |
| import java.util.function.BiFunction; |
| import java.util.function.BinaryOperator; |
| import java.util.function.Consumer; |
| import java.util.function.DoubleConsumer; |
| import java.util.function.Function; |
| import java.util.function.IntConsumer; |
| import java.util.function.IntFunction; |
| import java.util.function.LongConsumer; |
| import java.util.function.Predicate; |
| import java.util.function.Supplier; |
| import java.util.function.ToDoubleFunction; |
| import java.util.function.ToIntFunction; |
| import java.util.function.ToLongFunction; |
| |
| /** |
| * Main implementation of Stream, wrapping a single spliterator and an optional parent stream. |
| */ |
| final class StreamImpl<T> extends TerminatableStream<StreamImpl<T>> implements Stream<T> { |
| |
| /** |
| * Represents an empty stream, doing nothing for all methods. |
| */ |
| static class Empty<T> extends TerminatableStream<Empty<T>> implements Stream<T> { |
| |
| public Empty(TerminatableStream<?> previous) { |
| super(previous); |
| } |
| |
| @Override |
| public Stream<T> filter(Predicate<? super T> predicate) { |
| throwIfTerminated(); |
| return this; |
| } |
| |
| @Override |
| public <R> Stream<R> map(Function<? super T, ? extends R> mapper) { |
| throwIfTerminated(); |
| return (Stream) this; |
| } |
| |
| @Override |
| public IntStream mapToInt(ToIntFunction<? super T> mapper) { |
| throwIfTerminated(); |
| return new IntStreamImpl.Empty(this); |
| } |
| |
| @Override |
| public LongStream mapToLong(ToLongFunction<? super T> mapper) { |
| throwIfTerminated(); |
| return new LongStreamImpl.Empty(this); |
| } |
| |
| @Override |
| public DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) { |
| throwIfTerminated(); |
| return new DoubleStreamImpl.Empty(this); |
| } |
| |
| @Override |
| public <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) { |
| throwIfTerminated(); |
| return (Stream) this; |
| } |
| |
| @Override |
| public IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper) { |
| throwIfTerminated(); |
| return new IntStreamImpl.Empty(this); |
| } |
| |
| @Override |
| public LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper) { |
| throwIfTerminated(); |
| return new LongStreamImpl.Empty(this); |
| } |
| |
| @Override |
| public DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper) { |
| throwIfTerminated(); |
| return new DoubleStreamImpl.Empty(this); |
| } |
| |
| @Override |
| public Stream<T> distinct() { |
| throwIfTerminated(); |
| return this; |
| } |
| |
| @Override |
| public Stream<T> sorted() { |
| throwIfTerminated(); |
| return this; |
| } |
| |
| @Override |
| public Stream<T> sorted(Comparator<? super T> comparator) { |
| throwIfTerminated(); |
| return this; |
| } |
| |
| @Override |
| public Stream<T> peek(Consumer<? super T> action) { |
| throwIfTerminated(); |
| return this; |
| } |
| |
| @Override |
| public Stream<T> limit(long maxSize) { |
| throwIfTerminated(); |
| checkState(maxSize >= 0, "maxSize may not be negative"); |
| return this; |
| } |
| |
| @Override |
| public Stream<T> skip(long n) { |
| throwIfTerminated(); |
| checkState(n >= 0, "n may not be negative"); |
| return this; |
| } |
| |
| @Override |
| public void forEach(Consumer<? super T> action) { |
| terminate(); |
| // nothing to do |
| } |
| |
| @Override |
| public void forEachOrdered(Consumer<? super T> action) { |
| terminate(); |
| // nothing to do |
| } |
| |
| @Override |
| public Object[] toArray() { |
| terminate(); |
| return new Object[0]; |
| } |
| |
| @Override |
| public <A> A[] toArray(IntFunction<A[]> generator) { |
| terminate(); |
| return generator.apply(0); |
| } |
| |
| @Override |
| public T reduce(T identity, BinaryOperator<T> accumulator) { |
| terminate(); |
| return identity; |
| } |
| |
| @Override |
| public Optional<T> reduce(BinaryOperator<T> accumulator) { |
| terminate(); |
| return Optional.empty(); |
| } |
| |
| @Override |
| public <U> U reduce( |
| U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner) { |
| terminate(); |
| return identity; |
| } |
| |
| @Override |
| public <R> R collect( |
| Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner) { |
| terminate(); |
| return supplier.get(); |
| } |
| |
| @Override |
| public <R, A> R collect(Collector<? super T, A, R> collector) { |
| terminate(); |
| return collector.finisher().apply(collector.supplier().get()); |
| } |
| |
| @Override |
| public Optional<T> min(Comparator<? super T> comparator) { |
| terminate(); |
| return Optional.empty(); |
| } |
| |
| @Override |
| public Optional<T> max(Comparator<? super T> comparator) { |
| terminate(); |
| return Optional.empty(); |
| } |
| |
| @Override |
| public long count() { |
| terminate(); |
| return 0; |
| } |
| |
| @Override |
| public boolean anyMatch(Predicate<? super T> predicate) { |
| terminate(); |
| return false; |
| } |
| |
| @Override |
| public boolean allMatch(Predicate<? super T> predicate) { |
| terminate(); |
| return true; |
| } |
| |
| @Override |
| public boolean noneMatch(Predicate<? super T> predicate) { |
| terminate(); |
| return true; |
| } |
| |
| @Override |
| public Optional<T> findFirst() { |
| terminate(); |
| return Optional.empty(); |
| } |
| |
| @Override |
| public Optional<T> findAny() { |
| terminate(); |
| return Optional.empty(); |
| } |
| |
| @Override |
| public Iterator<T> iterator() { |
| terminate(); |
| return Collections.emptyIterator(); |
| } |
| |
| @Override |
| public Spliterator<T> spliterator() { |
| terminate(); |
| return Spliterators.emptySpliterator(); |
| } |
| |
| @Override |
| public boolean isParallel() { |
| throwIfTerminated(); |
| return false; |
| } |
| |
| @Override |
| public Stream<T> sequential() { |
| throwIfTerminated(); |
| return this; |
| } |
| |
| @Override |
| public Stream<T> parallel() { |
| throwIfTerminated(); |
| return this; |
| } |
| |
| @Override |
| public Stream<T> unordered() { |
| throwIfTerminated(); |
| return this; |
| } |
| } |
| |
| /** |
| * Object to Object map spliterator. |
| * |
| * @param <U> the input type |
| * @param <T> the output type |
| */ |
| private static final class MapToObjSpliterator<U, T> extends Spliterators.AbstractSpliterator<T> { |
| private final Function<? super U, ? extends T> map; |
| private final Spliterator<U> original; |
| |
| public MapToObjSpliterator(Function<? super U, ? extends T> map, Spliterator<U> original) { |
| super( |
| original.estimateSize(), |
| original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)); |
| checkNotNull(map); |
| this.map = map; |
| this.original = original; |
| } |
| |
| @Override |
| public boolean tryAdvance(final Consumer<? super T> action) { |
| return original.tryAdvance(u -> action.accept(map.apply(u))); |
| } |
| } |
| |
| /** |
| * Object to Int map spliterator. |
| * |
| * @param <T> the input type |
| */ |
| private static final class MapToIntSpliterator<T> extends Spliterators.AbstractIntSpliterator { |
| private final ToIntFunction<? super T> map; |
| private final Spliterator<T> original; |
| |
| public MapToIntSpliterator(ToIntFunction<? super T> map, Spliterator<T> original) { |
| super( |
| original.estimateSize(), |
| original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)); |
| checkNotNull(map); |
| this.map = map; |
| this.original = original; |
| } |
| |
| @Override |
| public boolean tryAdvance(final IntConsumer action) { |
| return original.tryAdvance(u -> action.accept(map.applyAsInt(u))); |
| } |
| } |
| |
| /** |
| * Object to Long map spliterator. |
| * |
| * @param <T> the input type |
| */ |
| private static final class MapToLongSpliterator<T> extends Spliterators.AbstractLongSpliterator { |
| private final ToLongFunction<? super T> map; |
| private final Spliterator<T> original; |
| |
| public MapToLongSpliterator(ToLongFunction<? super T> map, Spliterator<T> original) { |
| super( |
| original.estimateSize(), |
| original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)); |
| checkNotNull(map); |
| this.map = map; |
| this.original = original; |
| } |
| |
| @Override |
| public boolean tryAdvance(final LongConsumer action) { |
| return original.tryAdvance(u -> action.accept(map.applyAsLong(u))); |
| } |
| } |
| |
| /** |
| * Object to Double map spliterator. |
| * |
| * @param <T> the input type |
| */ |
| private static final class MapToDoubleSpliterator<T> |
| extends Spliterators.AbstractDoubleSpliterator { |
| private final ToDoubleFunction<? super T> map; |
| private final Spliterator<T> original; |
| |
| public MapToDoubleSpliterator(ToDoubleFunction<? super T> map, Spliterator<T> original) { |
| super( |
| original.estimateSize(), |
| original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)); |
| checkNotNull(map); |
| this.map = map; |
| this.original = original; |
| } |
| |
| @Override |
| public boolean tryAdvance(final DoubleConsumer action) { |
| return original.tryAdvance(u -> action.accept(map.applyAsDouble(u))); |
| } |
| } |
| |
| /** |
| * Object filter spliterator. |
| * |
| * @param <T> the type of data to iterate over |
| */ |
| private static final class FilterSpliterator<T> extends Spliterators.AbstractSpliterator<T> { |
| private final Predicate<? super T> filter; |
| private final Spliterator<T> original; |
| |
| private boolean found; |
| |
| public FilterSpliterator(Predicate<? super T> filter, Spliterator<T> original) { |
| super( |
| original.estimateSize(), |
| original.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED)); |
| checkNotNull(filter); |
| this.filter = filter; |
| this.original = original; |
| } |
| |
| @Override |
| public Comparator<? super T> getComparator() { |
| return original.getComparator(); |
| } |
| |
| @Override |
| public boolean tryAdvance(final Consumer<? super T> action) { |
| found = false; |
| while (!found |
| && original.tryAdvance( |
| item -> { |
| if (filter.test(item)) { |
| found = true; |
| action.accept(item); |
| } |
| })) { |
| // do nothing, work is done in tryAdvance |
| } |
| |
| return found; |
| } |
| } |
| |
| /** |
| * Object skip spliterator. |
| * |
| * @param <T> the type of data to iterate over |
| */ |
| private static final class SkipSpliterator<T> extends Spliterators.AbstractSpliterator<T> { |
| private long skip; |
| private final Spliterator<T> original; |
| |
| public SkipSpliterator(long skip, Spliterator<T> original) { |
| super( |
| original.hasCharacteristics(Spliterator.SIZED) |
| ? Math.max(0, original.estimateSize() - skip) |
| : Long.MAX_VALUE, |
| original.characteristics()); |
| this.skip = skip; |
| this.original = original; |
| } |
| |
| @Override |
| public Comparator<? super T> getComparator() { |
| return original.getComparator(); |
| } |
| |
| @Override |
| public boolean tryAdvance(Consumer<? super T> action) { |
| while (skip > 0) { |
| if (!original.tryAdvance(ignore -> { })) { |
| return false; |
| } |
| skip--; |
| } |
| return original.tryAdvance(action); |
| } |
| } |
| |
| /** |
| * Object limit spliterator. |
| * |
| * @param <T> the type of data to iterate over |
| */ |
| private static final class LimitSpliterator<T> extends Spliterators.AbstractSpliterator<T> { |
| private final long limit; |
| private final Spliterator<T> original; |
| private int position = 0; |
| |
| public LimitSpliterator(long limit, Spliterator<T> original) { |
| super( |
| original.hasCharacteristics(Spliterator.SIZED) |
| ? Math.min(original.estimateSize(), limit) |
| : Long.MAX_VALUE, |
| original.characteristics()); |
| this.limit = limit; |
| this.original = original; |
| } |
| |
| @Override |
| public Comparator<? super T> getComparator() { |
| return original.getComparator(); |
| } |
| |
| @Override |
| public boolean tryAdvance(Consumer<? super T> action) { |
| if (position >= limit) { |
| return false; |
| } |
| boolean result = original.tryAdvance(action); |
| position++; |
| return result; |
| } |
| } |
| |
| /** |
| * Value holder for various stream operations. |
| */ |
| private static final class ValueConsumer<T> implements Consumer<T> { |
| T value; |
| |
| @Override |
| public void accept(T value) { |
| this.value = value; |
| } |
| } |
| |
| private final Spliterator<T> spliterator; |
| |
| public StreamImpl(TerminatableStream<?> prev, Spliterator<T> spliterator) { |
| super(prev); |
| this.spliterator = spliterator; |
| } |
| |
| // terminal |
| @Override |
| public Spliterator<T> spliterator() { |
| terminate(); |
| return spliterator; |
| } |
| |
| @Override |
| public Iterator<T> iterator() { |
| return Spliterators.iterator(spliterator()); |
| } |
| |
| @Override |
| public long count() { |
| terminate(); |
| long count = 0; |
| while (spliterator.tryAdvance(a -> { })) { |
| count++; |
| } |
| return count; |
| } |
| |
| @Override |
| public void forEach(Consumer<? super T> action) { |
| forEachOrdered(action); |
| } |
| |
| @Override |
| public void forEachOrdered(Consumer<? super T> action) { |
| terminate(); |
| spliterator.forEachRemaining(action); |
| } |
| |
| @Override |
| public Object[] toArray() { |
| return toArray(Object[]::new); |
| } |
| |
| @Override |
| public <A> A[] toArray(IntFunction<A[]> generator) { |
| List<T> collected = collect(Collectors.toList()); |
| return collected.toArray(generator.apply(collected.size())); |
| } |
| |
| @Override |
| public <R> R collect( |
| Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner) { |
| return collect( |
| Collector.of( |
| supplier, |
| accumulator, |
| (a, b) -> { |
| combiner.accept(a, b); |
| return a; |
| })); |
| } |
| |
| @Override |
| public <R, A> R collect(final Collector<? super T, A, R> collector) { |
| return collector |
| .finisher() |
| .apply( |
| reduce( |
| collector.supplier().get(), |
| (a, t) -> { |
| collector.accumulator().accept(a, t); |
| return a; |
| }, |
| collector.combiner())); |
| } |
| |
| @Override |
| public Optional<T> findFirst() { |
| terminate(); |
| ValueConsumer<T> holder = new ValueConsumer<T>(); |
| if (spliterator.tryAdvance(holder)) { |
| return Optional.of(holder.value); |
| } |
| return Optional.empty(); |
| } |
| |
| @Override |
| public Optional<T> findAny() { |
| return findFirst(); |
| } |
| |
| private static final Consumer<Object> NULL_CONSUMER = value -> { }; |
| |
| @Override |
| public boolean anyMatch(Predicate<? super T> predicate) { |
| return filter(predicate).spliterator().tryAdvance(NULL_CONSUMER); |
| } |
| |
| @Override |
| public boolean allMatch(final Predicate<? super T> predicate) { |
| return !anyMatch(predicate.negate()); |
| } |
| |
| @Override |
| public boolean noneMatch(final Predicate<? super T> predicate) { |
| return !anyMatch(predicate); |
| } |
| |
| @Override |
| public Optional<T> min(final Comparator<? super T> comparator) { |
| return reduce(BinaryOperator.minBy(comparator)); |
| } |
| |
| @Override |
| public Optional<T> max(final Comparator<? super T> comparator) { |
| return reduce(BinaryOperator.maxBy(comparator)); |
| } |
| |
| @Override |
| public T reduce(T identity, BinaryOperator<T> accumulator) { |
| return reduce(identity, accumulator, accumulator); |
| } |
| |
| @Override |
| public Optional<T> reduce(BinaryOperator<T> accumulator) { |
| ValueConsumer<T> consumer = new ValueConsumer<T>(); |
| if (!spliterator.tryAdvance(consumer)) { |
| terminate(); |
| return Optional.empty(); |
| } |
| return Optional.of(reduce(consumer.value, accumulator)); |
| } |
| |
| // combiner is ignored, since we don't parallelize |
| @Override |
| public <U> U reduce( |
| U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner) { |
| terminate(); |
| final ValueConsumer<U> consumer = new ValueConsumer<U>(); |
| consumer.value = identity; |
| spliterator.forEachRemaining( |
| item -> { |
| consumer.accept(accumulator.apply(consumer.value, item)); |
| }); |
| return consumer.value; |
| } |
| // end terminal |
| |
| // intermediate |
| @Override |
| public Stream<T> filter(Predicate<? super T> predicate) { |
| throwIfTerminated(); |
| return new StreamImpl<>(this, new FilterSpliterator<>(predicate, spliterator)); |
| } |
| |
| @Override |
| public <R> Stream<R> map(Function<? super T, ? extends R> mapper) { |
| throwIfTerminated(); |
| return new StreamImpl<>(this, new MapToObjSpliterator<>(mapper, spliterator)); |
| } |
| |
| @Override |
| public IntStream mapToInt(ToIntFunction<? super T> mapper) { |
| throwIfTerminated(); |
| return new IntStreamImpl(this, new MapToIntSpliterator<>(mapper, spliterator)); |
| } |
| |
| @Override |
| public LongStream mapToLong(ToLongFunction<? super T> mapper) { |
| throwIfTerminated(); |
| return new LongStreamImpl(this, new MapToLongSpliterator<>(mapper, spliterator)); |
| } |
| |
| @Override |
| public DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) { |
| throwIfTerminated(); |
| return new DoubleStreamImpl(this, new MapToDoubleSpliterator<>(mapper, spliterator)); |
| } |
| |
| @Override |
| public <R> Stream<R> flatMap(final Function<? super T, ? extends Stream<? extends R>> mapper) { |
| throwIfTerminated(); |
| final Spliterator<? extends Stream<? extends R>> spliteratorOfStreams = |
| new MapToObjSpliterator<>(mapper, spliterator); |
| |
| AbstractSpliterator<R> flatMapSpliterator = |
| new Spliterators.AbstractSpliterator<R>(Long.MAX_VALUE, 0) { |
| Stream<? extends R> nextStream; |
| Spliterator<? extends R> next; |
| |
| @Override |
| public boolean tryAdvance(Consumer<? super R> action) { |
| // look for a new spliterator |
| while (advanceToNextSpliterator()) { |
| // if we have one, try to read and use it |
| if (next.tryAdvance(action)) { |
| return true; |
| } else { |
| nextStream.close(); |
| nextStream = null; |
| // failed, null it out so we can find another |
| next = null; |
| } |
| } |
| return false; |
| } |
| |
| private boolean advanceToNextSpliterator() { |
| while (next == null) { |
| if (!spliteratorOfStreams.tryAdvance( |
| n -> { |
| if (n != null) { |
| nextStream = n; |
| next = n.spliterator(); |
| } |
| })) { |
| return false; |
| } |
| } |
| return true; |
| } |
| }; |
| |
| return new StreamImpl<R>(this, flatMapSpliterator); |
| } |
| |
| @Override |
| public IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper) { |
| throwIfTerminated(); |
| final Spliterator<? extends IntStream> spliteratorOfStreams = |
| new MapToObjSpliterator<>(mapper, spliterator); |
| |
| AbstractIntSpliterator flatMapSpliterator = |
| new Spliterators.AbstractIntSpliterator(Long.MAX_VALUE, 0) { |
| IntStream nextStream; |
| Spliterator.OfInt next; |
| |
| @Override |
| public boolean tryAdvance(IntConsumer action) { |
| // look for a new spliterator |
| while (advanceToNextSpliterator()) { |
| // if we have one, try to read and use it |
| if (next.tryAdvance(action)) { |
| return true; |
| } else { |
| nextStream.close(); |
| nextStream = null; |
| // failed, null it out so we can find another |
| next = null; |
| } |
| } |
| return false; |
| } |
| |
| private boolean advanceToNextSpliterator() { |
| while (next == null) { |
| if (!spliteratorOfStreams.tryAdvance( |
| n -> { |
| if (n != null) { |
| nextStream = n; |
| next = n.spliterator(); |
| } |
| })) { |
| return false; |
| } |
| } |
| return true; |
| } |
| }; |
| |
| return new IntStreamImpl(this, flatMapSpliterator); |
| } |
| |
| @Override |
| public LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper) { |
| throwIfTerminated(); |
| final Spliterator<? extends LongStream> spliteratorOfStreams = |
| new MapToObjSpliterator<>(mapper, spliterator); |
| |
| AbstractLongSpliterator flatMapSpliterator = |
| new Spliterators.AbstractLongSpliterator(Long.MAX_VALUE, 0) { |
| LongStream nextStream; |
| Spliterator.OfLong next; |
| |
| @Override |
| public boolean tryAdvance(LongConsumer action) { |
| // look for a new spliterator |
| while (advanceToNextSpliterator()) { |
| // if we have one, try to read and use it |
| if (next.tryAdvance(action)) { |
| return true; |
| } else { |
| nextStream.close(); |
| nextStream = null; |
| // failed, null it out so we can find another |
| next = null; |
| } |
| } |
| return false; |
| } |
| |
| private boolean advanceToNextSpliterator() { |
| while (next == null) { |
| if (!spliteratorOfStreams.tryAdvance( |
| n -> { |
| if (n != null) { |
| nextStream = n; |
| next = n.spliterator(); |
| } |
| })) { |
| return false; |
| } |
| } |
| return true; |
| } |
| }; |
| |
| return new LongStreamImpl(this, flatMapSpliterator); |
| } |
| |
| @Override |
| public DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper) { |
| throwIfTerminated(); |
| final Spliterator<? extends DoubleStream> spliteratorOfStreams = |
| new MapToObjSpliterator<>(mapper, spliterator); |
| |
| AbstractDoubleSpliterator flatMapSpliterator = |
| new Spliterators.AbstractDoubleSpliterator(Long.MAX_VALUE, 0) { |
| DoubleStream nextStream; |
| Spliterator.OfDouble next; |
| |
| @Override |
| public boolean tryAdvance(DoubleConsumer action) { |
| // look for a new spliterator |
| while (advanceToNextSpliterator()) { |
| // if we have one, try to read and use it |
| if (next.tryAdvance(action)) { |
| return true; |
| } else { |
| nextStream.close(); |
| nextStream = null; |
| // failed, null it out so we can find another |
| next = null; |
| } |
| } |
| return false; |
| } |
| |
| private boolean advanceToNextSpliterator() { |
| while (next == null) { |
| if (!spliteratorOfStreams.tryAdvance( |
| n -> { |
| if (n != null) { |
| nextStream = n; |
| next = n.spliterator(); |
| } |
| })) { |
| return false; |
| } |
| } |
| return true; |
| } |
| }; |
| |
| return new DoubleStreamImpl(this, flatMapSpliterator); |
| } |
| |
| @Override |
| public Stream<T> distinct() { |
| throwIfTerminated(); |
| HashSet<T> seen = new HashSet<>(); |
| return filter(seen::add); |
| } |
| |
| @Override |
| public Stream<T> sorted() { |
| throwIfTerminated(); |
| Comparator<T> c = (Comparator) Comparator.naturalOrder(); |
| return sorted(c); |
| } |
| |
| @Override |
| public Stream<T> sorted(final Comparator<? super T> comparator) { |
| throwIfTerminated(); |
| |
| AbstractSpliterator<T> sortedSpliterator = |
| new Spliterators.AbstractSpliterator<T>( |
| spliterator.estimateSize(), spliterator.characteristics() | Spliterator.SORTED) { |
| Spliterator<T> ordered = null; |
| |
| @Override |
| public Comparator<? super T> getComparator() { |
| return comparator == Comparator.naturalOrder() ? null : comparator; |
| } |
| |
| @Override |
| public boolean tryAdvance(Consumer<? super T> action) { |
| if (ordered == null) { |
| List<T> list = new ArrayList<>(); |
| spliterator.forEachRemaining(list::add); |
| Collections.sort(list, comparator); |
| ordered = list.spliterator(); |
| } |
| return ordered.tryAdvance(action); |
| } |
| }; |
| |
| return new StreamImpl<>(this, sortedSpliterator); |
| } |
| |
| @Override |
| public Stream<T> peek(final Consumer<? super T> action) { |
| checkNotNull(action); |
| throwIfTerminated(); |
| |
| AbstractSpliterator<T> peekSpliterator = |
| new Spliterators.AbstractSpliterator<T>( |
| spliterator.estimateSize(), spliterator.characteristics()) { |
| @Override |
| public boolean tryAdvance(final Consumer<? super T> innerAction) { |
| return spliterator.tryAdvance( |
| item -> { |
| action.accept(item); |
| innerAction.accept(item); |
| }); |
| } |
| }; |
| |
| return new StreamImpl<>(this, peekSpliterator); |
| } |
| |
| @Override |
| public Stream<T> limit(long maxSize) { |
| throwIfTerminated(); |
| checkState(maxSize >= 0, "maxSize may not be negative"); |
| return new StreamImpl<>(this, new LimitSpliterator<>(maxSize, spliterator)); |
| } |
| |
| @Override |
| public Stream<T> skip(long n) { |
| throwIfTerminated(); |
| checkState(n >= 0, "n may not be negative"); |
| if (n == 0) { |
| return this; |
| } |
| return new StreamImpl<>(this, new SkipSpliterator<>(n, spliterator)); |
| } |
| |
| @Override |
| public boolean isParallel() { |
| throwIfTerminated(); |
| return false; |
| } |
| |
| @Override |
| public Stream<T> sequential() { |
| throwIfTerminated(); |
| return this; |
| } |
| |
| @Override |
| public Stream<T> parallel() { |
| throwIfTerminated(); |
| // do nothing, no such thing as gwt+parallel |
| return this; |
| } |
| |
| @Override |
| public Stream<T> unordered() { |
| throwIfTerminated(); |
| return this; |
| } |
| } |