/* * 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.Spliterators; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.DoubleConsumer; import java.util.function.IntConsumer; import java.util.function.LongConsumer; /** * 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 object instance representing no value, that cannot be an actual * data element of a stream. Used when processing streams that can contain * {@code null} elements to distinguish between a {@code null} value and no * value. */ static final Object NONE = new Object(); /** * 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) { 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 public void forEachRemaining(IntConsumer 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.ints() that is * implemented as range of 0 to Integer.MAX_VALUE but 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; // 2 <= size <= 2^32 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) { 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) { 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.longs() that is * implemented as range of 0 to Long.MAX_VALUE but 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 static abstract 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 StreamBuilder { // 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 StreamBuilder 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) : StreamSupport.stream(buffer.spliterator()); } 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) { if (count == -2) { action.accept(first); count = -1; return true; } else { return false; } } @Override public void forEachRemaining(Consumer action) { if (count == -2) { action.accept(first); count = -1; } } } static final class IntStreamBuilderImpl extends AbstractStreamBuilderImpl implements StreamBuilder.OfInt, 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) : StreamSupport.intStream(buffer.spliterator()); } 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) { if (count == -2) { action.accept(first); count = -1; return true; } else { return false; } } @Override public void forEachRemaining(IntConsumer action) { if (count == -2) { action.accept(first); count = -1; } } } static final class LongStreamBuilderImpl extends AbstractStreamBuilderImpl implements StreamBuilder.OfLong, 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) : StreamSupport.longStream(buffer.spliterator()); } 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) { if (count == -2) { action.accept(first); count = -1; return true; } else { return false; } } @Override public void forEachRemaining(LongConsumer action) { if (count == -2) { action.accept(first); count = -1; } } } static final class DoubleStreamBuilderImpl extends AbstractStreamBuilderImpl implements StreamBuilder.OfDouble, 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) : StreamSupport.doubleStream(buffer.spliterator()); } 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) { if (count == -2) { action.accept(first); count = -1; return true; } else { return false; } } @Override public void forEachRemaining(DoubleConsumer 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 unsized before splitting if a and b are // sized and the sum of the estimates overflows unsized = aSpliterator.hasCharacteristics(SIZED) && aSpliterator.hasCharacteristics(SIZED) && aSpliterator.estimateSize() + bSpliterator.estimateSize() < 0; } @Override public T_SPLITR trySplit() { 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 static abstract 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); } } } }