/* * 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.Iterator; 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 */ 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 { private int from; private final int upTo; private final int step; RangeIntSpliterator(int from, int upTo, int step) { this.from = from; this.upTo = upTo; this.step = step; } @Override public boolean tryAdvance(IntConsumer consumer) { boolean hasNext = from < upTo; if (hasNext) { consumer.accept(from); from += step; } return hasNext; } @Override public void forEachRemaining(IntConsumer consumer) { int hUpTo = upTo; int hStep = step; // hoist accesses and checks from loop for (int i = from; i < hUpTo; i += hStep) consumer.accept(i); from = upTo; } @Override public long estimateSize() { int d = upTo - from; return (d / step) + ((d % step == 0) ? 0 : 1); } @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() { return estimateSize() <= 1 ? null : new RangeIntSpliterator(from, from = from + midPoint(), step); } private int midPoint() { // Size is known to be >= 2 int bisection = (upTo - from) / 2; // If bisection > step then round down to nearest multiple of step // otherwise round up to step return bisection > step ? bisection - bisection % step : step; } } /** * A {@code long} range spliterator. */ static final class RangeLongSpliterator implements Spliterator.OfLong { private long from; private final long upTo; private final long step; RangeLongSpliterator(long from, long upTo, long step) { this.from = from; this.upTo = upTo; this.step = step; } @Override public boolean tryAdvance(LongConsumer consumer) { boolean hasNext = from < upTo; if (hasNext) { consumer.accept(from); from += step; } return hasNext; } @Override public void forEachRemaining(LongConsumer consumer) { long hUpTo = upTo; long hStep = step; // hoist accesses and checks from loop for (long i = from; i < hUpTo; i += hStep) consumer.accept(i); from = upTo; } @Override public long estimateSize() { long d = upTo - from; return (d / step) + ((d % step == 0) ? 0 : 1); } @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() { return estimateSize() <= 1 ? null : new RangeLongSpliterator(from, from = from + midPoint(), step); } private long midPoint() { // Size is known to be >= 2 long bisection = (upTo - from) / 2; // If bisection > step then round down to nearest multiple of step // otherwise round up to step return bisection > step ? bisection - bisection % step : step; } } 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; } } } }