1 /*
2  * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package java.util.stream;
26 
27 import java.util.Comparator;
28 import java.util.Objects;
29 import java.util.Spliterator;
30 import java.util.concurrent.CountedCompleter;
31 import java.util.concurrent.atomic.AtomicBoolean;
32 import java.util.function.Consumer;
33 import java.util.function.DoubleConsumer;
34 import java.util.function.DoublePredicate;
35 import java.util.function.IntConsumer;
36 import java.util.function.IntFunction;
37 import java.util.function.IntPredicate;
38 import java.util.function.LongConsumer;
39 import java.util.function.LongPredicate;
40 import java.util.function.Predicate;
41 
42 /**
43  * Factory for instances of a takeWhile and dropWhile operations
44  * that produce subsequences of their input stream.
45  *
46  * @since 9
47  */
48 final class WhileOps {
49 
50     static final int TAKE_FLAGS = StreamOpFlag.NOT_SIZED | StreamOpFlag.IS_SHORT_CIRCUIT;
51 
52     static final int DROP_FLAGS = StreamOpFlag.NOT_SIZED;
53 
54     /**
55      * Appends a "takeWhile" operation to the provided Stream.
56      *
57      * @param <T> the type of both input and output elements
58      * @param upstream a reference stream with element type T
59      * @param predicate the predicate that returns false to halt taking.
60      */
makeTakeWhileRef(AbstractPipeline<?, T, ?> upstream, Predicate<? super T> predicate)61     static <T> Stream<T> makeTakeWhileRef(AbstractPipeline<?, T, ?> upstream,
62                                           Predicate<? super T> predicate) {
63         Objects.requireNonNull(predicate);
64         return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE, TAKE_FLAGS) {
65             @Override
66             // Android-changed: Make public, to match the method it's overriding.
67             public <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper,
68                                                          Spliterator<P_IN> spliterator) {
69                 if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
70                     return opEvaluateParallel(helper, spliterator, Nodes.castingArray())
71                             .spliterator();
72                 }
73                 else {
74                     return new UnorderedWhileSpliterator.OfRef.Taking<>(
75                             helper.wrapSpliterator(spliterator), false, predicate);
76                 }
77             }
78 
79             @Override
80             // Android-changed: Make public, to match the method it's overriding.
81             public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
82                                               Spliterator<P_IN> spliterator,
83                                               IntFunction<T[]> generator) {
84                 return new TakeWhileTask<>(this, helper, spliterator, generator)
85                         .invoke();
86             }
87 
88             @Override
89             // Android-changed: Make public, to match the method it's overriding.
90             public Sink<T> opWrapSink(int flags, Sink<T> sink) {
91                 return new Sink.ChainedReference<T, T>(sink) {
92                     boolean take = true;
93 
94                     @Override
95                     public void begin(long size) {
96                         downstream.begin(-1);
97                     }
98 
99                     @Override
100                     public void accept(T t) {
101                         if (take && (take = predicate.test(t))) {
102                             downstream.accept(t);
103                         }
104                     }
105 
106                     @Override
107                     public boolean cancellationRequested() {
108                         return !take || downstream.cancellationRequested();
109                     }
110                 };
111             }
112         };
113     }
114 
115     /**
116      * Appends a "takeWhile" operation to the provided IntStream.
117      *
118      * @param upstream a reference stream with element type T
119      * @param predicate the predicate that returns false to halt taking.
120      */
121     static IntStream makeTakeWhileInt(AbstractPipeline<?, Integer, ?> upstream,
122                                       IntPredicate predicate) {
123         Objects.requireNonNull(predicate);
124         return new IntPipeline.StatefulOp<Integer>(upstream, StreamShape.INT_VALUE, TAKE_FLAGS) {
125             @Override
126             // Android-changed: Make public, to match the method it's overriding.
127             public <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
128                                                                Spliterator<P_IN> spliterator) {
129                 if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
130                     return opEvaluateParallel(helper, spliterator, Integer[]::new)
131                             .spliterator();
132                 }
133                 else {
134                     return new UnorderedWhileSpliterator.OfInt.Taking(
135                             (Spliterator.OfInt) helper.wrapSpliterator(spliterator), false, predicate);
136                 }
137             }
138 
139             @Override
140             // Android-changed: Make public, to match the method it's overriding.
141             public <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
142                                                     Spliterator<P_IN> spliterator,
143                                                     IntFunction<Integer[]> generator) {
144                 return new TakeWhileTask<>(this, helper, spliterator, generator)
145                         .invoke();
146             }
147 
148             @Override
149             // Android-changed: Make public, to match the method it's overriding.
150             public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
151                 return new Sink.ChainedInt<Integer>(sink) {
152                     boolean take = true;
153 
154                     @Override
155                     public void begin(long size) {
156                         downstream.begin(-1);
157                     }
158 
159                     @Override
160                     public void accept(int t) {
161                         if (take && (take = predicate.test(t))) {
162                             downstream.accept(t);
163                         }
164                     }
165 
166                     @Override
167                     public boolean cancellationRequested() {
168                         return !take || downstream.cancellationRequested();
169                     }
170                 };
171             }
172         };
173     }
174 
175     /**
176      * Appends a "takeWhile" operation to the provided LongStream.
177      *
178      * @param upstream a reference stream with element type T
179      * @param predicate the predicate that returns false to halt taking.
180      */
181     static LongStream makeTakeWhileLong(AbstractPipeline<?, Long, ?> upstream,
182                                         LongPredicate predicate) {
183         Objects.requireNonNull(predicate);
184         return new LongPipeline.StatefulOp<Long>(upstream, StreamShape.LONG_VALUE, TAKE_FLAGS) {
185             @Override
186             // Android-changed: Make public, to match the method it's overriding.
187             public <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
188                                                             Spliterator<P_IN> spliterator) {
189                 if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
190                     return opEvaluateParallel(helper, spliterator, Long[]::new)
191                             .spliterator();
192                 }
193                 else {
194                     return new UnorderedWhileSpliterator.OfLong.Taking(
195                             (Spliterator.OfLong) helper.wrapSpliterator(spliterator), false, predicate);
196                 }
197             }
198 
199             @Override
200             // Android-changed: Make public, to match the method it's overriding.
201             public <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
202                                                  Spliterator<P_IN> spliterator,
203                                                  IntFunction<Long[]> generator) {
204                 return new TakeWhileTask<>(this, helper, spliterator, generator)
205                         .invoke();
206             }
207 
208             @Override
209             // Android-changed: Make public, to match the method it's overriding.
210             public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
211                 return new Sink.ChainedLong<Long>(sink) {
212                     boolean take = true;
213 
214                     @Override
215                     public void begin(long size) {
216                         downstream.begin(-1);
217                     }
218 
219                     @Override
220                     public void accept(long t) {
221                         if (take && (take = predicate.test(t))) {
222                             downstream.accept(t);
223                         }
224                     }
225 
226                     @Override
227                     public boolean cancellationRequested() {
228                         return !take || downstream.cancellationRequested();
229                     }
230                 };
231             }
232         };
233     }
234 
235     /**
236      * Appends a "takeWhile" operation to the provided DoubleStream.
237      *
238      * @param upstream a reference stream with element type T
239      * @param predicate the predicate that returns false to halt taking.
240      */
241     static DoubleStream makeTakeWhileDouble(AbstractPipeline<?, Double, ?> upstream,
242                                             DoublePredicate predicate) {
243         Objects.requireNonNull(predicate);
244         return new DoublePipeline.StatefulOp<Double>(upstream, StreamShape.DOUBLE_VALUE, TAKE_FLAGS) {
245             @Override
246             // Android-changed: Make public, to match the method it's overriding.
247             public <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
248                                                               Spliterator<P_IN> spliterator) {
249                 if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
250                     return opEvaluateParallel(helper, spliterator, Double[]::new)
251                             .spliterator();
252                 }
253                 else {
254                     return new UnorderedWhileSpliterator.OfDouble.Taking(
255                             (Spliterator.OfDouble) helper.wrapSpliterator(spliterator), false, predicate);
256                 }
257             }
258 
259             @Override
260             // Android-changed: Make public, to match the method it's overriding.
261             public <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
262                                                    Spliterator<P_IN> spliterator,
263                                                    IntFunction<Double[]> generator) {
264                 return new TakeWhileTask<>(this, helper, spliterator, generator)
265                         .invoke();
266             }
267 
268             @Override
269             // Android-changed: Make public, to match the method it's overriding.
270             public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
271                 return new Sink.ChainedDouble<Double>(sink) {
272                     boolean take = true;
273 
274                     @Override
275                     public void begin(long size) {
276                         downstream.begin(-1);
277                     }
278 
279                     @Override
280                     public void accept(double t) {
281                         if (take && (take = predicate.test(t))) {
282                             downstream.accept(t);
283                         }
284                     }
285 
286                     @Override
287                     public boolean cancellationRequested() {
288                         return !take || downstream.cancellationRequested();
289                     }
290                 };
291             }
292         };
293     }
294 
295     /**
296      * A specialization for the dropWhile operation that controls if
297      * elements to be dropped are counted and passed downstream.
298      * <p>
299      * This specialization is utilized by the {@link TakeWhileTask} for
300      * pipelines that are ordered.  In such cases elements cannot be dropped
301      * until all elements have been collected.
302      *
303      * @param <T> the type of both input and output elements
304      */
305     interface DropWhileOp<T> {
306         /**
307          * Accepts a {@code Sink} which will receive the results of this
308          * dropWhile operation, and return a {@code DropWhileSink} which
309          * accepts
310          * elements and which performs the dropWhile operation passing the
311          * results to the provided {@code Sink}.
312          *
313          * @param sink sink to which elements should be sent after processing
314          * @param retainAndCountDroppedElements true if elements to be dropped
315          * are counted and passed to the sink, otherwise such elements
316          * are actually dropped and not passed to the sink.
317          * @return a dropWhile sink
318          */
319         DropWhileSink<T> opWrapSink(Sink<T> sink, boolean retainAndCountDroppedElements);
320     }
321 
322     /**
323      * A specialization for a dropWhile sink.
324      *
325      * @param <T> the type of both input and output elements
326      */
327     interface DropWhileSink<T> extends Sink<T> {
328         /**
329          * @return the could of elements that would have been dropped and
330          * instead were passed downstream.
331          */
332         long getDropCount();
333     }
334 
335     /**
336      * Appends a "dropWhile" operation to the provided Stream.
337      *
338      * @param <T> the type of both input and output elements
339      * @param upstream a reference stream with element type T
340      * @param predicate the predicate that returns false to halt dropping.
341      */
342     static <T> Stream<T> makeDropWhileRef(AbstractPipeline<?, T, ?> upstream,
343                                           Predicate<? super T> predicate) {
344         Objects.requireNonNull(predicate);
345 
346         class Op extends ReferencePipeline.StatefulOp<T, T> implements DropWhileOp<T> {
347             public Op(AbstractPipeline<?, T, ?> upstream, StreamShape inputShape, int opFlags) {
348                 super(upstream, inputShape, opFlags);
349             }
350 
351             @Override
352             // Android-changed: Make public, to match the method it's overriding.
353             public <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper,
354                                                          Spliterator<P_IN> spliterator) {
355                 if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
356                     return opEvaluateParallel(helper, spliterator, Nodes.castingArray())
357                             .spliterator();
358                 }
359                 else {
360                     return new UnorderedWhileSpliterator.OfRef.Dropping<>(
361                             helper.wrapSpliterator(spliterator), false, predicate);
362                 }
363             }
364 
365             @Override
366             // Android-changed: Make public, to match the method it's overriding.
367             public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
368                                               Spliterator<P_IN> spliterator,
369                                               IntFunction<T[]> generator) {
370                 return new DropWhileTask<>(this, helper, spliterator, generator)
371                         .invoke();
372             }
373 
374             @Override
375             // Android-changed: Make public, to match the method it's overriding.
376             public Sink<T> opWrapSink(int flags, Sink<T> sink) {
377                 return opWrapSink(sink, false);
378             }
379 
380             public DropWhileSink<T> opWrapSink(Sink<T> sink, boolean retainAndCountDroppedElements) {
381                 class OpSink extends Sink.ChainedReference<T, T> implements DropWhileSink<T> {
382                     long dropCount;
383                     boolean take;
384 
385                     OpSink() {
386                         super(sink);
387                     }
388 
389                     @Override
390                     public void accept(T t) {
391                         boolean takeElement = take || (take = !predicate.test(t));
392 
393                         // If ordered and element is dropped increment index
394                         // for possible future truncation
395                         if (retainAndCountDroppedElements && !takeElement)
396                             dropCount++;
397 
398                         // If ordered need to process element, otherwise
399                         // skip if element is dropped
400                         if (retainAndCountDroppedElements || takeElement)
401                             downstream.accept(t);
402                     }
403 
404                     @Override
405                     public long getDropCount() {
406                         return dropCount;
407                     }
408                 }
409                 return new OpSink();
410             }
411         }
412         return new Op(upstream, StreamShape.REFERENCE, DROP_FLAGS);
413     }
414 
415     /**
416      * Appends a "dropWhile" operation to the provided IntStream.
417      *
418      * @param upstream a reference stream with element type T
419      * @param predicate the predicate that returns false to halt dropping.
420      */
421     static IntStream makeDropWhileInt(AbstractPipeline<?, Integer, ?> upstream,
422                                       IntPredicate predicate) {
423         Objects.requireNonNull(predicate);
424         class Op extends IntPipeline.StatefulOp<Integer> implements DropWhileOp<Integer> {
425             public Op(AbstractPipeline<?, Integer, ?> upstream, StreamShape inputShape, int opFlags) {
426                 super(upstream, inputShape, opFlags);
427             }
428 
429             @Override
430             // Android-changed: Make public, to match the method it's overriding.
431             public <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
432                                                                Spliterator<P_IN> spliterator) {
433                 if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
434                     return opEvaluateParallel(helper, spliterator, Integer[]::new)
435                             .spliterator();
436                 }
437                 else {
438                     return new UnorderedWhileSpliterator.OfInt.Dropping(
439                             (Spliterator.OfInt) helper.wrapSpliterator(spliterator), false, predicate);
440                 }
441             }
442 
443             @Override
444             // Android-changed: Make public, to match the method it's overriding.
445             public <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
446                                                     Spliterator<P_IN> spliterator,
447                                                     IntFunction<Integer[]> generator) {
448                 return new DropWhileTask<>(this, helper, spliterator, generator)
449                         .invoke();
450             }
451 
452             @Override
453             // Android-changed: Make public, to match the method it's overriding.
454             public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
455                 return opWrapSink(sink, false);
456             }
457 
458             public DropWhileSink<Integer> opWrapSink(Sink<Integer> sink, boolean retainAndCountDroppedElements) {
459                 class OpSink extends Sink.ChainedInt<Integer> implements DropWhileSink<Integer> {
460                     long dropCount;
461                     boolean take;
462 
463                     OpSink() {
464                         super(sink);
465                     }
466 
467                     @Override
468                     public void accept(int t) {
469                         boolean takeElement = take || (take = !predicate.test(t));
470 
471                         // If ordered and element is dropped increment index
472                         // for possible future truncation
473                         if (retainAndCountDroppedElements && !takeElement)
474                             dropCount++;
475 
476                         // If ordered need to process element, otherwise
477                         // skip if element is dropped
478                         if (retainAndCountDroppedElements || takeElement)
479                             downstream.accept(t);
480                     }
481 
482                     @Override
483                     public long getDropCount() {
484                         return dropCount;
485                     }
486                 }
487                 return new OpSink();
488             }
489         }
490         return new Op(upstream, StreamShape.INT_VALUE, DROP_FLAGS);
491     }
492 
493     /**
494      * Appends a "dropWhile" operation to the provided LongStream.
495      *
496      * @param upstream a reference stream with element type T
497      * @param predicate the predicate that returns false to halt dropping.
498      */
499     static LongStream makeDropWhileLong(AbstractPipeline<?, Long, ?> upstream,
500                                         LongPredicate predicate) {
501         Objects.requireNonNull(predicate);
502         class Op extends LongPipeline.StatefulOp<Long> implements DropWhileOp<Long> {
503             public Op(AbstractPipeline<?, Long, ?> upstream, StreamShape inputShape, int opFlags) {
504                 super(upstream, inputShape, opFlags);
505             }
506 
507             @Override
508             // Android-changed: Make public, to match the method it's overriding.
509             public <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
510                                                             Spliterator<P_IN> spliterator) {
511                 if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
512                     return opEvaluateParallel(helper, spliterator, Long[]::new)
513                             .spliterator();
514                 }
515                 else {
516                     return new UnorderedWhileSpliterator.OfLong.Dropping(
517                             (Spliterator.OfLong) helper.wrapSpliterator(spliterator), false, predicate);
518                 }
519             }
520 
521             @Override
522             // Android-changed: Make public, to match the method it's overriding.
523             public <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
524                                                  Spliterator<P_IN> spliterator,
525                                                  IntFunction<Long[]> generator) {
526                 return new DropWhileTask<>(this, helper, spliterator, generator)
527                         .invoke();
528             }
529 
530             @Override
531             // Android-changed: Make public, to match the method it's overriding.
532             public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
533                 return opWrapSink(sink, false);
534             }
535 
536             public DropWhileSink<Long> opWrapSink(Sink<Long> sink, boolean retainAndCountDroppedElements) {
537                 class OpSink extends Sink.ChainedLong<Long> implements DropWhileSink<Long> {
538                     long dropCount;
539                     boolean take;
540 
541                     OpSink() {
542                         super(sink);
543                     }
544 
545                     @Override
546                     public void accept(long t) {
547                         boolean takeElement = take || (take = !predicate.test(t));
548 
549                         // If ordered and element is dropped increment index
550                         // for possible future truncation
551                         if (retainAndCountDroppedElements && !takeElement)
552                             dropCount++;
553 
554                         // If ordered need to process element, otherwise
555                         // skip if element is dropped
556                         if (retainAndCountDroppedElements || takeElement)
557                             downstream.accept(t);
558                     }
559 
560                     @Override
561                     public long getDropCount() {
562                         return dropCount;
563                     }
564                 }
565                 return new OpSink();
566             }
567         }
568         return new Op(upstream, StreamShape.LONG_VALUE, DROP_FLAGS);
569     }
570 
571     /**
572      * Appends a "dropWhile" operation to the provided DoubleStream.
573      *
574      * @param upstream a reference stream with element type T
575      * @param predicate the predicate that returns false to halt dropping.
576      */
577     static DoubleStream makeDropWhileDouble(AbstractPipeline<?, Double, ?> upstream,
578                                             DoublePredicate predicate) {
579         Objects.requireNonNull(predicate);
580         class Op extends DoublePipeline.StatefulOp<Double> implements DropWhileOp<Double> {
581             public Op(AbstractPipeline<?, Double, ?> upstream, StreamShape inputShape, int opFlags) {
582                 super(upstream, inputShape, opFlags);
583             }
584 
585             @Override
586             // Android-changed: Make public, to match the method it's overriding.
587             public <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
588                                                               Spliterator<P_IN> spliterator) {
589                 if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
590                     return opEvaluateParallel(helper, spliterator, Double[]::new)
591                             .spliterator();
592                 }
593                 else {
594                     return new UnorderedWhileSpliterator.OfDouble.Dropping(
595                             (Spliterator.OfDouble) helper.wrapSpliterator(spliterator), false, predicate);
596                 }
597             }
598 
599             @Override
600             // Android-changed: Make public, to match the method it's overriding.
601             public <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
602                                                    Spliterator<P_IN> spliterator,
603                                                    IntFunction<Double[]> generator) {
604                 return new DropWhileTask<>(this, helper, spliterator, generator)
605                         .invoke();
606             }
607 
608             @Override
609             // Android-changed: Make public, to match the method it's overriding.
610             public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
611                 return opWrapSink(sink, false);
612             }
613 
614             public DropWhileSink<Double> opWrapSink(Sink<Double> sink, boolean retainAndCountDroppedElements) {
615                 class OpSink extends Sink.ChainedDouble<Double> implements DropWhileSink<Double> {
616                     long dropCount;
617                     boolean take;
618 
619                     OpSink() {
620                         super(sink);
621                     }
622 
623                     @Override
624                     public void accept(double t) {
625                         boolean takeElement = take || (take = !predicate.test(t));
626 
627                         // If ordered and element is dropped increment index
628                         // for possible future truncation
629                         if (retainAndCountDroppedElements && !takeElement)
630                             dropCount++;
631 
632                         // If ordered need to process element, otherwise
633                         // skip if element is dropped
634                         if (retainAndCountDroppedElements || takeElement)
635                             downstream.accept(t);
636                     }
637 
638                     @Override
639                     public long getDropCount() {
640                         return dropCount;
641                     }
642                 }
643                 return new OpSink();
644             }
645         }
646         return new Op(upstream, StreamShape.DOUBLE_VALUE, DROP_FLAGS);
647     }
648 
649     //
650 
651     /**
652      * A spliterator supporting takeWhile and dropWhile operations over an
653      * underlying spliterator whose covered elements have no encounter order.
654      * <p>
655      * Concrete subclasses of this spliterator support reference and primitive
656      * types for takeWhile and dropWhile.
657      * <p>
658      * For the takeWhile operation if during traversal taking completes then
659      * taking is cancelled globally for the splitting and traversal of all
660      * related spliterators.
661      * Cancellation is governed by a shared {@link AtomicBoolean} instance.  A
662      * spliterator in the process of taking when cancellation occurs will also
663      * be cancelled but not necessarily immediately.  To reduce contention on
664      * the {@link AtomicBoolean} instance, cancellation make be acted on after
665      * a small number of additional elements have been traversed.
666      * <p>
667      * For the dropWhile operation if during traversal dropping completes for
668      * some, but not all elements, then it is cancelled globally for the
669      * traversal of all related spliterators (splitting is not cancelled).
670      * Cancellation is governed in the same manner as for the takeWhile
671      * operation.
672      *
673      * @param <T> the type of elements returned by this spliterator
674      * @param <T_SPLITR> the type of the spliterator
675      */
676     abstract static class UnorderedWhileSpliterator<T, T_SPLITR extends Spliterator<T>> implements Spliterator<T> {
677         // Power of two constant minus one used for modulus of count
678         static final int CANCEL_CHECK_COUNT = (1 << 6) - 1;
679 
680         // The underlying spliterator
681         final T_SPLITR s;
682         // True if no splitting should be performed, if true then
683         // this spliterator may be used for an underlying spliterator whose
684         // covered elements have an encounter order
685         // See use in stream take/dropWhile default methods
686         final boolean noSplitting;
687         // True when operations are cancelled for all related spliterators
688         // For taking, spliterators cannot split or traversed
689         // For dropping, spliterators cannot be traversed
690         final AtomicBoolean cancel;
691         // True while taking or dropping should be performed when traversing
692         boolean takeOrDrop = true;
693         // The count of elements traversed
694         int count;
695 
696         UnorderedWhileSpliterator(T_SPLITR s, boolean noSplitting) {
697             this.s = s;
698             this.noSplitting = noSplitting;
699             this.cancel = new AtomicBoolean();
700         }
701 
702         UnorderedWhileSpliterator(T_SPLITR s, UnorderedWhileSpliterator<T, T_SPLITR> parent) {
703             this.s = s;
704             this.noSplitting = parent.noSplitting;
705             this.cancel = parent.cancel;
706         }
707 
708         @Override
709         public long estimateSize() {
710             return s.estimateSize();
711         }
712 
713         @Override
714         public int characteristics() {
715             // Size is not known
716             return s.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
717         }
718 
719         @Override
720         public long getExactSizeIfKnown() {
721             return -1L;
722         }
723 
724         @Override
725         public Comparator<? super T> getComparator() {
726             return s.getComparator();
727         }
728 
729         @Override
730         public T_SPLITR trySplit() {
731             @SuppressWarnings("unchecked")
732             T_SPLITR ls = noSplitting ? null : (T_SPLITR) s.trySplit();
733             return ls != null ? makeSpliterator(ls) : null;
734         }
735 
736         boolean checkCancelOnCount() {
737             return count != 0 || !cancel.get();
738         }
739 
740         abstract T_SPLITR makeSpliterator(T_SPLITR s);
741 
742         abstract static class OfRef<T> extends UnorderedWhileSpliterator<T, Spliterator<T>> implements Consumer<T> {
743             final Predicate<? super T> p;
744             T t;
745 
746             OfRef(Spliterator<T> s, boolean noSplitting, Predicate<? super T> p) {
747                 super(s, noSplitting);
748                 this.p = p;
749             }
750 
751             OfRef(Spliterator<T> s, OfRef<T> parent) {
752                 super(s, parent);
753                 this.p = parent.p;
754             }
755 
756             @Override
757             public void accept(T t) {
758                 count = (count + 1) & CANCEL_CHECK_COUNT;
759                 this.t = t;
760             }
761 
762             static final class Taking<T> extends OfRef<T> {
763                 Taking(Spliterator<T> s, boolean noSplitting, Predicate<? super T> p) {
764                     super(s, noSplitting, p);
765                 }
766 
767                 Taking(Spliterator<T> s, Taking<T> parent) {
768                     super(s, parent);
769                 }
770 
771                 @Override
772                 public boolean tryAdvance(Consumer<? super T> action) {
773                     boolean test = true;
774                     if (takeOrDrop &&               // If can take
775                         checkCancelOnCount() && // and if not cancelled
776                         s.tryAdvance(this) &&   // and if advanced one element
777                         (test = p.test(t))) {   // and test on element passes
778                         action.accept(t);           // then accept element
779                         return true;
780                     }
781                     else {
782                         // Taking is finished
783                         takeOrDrop = false;
784                         // Cancel all further traversal and splitting operations
785                         // only if test of element failed (short-circuited)
786                         if (!test)
787                             cancel.set(true);
788                         return false;
789                     }
790                 }
791 
792                 @Override
793                 public Spliterator<T> trySplit() {
794                     // Do not split if all operations are cancelled
795                     return cancel.get() ? null : super.trySplit();
796                 }
797 
798                 @Override
799                 Spliterator<T> makeSpliterator(Spliterator<T> s) {
800                     return new Taking<>(s, this);
801                 }
802             }
803 
804             static final class Dropping<T> extends OfRef<T> {
805                 Dropping(Spliterator<T> s, boolean noSplitting, Predicate<? super T> p) {
806                     super(s, noSplitting, p);
807                 }
808 
809                 Dropping(Spliterator<T> s, Dropping<T> parent) {
810                     super(s, parent);
811                 }
812 
813                 @Override
814                 public boolean tryAdvance(Consumer<? super T> action) {
815                     if (takeOrDrop) {
816                         takeOrDrop = false;
817                         boolean adv;
818                         boolean dropped = false;
819                         while ((adv = s.tryAdvance(this)) &&  // If advanced one element
820                                checkCancelOnCount() &&        // and if not cancelled
821                                p.test(t)) {                   // and test on element passes
822                             dropped = true;                   // then drop element
823                         }
824 
825                         // Report advanced element, if any
826                         if (adv) {
827                             // Cancel all further dropping if one or more elements
828                             // were previously dropped
829                             if (dropped)
830                                 cancel.set(true);
831                             action.accept(t);
832                         }
833                         return adv;
834                     }
835                     else {
836                         return s.tryAdvance(action);
837                     }
838                 }
839 
840                 @Override
841                 Spliterator<T> makeSpliterator(Spliterator<T> s) {
842                     return new Dropping<>(s, this);
843                 }
844             }
845         }
846 
847         abstract static class OfInt extends UnorderedWhileSpliterator<Integer, Spliterator.OfInt> implements IntConsumer, Spliterator.OfInt {
848             final IntPredicate p;
849             int t;
850 
851             OfInt(Spliterator.OfInt s, boolean noSplitting, IntPredicate p) {
852                 super(s, noSplitting);
853                 this.p = p;
854             }
855 
856             OfInt(Spliterator.OfInt s, UnorderedWhileSpliterator.OfInt parent) {
857                 super(s, parent);
858                 this.p = parent.p;
859             }
860 
861             @Override
862             public void accept(int t) {
863                 count = (count + 1) & CANCEL_CHECK_COUNT;
864                 this.t = t;
865             }
866 
867             static final class Taking extends UnorderedWhileSpliterator.OfInt {
868                 Taking(Spliterator.OfInt s, boolean noSplitting, IntPredicate p) {
869                     super(s, noSplitting, p);
870                 }
871 
872                 Taking(Spliterator.OfInt s, UnorderedWhileSpliterator.OfInt parent) {
873                     super(s, parent);
874                 }
875 
876                 @Override
877                 public boolean tryAdvance(IntConsumer action) {
878                     boolean test = true;
879                     if (takeOrDrop &&               // If can take
880                         checkCancelOnCount() && // and if not cancelled
881                         s.tryAdvance(this) &&   // and if advanced one element
882                         (test = p.test(t))) {   // and test on element passes
883                         action.accept(t);           // then accept element
884                         return true;
885                     }
886                     else {
887                         // Taking is finished
888                         takeOrDrop = false;
889                         // Cancel all further traversal and splitting operations
890                         // only if test of element failed (short-circuited)
891                         if (!test)
892                             cancel.set(true);
893                         return false;
894                     }
895                 }
896 
897                 @Override
898                 public Spliterator.OfInt trySplit() {
899                     // Do not split if all operations are cancelled
900                     return cancel.get() ? null : super.trySplit();
901                 }
902 
903                 @Override
904                 Spliterator.OfInt makeSpliterator(Spliterator.OfInt s) {
905                     return new Taking(s, this);
906                 }
907             }
908 
909             static final class Dropping extends UnorderedWhileSpliterator.OfInt {
910                 Dropping(Spliterator.OfInt s, boolean noSplitting, IntPredicate p) {
911                     super(s, noSplitting, p);
912                 }
913 
914                 Dropping(Spliterator.OfInt s, UnorderedWhileSpliterator.OfInt parent) {
915                     super(s, parent);
916                 }
917 
918                 @Override
919                 public boolean tryAdvance(IntConsumer action) {
920                     if (takeOrDrop) {
921                         takeOrDrop = false;
922                         boolean adv;
923                         boolean dropped = false;
924                         while ((adv = s.tryAdvance(this)) &&  // If advanced one element
925                                checkCancelOnCount() &&        // and if not cancelled
926                                p.test(t)) {                   // and test on element passes
927                             dropped = true;                   // then drop element
928                         }
929 
930                         // Report advanced element, if any
931                         if (adv) {
932                             // Cancel all further dropping if one or more elements
933                             // were previously dropped
934                             if (dropped)
935                                 cancel.set(true);
936                             action.accept(t);
937                         }
938                         return adv;
939                     }
940                     else {
941                         return s.tryAdvance(action);
942                     }
943                 }
944 
945                 @Override
946                 Spliterator.OfInt makeSpliterator(Spliterator.OfInt s) {
947                     return new Dropping(s, this);
948                 }
949             }
950         }
951 
952         abstract static class OfLong extends UnorderedWhileSpliterator<Long, Spliterator.OfLong> implements LongConsumer, Spliterator.OfLong {
953             final LongPredicate p;
954             long t;
955 
956             OfLong(Spliterator.OfLong s, boolean noSplitting, LongPredicate p) {
957                 super(s, noSplitting);
958                 this.p = p;
959             }
960 
961             OfLong(Spliterator.OfLong s, UnorderedWhileSpliterator.OfLong parent) {
962                 super(s, parent);
963                 this.p = parent.p;
964             }
965 
966             @Override
967             public void accept(long t) {
968                 count = (count + 1) & CANCEL_CHECK_COUNT;
969                 this.t = t;
970             }
971 
972             static final class Taking extends UnorderedWhileSpliterator.OfLong {
973                 Taking(Spliterator.OfLong s, boolean noSplitting, LongPredicate p) {
974                     super(s, noSplitting, p);
975                 }
976 
977                 Taking(Spliterator.OfLong s, UnorderedWhileSpliterator.OfLong parent) {
978                     super(s, parent);
979                 }
980 
981                 @Override
982                 public boolean tryAdvance(LongConsumer action) {
983                     boolean test = true;
984                     if (takeOrDrop &&               // If can take
985                         checkCancelOnCount() && // and if not cancelled
986                         s.tryAdvance(this) &&   // and if advanced one element
987                         (test = p.test(t))) {   // and test on element passes
988                         action.accept(t);           // then accept element
989                         return true;
990                     }
991                     else {
992                         // Taking is finished
993                         takeOrDrop = false;
994                         // Cancel all further traversal and splitting operations
995                         // only if test of element failed (short-circuited)
996                         if (!test)
997                             cancel.set(true);
998                         return false;
999                     }
1000                 }
1001 
1002                 @Override
1003                 public Spliterator.OfLong trySplit() {
1004                     // Do not split if all operations are cancelled
1005                     return cancel.get() ? null : super.trySplit();
1006                 }
1007 
1008                 @Override
1009                 Spliterator.OfLong makeSpliterator(Spliterator.OfLong s) {
1010                     return new Taking(s, this);
1011                 }
1012             }
1013 
1014             static final class Dropping extends UnorderedWhileSpliterator.OfLong {
1015                 Dropping(Spliterator.OfLong s, boolean noSplitting, LongPredicate p) {
1016                     super(s, noSplitting, p);
1017                 }
1018 
1019                 Dropping(Spliterator.OfLong s, UnorderedWhileSpliterator.OfLong parent) {
1020                     super(s, parent);
1021                 }
1022 
1023                 @Override
1024                 public boolean tryAdvance(LongConsumer action) {
1025                     if (takeOrDrop) {
1026                         takeOrDrop = false;
1027                         boolean adv;
1028                         boolean dropped = false;
1029                         while ((adv = s.tryAdvance(this)) &&  // If advanced one element
1030                                checkCancelOnCount() &&        // and if not cancelled
1031                                p.test(t)) {                   // and test on element passes
1032                             dropped = true;                   // then drop element
1033                         }
1034 
1035                         // Report advanced element, if any
1036                         if (adv) {
1037                             // Cancel all further dropping if one or more elements
1038                             // were previously dropped
1039                             if (dropped)
1040                                 cancel.set(true);
1041                             action.accept(t);
1042                         }
1043                         return adv;
1044                     }
1045                     else {
1046                         return s.tryAdvance(action);
1047                     }
1048                 }
1049 
1050                 @Override
1051                 Spliterator.OfLong makeSpliterator(Spliterator.OfLong s) {
1052                     return new Dropping(s, this);
1053                 }
1054             }
1055         }
1056 
1057         abstract static class OfDouble extends UnorderedWhileSpliterator<Double, Spliterator.OfDouble> implements DoubleConsumer, Spliterator.OfDouble {
1058             final DoublePredicate p;
1059             double t;
1060 
1061             OfDouble(Spliterator.OfDouble s, boolean noSplitting, DoublePredicate p) {
1062                 super(s, noSplitting);
1063                 this.p = p;
1064             }
1065 
1066             OfDouble(Spliterator.OfDouble s, UnorderedWhileSpliterator.OfDouble parent) {
1067                 super(s, parent);
1068                 this.p = parent.p;
1069             }
1070 
1071             @Override
1072             public void accept(double t) {
1073                 count = (count + 1) & CANCEL_CHECK_COUNT;
1074                 this.t = t;
1075             }
1076 
1077             static final class Taking extends UnorderedWhileSpliterator.OfDouble {
1078                 Taking(Spliterator.OfDouble s, boolean noSplitting, DoublePredicate p) {
1079                     super(s, noSplitting, p);
1080                 }
1081 
1082                 Taking(Spliterator.OfDouble s, UnorderedWhileSpliterator.OfDouble parent) {
1083                     super(s, parent);
1084                 }
1085 
1086                 @Override
1087                 public boolean tryAdvance(DoubleConsumer action) {
1088                     boolean test = true;
1089                     if (takeOrDrop &&               // If can take
1090                         checkCancelOnCount() && // and if not cancelled
1091                         s.tryAdvance(this) &&   // and if advanced one element
1092                         (test = p.test(t))) {   // and test on element passes
1093                         action.accept(t);           // then accept element
1094                         return true;
1095                     }
1096                     else {
1097                         // Taking is finished
1098                         takeOrDrop = false;
1099                         // Cancel all further traversal and splitting operations
1100                         // only if test of element failed (short-circuited)
1101                         if (!test)
1102                             cancel.set(true);
1103                         return false;
1104                     }
1105                 }
1106 
1107                 @Override
1108                 public Spliterator.OfDouble trySplit() {
1109                     // Do not split if all operations are cancelled
1110                     return cancel.get() ? null : super.trySplit();
1111                 }
1112 
1113                 @Override
1114                 Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s) {
1115                     return new Taking(s, this);
1116                 }
1117             }
1118 
1119             static final class Dropping extends UnorderedWhileSpliterator.OfDouble {
1120                 Dropping(Spliterator.OfDouble s, boolean noSplitting, DoublePredicate p) {
1121                     super(s, noSplitting, p);
1122                 }
1123 
1124                 Dropping(Spliterator.OfDouble s, UnorderedWhileSpliterator.OfDouble parent) {
1125                     super(s, parent);
1126                 }
1127 
1128                 @Override
1129                 public boolean tryAdvance(DoubleConsumer action) {
1130                     if (takeOrDrop) {
1131                         takeOrDrop = false;
1132                         boolean adv;
1133                         boolean dropped = false;
1134                         while ((adv = s.tryAdvance(this)) &&  // If advanced one element
1135                                checkCancelOnCount() &&        // and if not cancelled
1136                                p.test(t)) {                   // and test on element passes
1137                             dropped = true;                   // then drop element
1138                         }
1139 
1140                         // Report advanced element, if any
1141                         if (adv) {
1142                             // Cancel all further dropping if one or more elements
1143                             // were previously dropped
1144                             if (dropped)
1145                                 cancel.set(true);
1146                             action.accept(t);
1147                         }
1148                         return adv;
1149                     }
1150                     else {
1151                         return s.tryAdvance(action);
1152                     }
1153                 }
1154 
1155                 @Override
1156                 Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s) {
1157                     return new Dropping(s, this);
1158                 }
1159             }
1160         }
1161     }
1162 
1163 
1164     //
1165 
1166     /**
1167      * {@code ForkJoinTask} implementing takeWhile computation.
1168      * <p>
1169      * If the pipeline has encounter order then all tasks to the right of
1170      * a task where traversal was short-circuited are cancelled.
1171      * The results of completed (and cancelled) tasks are discarded.
1172      * The result of merging a short-circuited left task and right task (which
1173      * may or may not be short-circuited) is that left task.
1174      * <p>
1175      * If the pipeline has no encounter order then all tasks to the right of
1176      * a task where traversal was short-circuited are cancelled.
1177      * The results of completed (and possibly cancelled) tasks are not
1178      * discarded, as there is no need to throw away computed results.
1179      * The result of merging does not change if a left task was
1180      * short-circuited.
1181      * No attempt is made, once a leaf task stopped taking, for it to cancel
1182      * all other tasks, and further more, short-circuit the computation with its
1183      * result.
1184      *
1185      * @param <P_IN> Input element type to the stream pipeline
1186      * @param <P_OUT> Output element type from the stream pipeline
1187      */
1188     @SuppressWarnings("serial")
1189     private static final class TakeWhileTask<P_IN, P_OUT>
1190             extends AbstractShortCircuitTask<P_IN, P_OUT, Node<P_OUT>, TakeWhileTask<P_IN, P_OUT>> {
1191         private final AbstractPipeline<P_OUT, P_OUT, ?> op;
1192         private final IntFunction<P_OUT[]> generator;
1193         private final boolean isOrdered;
1194         private long thisNodeSize;
1195         // True if a short-circuited
1196         private boolean shortCircuited;
1197         // True if completed, must be set after the local result
1198         private volatile boolean completed;
1199 
1200         TakeWhileTask(AbstractPipeline<P_OUT, P_OUT, ?> op,
1201                       PipelineHelper<P_OUT> helper,
1202                       Spliterator<P_IN> spliterator,
1203                       IntFunction<P_OUT[]> generator) {
1204             super(helper, spliterator);
1205             this.op = op;
1206             this.generator = generator;
1207             this.isOrdered = StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags());
1208         }
1209 
1210         TakeWhileTask(TakeWhileTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) {
1211             super(parent, spliterator);
1212             this.op = parent.op;
1213             this.generator = parent.generator;
1214             this.isOrdered = parent.isOrdered;
1215         }
1216 
1217         @Override
1218         protected TakeWhileTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) {
1219             return new TakeWhileTask<>(this, spliterator);
1220         }
1221 
1222         @Override
1223         protected final Node<P_OUT> getEmptyResult() {
1224             return Nodes.emptyNode(op.getOutputShape());
1225         }
1226 
1227         @Override
1228         protected final Node<P_OUT> doLeaf() {
1229             Node.Builder<P_OUT> builder = helper.makeNodeBuilder(-1, generator);
1230             Sink<P_OUT> s = op.opWrapSink(helper.getStreamAndOpFlags(), builder);
1231 
1232             if (shortCircuited = helper.copyIntoWithCancel(helper.wrapSink(s), spliterator)) {
1233                 // Cancel later nodes if the predicate returned false
1234                 // during traversal
1235                 cancelLaterNodes();
1236             }
1237 
1238             Node<P_OUT> node = builder.build();
1239             thisNodeSize = node.count();
1240             return node;
1241         }
1242 
1243         @Override
1244         public final void onCompletion(CountedCompleter<?> caller) {
1245             if (!isLeaf()) {
1246                 Node<P_OUT> result;
1247                 shortCircuited = leftChild.shortCircuited | rightChild.shortCircuited;
1248                 if (isOrdered && canceled) {
1249                     thisNodeSize = 0;
1250                     result = getEmptyResult();
1251                 }
1252                 else if (isOrdered && leftChild.shortCircuited) {
1253                     // If taking finished on the left node then
1254                     // use the left node result
1255                     thisNodeSize = leftChild.thisNodeSize;
1256                     result = leftChild.getLocalResult();
1257                 }
1258                 else {
1259                     thisNodeSize = leftChild.thisNodeSize + rightChild.thisNodeSize;
1260                     result = merge();
1261                 }
1262 
1263                 setLocalResult(result);
1264             }
1265 
1266             completed = true;
1267             super.onCompletion(caller);
1268         }
1269 
1270         Node<P_OUT> merge() {
1271             if (leftChild.thisNodeSize == 0) {
1272                 // If the left node size is 0 then
1273                 // use the right node result
1274                 return rightChild.getLocalResult();
1275             }
1276             else if (rightChild.thisNodeSize == 0) {
1277                 // If the right node size is 0 then
1278                 // use the left node result
1279                 return leftChild.getLocalResult();
1280             }
1281             else {
1282                 // Combine the left and right nodes
1283                 return Nodes.conc(op.getOutputShape(),
1284                                   leftChild.getLocalResult(), rightChild.getLocalResult());
1285             }
1286         }
1287 
1288         @Override
1289         protected void cancel() {
1290             super.cancel();
1291             if (isOrdered && completed)
1292                 // If the task is completed then clear the result, if any
1293                 // to aid GC
1294                 setLocalResult(getEmptyResult());
1295         }
1296     }
1297 
1298     /**
1299      * {@code ForkJoinTask} implementing dropWhile computation.
1300      * <p>
1301      * If the pipeline has encounter order then each leaf task will not
1302      * drop elements but will obtain a count of the elements that would have
1303      * been otherwise dropped. That count is used as an index to track
1304      * elements to be dropped. Merging will update the index so it corresponds
1305      * to the index that is the end of the global prefix of elements to be
1306      * dropped. The root is truncated according to that index.
1307      * <p>
1308      * If the pipeline has no encounter order then each leaf task will drop
1309      * elements. Leaf tasks are ordinarily merged. No truncation of the root
1310      * node is required.
1311      * No attempt is made, once a leaf task stopped dropping, for it to cancel
1312      * all other tasks, and further more, short-circuit the computation with
1313      * its result.
1314      *
1315      * @param <P_IN> Input element type to the stream pipeline
1316      * @param <P_OUT> Output element type from the stream pipeline
1317      */
1318     @SuppressWarnings("serial")
1319     private static final class DropWhileTask<P_IN, P_OUT>
1320             extends AbstractTask<P_IN, P_OUT, Node<P_OUT>, DropWhileTask<P_IN, P_OUT>> {
1321         private final AbstractPipeline<P_OUT, P_OUT, ?> op;
1322         private final IntFunction<P_OUT[]> generator;
1323         private final boolean isOrdered;
1324         private long thisNodeSize;
1325         // The index from which elements of the node should be taken
1326         // i.e. the node should be truncated from [takeIndex, thisNodeSize)
1327         // Equivalent to the count of dropped elements
1328         private long index;
1329 
1330         DropWhileTask(AbstractPipeline<P_OUT, P_OUT, ?> op,
1331                       PipelineHelper<P_OUT> helper,
1332                       Spliterator<P_IN> spliterator,
1333                       IntFunction<P_OUT[]> generator) {
1334             super(helper, spliterator);
1335             assert op instanceof DropWhileOp;
1336             this.op = op;
1337             this.generator = generator;
1338             this.isOrdered = StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags());
1339         }
1340 
1341         DropWhileTask(DropWhileTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) {
1342             super(parent, spliterator);
1343             this.op = parent.op;
1344             this.generator = parent.generator;
1345             this.isOrdered = parent.isOrdered;
1346         }
1347 
1348         @Override
1349         protected DropWhileTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) {
1350             return new DropWhileTask<>(this, spliterator);
1351         }
1352 
1353         @Override
1354         protected final Node<P_OUT> doLeaf() {
1355             boolean isChild = !isRoot();
1356             // If this not the root and pipeline is ordered and size is known
1357             // then pre-size the builder
1358             long sizeIfKnown = isChild && isOrdered && StreamOpFlag.SIZED.isPreserved(op.sourceOrOpFlags)
1359                                ? op.exactOutputSizeIfKnown(spliterator)
1360                                : -1;
1361             Node.Builder<P_OUT> builder = helper.makeNodeBuilder(sizeIfKnown, generator);
1362             @SuppressWarnings("unchecked")
1363             DropWhileOp<P_OUT> dropOp = (DropWhileOp<P_OUT>) op;
1364             // If this leaf is the root then there is no merging on completion
1365             // and there is no need to retain dropped elements
1366             DropWhileSink<P_OUT> s = dropOp.opWrapSink(builder, isOrdered && isChild);
1367             helper.wrapAndCopyInto(s, spliterator);
1368 
1369             Node<P_OUT> node = builder.build();
1370             thisNodeSize = node.count();
1371             index = s.getDropCount();
1372             return node;
1373         }
1374 
1375         @Override
1376         public final void onCompletion(CountedCompleter<?> caller) {
1377             if (!isLeaf()) {
1378                 if (isOrdered) {
1379                     index = leftChild.index;
1380                     // If a contiguous sequence of dropped elements
1381                     // include those of the right node, if any
1382                     if (index == leftChild.thisNodeSize)
1383                         index += rightChild.index;
1384                 }
1385 
1386                 thisNodeSize = leftChild.thisNodeSize + rightChild.thisNodeSize;
1387                 Node<P_OUT> result = merge();
1388                 setLocalResult(isRoot() ? doTruncate(result) : result);
1389             }
1390 
1391             super.onCompletion(caller);
1392         }
1393 
1394         private Node<P_OUT> merge() {
1395             if (leftChild.thisNodeSize == 0) {
1396                 // If the left node size is 0 then
1397                 // use the right node result
1398                 return rightChild.getLocalResult();
1399             }
1400             else if (rightChild.thisNodeSize == 0) {
1401                 // If the right node size is 0 then
1402                 // use the left node result
1403                 return leftChild.getLocalResult();
1404             }
1405             else {
1406                 // Combine the left and right nodes
1407                 return Nodes.conc(op.getOutputShape(),
1408                                   leftChild.getLocalResult(), rightChild.getLocalResult());
1409             }
1410         }
1411 
1412         private Node<P_OUT> doTruncate(Node<P_OUT> input) {
1413             return isOrdered
1414                    ? input.truncate(index, input.count(), generator)
1415                    : input;
1416         }
1417     }
1418 }
1419