/* * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.util.stream; import java.util.Comparator; import java.util.Objects; import java.util.Spliterator; import java.util.function.Consumer; import java.util.function.DoubleConsumer; import java.util.function.IntConsumer; import java.util.function.LongConsumer; import jdk.internal.HotSpotIntrinsicCandidate; /** * Utility methods for operating on and creating streams. * *

Unless otherwise stated, streams are created as sequential streams. A * sequential stream can be transformed into a parallel stream by calling the * {@code parallel()} method on the created stream. * * @since 1.8 */ final class Streams { private Streams() { throw new Error("no instances"); } /** * An {@code int} range spliterator. */ static final class RangeIntSpliterator implements Spliterator.OfInt { // Can never be greater that upTo, this avoids overflow if upper bound // is Integer.MAX_VALUE // All elements are traversed if from == upTo & last == 0 private int from; private final int upTo; // 1 if the range is closed and the last element has not been traversed // Otherwise, 0 if the range is open, or is a closed range and all // elements have been traversed private int last; RangeIntSpliterator(int from, int upTo, boolean closed) { this(from, upTo, closed ? 1 : 0); } private RangeIntSpliterator(int from, int upTo, int last) { this.from = from; this.upTo = upTo; this.last = last; } @Override public boolean tryAdvance(IntConsumer consumer) { Objects.requireNonNull(consumer); final int i = from; if (i < upTo) { from++; consumer.accept(i); return true; } else if (last > 0) { last = 0; consumer.accept(i); return true; } return false; } @Override @HotSpotIntrinsicCandidate public void forEachRemaining(IntConsumer consumer) { Objects.requireNonNull(consumer); int i = from; final int hUpTo = upTo; int hLast = last; from = upTo; last = 0; while (i < hUpTo) { consumer.accept(i++); } if (hLast > 0) { // Last element of closed range consumer.accept(i); } } @Override public long estimateSize() { // Ensure ranges of size > Integer.MAX_VALUE report the correct size return ((long) upTo) - from + last; } @Override public int characteristics() { return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.DISTINCT | Spliterator.SORTED; } @Override public Comparator getComparator() { return null; } @Override public Spliterator.OfInt trySplit() { long size = estimateSize(); return size <= 1 ? null // Left split always has a half-open range : new RangeIntSpliterator(from, from = from + splitPoint(size), 0); } /** * The spliterator size below which the spliterator will be split * at the mid-point to produce balanced splits. Above this size the * spliterator will be split at a ratio of * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1) * to produce right-balanced splits. * *

Such splitting ensures that for very large ranges that the left * side of the range will more likely be processed at a lower-depth * than a balanced tree at the expense of a higher-depth for the right * side of the range. * *

This is optimized for cases such as IntStream.range(0, Integer.MAX_VALUE) * that is likely to be augmented with a limit operation that limits the * number of elements to a count lower than this threshold. */ private static final int BALANCED_SPLIT_THRESHOLD = 1 << 24; /** * The split ratio of the left and right split when the spliterator * size is above BALANCED_SPLIT_THRESHOLD. */ private static final int RIGHT_BALANCED_SPLIT_RATIO = 1 << 3; private int splitPoint(long size) { int d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO; // Cast to int is safe since: // 2 <= size < 2^32 // 2 <= d <= 8 return (int) (size / d); } } /** * A {@code long} range spliterator. * * This implementation cannot be used for ranges whose size is greater * than Long.MAX_VALUE */ static final class RangeLongSpliterator implements Spliterator.OfLong { // Can never be greater that upTo, this avoids overflow if upper bound // is Long.MAX_VALUE // All elements are traversed if from == upTo & last == 0 private long from; private final long upTo; // 1 if the range is closed and the last element has not been traversed // Otherwise, 0 if the range is open, or is a closed range and all // elements have been traversed private int last; RangeLongSpliterator(long from, long upTo, boolean closed) { this(from, upTo, closed ? 1 : 0); } private RangeLongSpliterator(long from, long upTo, int last) { assert upTo - from + last > 0; this.from = from; this.upTo = upTo; this.last = last; } @Override public boolean tryAdvance(LongConsumer consumer) { Objects.requireNonNull(consumer); final long i = from; if (i < upTo) { from++; consumer.accept(i); return true; } else if (last > 0) { last = 0; consumer.accept(i); return true; } return false; } @Override public void forEachRemaining(LongConsumer consumer) { Objects.requireNonNull(consumer); long i = from; final long hUpTo = upTo; int hLast = last; from = upTo; last = 0; while (i < hUpTo) { consumer.accept(i++); } if (hLast > 0) { // Last element of closed range consumer.accept(i); } } @Override public long estimateSize() { return upTo - from + last; } @Override public int characteristics() { return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.DISTINCT | Spliterator.SORTED; } @Override public Comparator getComparator() { return null; } @Override public Spliterator.OfLong trySplit() { long size = estimateSize(); return size <= 1 ? null // Left split always has a half-open range : new RangeLongSpliterator(from, from = from + splitPoint(size), 0); } /** * The spliterator size below which the spliterator will be split * at the mid-point to produce balanced splits. Above this size the * spliterator will be split at a ratio of * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1) * to produce right-balanced splits. * *

Such splitting ensures that for very large ranges that the left * side of the range will more likely be processed at a lower-depth * than a balanced tree at the expense of a higher-depth for the right * side of the range. * *

This is optimized for cases such as LongStream.range(0, Long.MAX_VALUE) * that is likely to be augmented with a limit operation that limits the * number of elements to a count lower than this threshold. */ private static final long BALANCED_SPLIT_THRESHOLD = 1 << 24; /** * The split ratio of the left and right split when the spliterator * size is above BALANCED_SPLIT_THRESHOLD. */ private static final long RIGHT_BALANCED_SPLIT_RATIO = 1 << 3; private long splitPoint(long size) { long d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO; // 2 <= size <= Long.MAX_VALUE return size / d; } } private abstract static class AbstractStreamBuilderImpl> implements Spliterator { // >= 0 when building, < 0 when built // -1 == no elements // -2 == one element, held by first // -3 == two or more elements, held by buffer int count; // Spliterator implementation for 0 or 1 element // count == -1 for no elements // count == -2 for one element held by first @Override public S trySplit() { return null; } @Override public long estimateSize() { return -count - 1; } @Override public int characteristics() { return Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED | Spliterator.IMMUTABLE; } } static final class StreamBuilderImpl extends AbstractStreamBuilderImpl> implements Stream.Builder { // The first element in the stream // valid if count == 1 T first; // The first and subsequent elements in the stream // non-null if count == 2 SpinedBuffer buffer; /** * Constructor for building a stream of 0 or more elements. */ StreamBuilderImpl() { } /** * Constructor for a singleton stream. * * @param t the single element */ StreamBuilderImpl(T t) { first = t; count = -2; } // StreamBuilder implementation @Override public void accept(T t) { if (count == 0) { first = t; count++; } else if (count > 0) { if (buffer == null) { buffer = new SpinedBuffer<>(); buffer.accept(first); count++; } buffer.accept(t); } else { throw new IllegalStateException(); } } public Stream.Builder add(T t) { accept(t); return this; } @Override public Stream build() { int c = count; if (c >= 0) { // Switch count to negative value signalling the builder is built count = -count - 1; // Use this spliterator if 0 or 1 elements, otherwise use // the spliterator of the spined buffer return (c < 2) ? StreamSupport.stream(this, false) : StreamSupport.stream(buffer.spliterator(), false); } throw new IllegalStateException(); } // Spliterator implementation for 0 or 1 element // count == -1 for no elements // count == -2 for one element held by first @Override public boolean tryAdvance(Consumer action) { Objects.requireNonNull(action); if (count == -2) { action.accept(first); count = -1; return true; } else { return false; } } @Override public void forEachRemaining(Consumer action) { Objects.requireNonNull(action); if (count == -2) { action.accept(first); count = -1; } } } static final class IntStreamBuilderImpl extends AbstractStreamBuilderImpl implements IntStream.Builder, Spliterator.OfInt { // The first element in the stream // valid if count == 1 int first; // The first and subsequent elements in the stream // non-null if count == 2 SpinedBuffer.OfInt buffer; /** * Constructor for building a stream of 0 or more elements. */ IntStreamBuilderImpl() { } /** * Constructor for a singleton stream. * * @param t the single element */ IntStreamBuilderImpl(int t) { first = t; count = -2; } // StreamBuilder implementation @Override public void accept(int t) { if (count == 0) { first = t; count++; } else if (count > 0) { if (buffer == null) { buffer = new SpinedBuffer.OfInt(); buffer.accept(first); count++; } buffer.accept(t); } else { throw new IllegalStateException(); } } @Override public IntStream build() { int c = count; if (c >= 0) { // Switch count to negative value signalling the builder is built count = -count - 1; // Use this spliterator if 0 or 1 elements, otherwise use // the spliterator of the spined buffer return (c < 2) ? StreamSupport.intStream(this, false) : StreamSupport.intStream(buffer.spliterator(), false); } throw new IllegalStateException(); } // Spliterator implementation for 0 or 1 element // count == -1 for no elements // count == -2 for one element held by first @Override public boolean tryAdvance(IntConsumer action) { Objects.requireNonNull(action); if (count == -2) { action.accept(first); count = -1; return true; } else { return false; } } @Override public void forEachRemaining(IntConsumer action) { Objects.requireNonNull(action); if (count == -2) { action.accept(first); count = -1; } } } static final class LongStreamBuilderImpl extends AbstractStreamBuilderImpl implements LongStream.Builder, Spliterator.OfLong { // The first element in the stream // valid if count == 1 long first; // The first and subsequent elements in the stream // non-null if count == 2 SpinedBuffer.OfLong buffer; /** * Constructor for building a stream of 0 or more elements. */ LongStreamBuilderImpl() { } /** * Constructor for a singleton stream. * * @param t the single element */ LongStreamBuilderImpl(long t) { first = t; count = -2; } // StreamBuilder implementation @Override public void accept(long t) { if (count == 0) { first = t; count++; } else if (count > 0) { if (buffer == null) { buffer = new SpinedBuffer.OfLong(); buffer.accept(first); count++; } buffer.accept(t); } else { throw new IllegalStateException(); } } @Override public LongStream build() { int c = count; if (c >= 0) { // Switch count to negative value signalling the builder is built count = -count - 1; // Use this spliterator if 0 or 1 elements, otherwise use // the spliterator of the spined buffer return (c < 2) ? StreamSupport.longStream(this, false) : StreamSupport.longStream(buffer.spliterator(), false); } throw new IllegalStateException(); } // Spliterator implementation for 0 or 1 element // count == -1 for no elements // count == -2 for one element held by first @Override public boolean tryAdvance(LongConsumer action) { Objects.requireNonNull(action); if (count == -2) { action.accept(first); count = -1; return true; } else { return false; } } @Override public void forEachRemaining(LongConsumer action) { Objects.requireNonNull(action); if (count == -2) { action.accept(first); count = -1; } } } static final class DoubleStreamBuilderImpl extends AbstractStreamBuilderImpl implements DoubleStream.Builder, Spliterator.OfDouble { // The first element in the stream // valid if count == 1 double first; // The first and subsequent elements in the stream // non-null if count == 2 SpinedBuffer.OfDouble buffer; /** * Constructor for building a stream of 0 or more elements. */ DoubleStreamBuilderImpl() { } /** * Constructor for a singleton stream. * * @param t the single element */ DoubleStreamBuilderImpl(double t) { first = t; count = -2; } // StreamBuilder implementation @Override public void accept(double t) { if (count == 0) { first = t; count++; } else if (count > 0) { if (buffer == null) { buffer = new SpinedBuffer.OfDouble(); buffer.accept(first); count++; } buffer.accept(t); } else { throw new IllegalStateException(); } } @Override public DoubleStream build() { int c = count; if (c >= 0) { // Switch count to negative value signalling the builder is built count = -count - 1; // Use this spliterator if 0 or 1 elements, otherwise use // the spliterator of the spined buffer return (c < 2) ? StreamSupport.doubleStream(this, false) : StreamSupport.doubleStream(buffer.spliterator(), false); } throw new IllegalStateException(); } // Spliterator implementation for 0 or 1 element // count == -1 for no elements // count == -2 for one element held by first @Override public boolean tryAdvance(DoubleConsumer action) { Objects.requireNonNull(action); if (count == -2) { action.accept(first); count = -1; return true; } else { return false; } } @Override public void forEachRemaining(DoubleConsumer action) { Objects.requireNonNull(action); if (count == -2) { action.accept(first); count = -1; } } } abstract static class ConcatSpliterator> implements Spliterator { protected final T_SPLITR aSpliterator; protected final T_SPLITR bSpliterator; // True when no split has occurred, otherwise false boolean beforeSplit; // Never read after splitting final boolean unsized; public ConcatSpliterator(T_SPLITR aSpliterator, T_SPLITR bSpliterator) { this.aSpliterator = aSpliterator; this.bSpliterator = bSpliterator; beforeSplit = true; // The spliterator is known to be unsized before splitting if the // sum of the estimates overflows. unsized = aSpliterator.estimateSize() + bSpliterator.estimateSize() < 0; } @Override public T_SPLITR trySplit() { @SuppressWarnings("unchecked") T_SPLITR ret = beforeSplit ? aSpliterator : (T_SPLITR) bSpliterator.trySplit(); beforeSplit = false; return ret; } @Override public boolean tryAdvance(Consumer consumer) { boolean hasNext; if (beforeSplit) { hasNext = aSpliterator.tryAdvance(consumer); if (!hasNext) { beforeSplit = false; hasNext = bSpliterator.tryAdvance(consumer); } } else hasNext = bSpliterator.tryAdvance(consumer); return hasNext; } @Override public void forEachRemaining(Consumer consumer) { if (beforeSplit) aSpliterator.forEachRemaining(consumer); bSpliterator.forEachRemaining(consumer); } @Override public long estimateSize() { if (beforeSplit) { // If one or both estimates are Long.MAX_VALUE then the sum // will either be Long.MAX_VALUE or overflow to a negative value long size = aSpliterator.estimateSize() + bSpliterator.estimateSize(); return (size >= 0) ? size : Long.MAX_VALUE; } else { return bSpliterator.estimateSize(); } } @Override public int characteristics() { if (beforeSplit) { // Concatenation loses DISTINCT and SORTED characteristics return aSpliterator.characteristics() & bSpliterator.characteristics() & ~(Spliterator.DISTINCT | Spliterator.SORTED | (unsized ? Spliterator.SIZED | Spliterator.SUBSIZED : 0)); } else { return bSpliterator.characteristics(); } } @Override public Comparator getComparator() { if (beforeSplit) throw new IllegalStateException(); return bSpliterator.getComparator(); } static class OfRef extends ConcatSpliterator> { OfRef(Spliterator aSpliterator, Spliterator bSpliterator) { super(aSpliterator, bSpliterator); } } private abstract static class OfPrimitive> extends ConcatSpliterator implements Spliterator.OfPrimitive { private OfPrimitive(T_SPLITR aSpliterator, T_SPLITR bSpliterator) { super(aSpliterator, bSpliterator); } @Override public boolean tryAdvance(T_CONS action) { boolean hasNext; if (beforeSplit) { hasNext = aSpliterator.tryAdvance(action); if (!hasNext) { beforeSplit = false; hasNext = bSpliterator.tryAdvance(action); } } else hasNext = bSpliterator.tryAdvance(action); return hasNext; } @Override public void forEachRemaining(T_CONS action) { if (beforeSplit) aSpliterator.forEachRemaining(action); bSpliterator.forEachRemaining(action); } } static class OfInt extends ConcatSpliterator.OfPrimitive implements Spliterator.OfInt { OfInt(Spliterator.OfInt aSpliterator, Spliterator.OfInt bSpliterator) { super(aSpliterator, bSpliterator); } } static class OfLong extends ConcatSpliterator.OfPrimitive implements Spliterator.OfLong { OfLong(Spliterator.OfLong aSpliterator, Spliterator.OfLong bSpliterator) { super(aSpliterator, bSpliterator); } } static class OfDouble extends ConcatSpliterator.OfPrimitive implements Spliterator.OfDouble { OfDouble(Spliterator.OfDouble aSpliterator, Spliterator.OfDouble bSpliterator) { super(aSpliterator, bSpliterator); } } } /** * Given two Runnables, return a Runnable that executes both in sequence, * even if the first throws an exception, and if both throw exceptions, add * any exceptions thrown by the second as suppressed exceptions of the first. */ static Runnable composeWithExceptions(Runnable a, Runnable b) { return new Runnable() { @Override public void run() { try { a.run(); } catch (Throwable e1) { try { b.run(); } catch (Throwable e2) { try { e1.addSuppressed(e2); } catch (Throwable ignore) {} } throw e1; } b.run(); } }; } /** * Given two streams, return a Runnable that * executes both of their {@link BaseStream#close} methods in sequence, * even if the first throws an exception, and if both throw exceptions, add * any exceptions thrown by the second as suppressed exceptions of the first. */ static Runnable composedClose(BaseStream a, BaseStream b) { return new Runnable() { @Override public void run() { try { a.close(); } catch (Throwable e1) { try { b.close(); } catch (Throwable e2) { try { e1.addSuppressed(e2); } catch (Throwable ignore) {} } throw e1; } b.close(); } }; } }