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