1 /*
2  * Copyright (c) 2012, 2020, 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.vm.annotation.IntrinsicCandidate;
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 
Streams()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 
RangeIntSpliterator(int from, int upTo, boolean closed)65         RangeIntSpliterator(int from, int upTo, boolean closed) {
66             this(from, upTo, closed ? 1 : 0);
67         }
68 
RangeIntSpliterator(int from, int upTo, int last)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
tryAdvance(IntConsumer consumer)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         @IntrinsicCandidate
forEachRemaining(IntConsumer consumer)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
estimateSize()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
characteristics()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
getComparator()126         public Comparator<? super Integer> getComparator() {
127             return null;
128         }
129 
130         @Override
trySplit()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 
splitPoint(long size)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 
RangeLongSpliterator(long from, long upTo, boolean closed)189         RangeLongSpliterator(long from, long upTo, boolean closed) {
190             this(from, upTo, closed ? 1 : 0);
191         }
192 
RangeLongSpliterator(long from, long upTo, int last)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
tryAdvance(LongConsumer consumer)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
forEachRemaining(LongConsumer consumer)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
estimateSize()237         public long estimateSize() {
238             return upTo - from + last;
239         }
240 
241         @Override
characteristics()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
getComparator()249         public Comparator<? super Long> getComparator() {
250             return null;
251         }
252 
253         @Override
trySplit()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 
splitPoint(long size)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
trySplit()305         public S trySplit() {
306             return null;
307         }
308 
309         @Override
estimateSize()310         public long estimateSize() {
311             return -count - 1;
312         }
313 
314         @Override
characteristics()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          */
StreamBuilderImpl()335         StreamBuilderImpl() { }
336 
337         /**
338          * Constructor for a singleton stream.
339          *
340          * @param t the single element
341          */
StreamBuilderImpl(T t)342         StreamBuilderImpl(T t) {
343             first = t;
344             count = -2;
345         }
346 
347         // StreamBuilder implementation
348 
349         @Override
accept(T t)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 
add(T t)369         public Stream.Builder<T> add(T t) {
370             accept(t);
371             return this;
372         }
373 
374         @Override
build()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
tryAdvance(Consumer<? super T> action)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
forEachRemaining(Consumer<? super T> action)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          */
IntStreamBuilderImpl()431         IntStreamBuilderImpl() { }
432 
433         /**
434          * Constructor for a singleton stream.
435          *
436          * @param t the single element
437          */
IntStreamBuilderImpl(int t)438         IntStreamBuilderImpl(int t) {
439             first = t;
440             count = -2;
441         }
442 
443         // StreamBuilder implementation
444 
445         @Override
accept(int t)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
build()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
tryAdvance(IntConsumer action)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
forEachRemaining(IntConsumer action)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          */
LongStreamBuilderImpl()522         LongStreamBuilderImpl() { }
523 
524         /**
525          * Constructor for a singleton stream.
526          *
527          * @param t the single element
528          */
LongStreamBuilderImpl(long t)529         LongStreamBuilderImpl(long t) {
530             first = t;
531             count = -2;
532         }
533 
534         // StreamBuilder implementation
535 
536         @Override
accept(long t)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
build()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
tryAdvance(LongConsumer action)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
forEachRemaining(LongConsumer action)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          */
DoubleStreamBuilderImpl()613         DoubleStreamBuilderImpl() { }
614 
615         /**
616          * Constructor for a singleton stream.
617          *
618          * @param t the single element
619          */
DoubleStreamBuilderImpl(double t)620         DoubleStreamBuilderImpl(double t) {
621             first = t;
622             count = -2;
623         }
624 
625         // StreamBuilder implementation
626 
627         @Override
accept(double t)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
build()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
tryAdvance(DoubleConsumer action)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
forEachRemaining(DoubleConsumer action)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 
ConcatSpliterator(T_SPLITR aSpliterator, T_SPLITR bSpliterator)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
characteristics()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
getComparator()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>> {
OfRef(Spliterator<T> aSpliterator, Spliterator<T> bSpliterator)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> {
OfPrimitive(T_SPLITR aSpliterator, T_SPLITR bSpliterator)780             private OfPrimitive(T_SPLITR aSpliterator, T_SPLITR bSpliterator) {
781                 super(aSpliterator, bSpliterator);
782             }
783 
784             @Override
tryAdvance(T_CONS action)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
forEachRemaining(T_CONS action)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 {
OfInt(Spliterator.OfInt aSpliterator, Spliterator.OfInt bSpliterator)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 {
OfLong(Spliterator.OfLong aSpliterator, Spliterator.OfLong bSpliterator)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 {
OfDouble(Spliterator.OfDouble aSpliterator, Spliterator.OfDouble bSpliterator)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      */
composeWithExceptions(Runnable a, Runnable b)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 }
889