889 lines
28 KiB
Java
889 lines
28 KiB
Java
![]() |
/*
|
||
|
* Copyright (c) 2012, 2020, 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.vm.annotation.IntrinsicCandidate;
|
||
|
|
||
|
/**
|
||
|
* Utility methods for operating on and creating streams.
|
||
|
*
|
||
|
* <p>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
|
||
|
@IntrinsicCandidate
|
||
|
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<? super Integer> 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.
|
||
|
*
|
||
|
* <p>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.
|
||
|
*
|
||
|
* <p>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<? super Long> 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.
|
||
|
*
|
||
|
* <p>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.
|
||
|
*
|
||
|
* <p>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<T, S extends Spliterator<T>> implements Spliterator<T> {
|
||
|
// >= 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<T>
|
||
|
extends AbstractStreamBuilderImpl<T, Spliterator<T>>
|
||
|
implements Stream.Builder<T> {
|
||
|
// 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<T> 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<T> add(T t) {
|
||
|
accept(t);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public Stream<T> 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<? super T> action) {
|
||
|
Objects.requireNonNull(action);
|
||
|
|
||
|
if (count == -2) {
|
||
|
action.accept(first);
|
||
|
count = -1;
|
||
|
return true;
|
||
|
}
|
||
|
else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void forEachRemaining(Consumer<? super T> action) {
|
||
|
Objects.requireNonNull(action);
|
||
|
|
||
|
if (count == -2) {
|
||
|
action.accept(first);
|
||
|
count = -1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static final class IntStreamBuilderImpl
|
||
|
extends AbstractStreamBuilderImpl<Integer, Spliterator.OfInt>
|
||
|
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<Long, Spliterator.OfLong>
|
||
|
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<Double, Spliterator.OfDouble>
|
||
|
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<T, T_SPLITR extends Spliterator<T>>
|
||
|
implements Spliterator<T> {
|
||
|
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<? super T> 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<? super T> 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<? super T> getComparator() {
|
||
|
if (beforeSplit)
|
||
|
throw new IllegalStateException();
|
||
|
return bSpliterator.getComparator();
|
||
|
}
|
||
|
|
||
|
static class OfRef<T> extends ConcatSpliterator<T, Spliterator<T>> {
|
||
|
OfRef(Spliterator<T> aSpliterator, Spliterator<T> bSpliterator) {
|
||
|
super(aSpliterator, bSpliterator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private abstract static class OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
|
||
|
extends ConcatSpliterator<T, T_SPLITR>
|
||
|
implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
|
||
|
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<Integer, IntConsumer, Spliterator.OfInt>
|
||
|
implements Spliterator.OfInt {
|
||
|
OfInt(Spliterator.OfInt aSpliterator, Spliterator.OfInt bSpliterator) {
|
||
|
super(aSpliterator, bSpliterator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static class OfLong
|
||
|
extends ConcatSpliterator.OfPrimitive<Long, LongConsumer, Spliterator.OfLong>
|
||
|
implements Spliterator.OfLong {
|
||
|
OfLong(Spliterator.OfLong aSpliterator, Spliterator.OfLong bSpliterator) {
|
||
|
super(aSpliterator, bSpliterator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static class OfDouble
|
||
|
extends ConcatSpliterator.OfPrimitive<Double, DoubleConsumer, Spliterator.OfDouble>
|
||
|
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();
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
}
|