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