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