| /* |
| * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| package java.util.stream; |
| |
| import java.util.Comparator; |
| import java.util.Objects; |
| import java.util.Spliterator; |
| import java.util.concurrent.CountedCompleter; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| import java.util.function.Consumer; |
| import java.util.function.DoubleConsumer; |
| import java.util.function.DoublePredicate; |
| import java.util.function.IntConsumer; |
| import java.util.function.IntFunction; |
| import java.util.function.IntPredicate; |
| import java.util.function.LongConsumer; |
| import java.util.function.LongPredicate; |
| import java.util.function.Predicate; |
| |
| /** |
| * Factory for instances of a takeWhile and dropWhile operations |
| * that produce subsequences of their input stream. |
| * |
| * @since 9 |
| */ |
| final class WhileOps { |
| |
| static final int TAKE_FLAGS = StreamOpFlag.NOT_SIZED | StreamOpFlag.IS_SHORT_CIRCUIT; |
| |
| static final int DROP_FLAGS = StreamOpFlag.NOT_SIZED; |
| |
| /** |
| * Appends a "takeWhile" operation to the provided Stream. |
| * |
| * @param <T> the type of both input and output elements |
| * @param upstream a reference stream with element type T |
| * @param predicate the predicate that returns false to halt taking. |
| */ |
| static <T> Stream<T> makeTakeWhileRef(AbstractPipeline<?, T, ?> upstream, |
| Predicate<? super T> predicate) { |
| Objects.requireNonNull(predicate); |
| return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE, TAKE_FLAGS) { |
| @Override |
| <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper, |
| Spliterator<P_IN> spliterator) { |
| if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) { |
| return opEvaluateParallel(helper, spliterator, Nodes.castingArray()) |
| .spliterator(); |
| } |
| else { |
| return new UnorderedWhileSpliterator.OfRef.Taking<>( |
| helper.wrapSpliterator(spliterator), false, predicate); |
| } |
| } |
| |
| @Override |
| <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper, |
| Spliterator<P_IN> spliterator, |
| IntFunction<T[]> generator) { |
| return new TakeWhileTask<>(this, helper, spliterator, generator) |
| .invoke(); |
| } |
| |
| @Override |
| Sink<T> opWrapSink(int flags, Sink<T> sink) { |
| return new Sink.ChainedReference<T, T>(sink) { |
| boolean take = true; |
| |
| @Override |
| public void begin(long size) { |
| downstream.begin(-1); |
| } |
| |
| @Override |
| public void accept(T t) { |
| if (take = predicate.test(t)) { |
| downstream.accept(t); |
| } |
| } |
| |
| @Override |
| public boolean cancellationRequested() { |
| return !take || downstream.cancellationRequested(); |
| } |
| }; |
| } |
| }; |
| } |
| |
| /** |
| * Appends a "takeWhile" operation to the provided IntStream. |
| * |
| * @param upstream a reference stream with element type T |
| * @param predicate the predicate that returns false to halt taking. |
| */ |
| static IntStream makeTakeWhileInt(AbstractPipeline<?, Integer, ?> upstream, |
| IntPredicate predicate) { |
| Objects.requireNonNull(predicate); |
| return new IntPipeline.StatefulOp<Integer>(upstream, StreamShape.INT_VALUE, TAKE_FLAGS) { |
| @Override |
| <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper, |
| Spliterator<P_IN> spliterator) { |
| if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) { |
| return opEvaluateParallel(helper, spliterator, Integer[]::new) |
| .spliterator(); |
| } |
| else { |
| return new UnorderedWhileSpliterator.OfInt.Taking( |
| (Spliterator.OfInt) helper.wrapSpliterator(spliterator), false, predicate); |
| } |
| } |
| |
| @Override |
| <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper, |
| Spliterator<P_IN> spliterator, |
| IntFunction<Integer[]> generator) { |
| return new TakeWhileTask<>(this, helper, spliterator, generator) |
| .invoke(); |
| } |
| |
| @Override |
| Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) { |
| return new Sink.ChainedInt<Integer>(sink) { |
| boolean take = true; |
| |
| @Override |
| public void begin(long size) { |
| downstream.begin(-1); |
| } |
| |
| @Override |
| public void accept(int t) { |
| if (take = predicate.test(t)) { |
| downstream.accept(t); |
| } |
| } |
| |
| @Override |
| public boolean cancellationRequested() { |
| return !take || downstream.cancellationRequested(); |
| } |
| }; |
| } |
| }; |
| } |
| |
| /** |
| * Appends a "takeWhile" operation to the provided LongStream. |
| * |
| * @param upstream a reference stream with element type T |
| * @param predicate the predicate that returns false to halt taking. |
| */ |
| static LongStream makeTakeWhileLong(AbstractPipeline<?, Long, ?> upstream, |
| LongPredicate predicate) { |
| Objects.requireNonNull(predicate); |
| return new LongPipeline.StatefulOp<Long>(upstream, StreamShape.LONG_VALUE, TAKE_FLAGS) { |
| @Override |
| <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper, |
| Spliterator<P_IN> spliterator) { |
| if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) { |
| return opEvaluateParallel(helper, spliterator, Long[]::new) |
| .spliterator(); |
| } |
| else { |
| return new UnorderedWhileSpliterator.OfLong.Taking( |
| (Spliterator.OfLong) helper.wrapSpliterator(spliterator), false, predicate); |
| } |
| } |
| |
| @Override |
| <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper, |
| Spliterator<P_IN> spliterator, |
| IntFunction<Long[]> generator) { |
| return new TakeWhileTask<>(this, helper, spliterator, generator) |
| .invoke(); |
| } |
| |
| @Override |
| Sink<Long> opWrapSink(int flags, Sink<Long> sink) { |
| return new Sink.ChainedLong<Long>(sink) { |
| boolean take = true; |
| |
| @Override |
| public void begin(long size) { |
| downstream.begin(-1); |
| } |
| |
| @Override |
| public void accept(long t) { |
| if (take = predicate.test(t)) { |
| downstream.accept(t); |
| } |
| } |
| |
| @Override |
| public boolean cancellationRequested() { |
| return !take || downstream.cancellationRequested(); |
| } |
| }; |
| } |
| }; |
| } |
| |
| /** |
| * Appends a "takeWhile" operation to the provided DoubleStream. |
| * |
| * @param upstream a reference stream with element type T |
| * @param predicate the predicate that returns false to halt taking. |
| */ |
| static DoubleStream makeTakeWhileDouble(AbstractPipeline<?, Double, ?> upstream, |
| DoublePredicate predicate) { |
| Objects.requireNonNull(predicate); |
| return new DoublePipeline.StatefulOp<Double>(upstream, StreamShape.DOUBLE_VALUE, TAKE_FLAGS) { |
| @Override |
| <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper, |
| Spliterator<P_IN> spliterator) { |
| if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) { |
| return opEvaluateParallel(helper, spliterator, Double[]::new) |
| .spliterator(); |
| } |
| else { |
| return new UnorderedWhileSpliterator.OfDouble.Taking( |
| (Spliterator.OfDouble) helper.wrapSpliterator(spliterator), false, predicate); |
| } |
| } |
| |
| @Override |
| <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper, |
| Spliterator<P_IN> spliterator, |
| IntFunction<Double[]> generator) { |
| return new TakeWhileTask<>(this, helper, spliterator, generator) |
| .invoke(); |
| } |
| |
| @Override |
| Sink<Double> opWrapSink(int flags, Sink<Double> sink) { |
| return new Sink.ChainedDouble<Double>(sink) { |
| boolean take = true; |
| |
| @Override |
| public void begin(long size) { |
| downstream.begin(-1); |
| } |
| |
| @Override |
| public void accept(double t) { |
| if (take = predicate.test(t)) { |
| downstream.accept(t); |
| } |
| } |
| |
| @Override |
| public boolean cancellationRequested() { |
| return !take || downstream.cancellationRequested(); |
| } |
| }; |
| } |
| }; |
| } |
| |
| /** |
| * A specialization for the dropWhile operation that controls if |
| * elements to be dropped are counted and passed downstream. |
| * <p> |
| * This specialization is utilized by the {@link TakeWhileTask} for |
| * pipelines that are ordered. In such cases elements cannot be dropped |
| * until all elements have been collected. |
| * |
| * @param <T> the type of both input and output elements |
| */ |
| interface DropWhileOp<T> { |
| /** |
| * Accepts a {@code Sink} which will receive the results of this |
| * dropWhile operation, and return a {@code DropWhileSink} which |
| * accepts |
| * elements and which performs the dropWhile operation passing the |
| * results to the provided {@code Sink}. |
| * |
| * @param sink sink to which elements should be sent after processing |
| * @param retainAndCountDroppedElements true if elements to be dropped |
| * are counted and passed to the sink, otherwise such elements |
| * are actually dropped and not passed to the sink. |
| * @return a dropWhile sink |
| */ |
| DropWhileSink<T> opWrapSink(Sink<T> sink, boolean retainAndCountDroppedElements); |
| } |
| |
| /** |
| * A specialization for a dropWhile sink. |
| * |
| * @param <T> the type of both input and output elements |
| */ |
| interface DropWhileSink<T> extends Sink<T> { |
| /** |
| * @return the could of elements that would have been dropped and |
| * instead were passed downstream. |
| */ |
| long getDropCount(); |
| } |
| |
| /** |
| * Appends a "dropWhile" operation to the provided Stream. |
| * |
| * @param <T> the type of both input and output elements |
| * @param upstream a reference stream with element type T |
| * @param predicate the predicate that returns false to halt dropping. |
| */ |
| static <T> Stream<T> makeDropWhileRef(AbstractPipeline<?, T, ?> upstream, |
| Predicate<? super T> predicate) { |
| Objects.requireNonNull(predicate); |
| |
| class Op extends ReferencePipeline.StatefulOp<T, T> implements DropWhileOp<T> { |
| public Op(AbstractPipeline<?, T, ?> upstream, StreamShape inputShape, int opFlags) { |
| super(upstream, inputShape, opFlags); |
| } |
| |
| @Override |
| <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper, |
| Spliterator<P_IN> spliterator) { |
| if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) { |
| return opEvaluateParallel(helper, spliterator, Nodes.castingArray()) |
| .spliterator(); |
| } |
| else { |
| return new UnorderedWhileSpliterator.OfRef.Dropping<>( |
| helper.wrapSpliterator(spliterator), false, predicate); |
| } |
| } |
| |
| @Override |
| <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper, |
| Spliterator<P_IN> spliterator, |
| IntFunction<T[]> generator) { |
| return new DropWhileTask<>(this, helper, spliterator, generator) |
| .invoke(); |
| } |
| |
| @Override |
| Sink<T> opWrapSink(int flags, Sink<T> sink) { |
| return opWrapSink(sink, false); |
| } |
| |
| public DropWhileSink<T> opWrapSink(Sink<T> sink, boolean retainAndCountDroppedElements) { |
| class OpSink extends Sink.ChainedReference<T, T> implements DropWhileSink<T> { |
| long dropCount; |
| boolean take; |
| |
| OpSink() { |
| super(sink); |
| } |
| |
| @Override |
| public void accept(T t) { |
| boolean takeElement = take || (take = !predicate.test(t)); |
| |
| // If ordered and element is dropped increment index |
| // for possible future truncation |
| if (retainAndCountDroppedElements && !takeElement) |
| dropCount++; |
| |
| // If ordered need to process element, otherwise |
| // skip if element is dropped |
| if (retainAndCountDroppedElements || takeElement) |
| downstream.accept(t); |
| } |
| |
| @Override |
| public long getDropCount() { |
| return dropCount; |
| } |
| } |
| return new OpSink(); |
| } |
| } |
| return new Op(upstream, StreamShape.REFERENCE, DROP_FLAGS); |
| } |
| |
| /** |
| * Appends a "dropWhile" operation to the provided IntStream. |
| * |
| * @param upstream a reference stream with element type T |
| * @param predicate the predicate that returns false to halt dropping. |
| */ |
| static IntStream makeDropWhileInt(AbstractPipeline<?, Integer, ?> upstream, |
| IntPredicate predicate) { |
| Objects.requireNonNull(predicate); |
| class Op extends IntPipeline.StatefulOp<Integer> implements DropWhileOp<Integer> { |
| public Op(AbstractPipeline<?, Integer, ?> upstream, StreamShape inputShape, int opFlags) { |
| super(upstream, inputShape, opFlags); |
| } |
| |
| @Override |
| <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper, |
| Spliterator<P_IN> spliterator) { |
| if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) { |
| return opEvaluateParallel(helper, spliterator, Integer[]::new) |
| .spliterator(); |
| } |
| else { |
| return new UnorderedWhileSpliterator.OfInt.Dropping( |
| (Spliterator.OfInt) helper.wrapSpliterator(spliterator), false, predicate); |
| } |
| } |
| |
| @Override |
| <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper, |
| Spliterator<P_IN> spliterator, |
| IntFunction<Integer[]> generator) { |
| return new DropWhileTask<>(this, helper, spliterator, generator) |
| .invoke(); |
| } |
| |
| @Override |
| Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) { |
| return opWrapSink(sink, false); |
| } |
| |
| public DropWhileSink<Integer> opWrapSink(Sink<Integer> sink, boolean retainAndCountDroppedElements) { |
| class OpSink extends Sink.ChainedInt<Integer> implements DropWhileSink<Integer> { |
| long dropCount; |
| boolean take; |
| |
| OpSink() { |
| super(sink); |
| } |
| |
| @Override |
| public void accept(int t) { |
| boolean takeElement = take || (take = !predicate.test(t)); |
| |
| // If ordered and element is dropped increment index |
| // for possible future truncation |
| if (retainAndCountDroppedElements && !takeElement) |
| dropCount++; |
| |
| // If ordered need to process element, otherwise |
| // skip if element is dropped |
| if (retainAndCountDroppedElements || takeElement) |
| downstream.accept(t); |
| } |
| |
| @Override |
| public long getDropCount() { |
| return dropCount; |
| } |
| } |
| return new OpSink(); |
| } |
| } |
| return new Op(upstream, StreamShape.INT_VALUE, DROP_FLAGS); |
| } |
| |
| /** |
| * Appends a "dropWhile" operation to the provided LongStream. |
| * |
| * @param upstream a reference stream with element type T |
| * @param predicate the predicate that returns false to halt dropping. |
| */ |
| static LongStream makeDropWhileLong(AbstractPipeline<?, Long, ?> upstream, |
| LongPredicate predicate) { |
| Objects.requireNonNull(predicate); |
| class Op extends LongPipeline.StatefulOp<Long> implements DropWhileOp<Long> { |
| public Op(AbstractPipeline<?, Long, ?> upstream, StreamShape inputShape, int opFlags) { |
| super(upstream, inputShape, opFlags); |
| } |
| |
| @Override |
| <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper, |
| Spliterator<P_IN> spliterator) { |
| if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) { |
| return opEvaluateParallel(helper, spliterator, Long[]::new) |
| .spliterator(); |
| } |
| else { |
| return new UnorderedWhileSpliterator.OfLong.Dropping( |
| (Spliterator.OfLong) helper.wrapSpliterator(spliterator), false, predicate); |
| } |
| } |
| |
| @Override |
| <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper, |
| Spliterator<P_IN> spliterator, |
| IntFunction<Long[]> generator) { |
| return new DropWhileTask<>(this, helper, spliterator, generator) |
| .invoke(); |
| } |
| |
| @Override |
| Sink<Long> opWrapSink(int flags, Sink<Long> sink) { |
| return opWrapSink(sink, false); |
| } |
| |
| public DropWhileSink<Long> opWrapSink(Sink<Long> sink, boolean retainAndCountDroppedElements) { |
| class OpSink extends Sink.ChainedLong<Long> implements DropWhileSink<Long> { |
| long dropCount; |
| boolean take; |
| |
| OpSink() { |
| super(sink); |
| } |
| |
| @Override |
| public void accept(long t) { |
| boolean takeElement = take || (take = !predicate.test(t)); |
| |
| // If ordered and element is dropped increment index |
| // for possible future truncation |
| if (retainAndCountDroppedElements && !takeElement) |
| dropCount++; |
| |
| // If ordered need to process element, otherwise |
| // skip if element is dropped |
| if (retainAndCountDroppedElements || takeElement) |
| downstream.accept(t); |
| } |
| |
| @Override |
| public long getDropCount() { |
| return dropCount; |
| } |
| } |
| return new OpSink(); |
| } |
| } |
| return new Op(upstream, StreamShape.LONG_VALUE, DROP_FLAGS); |
| } |
| |
| /** |
| * Appends a "dropWhile" operation to the provided DoubleStream. |
| * |
| * @param upstream a reference stream with element type T |
| * @param predicate the predicate that returns false to halt dropping. |
| */ |
| static DoubleStream makeDropWhileDouble(AbstractPipeline<?, Double, ?> upstream, |
| DoublePredicate predicate) { |
| Objects.requireNonNull(predicate); |
| class Op extends DoublePipeline.StatefulOp<Double> implements DropWhileOp<Double> { |
| public Op(AbstractPipeline<?, Double, ?> upstream, StreamShape inputShape, int opFlags) { |
| super(upstream, inputShape, opFlags); |
| } |
| |
| @Override |
| <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper, |
| Spliterator<P_IN> spliterator) { |
| if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) { |
| return opEvaluateParallel(helper, spliterator, Double[]::new) |
| .spliterator(); |
| } |
| else { |
| return new UnorderedWhileSpliterator.OfDouble.Dropping( |
| (Spliterator.OfDouble) helper.wrapSpliterator(spliterator), false, predicate); |
| } |
| } |
| |
| @Override |
| <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper, |
| Spliterator<P_IN> spliterator, |
| IntFunction<Double[]> generator) { |
| return new DropWhileTask<>(this, helper, spliterator, generator) |
| .invoke(); |
| } |
| |
| @Override |
| Sink<Double> opWrapSink(int flags, Sink<Double> sink) { |
| return opWrapSink(sink, false); |
| } |
| |
| public DropWhileSink<Double> opWrapSink(Sink<Double> sink, boolean retainAndCountDroppedElements) { |
| class OpSink extends Sink.ChainedDouble<Double> implements DropWhileSink<Double> { |
| long dropCount; |
| boolean take; |
| |
| OpSink() { |
| super(sink); |
| } |
| |
| @Override |
| public void accept(double t) { |
| boolean takeElement = take || (take = !predicate.test(t)); |
| |
| // If ordered and element is dropped increment index |
| // for possible future truncation |
| if (retainAndCountDroppedElements && !takeElement) |
| dropCount++; |
| |
| // If ordered need to process element, otherwise |
| // skip if element is dropped |
| if (retainAndCountDroppedElements || takeElement) |
| downstream.accept(t); |
| } |
| |
| @Override |
| public long getDropCount() { |
| return dropCount; |
| } |
| } |
| return new OpSink(); |
| } |
| } |
| return new Op(upstream, StreamShape.DOUBLE_VALUE, DROP_FLAGS); |
| } |
| |
| // |
| |
| /** |
| * A spliterator supporting takeWhile and dropWhile operations over an |
| * underlying spliterator whose covered elements have no encounter order. |
| * <p> |
| * Concrete subclasses of this spliterator support reference and primitive |
| * types for takeWhile and dropWhile. |
| * <p> |
| * For the takeWhile operation if during traversal taking completes then |
| * taking is cancelled globally for the splitting and traversal of all |
| * related spliterators. |
| * Cancellation is governed by a shared {@link AtomicBoolean} instance. A |
| * spliterator in the process of taking when cancellation occurs will also |
| * be cancelled but not necessarily immediately. To reduce contention on |
| * the {@link AtomicBoolean} instance, cancellation make be acted on after |
| * a small number of additional elements have been traversed. |
| * <p> |
| * For the dropWhile operation if during traversal dropping completes for |
| * some, but not all elements, then it is cancelled globally for the |
| * traversal of all related spliterators (splitting is not cancelled). |
| * Cancellation is governed in the same manner as for the takeWhile |
| * operation. |
| * |
| * @param <T> the type of elements returned by this spliterator |
| * @param <T_SPLITR> the type of the spliterator |
| */ |
| abstract static class UnorderedWhileSpliterator<T, T_SPLITR extends Spliterator<T>> implements Spliterator<T> { |
| // Power of two constant minus one used for modulus of count |
| static final int CANCEL_CHECK_COUNT = (1 << 6) - 1; |
| |
| // The underlying spliterator |
| final T_SPLITR s; |
| // True if no splitting should be performed, if true then |
| // this spliterator may be used for an underlying spliterator whose |
| // covered elements have an encounter order |
| // See use in stream take/dropWhile default default methods |
| final boolean noSplitting; |
| // True when operations are cancelled for all related spliterators |
| // For taking, spliterators cannot split or traversed |
| // For dropping, spliterators cannot be traversed |
| final AtomicBoolean cancel; |
| // True while taking or dropping should be performed when traversing |
| boolean takeOrDrop = true; |
| // The count of elements traversed |
| int count; |
| |
| UnorderedWhileSpliterator(T_SPLITR s, boolean noSplitting) { |
| this.s = s; |
| this.noSplitting = noSplitting; |
| this.cancel = new AtomicBoolean(); |
| } |
| |
| UnorderedWhileSpliterator(T_SPLITR s, UnorderedWhileSpliterator<T, T_SPLITR> parent) { |
| this.s = s; |
| this.noSplitting = parent.noSplitting; |
| this.cancel = parent.cancel; |
| } |
| |
| @Override |
| public long estimateSize() { |
| return s.estimateSize(); |
| } |
| |
| @Override |
| public int characteristics() { |
| // Size is not known |
| return s.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED); |
| } |
| |
| @Override |
| public long getExactSizeIfKnown() { |
| return -1L; |
| } |
| |
| @Override |
| public Comparator<? super T> getComparator() { |
| return s.getComparator(); |
| } |
| |
| @Override |
| public T_SPLITR trySplit() { |
| @SuppressWarnings("unchecked") |
| T_SPLITR ls = noSplitting ? null : (T_SPLITR) s.trySplit(); |
| return ls != null ? makeSpliterator(ls) : null; |
| } |
| |
| boolean checkCancelOnCount() { |
| return count != 0 || !cancel.get(); |
| } |
| |
| abstract T_SPLITR makeSpliterator(T_SPLITR s); |
| |
| abstract static class OfRef<T> extends UnorderedWhileSpliterator<T, Spliterator<T>> implements Consumer<T> { |
| final Predicate<? super T> p; |
| T t; |
| |
| OfRef(Spliterator<T> s, boolean noSplitting, Predicate<? super T> p) { |
| super(s, noSplitting); |
| this.p = p; |
| } |
| |
| OfRef(Spliterator<T> s, OfRef<T> parent) { |
| super(s, parent); |
| this.p = parent.p; |
| } |
| |
| @Override |
| public void accept(T t) { |
| count = (count + 1) & CANCEL_CHECK_COUNT; |
| this.t = t; |
| } |
| |
| static final class Taking<T> extends OfRef<T> { |
| Taking(Spliterator<T> s, boolean noSplitting, Predicate<? super T> p) { |
| super(s, noSplitting, p); |
| } |
| |
| Taking(Spliterator<T> s, Taking<T> parent) { |
| super(s, parent); |
| } |
| |
| @Override |
| public boolean tryAdvance(Consumer<? super T> action) { |
| boolean test = true; |
| if (takeOrDrop && // If can take |
| checkCancelOnCount() && // and if not cancelled |
| s.tryAdvance(this) && // and if advanced one element |
| (test = p.test(t))) { // and test on element passes |
| action.accept(t); // then accept element |
| return true; |
| } |
| else { |
| // Taking is finished |
| takeOrDrop = false; |
| // Cancel all further traversal and splitting operations |
| // only if test of element failed (short-circuited) |
| if (!test) |
| cancel.set(true); |
| return false; |
| } |
| } |
| |
| @Override |
| public Spliterator<T> trySplit() { |
| // Do not split if all operations are cancelled |
| return cancel.get() ? null : super.trySplit(); |
| } |
| |
| @Override |
| Spliterator<T> makeSpliterator(Spliterator<T> s) { |
| return new Taking<>(s, this); |
| } |
| } |
| |
| static final class Dropping<T> extends OfRef<T> { |
| Dropping(Spliterator<T> s, boolean noSplitting, Predicate<? super T> p) { |
| super(s, noSplitting, p); |
| } |
| |
| Dropping(Spliterator<T> s, Dropping<T> parent) { |
| super(s, parent); |
| } |
| |
| @Override |
| public boolean tryAdvance(Consumer<? super T> action) { |
| if (takeOrDrop) { |
| takeOrDrop = false; |
| boolean adv; |
| boolean dropped = false; |
| while ((adv = s.tryAdvance(this)) && // If advanced one element |
| checkCancelOnCount() && // and if not cancelled |
| p.test(t)) { // and test on element passes |
| dropped = true; // then drop element |
| } |
| |
| // Report advanced element, if any |
| if (adv) { |
| // Cancel all further dropping if one or more elements |
| // were previously dropped |
| if (dropped) |
| cancel.set(true); |
| action.accept(t); |
| } |
| return adv; |
| } |
| else { |
| return s.tryAdvance(action); |
| } |
| } |
| |
| @Override |
| Spliterator<T> makeSpliterator(Spliterator<T> s) { |
| return new Dropping<>(s, this); |
| } |
| } |
| } |
| |
| abstract static class OfInt extends UnorderedWhileSpliterator<Integer, Spliterator.OfInt> implements IntConsumer, Spliterator.OfInt { |
| final IntPredicate p; |
| int t; |
| |
| OfInt(Spliterator.OfInt s, boolean noSplitting, IntPredicate p) { |
| super(s, noSplitting); |
| this.p = p; |
| } |
| |
| OfInt(Spliterator.OfInt s, UnorderedWhileSpliterator.OfInt parent) { |
| super(s, parent); |
| this.p = parent.p; |
| } |
| |
| @Override |
| public void accept(int t) { |
| count = (count + 1) & CANCEL_CHECK_COUNT; |
| this.t = t; |
| } |
| |
| static final class Taking extends UnorderedWhileSpliterator.OfInt { |
| Taking(Spliterator.OfInt s, boolean noSplitting, IntPredicate p) { |
| super(s, noSplitting, p); |
| } |
| |
| Taking(Spliterator.OfInt s, UnorderedWhileSpliterator.OfInt parent) { |
| super(s, parent); |
| } |
| |
| @Override |
| public boolean tryAdvance(IntConsumer action) { |
| boolean test = true; |
| if (takeOrDrop && // If can take |
| checkCancelOnCount() && // and if not cancelled |
| s.tryAdvance(this) && // and if advanced one element |
| (test = p.test(t))) { // and test on element passes |
| action.accept(t); // then accept element |
| return true; |
| } |
| else { |
| // Taking is finished |
| takeOrDrop = false; |
| // Cancel all further traversal and splitting operations |
| // only if test of element failed (short-circuited) |
| if (!test) |
| cancel.set(true); |
| return false; |
| } |
| } |
| |
| @Override |
| public Spliterator.OfInt trySplit() { |
| // Do not split if all operations are cancelled |
| return cancel.get() ? null : super.trySplit(); |
| } |
| |
| @Override |
| Spliterator.OfInt makeSpliterator(Spliterator.OfInt s) { |
| return new Taking(s, this); |
| } |
| } |
| |
| static final class Dropping extends UnorderedWhileSpliterator.OfInt { |
| Dropping(Spliterator.OfInt s, boolean noSplitting, IntPredicate p) { |
| super(s, noSplitting, p); |
| } |
| |
| Dropping(Spliterator.OfInt s, UnorderedWhileSpliterator.OfInt parent) { |
| super(s, parent); |
| } |
| |
| @Override |
| public boolean tryAdvance(IntConsumer action) { |
| if (takeOrDrop) { |
| takeOrDrop = false; |
| boolean adv; |
| boolean dropped = false; |
| while ((adv = s.tryAdvance(this)) && // If advanced one element |
| checkCancelOnCount() && // and if not cancelled |
| p.test(t)) { // and test on element passes |
| dropped = true; // then drop element |
| } |
| |
| // Report advanced element, if any |
| if (adv) { |
| // Cancel all further dropping if one or more elements |
| // were previously dropped |
| if (dropped) |
| cancel.set(true); |
| action.accept(t); |
| } |
| return adv; |
| } |
| else { |
| return s.tryAdvance(action); |
| } |
| } |
| |
| @Override |
| Spliterator.OfInt makeSpliterator(Spliterator.OfInt s) { |
| return new Dropping(s, this); |
| } |
| } |
| } |
| |
| abstract static class OfLong extends UnorderedWhileSpliterator<Long, Spliterator.OfLong> implements LongConsumer, Spliterator.OfLong { |
| final LongPredicate p; |
| long t; |
| |
| OfLong(Spliterator.OfLong s, boolean noSplitting, LongPredicate p) { |
| super(s, noSplitting); |
| this.p = p; |
| } |
| |
| OfLong(Spliterator.OfLong s, UnorderedWhileSpliterator.OfLong parent) { |
| super(s, parent); |
| this.p = parent.p; |
| } |
| |
| @Override |
| public void accept(long t) { |
| count = (count + 1) & CANCEL_CHECK_COUNT; |
| this.t = t; |
| } |
| |
| static final class Taking extends UnorderedWhileSpliterator.OfLong { |
| Taking(Spliterator.OfLong s, boolean noSplitting, LongPredicate p) { |
| super(s, noSplitting, p); |
| } |
| |
| Taking(Spliterator.OfLong s, UnorderedWhileSpliterator.OfLong parent) { |
| super(s, parent); |
| } |
| |
| @Override |
| public boolean tryAdvance(LongConsumer action) { |
| boolean test = true; |
| if (takeOrDrop && // If can take |
| checkCancelOnCount() && // and if not cancelled |
| s.tryAdvance(this) && // and if advanced one element |
| (test = p.test(t))) { // and test on element passes |
| action.accept(t); // then accept element |
| return true; |
| } |
| else { |
| // Taking is finished |
| takeOrDrop = false; |
| // Cancel all further traversal and splitting operations |
| // only if test of element failed (short-circuited) |
| if (!test) |
| cancel.set(true); |
| return false; |
| } |
| } |
| |
| @Override |
| public Spliterator.OfLong trySplit() { |
| // Do not split if all operations are cancelled |
| return cancel.get() ? null : super.trySplit(); |
| } |
| |
| @Override |
| Spliterator.OfLong makeSpliterator(Spliterator.OfLong s) { |
| return new Taking(s, this); |
| } |
| } |
| |
| static final class Dropping extends UnorderedWhileSpliterator.OfLong { |
| Dropping(Spliterator.OfLong s, boolean noSplitting, LongPredicate p) { |
| super(s, noSplitting, p); |
| } |
| |
| Dropping(Spliterator.OfLong s, UnorderedWhileSpliterator.OfLong parent) { |
| super(s, parent); |
| } |
| |
| @Override |
| public boolean tryAdvance(LongConsumer action) { |
| if (takeOrDrop) { |
| takeOrDrop = false; |
| boolean adv; |
| boolean dropped = false; |
| while ((adv = s.tryAdvance(this)) && // If advanced one element |
| checkCancelOnCount() && // and if not cancelled |
| p.test(t)) { // and test on element passes |
| dropped = true; // then drop element |
| } |
| |
| // Report advanced element, if any |
| if (adv) { |
| // Cancel all further dropping if one or more elements |
| // were previously dropped |
| if (dropped) |
| cancel.set(true); |
| action.accept(t); |
| } |
| return adv; |
| } |
| else { |
| return s.tryAdvance(action); |
| } |
| } |
| |
| @Override |
| Spliterator.OfLong makeSpliterator(Spliterator.OfLong s) { |
| return new Dropping(s, this); |
| } |
| } |
| } |
| |
| abstract static class OfDouble extends UnorderedWhileSpliterator<Double, Spliterator.OfDouble> implements DoubleConsumer, Spliterator.OfDouble { |
| final DoublePredicate p; |
| double t; |
| |
| OfDouble(Spliterator.OfDouble s, boolean noSplitting, DoublePredicate p) { |
| super(s, noSplitting); |
| this.p = p; |
| } |
| |
| OfDouble(Spliterator.OfDouble s, UnorderedWhileSpliterator.OfDouble parent) { |
| super(s, parent); |
| this.p = parent.p; |
| } |
| |
| @Override |
| public void accept(double t) { |
| count = (count + 1) & CANCEL_CHECK_COUNT; |
| this.t = t; |
| } |
| |
| static final class Taking extends UnorderedWhileSpliterator.OfDouble { |
| Taking(Spliterator.OfDouble s, boolean noSplitting, DoublePredicate p) { |
| super(s, noSplitting, p); |
| } |
| |
| Taking(Spliterator.OfDouble s, UnorderedWhileSpliterator.OfDouble parent) { |
| super(s, parent); |
| } |
| |
| @Override |
| public boolean tryAdvance(DoubleConsumer action) { |
| boolean test = true; |
| if (takeOrDrop && // If can take |
| checkCancelOnCount() && // and if not cancelled |
| s.tryAdvance(this) && // and if advanced one element |
| (test = p.test(t))) { // and test on element passes |
| action.accept(t); // then accept element |
| return true; |
| } |
| else { |
| // Taking is finished |
| takeOrDrop = false; |
| // Cancel all further traversal and splitting operations |
| // only if test of element failed (short-circuited) |
| if (!test) |
| cancel.set(true); |
| return false; |
| } |
| } |
| |
| @Override |
| public Spliterator.OfDouble trySplit() { |
| // Do not split if all operations are cancelled |
| return cancel.get() ? null : super.trySplit(); |
| } |
| |
| @Override |
| Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s) { |
| return new Taking(s, this); |
| } |
| } |
| |
| static final class Dropping extends UnorderedWhileSpliterator.OfDouble { |
| Dropping(Spliterator.OfDouble s, boolean noSplitting, DoublePredicate p) { |
| super(s, noSplitting, p); |
| } |
| |
| Dropping(Spliterator.OfDouble s, UnorderedWhileSpliterator.OfDouble parent) { |
| super(s, parent); |
| } |
| |
| @Override |
| public boolean tryAdvance(DoubleConsumer action) { |
| if (takeOrDrop) { |
| takeOrDrop = false; |
| boolean adv; |
| boolean dropped = false; |
| while ((adv = s.tryAdvance(this)) && // If advanced one element |
| checkCancelOnCount() && // and if not cancelled |
| p.test(t)) { // and test on element passes |
| dropped = true; // then drop element |
| } |
| |
| // Report advanced element, if any |
| if (adv) { |
| // Cancel all further dropping if one or more elements |
| // were previously dropped |
| if (dropped) |
| cancel.set(true); |
| action.accept(t); |
| } |
| return adv; |
| } |
| else { |
| return s.tryAdvance(action); |
| } |
| } |
| |
| @Override |
| Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s) { |
| return new Dropping(s, this); |
| } |
| } |
| } |
| } |
| |
| |
| // |
| |
| /** |
| * {@code ForkJoinTask} implementing takeWhile computation. |
| * <p> |
| * If the pipeline has encounter order then all tasks to the right of |
| * a task where traversal was short-circuited are cancelled. |
| * The results of completed (and cancelled) tasks are discarded. |
| * The result of merging a short-circuited left task and right task (which |
| * may or may not be short-circuited) is that left task. |
| * <p> |
| * If the pipeline has no encounter order then all tasks to the right of |
| * a task where traversal was short-circuited are cancelled. |
| * The results of completed (and possibly cancelled) tasks are not |
| * discarded, as there is no need to throw away computed results. |
| * The result of merging does not change if a left task was |
| * short-circuited. |
| * No attempt is made, once a leaf task stopped taking, for it to cancel |
| * all other tasks, and further more, short-circuit the computation with its |
| * result. |
| * |
| * @param <P_IN> Input element type to the stream pipeline |
| * @param <P_OUT> Output element type from the stream pipeline |
| */ |
| @SuppressWarnings("serial") |
| private static final class TakeWhileTask<P_IN, P_OUT> |
| extends AbstractShortCircuitTask<P_IN, P_OUT, Node<P_OUT>, TakeWhileTask<P_IN, P_OUT>> { |
| private final AbstractPipeline<P_OUT, P_OUT, ?> op; |
| private final IntFunction<P_OUT[]> generator; |
| private final boolean isOrdered; |
| private long thisNodeSize; |
| // True if a short-circuited |
| private boolean shortCircuited; |
| // True if completed, must be set after the local result |
| private volatile boolean completed; |
| |
| TakeWhileTask(AbstractPipeline<P_OUT, P_OUT, ?> op, |
| PipelineHelper<P_OUT> helper, |
| Spliterator<P_IN> spliterator, |
| IntFunction<P_OUT[]> generator) { |
| super(helper, spliterator); |
| this.op = op; |
| this.generator = generator; |
| this.isOrdered = StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags()); |
| } |
| |
| TakeWhileTask(TakeWhileTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) { |
| super(parent, spliterator); |
| this.op = parent.op; |
| this.generator = parent.generator; |
| this.isOrdered = parent.isOrdered; |
| } |
| |
| @Override |
| protected TakeWhileTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) { |
| return new TakeWhileTask<>(this, spliterator); |
| } |
| |
| @Override |
| protected final Node<P_OUT> getEmptyResult() { |
| return Nodes.emptyNode(op.getOutputShape()); |
| } |
| |
| @Override |
| protected final Node<P_OUT> doLeaf() { |
| Node.Builder<P_OUT> builder = helper.makeNodeBuilder(-1, generator); |
| Sink<P_OUT> s = op.opWrapSink(helper.getStreamAndOpFlags(), builder); |
| |
| if (shortCircuited = helper.copyIntoWithCancel(helper.wrapSink(s), spliterator)) { |
| // Cancel later nodes if the predicate returned false |
| // during traversal |
| cancelLaterNodes(); |
| } |
| |
| Node<P_OUT> node = builder.build(); |
| thisNodeSize = node.count(); |
| return node; |
| } |
| |
| @Override |
| public final void onCompletion(CountedCompleter<?> caller) { |
| if (!isLeaf()) { |
| Node<P_OUT> result; |
| shortCircuited = leftChild.shortCircuited | rightChild.shortCircuited; |
| if (isOrdered && canceled) { |
| thisNodeSize = 0; |
| result = getEmptyResult(); |
| } |
| else if (isOrdered && leftChild.shortCircuited) { |
| // If taking finished on the left node then |
| // use the left node result |
| thisNodeSize = leftChild.thisNodeSize; |
| result = leftChild.getLocalResult(); |
| } |
| else { |
| thisNodeSize = leftChild.thisNodeSize + rightChild.thisNodeSize; |
| result = merge(); |
| } |
| |
| setLocalResult(result); |
| } |
| |
| completed = true; |
| super.onCompletion(caller); |
| } |
| |
| Node<P_OUT> merge() { |
| if (leftChild.thisNodeSize == 0) { |
| // If the left node size is 0 then |
| // use the right node result |
| return rightChild.getLocalResult(); |
| } |
| else if (rightChild.thisNodeSize == 0) { |
| // If the right node size is 0 then |
| // use the left node result |
| return leftChild.getLocalResult(); |
| } |
| else { |
| // Combine the left and right nodes |
| return Nodes.conc(op.getOutputShape(), |
| leftChild.getLocalResult(), rightChild.getLocalResult()); |
| } |
| } |
| |
| @Override |
| protected void cancel() { |
| super.cancel(); |
| if (isOrdered && completed) |
| // If the task is completed then clear the result, if any |
| // to aid GC |
| setLocalResult(getEmptyResult()); |
| } |
| } |
| |
| /** |
| * {@code ForkJoinTask} implementing dropWhile computation. |
| * <p> |
| * If the pipeline has encounter order then each leaf task will not |
| * drop elements but will obtain a count of the elements that would have |
| * been otherwise dropped. That count is used as an index to track |
| * elements to be dropped. Merging will update the index so it corresponds |
| * to the index that is the end of the global prefix of elements to be |
| * dropped. The root is truncated according to that index. |
| * <p> |
| * If the pipeline has no encounter order then each leaf task will drop |
| * elements. Leaf tasks are ordinarily merged. No truncation of the root |
| * node is required. |
| * No attempt is made, once a leaf task stopped dropping, for it to cancel |
| * all other tasks, and further more, short-circuit the computation with |
| * its result. |
| * |
| * @param <P_IN> Input element type to the stream pipeline |
| * @param <P_OUT> Output element type from the stream pipeline |
| */ |
| @SuppressWarnings("serial") |
| private static final class DropWhileTask<P_IN, P_OUT> |
| extends AbstractTask<P_IN, P_OUT, Node<P_OUT>, DropWhileTask<P_IN, P_OUT>> { |
| private final AbstractPipeline<P_OUT, P_OUT, ?> op; |
| private final IntFunction<P_OUT[]> generator; |
| private final boolean isOrdered; |
| private long thisNodeSize; |
| // The index from which elements of the node should be taken |
| // i.e. the node should be truncated from [takeIndex, thisNodeSize) |
| // Equivalent to the count of dropped elements |
| private long index; |
| |
| DropWhileTask(AbstractPipeline<P_OUT, P_OUT, ?> op, |
| PipelineHelper<P_OUT> helper, |
| Spliterator<P_IN> spliterator, |
| IntFunction<P_OUT[]> generator) { |
| super(helper, spliterator); |
| assert op instanceof DropWhileOp; |
| this.op = op; |
| this.generator = generator; |
| this.isOrdered = StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags()); |
| } |
| |
| DropWhileTask(DropWhileTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) { |
| super(parent, spliterator); |
| this.op = parent.op; |
| this.generator = parent.generator; |
| this.isOrdered = parent.isOrdered; |
| } |
| |
| @Override |
| protected DropWhileTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) { |
| return new DropWhileTask<>(this, spliterator); |
| } |
| |
| @Override |
| protected final Node<P_OUT> doLeaf() { |
| boolean isChild = !isRoot(); |
| // If this not the root and pipeline is ordered and size is known |
| // then pre-size the builder |
| long sizeIfKnown = isChild && isOrdered && StreamOpFlag.SIZED.isPreserved(op.sourceOrOpFlags) |
| ? op.exactOutputSizeIfKnown(spliterator) |
| : -1; |
| Node.Builder<P_OUT> builder = helper.makeNodeBuilder(sizeIfKnown, generator); |
| @SuppressWarnings("unchecked") |
| DropWhileOp<P_OUT> dropOp = (DropWhileOp<P_OUT>) op; |
| // If this leaf is the root then there is no merging on completion |
| // and there is no need to retain dropped elements |
| DropWhileSink<P_OUT> s = dropOp.opWrapSink(builder, isOrdered && isChild); |
| helper.wrapAndCopyInto(s, spliterator); |
| |
| Node<P_OUT> node = builder.build(); |
| thisNodeSize = node.count(); |
| index = s.getDropCount(); |
| return node; |
| } |
| |
| @Override |
| public final void onCompletion(CountedCompleter<?> caller) { |
| if (!isLeaf()) { |
| if (isOrdered) { |
| index = leftChild.index; |
| // If a contiguous sequence of dropped elements |
| // include those of the right node, if any |
| if (index == leftChild.thisNodeSize) |
| index += rightChild.index; |
| } |
| |
| thisNodeSize = leftChild.thisNodeSize + rightChild.thisNodeSize; |
| Node<P_OUT> result = merge(); |
| setLocalResult(isRoot() ? doTruncate(result) : result); |
| } |
| |
| super.onCompletion(caller); |
| } |
| |
| private Node<P_OUT> merge() { |
| if (leftChild.thisNodeSize == 0) { |
| // If the left node size is 0 then |
| // use the right node result |
| return rightChild.getLocalResult(); |
| } |
| else if (rightChild.thisNodeSize == 0) { |
| // If the right node size is 0 then |
| // use the left node result |
| return leftChild.getLocalResult(); |
| } |
| else { |
| // Combine the left and right nodes |
| return Nodes.conc(op.getOutputShape(), |
| leftChild.getLocalResult(), rightChild.getLocalResult()); |
| } |
| } |
| |
| private Node<P_OUT> doTruncate(Node<P_OUT> input) { |
| return isOrdered |
| ? input.truncate(index, input.count(), generator) |
| : input; |
| } |
| } |
| } |