1 /*
   2  * Copyright (c) 2012, 2013, 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.function.Consumer;
  31 import java.util.function.DoubleConsumer;
  32 import java.util.function.IntConsumer;
  33 import java.util.function.LongConsumer;
  34 import jdk.internal.HotSpotIntrinsicCandidate;
  35 
  36 /**
  37  * Utility methods for operating on and creating streams.
  38  *
  39  * <p>Unless otherwise stated, streams are created as sequential streams.  A
  40  * sequential stream can be transformed into a parallel stream by calling the
  41  * {@code parallel()} method on the created stream.
  42  *
  43  * @since 1.8
  44  */
  45 final class Streams {
  46 
  47     private Streams() {
  48         throw new Error("no instances");
  49     }
  50 
  51     /**
  52      * An object instance representing no value, that cannot be an actual
  53      * data element of a stream.  Used when processing streams that can contain
  54      * {@code null} elements to distinguish between a {@code null} value and no
  55      * value.
  56      */
  57     static final Object NONE = new Object();
  58 
  59     /**
  60      * An {@code int} range spliterator.
  61      */
  62     static final class RangeIntSpliterator implements Spliterator.OfInt {
  63         // Can never be greater that upTo, this avoids overflow if upper bound
  64         // is Integer.MAX_VALUE
  65         // All elements are traversed if from == upTo & last == 0
  66         private int from;
  67         private final int upTo;
  68         // 1 if the range is closed and the last element has not been traversed
  69         // Otherwise, 0 if the range is open, or is a closed range and all
  70         // elements have been traversed
  71         private int last;
  72 
  73         RangeIntSpliterator(int from, int upTo, boolean closed) {
  74             this(from, upTo, closed ? 1 : 0);
  75         }
  76 
  77         private RangeIntSpliterator(int from, int upTo, int last) {
  78             this.from = from;
  79             this.upTo = upTo;
  80             this.last = last;
  81         }
  82 
  83         @Override
  84         public boolean tryAdvance(IntConsumer consumer) {
  85             Objects.requireNonNull(consumer);
  86 
  87             final int i = from;
  88             if (i < upTo) {
  89                 from++;
  90                 consumer.accept(i);
  91                 return true;
  92             }
  93             else if (last > 0) {
  94                 last = 0;
  95                 consumer.accept(i);
  96                 return true;
  97             }
  98             return false;
  99         }
 100 
 101         @Override
 102         @HotSpotIntrinsicCandidate
 103         public void forEachRemaining(IntConsumer consumer) {
 104             Objects.requireNonNull(consumer);
 105 
 106             int i = from;
 107             final int hUpTo = upTo;
 108             int hLast = last;
 109             from = upTo;
 110             last = 0;
 111             while (i < hUpTo) {
 112                 consumer.accept(i++);
 113             }
 114             if (hLast > 0) {
 115                 // Last element of closed range
 116                 consumer.accept(i);
 117             }
 118         }
 119 
 120         @Override
 121         public long estimateSize() {
 122             // Ensure ranges of size > Integer.MAX_VALUE report the correct size
 123             return ((long) upTo) - from + last;
 124         }
 125 
 126         @Override
 127         public int characteristics() {
 128             return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
 129                    Spliterator.IMMUTABLE | Spliterator.NONNULL |
 130                    Spliterator.DISTINCT | Spliterator.SORTED;
 131         }
 132 
 133         @Override
 134         public Comparator<? super Integer> getComparator() {
 135             return null;
 136         }
 137 
 138         @Override
 139         public Spliterator.OfInt trySplit() {
 140             long size = estimateSize();
 141             return size <= 1
 142                    ? null
 143                    // Left split always has a half-open range
 144                    : new RangeIntSpliterator(from, from = from + splitPoint(size), 0);
 145         }
 146 
 147         /**
 148          * The spliterator size below which the spliterator will be split
 149          * at the mid-point to produce balanced splits. Above this size the
 150          * spliterator will be split at a ratio of
 151          * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1)
 152          * to produce right-balanced splits.
 153          *
 154          * <p>Such splitting ensures that for very large ranges that the left
 155          * side of the range will more likely be processed at a lower-depth
 156          * than a balanced tree at the expense of a higher-depth for the right
 157          * side of the range.
 158          *
 159          * <p>This is optimized for cases such as IntStream.ints() that is
 160          * implemented as range of 0 to Integer.MAX_VALUE but is likely to be
 161          * augmented with a limit operation that limits the number of elements
 162          * to a count lower than this threshold.
 163          */
 164         private static final int BALANCED_SPLIT_THRESHOLD = 1 << 24;
 165 
 166         /**
 167          * The split ratio of the left and right split when the spliterator
 168          * size is above BALANCED_SPLIT_THRESHOLD.
 169          */
 170         private static final int RIGHT_BALANCED_SPLIT_RATIO = 1 << 3;
 171 
 172         private int splitPoint(long size) {
 173             int d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO;
 174             // Cast to int is safe since:
 175             //   2 <= size < 2^32
 176             //   2 <= d <= 8
 177             return (int) (size / d);
 178         }
 179     }
 180 
 181     /**
 182      * A {@code long} range spliterator.
 183      *
 184      * This implementation cannot be used for ranges whose size is greater
 185      * than Long.MAX_VALUE
 186      */
 187     static final class RangeLongSpliterator implements Spliterator.OfLong {
 188         // Can never be greater that upTo, this avoids overflow if upper bound
 189         // is Long.MAX_VALUE
 190         // All elements are traversed if from == upTo & last == 0
 191         private long from;
 192         private final long upTo;
 193         // 1 if the range is closed and the last element has not been traversed
 194         // Otherwise, 0 if the range is open, or is a closed range and all
 195         // elements have been traversed
 196         private int last;
 197 
 198         RangeLongSpliterator(long from, long upTo, boolean closed) {
 199             this(from, upTo, closed ? 1 : 0);
 200         }
 201 
 202         private RangeLongSpliterator(long from, long upTo, int last) {
 203             assert upTo - from + last > 0;
 204             this.from = from;
 205             this.upTo = upTo;
 206             this.last = last;
 207         }
 208 
 209         @Override
 210         public boolean tryAdvance(LongConsumer consumer) {
 211             Objects.requireNonNull(consumer);
 212 
 213             final long i = from;
 214             if (i < upTo) {
 215                 from++;
 216                 consumer.accept(i);
 217                 return true;
 218             }
 219             else if (last > 0) {
 220                 last = 0;
 221                 consumer.accept(i);
 222                 return true;
 223             }
 224             return false;
 225         }
 226 
 227         @Override
 228         public void forEachRemaining(LongConsumer consumer) {
 229             Objects.requireNonNull(consumer);
 230 
 231             long i = from;
 232             final long hUpTo = upTo;
 233             int hLast = last;
 234             from = upTo;
 235             last = 0;
 236             while (i < hUpTo) {
 237                 consumer.accept(i++);
 238             }
 239             if (hLast > 0) {
 240                 // Last element of closed range
 241                 consumer.accept(i);
 242             }
 243         }
 244 
 245         @Override
 246         public long estimateSize() {
 247             return upTo - from + last;
 248         }
 249 
 250         @Override
 251         public int characteristics() {
 252             return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
 253                    Spliterator.IMMUTABLE | Spliterator.NONNULL |
 254                    Spliterator.DISTINCT | Spliterator.SORTED;
 255         }
 256 
 257         @Override
 258         public Comparator<? super Long> getComparator() {
 259             return null;
 260         }
 261 
 262         @Override
 263         public Spliterator.OfLong trySplit() {
 264             long size = estimateSize();
 265             return size <= 1
 266                    ? null
 267                    // Left split always has a half-open range
 268                    : new RangeLongSpliterator(from, from = from + splitPoint(size), 0);
 269         }
 270 
 271         /**
 272          * The spliterator size below which the spliterator will be split
 273          * at the mid-point to produce balanced splits. Above this size the
 274          * spliterator will be split at a ratio of
 275          * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1)
 276          * to produce right-balanced splits.
 277          *
 278          * <p>Such splitting ensures that for very large ranges that the left
 279          * side of the range will more likely be processed at a lower-depth
 280          * than a balanced tree at the expense of a higher-depth for the right
 281          * side of the range.
 282          *
 283          * <p>This is optimized for cases such as LongStream.longs() that is
 284          * implemented as range of 0 to Long.MAX_VALUE but is likely to be
 285          * augmented with a limit operation that limits the number of elements
 286          * to a count lower than this threshold.
 287          */
 288         private static final long BALANCED_SPLIT_THRESHOLD = 1 << 24;
 289 
 290         /**
 291          * The split ratio of the left and right split when the spliterator
 292          * size is above BALANCED_SPLIT_THRESHOLD.
 293          */
 294         private static final long RIGHT_BALANCED_SPLIT_RATIO = 1 << 3;
 295 
 296         private long splitPoint(long size) {
 297             long d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO;
 298             // 2 <= size <= Long.MAX_VALUE
 299             return size / d;
 300         }
 301     }
 302 
 303     private static abstract class AbstractStreamBuilderImpl<T, S extends Spliterator<T>> implements Spliterator<T> {
 304         // >= 0 when building, < 0 when built
 305         // -1 == no elements
 306         // -2 == one element, held by first
 307         // -3 == two or more elements, held by buffer
 308         int count;
 309 
 310         // Spliterator implementation for 0 or 1 element
 311         // count == -1 for no elements
 312         // count == -2 for one element held by first
 313 
 314         @Override
 315         public S trySplit() {
 316             return null;
 317         }
 318 
 319         @Override
 320         public long estimateSize() {
 321             return -count - 1;
 322         }
 323 
 324         @Override
 325         public int characteristics() {
 326             return Spliterator.SIZED | Spliterator.SUBSIZED |
 327                    Spliterator.ORDERED | Spliterator.IMMUTABLE;
 328         }
 329     }
 330 
 331     static final class StreamBuilderImpl<T>
 332             extends AbstractStreamBuilderImpl<T, Spliterator<T>>
 333             implements Stream.Builder<T> {
 334         // The first element in the stream
 335         // valid if count == 1
 336         T first;
 337 
 338         // The first and subsequent elements in the stream
 339         // non-null if count == 2
 340         SpinedBuffer<T> buffer;
 341 
 342         /**
 343          * Constructor for building a stream of 0 or more elements.
 344          */
 345         StreamBuilderImpl() { }
 346 
 347         /**
 348          * Constructor for a singleton stream.
 349          *
 350          * @param t the single element
 351          */
 352         StreamBuilderImpl(T t) {
 353             first = t;
 354             count = -2;
 355         }
 356 
 357         // StreamBuilder implementation
 358 
 359         @Override
 360         public void accept(T t) {
 361             if (count == 0) {
 362                 first = t;
 363                 count++;
 364             }
 365             else if (count > 0) {
 366                 if (buffer == null) {
 367                     buffer = new SpinedBuffer<>();
 368                     buffer.accept(first);
 369                     count++;
 370                 }
 371 
 372                 buffer.accept(t);
 373             }
 374             else {
 375                 throw new IllegalStateException();
 376             }
 377         }
 378 
 379         public Stream.Builder<T> add(T t) {
 380             accept(t);
 381             return this;
 382         }
 383 
 384         @Override
 385         public Stream<T> build() {
 386             int c = count;
 387             if (c >= 0) {
 388                 // Switch count to negative value signalling the builder is built
 389                 count = -count - 1;
 390                 // Use this spliterator if 0 or 1 elements, otherwise use
 391                 // the spliterator of the spined buffer
 392                 return (c < 2) ? StreamSupport.stream(this, false) : StreamSupport.stream(buffer.spliterator(), false);
 393             }
 394 
 395             throw new IllegalStateException();
 396         }
 397 
 398         // Spliterator implementation for 0 or 1 element
 399         // count == -1 for no elements
 400         // count == -2 for one element held by first
 401 
 402         @Override
 403         public boolean tryAdvance(Consumer<? super T> action) {
 404             Objects.requireNonNull(action);
 405 
 406             if (count == -2) {
 407                 action.accept(first);
 408                 count = -1;
 409                 return true;
 410             }
 411             else {
 412                 return false;
 413             }
 414         }
 415 
 416         @Override
 417         public void forEachRemaining(Consumer<? super T> action) {
 418             Objects.requireNonNull(action);
 419 
 420             if (count == -2) {
 421                 action.accept(first);
 422                 count = -1;
 423             }
 424         }
 425     }
 426 
 427     static final class IntStreamBuilderImpl
 428             extends AbstractStreamBuilderImpl<Integer, Spliterator.OfInt>
 429             implements IntStream.Builder, Spliterator.OfInt {
 430         // The first element in the stream
 431         // valid if count == 1
 432         int first;
 433 
 434         // The first and subsequent elements in the stream
 435         // non-null if count == 2
 436         SpinedBuffer.OfInt buffer;
 437 
 438         /**
 439          * Constructor for building a stream of 0 or more elements.
 440          */
 441         IntStreamBuilderImpl() { }
 442 
 443         /**
 444          * Constructor for a singleton stream.
 445          *
 446          * @param t the single element
 447          */
 448         IntStreamBuilderImpl(int t) {
 449             first = t;
 450             count = -2;
 451         }
 452 
 453         // StreamBuilder implementation
 454 
 455         @Override
 456         public void accept(int t) {
 457             if (count == 0) {
 458                 first = t;
 459                 count++;
 460             }
 461             else if (count > 0) {
 462                 if (buffer == null) {
 463                     buffer = new SpinedBuffer.OfInt();
 464                     buffer.accept(first);
 465                     count++;
 466                 }
 467 
 468                 buffer.accept(t);
 469             }
 470             else {
 471                 throw new IllegalStateException();
 472             }
 473         }
 474 
 475         @Override
 476         public IntStream build() {
 477             int c = count;
 478             if (c >= 0) {
 479                 // Switch count to negative value signalling the builder is built
 480                 count = -count - 1;
 481                 // Use this spliterator if 0 or 1 elements, otherwise use
 482                 // the spliterator of the spined buffer
 483                 return (c < 2) ? StreamSupport.intStream(this, false) : StreamSupport.intStream(buffer.spliterator(), false);
 484             }
 485 
 486             throw new IllegalStateException();
 487         }
 488 
 489         // Spliterator implementation for 0 or 1 element
 490         // count == -1 for no elements
 491         // count == -2 for one element held by first
 492 
 493         @Override
 494         public boolean tryAdvance(IntConsumer action) {
 495             Objects.requireNonNull(action);
 496 
 497             if (count == -2) {
 498                 action.accept(first);
 499                 count = -1;
 500                 return true;
 501             }
 502             else {
 503                 return false;
 504             }
 505         }
 506 
 507         @Override
 508         public void forEachRemaining(IntConsumer action) {
 509             Objects.requireNonNull(action);
 510 
 511             if (count == -2) {
 512                 action.accept(first);
 513                 count = -1;
 514             }
 515         }
 516     }
 517 
 518     static final class LongStreamBuilderImpl
 519             extends AbstractStreamBuilderImpl<Long, Spliterator.OfLong>
 520             implements LongStream.Builder, Spliterator.OfLong {
 521         // The first element in the stream
 522         // valid if count == 1
 523         long first;
 524 
 525         // The first and subsequent elements in the stream
 526         // non-null if count == 2
 527         SpinedBuffer.OfLong buffer;
 528 
 529         /**
 530          * Constructor for building a stream of 0 or more elements.
 531          */
 532         LongStreamBuilderImpl() { }
 533 
 534         /**
 535          * Constructor for a singleton stream.
 536          *
 537          * @param t the single element
 538          */
 539         LongStreamBuilderImpl(long t) {
 540             first = t;
 541             count = -2;
 542         }
 543 
 544         // StreamBuilder implementation
 545 
 546         @Override
 547         public void accept(long t) {
 548             if (count == 0) {
 549                 first = t;
 550                 count++;
 551             }
 552             else if (count > 0) {
 553                 if (buffer == null) {
 554                     buffer = new SpinedBuffer.OfLong();
 555                     buffer.accept(first);
 556                     count++;
 557                 }
 558 
 559                 buffer.accept(t);
 560             }
 561             else {
 562                 throw new IllegalStateException();
 563             }
 564         }
 565 
 566         @Override
 567         public LongStream build() {
 568             int c = count;
 569             if (c >= 0) {
 570                 // Switch count to negative value signalling the builder is built
 571                 count = -count - 1;
 572                 // Use this spliterator if 0 or 1 elements, otherwise use
 573                 // the spliterator of the spined buffer
 574                 return (c < 2) ? StreamSupport.longStream(this, false) : StreamSupport.longStream(buffer.spliterator(), false);
 575             }
 576 
 577             throw new IllegalStateException();
 578         }
 579 
 580         // Spliterator implementation for 0 or 1 element
 581         // count == -1 for no elements
 582         // count == -2 for one element held by first
 583 
 584         @Override
 585         public boolean tryAdvance(LongConsumer action) {
 586             Objects.requireNonNull(action);
 587 
 588             if (count == -2) {
 589                 action.accept(first);
 590                 count = -1;
 591                 return true;
 592             }
 593             else {
 594                 return false;
 595             }
 596         }
 597 
 598         @Override
 599         public void forEachRemaining(LongConsumer action) {
 600             Objects.requireNonNull(action);
 601 
 602             if (count == -2) {
 603                 action.accept(first);
 604                 count = -1;
 605             }
 606         }
 607     }
 608 
 609     static final class DoubleStreamBuilderImpl
 610             extends AbstractStreamBuilderImpl<Double, Spliterator.OfDouble>
 611             implements DoubleStream.Builder, Spliterator.OfDouble {
 612         // The first element in the stream
 613         // valid if count == 1
 614         double first;
 615 
 616         // The first and subsequent elements in the stream
 617         // non-null if count == 2
 618         SpinedBuffer.OfDouble buffer;
 619 
 620         /**
 621          * Constructor for building a stream of 0 or more elements.
 622          */
 623         DoubleStreamBuilderImpl() { }
 624 
 625         /**
 626          * Constructor for a singleton stream.
 627          *
 628          * @param t the single element
 629          */
 630         DoubleStreamBuilderImpl(double t) {
 631             first = t;
 632             count = -2;
 633         }
 634 
 635         // StreamBuilder implementation
 636 
 637         @Override
 638         public void accept(double t) {
 639             if (count == 0) {
 640                 first = t;
 641                 count++;
 642             }
 643             else if (count > 0) {
 644                 if (buffer == null) {
 645                     buffer = new SpinedBuffer.OfDouble();
 646                     buffer.accept(first);
 647                     count++;
 648                 }
 649 
 650                 buffer.accept(t);
 651             }
 652             else {
 653                 throw new IllegalStateException();
 654             }
 655         }
 656 
 657         @Override
 658         public DoubleStream build() {
 659             int c = count;
 660             if (c >= 0) {
 661                 // Switch count to negative value signalling the builder is built
 662                 count = -count - 1;
 663                 // Use this spliterator if 0 or 1 elements, otherwise use
 664                 // the spliterator of the spined buffer
 665                 return (c < 2) ? StreamSupport.doubleStream(this, false) : StreamSupport.doubleStream(buffer.spliterator(), false);
 666             }
 667 
 668             throw new IllegalStateException();
 669         }
 670 
 671         // Spliterator implementation for 0 or 1 element
 672         // count == -1 for no elements
 673         // count == -2 for one element held by first
 674 
 675         @Override
 676         public boolean tryAdvance(DoubleConsumer action) {
 677             Objects.requireNonNull(action);
 678 
 679             if (count == -2) {
 680                 action.accept(first);
 681                 count = -1;
 682                 return true;
 683             }
 684             else {
 685                 return false;
 686             }
 687         }
 688 
 689         @Override
 690         public void forEachRemaining(DoubleConsumer action) {
 691             Objects.requireNonNull(action);
 692 
 693             if (count == -2) {
 694                 action.accept(first);
 695                 count = -1;
 696             }
 697         }
 698     }
 699 
 700     abstract static class ConcatSpliterator<T, T_SPLITR extends Spliterator<T>>
 701             implements Spliterator<T> {
 702         protected final T_SPLITR aSpliterator;
 703         protected final T_SPLITR bSpliterator;
 704         // True when no split has occurred, otherwise false
 705         boolean beforeSplit;
 706         // Never read after splitting
 707         final boolean unsized;
 708 
 709         public ConcatSpliterator(T_SPLITR aSpliterator, T_SPLITR bSpliterator) {
 710             this.aSpliterator = aSpliterator;
 711             this.bSpliterator = bSpliterator;
 712             beforeSplit = true;
 713             // The spliterator is known to be unsized before splitting if the
 714             // sum of the estimates overflows.
 715             unsized = aSpliterator.estimateSize() + bSpliterator.estimateSize() < 0;
 716         }
 717 
 718         @Override
 719         public T_SPLITR trySplit() {
 720             @SuppressWarnings("unchecked")
 721             T_SPLITR ret = beforeSplit ? aSpliterator : (T_SPLITR) bSpliterator.trySplit();
 722             beforeSplit = false;
 723             return ret;
 724         }
 725 
 726         @Override
 727         public boolean tryAdvance(Consumer<? super T> consumer) {
 728             boolean hasNext;
 729             if (beforeSplit) {
 730                 hasNext = aSpliterator.tryAdvance(consumer);
 731                 if (!hasNext) {
 732                     beforeSplit = false;
 733                     hasNext = bSpliterator.tryAdvance(consumer);
 734                 }
 735             }
 736             else
 737                 hasNext = bSpliterator.tryAdvance(consumer);
 738             return hasNext;
 739         }
 740 
 741         @Override
 742         public void forEachRemaining(Consumer<? super T> consumer) {
 743             if (beforeSplit)
 744                 aSpliterator.forEachRemaining(consumer);
 745             bSpliterator.forEachRemaining(consumer);
 746         }
 747 
 748         @Override
 749         public long estimateSize() {
 750             if (beforeSplit) {
 751                 // If one or both estimates are Long.MAX_VALUE then the sum
 752                 // will either be Long.MAX_VALUE or overflow to a negative value
 753                 long size = aSpliterator.estimateSize() + bSpliterator.estimateSize();
 754                 return (size >= 0) ? size : Long.MAX_VALUE;
 755             }
 756             else {
 757                 return bSpliterator.estimateSize();
 758             }
 759         }
 760 
 761         @Override
 762         public int characteristics() {
 763             if (beforeSplit) {
 764                 // Concatenation loses DISTINCT and SORTED characteristics
 765                 return aSpliterator.characteristics() & bSpliterator.characteristics()
 766                        & ~(Spliterator.DISTINCT | Spliterator.SORTED
 767                            | (unsized ? Spliterator.SIZED | Spliterator.SUBSIZED : 0));
 768             }
 769             else {
 770                 return bSpliterator.characteristics();
 771             }
 772         }
 773 
 774         @Override
 775         public Comparator<? super T> getComparator() {
 776             if (beforeSplit)
 777                 throw new IllegalStateException();
 778             return bSpliterator.getComparator();
 779         }
 780 
 781         static class OfRef<T> extends ConcatSpliterator<T, Spliterator<T>> {
 782             OfRef(Spliterator<T> aSpliterator, Spliterator<T> bSpliterator) {
 783                 super(aSpliterator, bSpliterator);
 784             }
 785         }
 786 
 787         private static abstract class OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
 788                 extends ConcatSpliterator<T, T_SPLITR>
 789                 implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
 790             private OfPrimitive(T_SPLITR aSpliterator, T_SPLITR bSpliterator) {
 791                 super(aSpliterator, bSpliterator);
 792             }
 793 
 794             @Override
 795             public boolean tryAdvance(T_CONS action) {
 796                 boolean hasNext;
 797                 if (beforeSplit) {
 798                     hasNext = aSpliterator.tryAdvance(action);
 799                     if (!hasNext) {
 800                         beforeSplit = false;
 801                         hasNext = bSpliterator.tryAdvance(action);
 802                     }
 803                 }
 804                 else
 805                     hasNext = bSpliterator.tryAdvance(action);
 806                 return hasNext;
 807             }
 808 
 809             @Override
 810             public void forEachRemaining(T_CONS action) {
 811                 if (beforeSplit)
 812                     aSpliterator.forEachRemaining(action);
 813                 bSpliterator.forEachRemaining(action);
 814             }
 815         }
 816 
 817         static class OfInt
 818                 extends ConcatSpliterator.OfPrimitive<Integer, IntConsumer, Spliterator.OfInt>
 819                 implements Spliterator.OfInt {
 820             OfInt(Spliterator.OfInt aSpliterator, Spliterator.OfInt bSpliterator) {
 821                 super(aSpliterator, bSpliterator);
 822             }
 823         }
 824 
 825         static class OfLong
 826                 extends ConcatSpliterator.OfPrimitive<Long, LongConsumer, Spliterator.OfLong>
 827                 implements Spliterator.OfLong {
 828             OfLong(Spliterator.OfLong aSpliterator, Spliterator.OfLong bSpliterator) {
 829                 super(aSpliterator, bSpliterator);
 830             }
 831         }
 832 
 833         static class OfDouble
 834                 extends ConcatSpliterator.OfPrimitive<Double, DoubleConsumer, Spliterator.OfDouble>
 835                 implements Spliterator.OfDouble {
 836             OfDouble(Spliterator.OfDouble aSpliterator, Spliterator.OfDouble bSpliterator) {
 837                 super(aSpliterator, bSpliterator);
 838             }
 839         }
 840     }
 841 
 842     /**
 843      * Given two Runnables, return a Runnable that executes both in sequence,
 844      * even if the first throws an exception, and if both throw exceptions, add
 845      * any exceptions thrown by the second as suppressed exceptions of the first.
 846      */
 847     static Runnable composeWithExceptions(Runnable a, Runnable b) {
 848         return new Runnable() {
 849             @Override
 850             public void run() {
 851                 try {
 852                     a.run();
 853                 }
 854                 catch (Throwable e1) {
 855                     try {
 856                         b.run();
 857                     }
 858                     catch (Throwable e2) {
 859                         try {
 860                             e1.addSuppressed(e2);
 861                         } catch (Throwable ignore) {}
 862                     }
 863                     throw e1;
 864                 }
 865                 b.run();
 866             }
 867         };
 868     }
 869 
 870     /**
 871      * Given two streams, return a Runnable that
 872      * executes both of their {@link BaseStream#close} methods in sequence,
 873      * even if the first throws an exception, and if both throw exceptions, add
 874      * any exceptions thrown by the second as suppressed exceptions of the first.
 875      */
 876     static Runnable composedClose(BaseStream<?, ?> a, BaseStream<?, ?> b) {
 877         return new Runnable() {
 878             @Override
 879             public void run() {
 880                 try {
 881                     a.close();
 882                 }
 883                 catch (Throwable e1) {
 884                     try {
 885                         b.close();
 886                     }
 887                     catch (Throwable e2) {
 888                         try {
 889                             e1.addSuppressed(e2);
 890                         } catch (Throwable ignore) {}
 891                     }
 892                     throw e1;
 893                 }
 894                 b.close();
 895             }
 896         };
 897     }
 898 }