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