Emulate Java 8 Streams.
Change-Id: Ifbe0c001f1a53f5cb9c4c1a77ee203b2660d4e23
diff --git a/user/super/com/google/gwt/emul/java/util/Arrays.java b/user/super/com/google/gwt/emul/java/util/Arrays.java
index 72da442..4229fe6 100644
--- a/user/super/com/google/gwt/emul/java/util/Arrays.java
+++ b/user/super/com/google/gwt/emul/java/util/Arrays.java
@@ -35,6 +35,11 @@
import java.util.function.IntUnaryOperator;
import java.util.function.LongBinaryOperator;
import java.util.function.UnaryOperator;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
import javaemul.internal.ArrayHelper;
import javaemul.internal.LongCompareHolder;
@@ -1452,6 +1457,38 @@
Spliterator.IMMUTABLE | Spliterator.ORDERED);
}
+ public static DoubleStream stream(double[] array) {
+ return stream(array, 0, array.length);
+ }
+
+ public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) {
+ return StreamSupport.doubleStream(spliterator(array, startInclusive, endExclusive), false);
+ }
+
+ public static IntStream stream(int[] array) {
+ return stream(array, 0, array.length);
+ }
+
+ public static IntStream stream(int[] array, int startInclusive, int endExclusive) {
+ return StreamSupport.intStream(spliterator(array, startInclusive, endExclusive), false);
+ }
+
+ public static LongStream stream(long[] array) {
+ return stream(array, 0, array.length);
+ }
+
+ public static LongStream stream(long[] array, int startInclusive, int endExclusive) {
+ return StreamSupport.longStream(spliterator(array, startInclusive, endExclusive), false);
+ }
+
+ public static <T> Stream<T> stream(T[] array) {
+ return stream(array, 0, array.length);
+ }
+
+ public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive) {
+ return StreamSupport.stream(spliterator(array, startInclusive, endExclusive), false);
+ }
+
public static String toString(boolean[] a) {
if (a == null) {
return "null";
diff --git a/user/super/com/google/gwt/emul/java/util/Collection.java b/user/super/com/google/gwt/emul/java/util/Collection.java
index 379be6d..d678e05 100644
--- a/user/super/com/google/gwt/emul/java/util/Collection.java
+++ b/user/super/com/google/gwt/emul/java/util/Collection.java
@@ -18,6 +18,8 @@
import static javaemul.internal.InternalPreconditions.checkNotNull;
import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
/**
* General-purpose interface for storing collections of objects.
@@ -49,6 +51,11 @@
@Override
Iterator<E> iterator();
+ default Stream<E> parallelStream() {
+ // no parallelism in gwt
+ return stream();
+ }
+
boolean remove(Object o);
boolean removeAll(Collection<?> c);
@@ -74,6 +81,10 @@
return Spliterators.spliterator(this, 0);
}
+ default Stream<E> stream() {
+ return StreamSupport.stream(spliterator(), false);
+ }
+
Object[] toArray();
<T> T[] toArray(T[] a);
diff --git a/user/super/com/google/gwt/emul/java/util/stream/BaseStream.java b/user/super/com/google/gwt/emul/java/util/stream/BaseStream.java
new file mode 100644
index 0000000..3d08e80
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/stream/BaseStream.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package java.util.stream;
+
+import java.util.Iterator;
+import java.util.Spliterator;
+
+/**
+ * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/BaseStream.html">
+ * the official Java API doc</a> for details.
+ *
+ * @param <T> the contents of the stream
+ * @param <S> the type of stream implementing this interface
+ */
+public interface BaseStream<T,S extends BaseStream<T,S>> extends AutoCloseable {
+ Iterator<T> iterator();
+
+ Spliterator<T> spliterator();
+
+ boolean isParallel();
+
+ S sequential();
+
+ S parallel();
+
+ S unordered();
+
+ S onClose(Runnable closeHandler);
+
+ void close();
+}
diff --git a/user/super/com/google/gwt/emul/java/util/stream/DoubleStream.java b/user/super/com/google/gwt/emul/java/util/stream/DoubleStream.java
new file mode 100644
index 0000000..492f621
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/stream/DoubleStream.java
@@ -0,0 +1,1028 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package java.util.stream;
+
+import static javaemul.internal.InternalPreconditions.checkCriticalState;
+import static javaemul.internal.InternalPreconditions.checkNotNull;
+import static javaemul.internal.InternalPreconditions.checkState;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.DoubleSummaryStatistics;
+import java.util.HashSet;
+import java.util.OptionalDouble;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleFunction;
+import java.util.function.DoublePredicate;
+import java.util.function.DoubleSupplier;
+import java.util.function.DoubleToIntFunction;
+import java.util.function.DoubleToLongFunction;
+import java.util.function.DoubleUnaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.function.ObjDoubleConsumer;
+import java.util.function.Supplier;
+
+/**
+ * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/DoubleStream.html">
+ * the official Java API doc</a> for details.
+ */
+public interface DoubleStream extends BaseStream<Double,DoubleStream> {
+
+ /**
+ * Value holder for various stream operations.
+ */
+ static final class ValueConsumer implements DoubleConsumer {
+ double value;
+
+ @Override
+ public void accept(double value) {
+ this.value = value;
+ }
+ }
+
+ static DoubleStream.Builder builder() {
+ return new Builder() {
+ private double[] items = new double[0];
+
+ @Override
+ public void accept(double t) {
+ checkState(items != null, "Builder already built");
+ items[items.length] = t;
+ }
+
+ @Override
+ public DoubleStream build() {
+ checkCriticalState(items != null, "Builder already built");
+ DoubleStream stream = Arrays.stream(items);
+ items = null;
+ return stream;
+ }
+ };
+ }
+
+ static DoubleStream concat(DoubleStream a, DoubleStream b) {
+ // This is nearly the same as flatMap, but inlined, wrapped around a single spliterator of
+ // these two objects, and without close() called as the stream progresses. Instead, close is
+ // invoked as part of the resulting stream's own onClose, so that either can fail without
+ // affecting the other, and correctly collecting suppressed exceptions.
+
+ // TODO replace this flatMap-ish spliterator with one that directly combines the two root
+ // streams
+ Spliterator<? extends DoubleStream> spliteratorOfStreams =
+ Arrays.asList(a, b).spliterator();
+ DoubleStream result = new DoubleStreamSource(null, new Spliterators.AbstractDoubleSpliterator(
+ Long.MAX_VALUE,
+ 0
+ ) {
+ DoubleStream nextStream;
+ Spliterator.OfDouble next;
+
+ @Override
+ public boolean tryAdvance(DoubleConsumer action) {
+ // look for a new spliterator
+ while (advanceToNextSpliterator()) {
+ // if we have one, try to read and use it
+ if (next.tryAdvance(action)) {
+ return true;
+ } else {
+ nextStream = null;
+ // failed, null it out so we can find another
+ next = null;
+ }
+ }
+ return false;
+ }
+
+ private boolean advanceToNextSpliterator() {
+ while (next == null) {
+ if (!spliteratorOfStreams.tryAdvance(n -> {
+ if (n != null) {
+ nextStream = n;
+ next = n.spliterator();
+ }
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+
+ result.onClose(a::close);
+ result.onClose(b::close);
+
+ return result;
+ }
+
+ static DoubleStream empty() {
+ return new EmptyDoubleStreamSource(null);
+ }
+
+ static DoubleStream generate(DoubleSupplier s) {
+ return StreamSupport.doubleStream(new Spliterators.AbstractDoubleSpliterator(
+ Long.MAX_VALUE,
+ Spliterator.IMMUTABLE | Spliterator.ORDERED
+ ) {
+ @Override
+ public boolean tryAdvance(DoubleConsumer action) {
+ action.accept(s.getAsDouble());
+ return true;
+ }
+ }, false);
+ }
+
+ static DoubleStream iterate(double seed, DoubleUnaryOperator f) {
+ return StreamSupport.doubleStream(new Spliterators.AbstractDoubleSpliterator(
+ Long.MAX_VALUE,
+ Spliterator.IMMUTABLE | Spliterator.ORDERED
+ ) {
+ private double next = seed;
+
+ @Override
+ public boolean tryAdvance(DoubleConsumer action) {
+ action.accept(next);
+ next = f.applyAsDouble(next);
+ return true;
+ }
+ }, false);
+ }
+
+ static DoubleStream of(double... values) {
+ return Arrays.stream(values);
+ }
+
+ static DoubleStream of(double t) {
+ // TODO consider a splittable that returns only a single value
+ return of(new double[]{t});
+ }
+
+ /**
+ * See
+ * <a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/DoubleStream.Builder.html">
+ * the official Java API doc</a> for details.
+ */
+ public interface Builder extends DoubleConsumer {
+ @Override
+ void accept(double t);
+
+ default DoubleStream.Builder add(double t) {
+ accept(t);
+ return this;
+ }
+
+ DoubleStream build();
+ }
+
+ boolean allMatch(DoublePredicate predicate);
+
+ boolean anyMatch(DoublePredicate predicate);
+
+ OptionalDouble average();
+
+ Stream<Double> boxed();
+
+ <R> R collect(Supplier<R> supplier, ObjDoubleConsumer<R> accumulator, BiConsumer<R,R> combiner);
+
+ long count();
+
+ DoubleStream distinct();
+
+ DoubleStream filter(DoublePredicate predicate);
+
+ OptionalDouble findAny();
+
+ OptionalDouble findFirst();
+
+ DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper);
+
+ void forEach(DoubleConsumer action);
+
+ void forEachOrdered(DoubleConsumer action);
+
+ PrimitiveIterator.OfDouble iterator();
+
+ DoubleStream limit(long maxSize);
+
+ DoubleStream map(DoubleUnaryOperator mapper);
+
+ IntStream mapToInt(DoubleToIntFunction mapper);
+
+ LongStream mapToLong(DoubleToLongFunction mapper);
+
+ <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper);
+
+ OptionalDouble max();
+
+ OptionalDouble min();
+
+ boolean noneMatch(DoublePredicate predicate);
+
+ DoubleStream parallel();
+
+ DoubleStream peek(DoubleConsumer action);
+
+ OptionalDouble reduce(DoubleBinaryOperator op);
+
+ double reduce(double identity, DoubleBinaryOperator op);
+
+ DoubleStream sequential();
+
+ DoubleStream skip(long n);
+
+ DoubleStream sorted();
+
+ Spliterator.OfDouble spliterator();
+
+ double sum();
+
+ DoubleSummaryStatistics summaryStatistics();
+
+ double[] toArray();
+
+ /**
+ * Represents an empty stream, doing nothing for all methods.
+ */
+ static class EmptyDoubleStreamSource extends TerminatableStream<EmptyDoubleStreamSource>
+ implements DoubleStream {
+ public EmptyDoubleStreamSource(TerminatableStream<?> previous) {
+ super(previous);
+ }
+
+ @Override
+ public DoubleStream filter(DoublePredicate predicate) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public DoubleStream map(DoubleUnaryOperator mapper) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper) {
+ throwIfTerminated();
+ return new Stream.EmptyStreamSource<U>(this);
+ }
+
+ @Override
+ public IntStream mapToInt(DoubleToIntFunction mapper) {
+ throwIfTerminated();
+ return new IntStream.EmptyIntStreamSource(this);
+ }
+
+ @Override
+ public LongStream mapToLong(DoubleToLongFunction mapper) {
+ throwIfTerminated();
+ return new LongStream.EmptyLongStreamSource(this);
+ }
+
+ @Override
+ public DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public DoubleStream distinct() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public DoubleStream sorted() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public DoubleStream peek(DoubleConsumer action) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public DoubleStream limit(long maxSize) {
+ throwIfTerminated();
+ checkState(maxSize >= 0, "maxSize may not be negative");
+ return this;
+ }
+
+ @Override
+ public DoubleStream skip(long n) {
+ throwIfTerminated();
+ checkState(n >= 0, "n may not be negative");
+ return this;
+ }
+
+ @Override
+ public void forEach(DoubleConsumer action) {
+ terminate();
+ // do nothing
+ }
+
+ @Override
+ public void forEachOrdered(DoubleConsumer action) {
+ terminate();
+ // do nothing
+ }
+
+ @Override
+ public double[] toArray() {
+ terminate();
+ return new double[0];
+ }
+
+ @Override
+ public double reduce(double identity, DoubleBinaryOperator op) {
+ terminate();
+ return identity;
+ }
+
+ @Override
+ public OptionalDouble reduce(DoubleBinaryOperator op) {
+ terminate();
+ return OptionalDouble.empty();
+ }
+
+ @Override
+ public <R> R collect(Supplier<R> supplier,
+ ObjDoubleConsumer<R> accumulator,
+ BiConsumer<R, R> combiner) {
+ terminate();
+ return supplier.get();
+ }
+
+ @Override
+ public double sum() {
+ terminate();
+ return 0;
+ }
+
+ @Override
+ public OptionalDouble min() {
+ terminate();
+ return OptionalDouble.empty();
+ }
+
+ @Override
+ public OptionalDouble max() {
+ terminate();
+ return OptionalDouble.empty();
+ }
+
+ @Override
+ public long count() {
+ terminate();
+ return 0;
+ }
+
+ @Override
+ public OptionalDouble average() {
+ terminate();
+ return OptionalDouble.empty();
+ }
+
+ @Override
+ public DoubleSummaryStatistics summaryStatistics() {
+ terminate();
+ return new DoubleSummaryStatistics();
+ }
+
+ @Override
+ public boolean anyMatch(DoublePredicate predicate) {
+ terminate();
+ return false;
+ }
+
+ @Override
+ public boolean allMatch(DoublePredicate predicate) {
+ terminate();
+ return true;
+ }
+
+ @Override
+ public boolean noneMatch(DoublePredicate predicate) {
+ terminate();
+ return true;
+ }
+
+ @Override
+ public OptionalDouble findFirst() {
+ terminate();
+ return OptionalDouble.empty();
+ }
+
+ @Override
+ public OptionalDouble findAny() {
+ terminate();
+ return OptionalDouble.empty();
+ }
+
+ @Override
+ public Stream<Double> boxed() {
+ throwIfTerminated();
+ return new Stream.EmptyStreamSource<Double>(this);
+ }
+
+ @Override
+ public DoubleStream sequential() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public DoubleStream parallel() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public PrimitiveIterator.OfDouble iterator() {
+ return Spliterators.iterator(spliterator());
+ }
+
+ @Override
+ public Spliterator.OfDouble spliterator() {
+ terminate();
+ return Spliterators.emptyDoubleSpliterator();
+ }
+
+ @Override
+ public boolean isParallel() {
+ throwIfTerminated();
+ return false;
+ }
+
+ @Override
+ public DoubleStream unordered() {
+ throwIfTerminated();
+ return this;
+ }
+ }
+
+ /**
+ * Double to Int map spliterator.
+ */
+ static final class MapToIntSpliterator extends Spliterators.AbstractIntSpliterator {
+ private final DoubleToIntFunction map;
+ private final Spliterator.OfDouble original;
+
+ public MapToIntSpliterator(DoubleToIntFunction map, Spliterator.OfDouble original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final IntConsumer action) {
+ return original.tryAdvance((double u) -> action.accept(map.applyAsInt(u)));
+ }
+ }
+
+ /**
+ * Double to Object map spliterator.
+ * @param <T> the type of Object in the spliterator
+ */
+ static final class MapToObjSpliterator<T> extends Spliterators.AbstractSpliterator<T> {
+ private final DoubleFunction<? extends T> map;
+ private final Spliterator.OfDouble original;
+
+ public MapToObjSpliterator(DoubleFunction<? extends T> map, Spliterator.OfDouble original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final Consumer<? super T> action) {
+ return original.tryAdvance((double u) -> action.accept(map.apply(u)));
+ }
+ }
+
+ /**
+ * Double to Long map spliterator.
+ */
+ static final class MapToLongSpliterator extends Spliterators.AbstractLongSpliterator {
+ private final DoubleToLongFunction map;
+ private final Spliterator.OfDouble original;
+
+ public MapToLongSpliterator(DoubleToLongFunction map, Spliterator.OfDouble original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final LongConsumer action) {
+ return original.tryAdvance((double u) -> action.accept(map.applyAsLong(u)));
+ }
+ }
+
+ /**
+ * Double to Double map spliterator.
+ */
+ static final class MapToDoubleSpliterator extends Spliterators.AbstractDoubleSpliterator {
+ private final DoubleUnaryOperator map;
+ private final Spliterator.OfDouble original;
+
+ public MapToDoubleSpliterator(DoubleUnaryOperator map, Spliterator.OfDouble original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final DoubleConsumer action) {
+ return original.tryAdvance((double u) -> action.accept(map.applyAsDouble(u)));
+ }
+ }
+
+ /**
+ * Double filter spliterator.
+ */
+ static final class FilterSpliterator extends Spliterators.AbstractDoubleSpliterator {
+ private final DoublePredicate filter;
+ private final Spliterator.OfDouble original;
+
+ private boolean found;
+
+ public FilterSpliterator(DoublePredicate filter, Spliterator.OfDouble original) {
+ super(original.estimateSize(), original.characteristics() & ~Spliterator.SIZED);
+ checkNotNull(filter);
+ this.filter = filter;
+ this.original = original;
+ }
+
+ @Override
+ public Comparator<? super Double> getComparator() {
+ return original.getComparator();
+ }
+
+ @Override
+ public boolean tryAdvance(final DoubleConsumer action) {
+ found = false;
+ while (!found && original.tryAdvance((double item) -> {
+ if (filter.test(item)) {
+ found = true;
+ action.accept(item);
+ }
+ })) {
+ // do nothing, work is done in tryAdvance
+ }
+
+ return found;
+ }
+ }
+
+ /**
+ * Double skip spliterator.
+ */
+ static final class SkipSpliterator extends Spliterators.AbstractDoubleSpliterator {
+ private long skip;
+ private final Spliterator.OfDouble original;
+
+ public SkipSpliterator(long skip, Spliterator.OfDouble original) {
+ super(
+ original.hasCharacteristics(Spliterator.SIZED)
+ ? Math.max(0, original.estimateSize() - skip)
+ : Long.MAX_VALUE,
+ original.characteristics()
+ );
+ this.skip = skip;
+ this.original = original;
+ }
+
+ @Override
+ public Comparator<? super Double> getComparator() {
+ return original.getComparator();
+ }
+
+ @Override
+ public boolean tryAdvance(DoubleConsumer action) {
+ while (skip > 0) {
+ if (!original.tryAdvance((double ignore) -> { })) {
+ return false;
+ }
+ skip--;
+ }
+ return original.tryAdvance(action);
+ }
+ }
+
+ /**
+ * Double limit spliterator.
+ */
+ static final class LimitSpliterator extends Spliterators.AbstractDoubleSpliterator {
+ private final long limit;
+ private final Spliterator.OfDouble original;
+ private int position = 0;
+
+ public LimitSpliterator(long limit, Spliterator.OfDouble original) {
+ super(
+ original.hasCharacteristics(Spliterator.SIZED)
+ ? Math.min(original.estimateSize(), limit)
+ : Long.MAX_VALUE,
+ original.characteristics()
+ );
+ this.limit = limit;
+ this.original = original;
+ }
+
+ @Override
+ public Comparator<? super Double> getComparator() {
+ return original.getComparator();
+ }
+
+ @Override
+ public boolean tryAdvance(DoubleConsumer action) {
+ if (limit <= position) {
+ return false;
+ }
+ boolean result = original.tryAdvance(action);
+ position++;
+ return result;
+ }
+ }
+
+ /**
+ * Main implementation of DoubleStream, wrapping a single spliterator, and an optional parent
+ * stream.
+ */
+ static class DoubleStreamSource extends TerminatableStream<DoubleStreamSource>
+ implements DoubleStream {
+ private final Spliterator.OfDouble spliterator;
+
+ public DoubleStreamSource(TerminatableStream<?> previous, Spliterator.OfDouble spliterator) {
+ super(previous);
+ this.spliterator = spliterator;
+ }
+
+ // terminals
+
+ @Override
+ public void forEach(DoubleConsumer action) {
+ forEachOrdered(action);
+ }
+
+ @Override
+ public void forEachOrdered(DoubleConsumer action) {
+ terminate();
+ spliterator.forEachRemaining(action);
+ }
+
+ @Override
+ public double[] toArray() {
+ terminate();
+ double[] entries = new double[0];
+ // this is legal in js, since the array will be backed by a JS array
+ spliterator.forEachRemaining((double value) -> entries[entries.length] = value);
+
+ return entries;
+ }
+
+ @Override
+ public double reduce(double identity, DoubleBinaryOperator op) {
+ terminate();
+ ValueConsumer holder = new ValueConsumer();
+ holder.value = identity;
+ spliterator.forEachRemaining((double value) -> {
+ holder.accept(op.applyAsDouble(holder.value, value));
+ });
+ return holder.value;
+ }
+
+ @Override
+ public OptionalDouble reduce(DoubleBinaryOperator op) {
+ ValueConsumer holder = new ValueConsumer();
+ if (spliterator.tryAdvance(holder)) {
+ return OptionalDouble.of(reduce(holder.value, op));
+ }
+ terminate();
+ return OptionalDouble.empty();
+ }
+
+ @Override
+ public <R> R collect(Supplier<R> supplier,
+ ObjDoubleConsumer<R> accumulator,
+ BiConsumer<R, R> combiner) {
+ terminate();
+ final R acc = supplier.get();
+ spliterator.forEachRemaining((double value) -> accumulator.accept(acc, value));
+ return acc;
+ }
+
+ @Override
+ public double sum() {
+ return summaryStatistics().getSum();
+ }
+
+ @Override
+ public OptionalDouble min() {
+ terminate();
+ final ValueConsumer holder = new ValueConsumer();
+ if (spliterator.tryAdvance((double value) -> holder.value = value)) {
+ spliterator.forEachRemaining((double value) -> {
+ holder.value = Math.min(holder.value, value);
+ });
+ return OptionalDouble.of(holder.value);
+ }
+ return OptionalDouble.empty();
+ }
+
+ @Override
+ public OptionalDouble max() {
+ terminate();
+ final ValueConsumer holder = new ValueConsumer();
+ if (spliterator.tryAdvance((double value) -> holder.value = value)) {
+ spliterator.forEachRemaining((double value) -> {
+ holder.value = Math.max(holder.value, value);
+ });
+ return OptionalDouble.of(holder.value);
+ }
+ return OptionalDouble.empty();
+ }
+
+ @Override
+ public long count() {
+ terminate();
+ long count = 0;
+ while (spliterator.tryAdvance((double value) -> { })) {
+ count++;
+ }
+ return count;
+ }
+
+ @Override
+ public OptionalDouble average() {
+ DoubleSummaryStatistics stats = summaryStatistics();
+ if (stats.getCount() == 0) {
+ return OptionalDouble.empty();
+ }
+ return OptionalDouble.of(stats.getAverage());
+ }
+
+ @Override
+ public DoubleSummaryStatistics summaryStatistics() {
+ return collect(
+ DoubleSummaryStatistics::new,
+ // TODO switch to a lambda reference once #9340 is fixed
+ (doubleSummaryStatistics, value) -> doubleSummaryStatistics.accept(value),
+ DoubleSummaryStatistics::combine
+ );
+ }
+
+ @Override
+ public boolean anyMatch(DoublePredicate predicate) {
+ return filter(predicate).findFirst().isPresent();
+ }
+
+ @Override
+ public boolean allMatch(DoublePredicate predicate) {
+ return !anyMatch(predicate.negate());
+ }
+
+ @Override
+ public boolean noneMatch(DoublePredicate predicate) {
+ return !anyMatch(predicate);
+ }
+
+ @Override
+ public OptionalDouble findFirst() {
+ terminate();
+ ValueConsumer holder = new ValueConsumer();
+ if (spliterator.tryAdvance(holder)) {
+ return OptionalDouble.of(holder.value);
+ }
+ return OptionalDouble.empty();
+ }
+
+ @Override
+ public OptionalDouble findAny() {
+ return findFirst();
+ }
+
+ @Override
+ public PrimitiveIterator.OfDouble iterator() {
+ return Spliterators.iterator(spliterator());
+ }
+
+ @Override
+ public Spliterator.OfDouble spliterator() {
+ terminate();
+ return spliterator;
+ }
+
+ // end terminals
+
+ // intermediates
+
+ @Override
+ public DoubleStream filter(DoublePredicate predicate) {
+ throwIfTerminated();
+ return new DoubleStreamSource(this, new FilterSpliterator(predicate, spliterator));
+ }
+
+ @Override
+ public DoubleStream map(DoubleUnaryOperator mapper) {
+ throwIfTerminated();
+ return new DoubleStreamSource(this, new MapToDoubleSpliterator(mapper, spliterator));
+ }
+
+ @Override
+ public <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper) {
+ throwIfTerminated();
+ return new Stream.StreamSource(this, new MapToObjSpliterator<U>(mapper, spliterator));
+ }
+
+ @Override
+ public IntStream mapToInt(DoubleToIntFunction mapper) {
+ throwIfTerminated();
+ return new IntStream.IntStreamSource(this, new MapToIntSpliterator(mapper, spliterator));
+ }
+
+ @Override
+ public LongStream mapToLong(DoubleToLongFunction mapper) {
+ throwIfTerminated();
+ return new LongStream.LongStreamSource(this, new MapToLongSpliterator(mapper, spliterator));
+ }
+
+ @Override
+ public DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper) {
+ throwIfTerminated();
+ final Spliterator<? extends DoubleStream> spliteratorOfStreams =
+ new MapToObjSpliterator<DoubleStream>(mapper, spliterator);
+ return new DoubleStreamSource(this, new Spliterators.AbstractDoubleSpliterator(
+ Long.MAX_VALUE,
+ 0
+ ) {
+ DoubleStream nextStream;
+ Spliterator.OfDouble next;
+
+ @Override
+ public boolean tryAdvance(DoubleConsumer action) {
+ // look for a new spliterator
+ while (advanceToNextSpliterator()) {
+ // if we have one, try to read and use it
+ if (next.tryAdvance(action)) {
+ return true;
+ } else {
+ nextStream.close();
+ nextStream = null;
+ // failed, null it out so we can find another
+ next = null;
+ }
+ }
+ return false;
+ }
+
+ private boolean advanceToNextSpliterator() {
+ while (next == null) {
+ if (!spliteratorOfStreams.tryAdvance(n -> {
+ if (n != null) {
+ nextStream = n;
+ next = n.spliterator();
+ }
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+ }
+
+ @Override
+ public DoubleStream distinct() {
+ throwIfTerminated();
+ HashSet<Double> seen = new HashSet<>();
+ return filter(seen::add);
+ }
+
+ @Override
+ public DoubleStream sorted() {
+ throwIfTerminated();
+ return new DoubleStreamSource(this, new Spliterators.AbstractDoubleSpliterator(
+ spliterator.estimateSize(),
+ spliterator.characteristics() | Spliterator.SORTED
+ ) {
+ Spliterator.OfDouble ordered = null;
+
+ @Override
+ public Comparator<? super Double> getComparator() {
+ return null;
+ }
+
+ @Override
+ public boolean tryAdvance(DoubleConsumer action) {
+ if (ordered == null) {
+ double[] list = new double[0];
+ spliterator.forEachRemaining((double item) -> list[list.length] = item);
+ Arrays.sort(list);
+ ordered = Spliterators.spliterator(list, characteristics());
+ }
+ return ordered.tryAdvance(action);
+ }
+ });
+ }
+
+ @Override
+ public DoubleStream peek(DoubleConsumer action) {
+ checkNotNull(action);
+ throwIfTerminated();
+ return new DoubleStreamSource(this, new Spliterators.AbstractDoubleSpliterator(
+ spliterator.estimateSize(),
+ spliterator.characteristics()
+ ) {
+ @Override
+ public boolean tryAdvance(final DoubleConsumer innerAction) {
+ return spliterator.tryAdvance(action.andThen(innerAction));
+ }
+ });
+ }
+
+ @Override
+ public DoubleStream limit(long maxSize) {
+ throwIfTerminated();
+ checkState(maxSize >= 0, "maxSize may not be negative");
+ return new DoubleStreamSource(this, new LimitSpliterator(maxSize, spliterator));
+ }
+
+ @Override
+ public DoubleStream skip(long n) {
+ throwIfTerminated();
+ checkState(n >= 0, "n may not be negative");
+ if (n == 0) {
+ return this;
+ }
+ return new DoubleStreamSource(this, new SkipSpliterator(n, spliterator));
+ }
+
+ @Override
+ public Stream<Double> boxed() {
+ return mapToObj(Double::valueOf);
+ }
+
+ @Override
+ public DoubleStream sequential() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public DoubleStream parallel() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public boolean isParallel() {
+ throwIfTerminated();
+ return false;
+ }
+
+ @Override
+ public DoubleStream unordered() {
+ throwIfTerminated();
+ return this;
+ }
+ }
+}
diff --git a/user/super/com/google/gwt/emul/java/util/stream/IntStream.java b/user/super/com/google/gwt/emul/java/util/stream/IntStream.java
new file mode 100644
index 0000000..8a0816e
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/stream/IntStream.java
@@ -0,0 +1,1081 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package java.util.stream;
+
+import static javaemul.internal.InternalPreconditions.checkCriticalState;
+import static javaemul.internal.InternalPreconditions.checkNotNull;
+import static javaemul.internal.InternalPreconditions.checkState;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.IntSummaryStatistics;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntSupplier;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.ObjIntConsumer;
+import java.util.function.Supplier;
+
+/**
+ * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html">
+ * the official Java API doc</a> for details.
+ */
+public interface IntStream extends BaseStream<Integer,IntStream> {
+
+ /**
+ * Value holder for various stream operations.
+ */
+ static final class ValueConsumer implements IntConsumer {
+ int value;
+
+ @Override
+ public void accept(int value) {
+ this.value = value;
+ }
+ }
+
+ static IntStream.Builder builder() {
+ return new Builder() {
+ private int[] items = new int[0];
+
+ @Override
+ public void accept(int t) {
+ checkState(items != null, "Builder already built");
+ items[items.length] = t;
+ }
+
+ @Override
+ public IntStream build() {
+ checkCriticalState(items != null, "Builder already built");
+ IntStream stream = Arrays.stream(items);
+ items = null;
+ return stream;
+ }
+ };
+ }
+
+ static IntStream concat(IntStream a, IntStream b) {
+ // This is nearly the same as flatMap, but inlined, wrapped around a single spliterator of
+ // these two objects, and without close() called as the stream progresses. Instead, close is
+ // invoked as part of the resulting stream's own onClose, so that either can fail without
+ // affecting the other, and correctly collecting suppressed exceptions.
+
+ // TODO replace this flatMap-ish spliterator with one that directly combines the two root
+ // streams
+ Spliterator<? extends IntStream> spliteratorOfStreams =
+ Arrays.asList(a, b).spliterator();
+ IntStream result = new IntStreamSource(null, new Spliterators.AbstractIntSpliterator(Long
+ .MAX_VALUE, 0) {
+ IntStream nextStream;
+ Spliterator.OfInt next;
+
+ @Override
+ public boolean tryAdvance(IntConsumer action) {
+ // look for a new spliterator
+ while (advanceToNextSpliterator()) {
+ // if we have one, try to read and use it
+ if (next.tryAdvance(action)) {
+ return true;
+ } else {
+ nextStream = null;
+ // failed, null it out so we can find another
+ next = null;
+ }
+ }
+ return false;
+ }
+
+ private boolean advanceToNextSpliterator() {
+ while (next == null) {
+ if (!spliteratorOfStreams.tryAdvance(n -> {
+ if (n != null) {
+ nextStream = n;
+ next = n.spliterator();
+ }
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+
+ result.onClose(a::close);
+ result.onClose(b::close);
+
+ return result;
+ }
+
+ static IntStream empty() {
+ return new EmptyIntStreamSource(null);
+ }
+
+ static IntStream generate(final IntSupplier s) {
+ return StreamSupport.intStream(new Spliterators.AbstractIntSpliterator(
+ Long.MAX_VALUE,
+ Spliterator.IMMUTABLE | Spliterator.ORDERED
+ ) {
+ @Override
+ public boolean tryAdvance(IntConsumer action) {
+ action.accept(s.getAsInt());
+ return true;
+ }
+ }, false);
+ }
+
+ static IntStream iterate(int seed, IntUnaryOperator f) {
+ return StreamSupport.intStream(new Spliterators.AbstractIntSpliterator(
+ Long.MAX_VALUE,
+ Spliterator.IMMUTABLE | Spliterator.ORDERED
+ ) {
+ private int next = seed;
+
+ @Override
+ public boolean tryAdvance(IntConsumer action) {
+ action.accept(next);
+ next = f.applyAsInt(next);
+ return true;
+ }
+ }, false);
+ }
+
+ static IntStream of(int... values) {
+ return Arrays.stream(values);
+ }
+
+ static IntStream of(int t) {
+ // TODO consider a splittable that returns only a single value
+ return of(new int[]{t});
+ }
+
+ static IntStream range(int startInclusive, int endExclusive) {
+ if (startInclusive >= endExclusive) {
+ return empty();
+ }
+ return rangeClosed(startInclusive, endExclusive - 1);
+ }
+
+ static IntStream rangeClosed(int startInclusive, int endInclusive) {
+ if (startInclusive > endInclusive) {
+ return empty();
+ }
+ int count = endInclusive - startInclusive + 1;
+
+ return StreamSupport.intStream(new Spliterators.AbstractIntSpliterator(
+ count,
+ Spliterator.IMMUTABLE | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED
+ | Spliterator.SORTED | Spliterator.DISTINCT
+ ) {
+ private int next = startInclusive;
+
+ @Override
+ public Comparator<? super Integer> getComparator() {
+ return null;
+ }
+
+ @Override
+ public boolean tryAdvance(IntConsumer action) {
+ if (next <= endInclusive) {
+ action.accept(next++);
+ return true;
+ }
+ return false;
+ }
+ }, false);
+ }
+
+ /**
+ * See
+ * <a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.Builder.html">
+ * the official Java API doc</a> for details.
+ */
+ public interface Builder extends IntConsumer {
+ @Override
+ void accept(int t);
+
+ default IntStream.Builder add(int t) {
+ accept(t);
+ return this;
+ }
+
+ IntStream build();
+ }
+
+ boolean allMatch(IntPredicate predicate);
+
+ boolean anyMatch(IntPredicate predicate);
+
+ DoubleStream asDoubleStream();
+
+ LongStream asLongStream();
+
+ OptionalDouble average();
+
+ Stream<Integer> boxed();
+
+ <R> R collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R,R> combiner);
+
+ long count();
+
+ IntStream distinct();
+
+ IntStream filter(IntPredicate predicate);
+
+ OptionalInt findAny();
+
+ OptionalInt findFirst();
+
+ IntStream flatMap(IntFunction<? extends IntStream> mapper);
+
+ void forEach(IntConsumer action);
+
+ void forEachOrdered(IntConsumer action);
+
+ PrimitiveIterator.OfInt iterator();
+
+ IntStream limit(long maxSize);
+
+ IntStream map(IntUnaryOperator mapper);
+
+ DoubleStream mapToDouble(IntToDoubleFunction mapper);
+
+ LongStream mapToLong(IntToLongFunction mapper);
+
+ <U> Stream<U> mapToObj(IntFunction<? extends U> mapper);
+
+ OptionalInt max();
+
+ OptionalInt min();
+
+ boolean noneMatch(IntPredicate predicate);
+
+ IntStream parallel();
+
+ IntStream peek(IntConsumer action);
+
+ OptionalInt reduce(IntBinaryOperator op);
+
+ int reduce(int identity, IntBinaryOperator op);
+
+ IntStream sequential();
+
+ IntStream skip(long n);
+
+ IntStream sorted();
+
+ Spliterator.OfInt spliterator();
+
+ int sum();
+
+ IntSummaryStatistics summaryStatistics();
+
+ int[] toArray();
+
+ /**
+ * Represents an empty stream, doing nothing for all methods.
+ */
+ static class EmptyIntStreamSource extends TerminatableStream<EmptyIntStreamSource>
+ implements IntStream {
+ public EmptyIntStreamSource(TerminatableStream<?> previous) {
+ super(previous);
+ }
+
+ @Override
+ public IntStream filter(IntPredicate predicate) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public IntStream map(IntUnaryOperator mapper) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public <U> Stream<U> mapToObj(IntFunction<? extends U> mapper) {
+ throwIfTerminated();
+ return new Stream.EmptyStreamSource<U>(this);
+ }
+
+ @Override
+ public LongStream mapToLong(IntToLongFunction mapper) {
+ throwIfTerminated();
+ return new LongStream.EmptyLongStreamSource(this);
+ }
+
+ @Override
+ public DoubleStream mapToDouble(IntToDoubleFunction mapper) {
+ throwIfTerminated();
+ return new DoubleStream.EmptyDoubleStreamSource(this);
+ }
+
+ @Override
+ public IntStream flatMap(IntFunction<? extends IntStream> mapper) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public IntStream distinct() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public IntStream sorted() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public IntStream peek(IntConsumer action) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public IntStream limit(long maxSize) {
+ throwIfTerminated();
+ checkState(maxSize >= 0, "maxSize may not be negative");
+ return this;
+ }
+
+ @Override
+ public IntStream skip(long n) {
+ throwIfTerminated();
+ checkState(n >= 0, "n may not be negative");
+ return this;
+ }
+
+ @Override
+ public void forEach(IntConsumer action) {
+ terminate();
+ // do nothing
+ }
+
+ @Override
+ public void forEachOrdered(IntConsumer action) {
+ terminate();
+ // do nothing
+ }
+
+ @Override
+ public int[] toArray() {
+ terminate();
+ return new int[0];
+ }
+
+ @Override
+ public int reduce(int identity, IntBinaryOperator op) {
+ terminate();
+ return identity;
+ }
+
+ @Override
+ public OptionalInt reduce(IntBinaryOperator op) {
+ terminate();
+ return OptionalInt.empty();
+ }
+
+ @Override
+ public <R> R collect(Supplier<R> supplier,
+ ObjIntConsumer<R> accumulator,
+ BiConsumer<R, R> combiner) {
+ terminate();
+ return supplier.get();
+ }
+
+ @Override
+ public int sum() {
+ terminate();
+ return 0;
+ }
+
+ @Override
+ public OptionalInt min() {
+ terminate();
+ return OptionalInt.empty();
+ }
+
+ @Override
+ public OptionalInt max() {
+ terminate();
+ return OptionalInt.empty();
+ }
+
+ @Override
+ public long count() {
+ terminate();
+ return 0;
+ }
+
+ @Override
+ public OptionalDouble average() {
+ terminate();
+ return OptionalDouble.empty();
+ }
+
+ @Override
+ public IntSummaryStatistics summaryStatistics() {
+ terminate();
+ return new IntSummaryStatistics();
+ }
+
+ @Override
+ public boolean anyMatch(IntPredicate predicate) {
+ terminate();
+ return false;
+ }
+
+ @Override
+ public boolean allMatch(IntPredicate predicate) {
+ terminate();
+ return true;
+ }
+
+ @Override
+ public boolean noneMatch(IntPredicate predicate) {
+ terminate();
+ return true;
+ }
+
+ @Override
+ public OptionalInt findFirst() {
+ terminate();
+ return OptionalInt.empty();
+ }
+
+ @Override
+ public OptionalInt findAny() {
+ terminate();
+ return OptionalInt.empty();
+ }
+
+ @Override
+ public LongStream asLongStream() {
+ throwIfTerminated();
+ return new LongStream.EmptyLongStreamSource(this);
+ }
+
+ @Override
+ public DoubleStream asDoubleStream() {
+ throwIfTerminated();
+ return new DoubleStream.EmptyDoubleStreamSource(this);
+ }
+
+ @Override
+ public Stream<Integer> boxed() {
+ throwIfTerminated();
+ return new Stream.EmptyStreamSource<Integer>(this);
+ }
+
+ @Override
+ public IntStream sequential() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public IntStream parallel() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public PrimitiveIterator.OfInt iterator() {
+ return Spliterators.iterator(spliterator());
+ }
+
+ @Override
+ public Spliterator.OfInt spliterator() {
+ terminate();
+ return Spliterators.emptyIntSpliterator();
+ }
+
+ @Override
+ public boolean isParallel() {
+ throwIfTerminated();
+ return false;
+ }
+
+ @Override
+ public IntStream unordered() {
+ throwIfTerminated();
+ return this;
+ }
+ }
+
+ /**
+ * Int to Int map spliterator.
+ */
+ static final class MapToIntSpliterator extends Spliterators.AbstractIntSpliterator {
+ private final IntUnaryOperator map;
+ private final Spliterator.OfInt original;
+
+ public MapToIntSpliterator(IntUnaryOperator map, Spliterator.OfInt original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final IntConsumer action) {
+ return original.tryAdvance((int u) -> action.accept(map.applyAsInt(u)));
+ }
+ }
+
+ /**
+ * Int to Object map spliterator.
+ * @param <T> the type of data in the object spliterator
+ */
+ static final class MapToObjSpliterator<T> extends Spliterators.AbstractSpliterator<T> {
+ private final IntFunction<? extends T> map;
+ private final Spliterator.OfInt original;
+
+ public MapToObjSpliterator(IntFunction<? extends T> map, Spliterator.OfInt original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final Consumer<? super T> action) {
+ return original.tryAdvance((int u) -> action.accept(map.apply(u)));
+ }
+ }
+
+ /**
+ * Int to Long map spliterator.
+ */
+ static final class MapToLongSpliterator extends Spliterators.AbstractLongSpliterator {
+ private final IntToLongFunction map;
+ private final Spliterator.OfInt original;
+
+ public MapToLongSpliterator(IntToLongFunction map, Spliterator.OfInt original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final LongConsumer action) {
+ return original.tryAdvance((int u) -> action.accept(map.applyAsLong(u)));
+ }
+ }
+
+ /**
+ * Int to Double map spliterator.
+ */
+ static final class MapToDoubleSpliterator extends Spliterators.AbstractDoubleSpliterator {
+ private final IntToDoubleFunction map;
+ private final Spliterator.OfInt original;
+
+ public MapToDoubleSpliterator(IntToDoubleFunction map, Spliterator.OfInt original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final DoubleConsumer action) {
+ return original.tryAdvance((int u) -> action.accept(map.applyAsDouble(u)));
+ }
+ }
+
+ /**
+ * Int filter spliterator.
+ */
+ static final class FilterSpliterator extends Spliterators.AbstractIntSpliterator {
+ private final IntPredicate filter;
+ private final Spliterator.OfInt original;
+
+ private boolean found;
+
+ public FilterSpliterator(IntPredicate filter, Spliterator.OfInt original) {
+ super(original.estimateSize(), original.characteristics() & ~Spliterator.SIZED);
+ checkNotNull(filter);
+ this.filter = filter;
+ this.original = original;
+ }
+
+ @Override
+ public Comparator<? super Integer> getComparator() {
+ return original.getComparator();
+ }
+
+ @Override
+ public boolean tryAdvance(final IntConsumer action) {
+ found = false;
+ while (!found && original.tryAdvance((int item) -> {
+ if (filter.test(item)) {
+ found = true;
+ action.accept(item);
+ }
+ })) {
+ // do nothing, work is done in tryAdvance
+ }
+
+ return found;
+ }
+ }
+
+ /**
+ * Int skip spliterator.
+ */
+ static final class SkipSpliterator extends Spliterators.AbstractIntSpliterator {
+ private long skip;
+ private final Spliterator.OfInt original;
+
+ public SkipSpliterator(long skip, Spliterator.OfInt original) {
+ super(
+ original.hasCharacteristics(Spliterator.SIZED)
+ ? Math.max(0, original.estimateSize() - skip)
+ : Long.MAX_VALUE,
+ original.characteristics()
+ );
+ this.skip = skip;
+ this.original = original;
+ }
+
+ @Override
+ public Comparator<? super Integer> getComparator() {
+ return original.getComparator();
+ }
+
+ @Override
+ public boolean tryAdvance(IntConsumer action) {
+ while (skip > 0) {
+ if (!original.tryAdvance((int ignore) -> { })) {
+ return false;
+ }
+ skip--;
+ }
+ return original.tryAdvance(action);
+ }
+ }
+
+ /**
+ * Int limit spliterator.
+ */
+ static final class LimitSpliterator extends Spliterators.AbstractIntSpliterator {
+ private final long limit;
+ private final Spliterator.OfInt original;
+ private int position = 0;
+
+ public LimitSpliterator(long limit, Spliterator.OfInt original) {
+ super(
+ original.hasCharacteristics(Spliterator.SIZED)
+ ? Math.min(original.estimateSize(), limit)
+ : Long.MAX_VALUE,
+ original.characteristics()
+ );
+ this.limit = limit;
+ this.original = original;
+ }
+
+ @Override
+ public Comparator<? super Integer> getComparator() {
+ return original.getComparator();
+ }
+
+ @Override
+ public boolean tryAdvance(IntConsumer action) {
+ if (limit <= position) {
+ return false;
+ }
+ boolean result = original.tryAdvance(action);
+ position++;
+ return result;
+ }
+ }
+
+ /**
+ * Main implementation of IntStream, wrapping a single spliterator, and an optional parent stream.
+ */
+ static class IntStreamSource extends TerminatableStream<IntStreamSource> implements IntStream {
+ private final Spliterator.OfInt spliterator;
+
+ public IntStreamSource(TerminatableStream<?> previous, Spliterator.OfInt spliterator) {
+ super(previous);
+ this.spliterator = spliterator;
+ }
+
+ // terminals
+ @Override
+ public Spliterator.OfInt spliterator() {
+ terminate();
+ return spliterator;
+ }
+
+ @Override
+ public PrimitiveIterator.OfInt iterator() {
+ return Spliterators.iterator(spliterator());
+ }
+
+ @Override
+ public OptionalInt findFirst() {
+ terminate();
+ ValueConsumer holder = new ValueConsumer();
+ if (spliterator.tryAdvance(holder)) {
+ return OptionalInt.of(holder.value);
+ }
+ return OptionalInt.empty();
+ }
+
+ @Override
+ public OptionalInt findAny() {
+ return findFirst();
+ }
+
+ @Override
+ public boolean noneMatch(IntPredicate predicate) {
+ return !anyMatch(predicate);
+ }
+
+ @Override
+ public boolean allMatch(IntPredicate predicate) {
+ return !anyMatch(predicate.negate());
+ }
+
+ @Override
+ public boolean anyMatch(IntPredicate predicate) {
+ return filter(predicate).findFirst().isPresent();
+ }
+
+ @Override
+ public IntSummaryStatistics summaryStatistics() {
+ return collect(
+ IntSummaryStatistics::new,
+ // TODO switch to a lambda reference once #9340 is fixed
+ (intSummaryStatistics, value) -> intSummaryStatistics.accept(value),
+ IntSummaryStatistics::combine
+ );
+ }
+
+ @Override
+ public OptionalDouble average() {
+ IntSummaryStatistics stats = summaryStatistics();
+ if (stats.getCount() == 0) {
+ return OptionalDouble.empty();
+ }
+ return OptionalDouble.of(stats.getAverage());
+ }
+
+ @Override
+ public long count() {
+ terminate();
+ long count = 0;
+ while (spliterator.tryAdvance((int value) -> { })) {
+ count++;
+ }
+ return count;
+ }
+
+ @Override
+ public OptionalInt max() {
+ terminate();
+ final ValueConsumer holder = new ValueConsumer();
+ if (spliterator.tryAdvance((int value) -> holder.value = value)) {
+ spliterator.forEachRemaining((int value) -> holder.value = Math.max(holder.value, value));
+ return OptionalInt.of(holder.value);
+ }
+ return OptionalInt.empty();
+ }
+
+ @Override
+ public OptionalInt min() {
+ terminate();
+ final ValueConsumer holder = new ValueConsumer();
+ if (spliterator.tryAdvance((int value) -> holder.value = value)) {
+ spliterator.forEachRemaining((int value) -> holder.value = Math.min(holder.value, value));
+ return OptionalInt.of(holder.value);
+ }
+ return OptionalInt.empty();
+ }
+
+ @Override
+ public int sum() {
+ return (int) summaryStatistics().getSum();
+ }
+
+ @Override
+ public <R> R collect(Supplier<R> supplier,
+ final ObjIntConsumer<R> accumulator,
+ BiConsumer<R, R> combiner) {
+ terminate();
+ final R acc = supplier.get();
+ spliterator.forEachRemaining((int value) -> accumulator.accept(acc, value));
+ return acc;
+ }
+
+ @Override
+ public OptionalInt reduce(IntBinaryOperator op) {
+ ValueConsumer holder = new ValueConsumer();
+ if (spliterator.tryAdvance(holder)) {
+ return OptionalInt.of(reduce(holder.value, op));
+ }
+ terminate();
+ return OptionalInt.empty();
+ }
+
+ @Override
+ public int reduce(int identity, IntBinaryOperator op) {
+ terminate();
+ ValueConsumer holder = new ValueConsumer();
+ holder.value = identity;
+ spliterator.forEachRemaining((int value) -> {
+ holder.accept(op.applyAsInt(holder.value, value));
+ });
+ return holder.value;
+ }
+
+ @Override
+ public int[] toArray() {
+ terminate();
+ int[] entries = new int[0];
+ // this is legal in js, since the array will be backed by a JS array
+ spliterator.forEachRemaining((int value) -> entries[entries.length] = value);
+
+ return entries;
+ }
+
+ @Override
+ public void forEachOrdered(IntConsumer action) {
+ terminate();
+ spliterator.forEachRemaining(action);
+ }
+
+ @Override
+ public void forEach(IntConsumer action) {
+ forEachOrdered(action);
+ }
+ // end terminals
+
+ // intermediates
+
+ @Override
+ public IntStream filter(IntPredicate predicate) {
+ throwIfTerminated();
+ return new IntStreamSource(this, new FilterSpliterator(predicate, spliterator));
+ }
+
+ @Override
+ public IntStream map(IntUnaryOperator mapper) {
+ throwIfTerminated();
+ return new IntStreamSource(this, new MapToIntSpliterator(mapper, spliterator));
+ }
+
+ @Override
+ public <U> Stream<U> mapToObj(IntFunction<? extends U> mapper) {
+ throwIfTerminated();
+ return new Stream.StreamSource(this, new MapToObjSpliterator<U>(mapper, spliterator));
+ }
+
+ @Override
+ public LongStream mapToLong(IntToLongFunction mapper) {
+ throwIfTerminated();
+ return new LongStream.LongStreamSource(this, new MapToLongSpliterator(mapper, spliterator));
+ }
+
+ @Override
+ public DoubleStream mapToDouble(IntToDoubleFunction mapper) {
+ throwIfTerminated();
+ return new DoubleStream.DoubleStreamSource(
+ this,
+ new MapToDoubleSpliterator(mapper, spliterator)
+ );
+ }
+
+ @Override
+ public IntStream flatMap(IntFunction<? extends IntStream> mapper) {
+ throwIfTerminated();
+ final Spliterator<? extends IntStream> spliteratorOfStreams =
+ new MapToObjSpliterator<>(mapper, spliterator);
+ return new IntStreamSource(this, new Spliterators.AbstractIntSpliterator(Long.MAX_VALUE, 0) {
+ IntStream nextStream;
+ Spliterator.OfInt next;
+
+ @Override
+ public boolean tryAdvance(IntConsumer action) {
+ // look for a new spliterator
+ while (advanceToNextSpliterator()) {
+ // if we have one, try to read and use it
+ if (next.tryAdvance(action)) {
+ return true;
+ } else {
+ nextStream.close();
+ nextStream = null;
+ // failed, null it out so we can find another
+ next = null;
+ }
+ }
+ return false;
+ }
+
+ private boolean advanceToNextSpliterator() {
+ while (next == null) {
+ if (!spliteratorOfStreams.tryAdvance(n -> {
+ if (n != null) {
+ nextStream = n;
+ next = n.spliterator();
+ }
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+ }
+
+ @Override
+ public IntStream distinct() {
+ throwIfTerminated();
+ HashSet<Integer> seen = new HashSet<>();
+ return filter(seen::add);
+ }
+
+ @Override
+ public IntStream sorted() {
+ throwIfTerminated();
+ return new IntStreamSource(this, new Spliterators.AbstractIntSpliterator(
+ spliterator.estimateSize(),
+ spliterator.characteristics() | Spliterator.SORTED
+ ) {
+ Spliterator.OfInt ordered = null;
+
+ @Override
+ public Comparator<? super Integer> getComparator() {
+ return null;
+ }
+
+ @Override
+ public boolean tryAdvance(IntConsumer action) {
+ if (ordered == null) {
+ int[] list = new int[0];
+ spliterator.forEachRemaining((int item) -> list[list.length] = item);
+ Arrays.sort(list);
+ ordered = Spliterators.spliterator(list, characteristics());
+ }
+ return ordered.tryAdvance(action);
+ }
+ });
+ }
+
+ @Override
+ public IntStream peek(IntConsumer action) {
+ checkNotNull(action);
+ throwIfTerminated();
+ return new IntStreamSource(this, new Spliterators.AbstractIntSpliterator(
+ spliterator.estimateSize(),
+ spliterator.characteristics()
+ ) {
+ @Override
+ public boolean tryAdvance(final IntConsumer innerAction) {
+ return spliterator.tryAdvance(action.andThen(innerAction));
+ }
+ });
+ }
+
+ @Override
+ public IntStream limit(long maxSize) {
+ throwIfTerminated();
+ checkState(maxSize >= 0, "maxSize may not be negative");
+ return new IntStreamSource(this, new LimitSpliterator(maxSize, spliterator));
+ }
+
+ @Override
+ public IntStream skip(long n) {
+ throwIfTerminated();
+ checkState(n >= 0, "n may not be negative");
+ if (n == 0) {
+ return this;
+ }
+ return new IntStreamSource(this, new SkipSpliterator(n, spliterator));
+ }
+
+ @Override
+ public LongStream asLongStream() {
+ return mapToLong(i -> (long) i);
+ }
+
+ @Override
+ public DoubleStream asDoubleStream() {
+ return mapToDouble(i -> (double) i);
+ }
+
+ @Override
+ public Stream<Integer> boxed() {
+ return mapToObj(Integer::valueOf);
+ }
+
+ @Override
+ public IntStream sequential() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public IntStream parallel() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public boolean isParallel() {
+ throwIfTerminated();
+ return false;
+ }
+
+ @Override
+ public IntStream unordered() {
+ throwIfTerminated();
+ return this;
+ }
+ }
+}
diff --git a/user/super/com/google/gwt/emul/java/util/stream/LongStream.java b/user/super/com/google/gwt/emul/java/util/stream/LongStream.java
new file mode 100644
index 0000000..f2b6ba1
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/stream/LongStream.java
@@ -0,0 +1,1072 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package java.util.stream;
+
+import static javaemul.internal.InternalPreconditions.checkCriticalState;
+import static javaemul.internal.InternalPreconditions.checkNotNull;
+import static javaemul.internal.InternalPreconditions.checkState;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LongSummaryStatistics;
+import java.util.OptionalDouble;
+import java.util.OptionalLong;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.LongFunction;
+import java.util.function.LongPredicate;
+import java.util.function.LongSupplier;
+import java.util.function.LongToDoubleFunction;
+import java.util.function.LongToIntFunction;
+import java.util.function.LongUnaryOperator;
+import java.util.function.ObjLongConsumer;
+import java.util.function.Supplier;
+
+/**
+ * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/LongStream.html">
+ * the official Java API doc</a> for details.
+ */
+public interface LongStream extends BaseStream<Long,LongStream> {
+
+ /**
+ * Value holder for various stream operations.
+ */
+ static final class ValueConsumer implements LongConsumer {
+ long value;
+
+ @Override
+ public void accept(long value) {
+ this.value = value;
+ }
+ }
+
+ static LongStream.Builder builder() {
+ return new Builder() {
+ private long[] items = new long[0];
+
+ @Override
+ public void accept(long t) {
+ checkState(items != null, "Builder already built");
+ items[items.length] = t;
+ }
+
+ @Override
+ public LongStream build() {
+ checkCriticalState(items != null, "Builder already built");
+ LongStream stream = Arrays.stream(items);
+ items = null;
+ return stream;
+ }
+ };
+ }
+
+ static LongStream concat(LongStream a, LongStream b) {
+ // This is nearly the same as flatMap, but inlined, wrapped around a single spliterator of
+ // these two objects, and without close() called as the stream progresses. Instead, close is
+ // invoked as part of the resulting stream's own onClose, so that either can fail without
+ // affecting the other, and correctly collecting suppressed exceptions.
+
+ // TODO replace this flatMap-ish spliterator with one that directly combines the two root
+ // streams
+ Spliterator<? extends LongStream> spliteratorOfStreams =
+ Arrays.asList(a, b).spliterator();
+ LongStream result = new LongStreamSource(null, new Spliterators.AbstractLongSpliterator(Long
+ .MAX_VALUE, 0) {
+ LongStream nextStream;
+ Spliterator.OfLong next;
+
+ @Override
+ public boolean tryAdvance(LongConsumer action) {
+ // look for a new spliterator
+ while (advanceToNextSpliterator()) {
+ // if we have one, try to read and use it
+ if (next.tryAdvance(action)) {
+ return true;
+ } else {
+ nextStream = null;
+ // failed, null it out so we can find another
+ next = null;
+ }
+ }
+ return false;
+ }
+
+ private boolean advanceToNextSpliterator() {
+ while (next == null) {
+ if (!spliteratorOfStreams.tryAdvance(n -> {
+ if (n != null) {
+ nextStream = n;
+ next = n.spliterator();
+ }
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+
+ result.onClose(a::close);
+ result.onClose(b::close);
+
+ return result;
+ }
+
+ static LongStream empty() {
+ return new EmptyLongStreamSource(null);
+ }
+
+ static LongStream generate(LongSupplier s) {
+ return StreamSupport.longStream(new Spliterators.AbstractLongSpliterator(
+ Long.MAX_VALUE,
+ Spliterator.IMMUTABLE | Spliterator.ORDERED
+ ) {
+ @Override
+ public boolean tryAdvance(LongConsumer action) {
+ action.accept(s.getAsLong());
+ return true;
+ }
+ }, false);
+ }
+
+ static LongStream iterate(long seed, LongUnaryOperator f) {
+ return StreamSupport.longStream(new Spliterators.AbstractLongSpliterator(
+ Long.MAX_VALUE,
+ Spliterator.IMMUTABLE | Spliterator.ORDERED
+ ) {
+ private long next = seed;
+
+ @Override
+ public boolean tryAdvance(LongConsumer action) {
+ action.accept(next);
+ next = f.applyAsLong(next);
+ return true;
+ }
+ }, false);
+ }
+
+ static LongStream of(long... values) {
+ return Arrays.stream(values);
+ }
+
+ static LongStream of(long t) {
+ // TODO consider a splittable that returns only a single value
+ return of(new long[]{t});
+ }
+
+ static LongStream range(long startInclusive, long endExclusive) {
+ if (startInclusive >= endExclusive) {
+ return empty();
+ }
+ return rangeClosed(startInclusive, endExclusive - 1);
+ }
+
+ static LongStream rangeClosed(long startInclusive, long endInclusive) {
+ if (startInclusive > endInclusive) {
+ return empty();
+ }
+ long count = endInclusive - startInclusive + 1;
+
+ return StreamSupport.longStream(new Spliterators.AbstractLongSpliterator(
+ count,
+ Spliterator.IMMUTABLE | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED
+ | Spliterator.SORTED | Spliterator.DISTINCT
+ ) {
+ private long next = startInclusive;
+
+ @Override
+ public Comparator<? super Long> getComparator() {
+ return null;
+ }
+
+ @Override
+ public boolean tryAdvance(LongConsumer action) {
+ if (next <= endInclusive) {
+ action.accept(next++);
+ return true;
+ }
+ return false;
+ }
+ }, false);
+ }
+
+ /**
+ * See
+ * <a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/LongStream.Builder.html">
+ * the official Java API doc</a> for details.
+ */
+ public interface Builder extends LongConsumer {
+ @Override
+ void accept(long t);
+
+ default LongStream.Builder add(long t) {
+ accept(t);
+ return this;
+ }
+
+ LongStream build();
+ }
+
+ boolean allMatch(LongPredicate predicate);
+
+ boolean anyMatch(LongPredicate predicate);
+
+ DoubleStream asDoubleStream();
+
+ OptionalDouble average();
+
+ Stream<Long> boxed();
+
+ <R> R collect(Supplier<R> supplier, ObjLongConsumer<R> accumulator, BiConsumer<R, R> combiner);
+
+ long count();
+
+ LongStream distinct();
+
+ LongStream filter(LongPredicate predicate);
+
+ OptionalLong findAny();
+
+ OptionalLong findFirst();
+
+ LongStream flatMap(LongFunction<? extends LongStream> mapper);
+
+ void forEach(LongConsumer action);
+
+ void forEachOrdered(LongConsumer action);
+
+ PrimitiveIterator.OfLong iterator();
+
+ LongStream limit(long maxSize);
+
+ LongStream map(LongUnaryOperator mapper);
+
+ DoubleStream mapToDouble(LongToDoubleFunction mapper);
+
+ IntStream mapToInt(LongToIntFunction mapper);
+
+ <U> Stream<U> mapToObj(LongFunction<? extends U> mapper);
+
+ OptionalLong max();
+
+ OptionalLong min();
+
+ boolean noneMatch(LongPredicate predicate);
+
+ LongStream parallel();
+
+ LongStream peek(LongConsumer action);
+
+ OptionalLong reduce(LongBinaryOperator op);
+
+ long reduce(long identity, LongBinaryOperator op);
+
+ LongStream sequential();
+
+ LongStream skip(long n);
+
+ LongStream sorted();
+
+ Spliterator.OfLong spliterator();
+
+ long sum();
+
+ LongSummaryStatistics summaryStatistics();
+
+ long[] toArray();
+
+ /**
+ * Represents an empty stream, doing nothing for all methods.
+ */
+ static class EmptyLongStreamSource extends TerminatableStream<EmptyLongStreamSource>
+ implements LongStream {
+ public EmptyLongStreamSource(TerminatableStream<?> previous) {
+ super(previous);
+ }
+
+ @Override
+ public LongStream filter(LongPredicate predicate) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public LongStream map(LongUnaryOperator mapper) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public <U> Stream<U> mapToObj(LongFunction<? extends U> mapper) {
+ throwIfTerminated();
+ return new Stream.EmptyStreamSource<U>(this);
+ }
+
+ @Override
+ public IntStream mapToInt(LongToIntFunction mapper) {
+ throwIfTerminated();
+ return new IntStream.EmptyIntStreamSource(this);
+ }
+
+ @Override
+ public DoubleStream mapToDouble(LongToDoubleFunction mapper) {
+ throwIfTerminated();
+ return new DoubleStream.EmptyDoubleStreamSource(this);
+ }
+
+ @Override
+ public LongStream flatMap(LongFunction<? extends LongStream> mapper) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public LongStream distinct() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public LongStream sorted() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public LongStream peek(LongConsumer action) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public LongStream limit(long maxSize) {
+ throwIfTerminated();
+ checkState(maxSize >= 0, "maxSize may not be negative");
+ return this;
+ }
+
+ @Override
+ public LongStream skip(long n) {
+ throwIfTerminated();
+ checkState(n >= 0, "n may not be negative");
+ return this;
+ }
+
+ @Override
+ public void forEach(LongConsumer action) {
+ terminate();
+ }
+
+ @Override
+ public void forEachOrdered(LongConsumer action) {
+ terminate();
+ }
+
+ @Override
+ public long[] toArray() {
+ terminate();
+ return new long[0];
+ }
+
+ @Override
+ public long reduce(long identity, LongBinaryOperator op) {
+ terminate();
+ return identity;
+ }
+
+ @Override
+ public OptionalLong reduce(LongBinaryOperator op) {
+ terminate();
+ return OptionalLong.empty();
+ }
+
+ @Override
+ public <R> R collect(Supplier<R> supplier,
+ ObjLongConsumer<R> accumulator,
+ BiConsumer<R, R> combiner) {
+ terminate();
+ return supplier.get();
+ }
+
+ @Override
+ public long sum() {
+ terminate();
+ return 0;
+ }
+
+ @Override
+ public OptionalLong min() {
+ terminate();
+ return OptionalLong.empty();
+ }
+
+ @Override
+ public OptionalLong max() {
+ terminate();
+ return OptionalLong.empty();
+ }
+
+ @Override
+ public long count() {
+ terminate();
+ return 0;
+ }
+
+ @Override
+ public OptionalDouble average() {
+ terminate();
+ return OptionalDouble.empty();
+ }
+
+ @Override
+ public LongSummaryStatistics summaryStatistics() {
+ terminate();
+ return new LongSummaryStatistics();
+ }
+
+ @Override
+ public boolean anyMatch(LongPredicate predicate) {
+ terminate();
+ return false;
+ }
+
+ @Override
+ public boolean allMatch(LongPredicate predicate) {
+ terminate();
+ return true;
+ }
+
+ @Override
+ public boolean noneMatch(LongPredicate predicate) {
+ terminate();
+ return true;
+ }
+
+ @Override
+ public OptionalLong findFirst() {
+ terminate();
+ return OptionalLong.empty();
+ }
+
+ @Override
+ public OptionalLong findAny() {
+ terminate();
+ return OptionalLong.empty();
+ }
+
+ @Override
+ public DoubleStream asDoubleStream() {
+ throwIfTerminated();
+ return new DoubleStream.EmptyDoubleStreamSource(this);
+ }
+
+ @Override
+ public Stream<Long> boxed() {
+ throwIfTerminated();
+ return new Stream.EmptyStreamSource<Long>(this);
+ }
+
+ @Override
+ public LongStream sequential() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public LongStream parallel() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public PrimitiveIterator.OfLong iterator() {
+ return Spliterators.iterator(spliterator());
+ }
+
+ @Override
+ public Spliterator.OfLong spliterator() {
+ terminate();
+ return Spliterators.emptyLongSpliterator();
+ }
+
+ @Override
+ public boolean isParallel() {
+ throwIfTerminated();
+ return false;
+ }
+
+ @Override
+ public LongStream unordered() {
+ throwIfTerminated();
+ return this;
+ }
+ }
+
+ /**
+ * Long to Int map spliterator.
+ */
+ static final class MapToIntSpliterator extends Spliterators.AbstractIntSpliterator {
+ private final LongToIntFunction map;
+ private final Spliterator.OfLong original;
+
+ public MapToIntSpliterator(LongToIntFunction map, Spliterator.OfLong original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final IntConsumer action) {
+ return original.tryAdvance((long u) -> action.accept(map.applyAsInt(u)));
+ }
+ }
+
+ /**
+ * Long to Object map spliterator.
+ * @param <T> the type of data in the object spliterator
+ */
+ static final class MapToObjSpliterator<T> extends Spliterators.AbstractSpliterator<T> {
+ private final LongFunction<? extends T> map;
+ private final Spliterator.OfLong original;
+
+ public MapToObjSpliterator(LongFunction<? extends T> map, Spliterator.OfLong original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final Consumer<? super T> action) {
+ return original.tryAdvance((long u) -> action.accept(map.apply(u)));
+ }
+ }
+
+ /**
+ * Long to Long map spliterator.
+ */
+ static final class MapToLongSpliterator extends Spliterators.AbstractLongSpliterator {
+ private final LongUnaryOperator map;
+ private final Spliterator.OfLong original;
+
+ public MapToLongSpliterator(LongUnaryOperator map, Spliterator.OfLong original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final LongConsumer action) {
+ return original.tryAdvance((long u) -> action.accept(map.applyAsLong(u)));
+ }
+ }
+
+ /**
+ * Long to Double map Spliterator.
+ */
+ static final class MapToDoubleSpliterator extends Spliterators.AbstractDoubleSpliterator {
+ private final LongToDoubleFunction map;
+ private final Spliterator.OfLong original;
+
+ public MapToDoubleSpliterator(LongToDoubleFunction map, Spliterator.OfLong original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final DoubleConsumer action) {
+ return original.tryAdvance((long u) -> action.accept(map.applyAsDouble(u)));
+ }
+ }
+
+ /**
+ * Long filter spliterator.
+ */
+ static final class FilterSpliterator extends Spliterators.AbstractLongSpliterator {
+ private final LongPredicate filter;
+ private final Spliterator.OfLong original;
+
+ private boolean found;
+
+ public FilterSpliterator(LongPredicate filter, Spliterator.OfLong original) {
+ super(original.estimateSize(), original.characteristics() & ~Spliterator.SIZED);
+ checkNotNull(filter);
+ this.filter = filter;
+ this.original = original;
+ }
+
+ @Override
+ public Comparator<? super Long> getComparator() {
+ return original.getComparator();
+ }
+
+ @Override
+ public boolean tryAdvance(final LongConsumer action) {
+ found = false;
+ while (!found && original.tryAdvance((long item) -> {
+ if (filter.test(item)) {
+ found = true;
+ action.accept(item);
+ }
+ })) {
+ // do nothing, work is done in tryAdvance
+ }
+
+ return found;
+ }
+ }
+
+ /**
+ * Long skip spliterator.
+ */
+ static final class SkipSpliterator extends Spliterators.AbstractLongSpliterator {
+ private long skip;
+ private final Spliterator.OfLong original;
+
+ public SkipSpliterator(long skip, Spliterator.OfLong original) {
+ super(
+ original.hasCharacteristics(Spliterator.SIZED)
+ ? Math.max(0, original.estimateSize() - skip)
+ : Long.MAX_VALUE,
+ original.characteristics()
+ );
+ this.skip = skip;
+ this.original = original;
+ }
+
+ @Override
+ public Comparator<? super Long> getComparator() {
+ return original.getComparator();
+ }
+
+ @Override
+ public boolean tryAdvance(LongConsumer action) {
+ while (skip > 0) {
+ if (!original.tryAdvance((long ignore) -> { })) {
+ return false;
+ }
+ skip--;
+ }
+ return original.tryAdvance(action);
+ }
+ }
+
+ /**
+ * Long limit spliterator.
+ */
+ static final class LimitSpliterator extends Spliterators.AbstractLongSpliterator {
+ private final long limit;
+ private final Spliterator.OfLong original;
+ private int position = 0;
+
+ public LimitSpliterator(long limit, Spliterator.OfLong original) {
+ super(
+ original.hasCharacteristics(Spliterator.SIZED)
+ ? Math.min(original.estimateSize(), limit)
+ : Long.MAX_VALUE,
+ original.characteristics()
+ );
+ this.limit = limit;
+ this.original = original;
+ }
+
+ @Override
+ public Comparator<? super Long> getComparator() {
+ return original.getComparator();
+ }
+
+ @Override
+ public boolean tryAdvance(LongConsumer action) {
+ if (limit <= position) {
+ return false;
+ }
+ boolean result = original.tryAdvance(action);
+ position++;
+ return result;
+ }
+ }
+
+ /**
+ * Main implementation of LongStream, wrapping a single spliterator, and an optional parent
+ * stream.
+ */
+ static class LongStreamSource extends TerminatableStream<LongStreamSource> implements LongStream {
+ private final Spliterator.OfLong spliterator;
+
+ public LongStreamSource(TerminatableStream<?> previous, Spliterator.OfLong spliterator) {
+ super(previous);
+ this.spliterator = spliterator;
+ }
+
+ // terminals
+
+ @Override
+ public void forEach(LongConsumer action) {
+ forEachOrdered(action);
+ }
+
+ @Override
+ public void forEachOrdered(LongConsumer action) {
+ terminate();
+ spliterator.forEachRemaining(action);
+ }
+
+ @Override
+ public long[] toArray() {
+ terminate();
+ long[] entries = new long[0];
+ // this is legal in js, since the array will be backed by a JS array
+ spliterator.forEachRemaining((long value) -> entries[entries.length] = value);
+
+ return entries;
+ }
+
+ @Override
+ public long reduce(long identity, LongBinaryOperator op) {
+ terminate();
+ ValueConsumer holder = new ValueConsumer();
+ holder.value = identity;
+ spliterator.forEachRemaining((long value) -> {
+ holder.accept(op.applyAsLong(holder.value, value));
+ });
+ return holder.value;
+ }
+
+ @Override
+ public OptionalLong reduce(LongBinaryOperator op) {
+ ValueConsumer holder = new ValueConsumer();
+ if (spliterator.tryAdvance(holder)) {
+ return OptionalLong.of(reduce(holder.value, op));
+ }
+ terminate();
+ return OptionalLong.empty();
+ }
+
+ @Override
+ public <R> R collect(Supplier<R> supplier,
+ ObjLongConsumer<R> accumulator,
+ BiConsumer<R, R> combiner) {
+ terminate();
+ final R acc = supplier.get();
+ spliterator.forEachRemaining((long value) -> accumulator.accept(acc, value));
+ return acc;
+ }
+
+ @Override
+ public long sum() {
+ return summaryStatistics().getSum();
+ }
+
+ @Override
+ public OptionalLong min() {
+ terminate();
+ final ValueConsumer holder = new ValueConsumer();
+ if (spliterator.tryAdvance((long value) -> holder.value = value)) {
+ spliterator.forEachRemaining((long value) -> holder.value = Math.min(holder.value, value));
+ return OptionalLong.of(holder.value);
+ }
+ return OptionalLong.empty();
+ }
+
+ @Override
+ public OptionalLong max() {
+ terminate();
+ final ValueConsumer holder = new ValueConsumer();
+ if (spliterator.tryAdvance((long value) -> holder.value = value)) {
+ spliterator.forEachRemaining((long value) -> holder.value = Math.max(holder.value, value));
+ return OptionalLong.of(holder.value);
+ }
+ return OptionalLong.empty();
+ }
+
+ @Override
+ public long count() {
+ terminate();
+ long count = 0;
+ while (spliterator.tryAdvance((long value) -> { })) {
+ count++;
+ }
+ return count;
+ }
+
+ @Override
+ public OptionalDouble average() {
+ LongSummaryStatistics stats = summaryStatistics();
+ if (stats.getCount() == 0) {
+ return OptionalDouble.empty();
+ }
+ return OptionalDouble.of(stats.getAverage());
+ }
+
+ @Override
+ public LongSummaryStatistics summaryStatistics() {
+ return collect(
+ LongSummaryStatistics::new,
+ // TODO switch to a lambda reference once #9340 is fixed
+ (longSummaryStatistics, value) -> longSummaryStatistics.accept(value),
+ LongSummaryStatistics::combine
+ );
+ }
+
+ @Override
+ public boolean anyMatch(LongPredicate predicate) {
+ return filter(predicate).findFirst().isPresent();
+ }
+
+ @Override
+ public boolean allMatch(LongPredicate predicate) {
+ return !anyMatch(predicate.negate());
+ }
+
+ @Override
+ public boolean noneMatch(LongPredicate predicate) {
+ return !anyMatch(predicate);
+ }
+
+ @Override
+ public OptionalLong findFirst() {
+ terminate();
+ ValueConsumer holder = new ValueConsumer();
+ if (spliterator.tryAdvance(holder)) {
+ return OptionalLong.of(holder.value);
+ }
+ return OptionalLong.empty();
+ }
+
+ @Override
+ public OptionalLong findAny() {
+ return findFirst();
+ }
+
+ @Override
+ public PrimitiveIterator.OfLong iterator() {
+ return Spliterators.iterator(spliterator());
+ }
+
+ @Override
+ public Spliterator.OfLong spliterator() {
+ terminate();
+ return spliterator;
+ }
+ // end terminals
+
+ // intermediates
+ @Override
+ public LongStream filter(LongPredicate predicate) {
+ throwIfTerminated();
+ return new LongStreamSource(this, new FilterSpliterator(predicate, spliterator));
+ }
+
+ @Override
+ public LongStream map(LongUnaryOperator mapper) {
+ throwIfTerminated();
+ return new LongStream.LongStreamSource(this, new MapToLongSpliterator(mapper, spliterator));
+ }
+
+ @Override
+ public <U> Stream<U> mapToObj(LongFunction<? extends U> mapper) {
+ throwIfTerminated();
+ return new Stream.StreamSource(this, new MapToObjSpliterator<U>(mapper, spliterator));
+ }
+
+ @Override
+ public IntStream mapToInt(LongToIntFunction mapper) {
+ throwIfTerminated();
+ return new IntStream.IntStreamSource(this, new MapToIntSpliterator(mapper, spliterator));
+ }
+
+ @Override
+ public DoubleStream mapToDouble(LongToDoubleFunction mapper) {
+ throwIfTerminated();
+ return new DoubleStream.DoubleStreamSource(this, new MapToDoubleSpliterator(
+ mapper,
+ spliterator)
+ );
+ }
+
+ @Override
+ public LongStream flatMap(LongFunction<? extends LongStream> mapper) {
+ throwIfTerminated();
+ final Spliterator<? extends LongStream> spliteratorOfStreams = new MapToObjSpliterator<>(
+ mapper,
+ spliterator
+ );
+ return new LongStreamSource(
+ this,
+ new Spliterators.AbstractLongSpliterator(Long.MAX_VALUE, 0
+ ) {
+ LongStream nextStream;
+ Spliterator.OfLong next;
+
+ @Override
+ public boolean tryAdvance(LongConsumer action) {
+ // look for a new spliterator
+ while (advanceToNextSpliterator()) {
+ // if we have one, try to read and use it
+ if (next.tryAdvance(action)) {
+ return true;
+ } else {
+ nextStream.close();
+ nextStream = null;
+ // failed, null it out so we can find another
+ next = null;
+ }
+ }
+ return false;
+ }
+
+ private boolean advanceToNextSpliterator() {
+ while (next == null) {
+ if (!spliteratorOfStreams.tryAdvance(n -> {
+ if (n != null) {
+ nextStream = n;
+ next = n.spliterator();
+ }
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+ }
+
+ @Override
+ public LongStream distinct() {
+ throwIfTerminated();
+ HashSet<Long> seen = new HashSet<>();
+ return filter(seen::add);
+ }
+
+ @Override
+ public LongStream sorted() {
+ throwIfTerminated();
+ return new LongStreamSource(this, new Spliterators.AbstractLongSpliterator(
+ spliterator.estimateSize(),
+ spliterator.characteristics() | Spliterator.SORTED
+ ) {
+ Spliterator.OfLong ordered = null;
+
+ @Override
+ public Comparator<? super Long> getComparator() {
+ return null;
+ }
+
+ @Override
+ public boolean tryAdvance(LongConsumer action) {
+ if (ordered == null) {
+ long[] list = new long[0];
+ spliterator.forEachRemaining((long item) -> list[list.length] = item);
+ Arrays.sort(list);
+ ordered = Spliterators.spliterator(list, characteristics());
+ }
+ return ordered.tryAdvance(action);
+ }
+ });
+ }
+
+ @Override
+ public LongStream peek(LongConsumer action) {
+ checkNotNull(action);
+ throwIfTerminated();
+ return new LongStreamSource(this, new Spliterators.AbstractLongSpliterator(
+ spliterator.estimateSize(),
+ spliterator.characteristics()
+ ) {
+ @Override
+ public boolean tryAdvance(final LongConsumer innerAction) {
+ return spliterator.tryAdvance(action.andThen(innerAction));
+ }
+ });
+ }
+
+ @Override
+ public LongStream limit(long maxSize) {
+ throwIfTerminated();
+ checkState(maxSize >= 0, "maxSize may not be negative");
+ return new LongStreamSource(this, new LimitSpliterator(maxSize, spliterator));
+ }
+
+ @Override
+ public LongStream skip(long n) {
+ throwIfTerminated();
+ checkState(n >= 0, "n may not be negative");
+ if (n == 0) {
+ return this;
+ }
+ return new LongStreamSource(this, new SkipSpliterator(n, spliterator));
+ }
+
+ @Override
+ public DoubleStream asDoubleStream() {
+ return mapToDouble(x -> (double) x);
+ }
+
+ @Override
+ public Stream<Long> boxed() {
+ return mapToObj(Long::valueOf);
+ }
+
+ @Override
+ public LongStream sequential() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public LongStream parallel() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public boolean isParallel() {
+ throwIfTerminated();
+ return false;
+ }
+
+ @Override
+ public LongStream unordered() {
+ throwIfTerminated();
+ return this;
+ }
+ }
+}
diff --git a/user/super/com/google/gwt/emul/java/util/stream/Stream.java b/user/super/com/google/gwt/emul/java/util/stream/Stream.java
new file mode 100644
index 0000000..b61486d
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/stream/Stream.java
@@ -0,0 +1,1180 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package java.util.stream;
+
+import static javaemul.internal.InternalPreconditions.checkCriticalState;
+import static javaemul.internal.InternalPreconditions.checkNotNull;
+import static javaemul.internal.InternalPreconditions.checkState;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+import java.util.function.UnaryOperator;
+
+/**
+ * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html">
+ * the official Java API doc</a> for details.
+ *
+ * @param <T> the type of data being streamed
+ */
+public interface Stream<T> extends BaseStream<T, Stream<T>> {
+ /**
+ * Value holder for various stream operations.
+ */
+ static final class ValueConsumer<T> implements Consumer<T> {
+ T value;
+
+ @Override
+ public void accept(T value) {
+ this.value = value;
+ }
+ }
+
+ static <T> Stream.Builder<T> builder() {
+ return new Builder<T>() {
+ private Object[] items = new Object[0];
+
+ @Override
+ public void accept(T t) {
+ checkState(items != null, "Builder already built");
+ items[items.length] = t;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Stream<T> build() {
+ checkCriticalState(items != null, "Builder already built");
+ Stream<T> stream = (Stream<T>) Arrays.stream(items);
+ items = null;
+ return stream;
+ }
+ };
+ }
+
+ static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
+ // This is nearly the same as flatMap, but inlined, wrapped around a single spliterator of
+ // these two objects, and without close() called as the stream progresses. Instead, close is
+ // invoked as part of the resulting stream's own onClose, so that either can fail without
+ // affecting the other, and correctly collecting suppressed exceptions.
+
+ // TODO replace this flatMap-ish spliterator with one that directly combines the two root
+ // streams
+ Spliterator<? extends Stream<? extends T>> spliteratorOfStreams =
+ Arrays.asList(a, b).spliterator();
+ Stream<T> result = new StreamSource<T>(null, new Spliterators.AbstractSpliterator<T>(Long
+ .MAX_VALUE, 0) {
+ Stream<? extends T> nextStream;
+ Spliterator<? extends T> next;
+
+ @Override
+ public boolean tryAdvance(Consumer<? super T> action) {
+ // look for a new spliterator
+ while (advanceToNextSpliterator()) {
+ // if we have one, try to read and use it
+ if (next.tryAdvance(action)) {
+ return true;
+ } else {
+ nextStream = null;
+ // failed, null it out so we can find another
+ next = null;
+ }
+ }
+ return false;
+ }
+
+ private boolean advanceToNextSpliterator() {
+ while (next == null) {
+ if (!spliteratorOfStreams.tryAdvance(n -> {
+ if (n != null) {
+ nextStream = n;
+ next = n.spliterator();
+ }
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+
+ result.onClose(a::close);
+ result.onClose(b::close);
+
+ return result;
+ }
+
+ static <T> Stream<T> empty() {
+ return new EmptyStreamSource<T>(null);
+ }
+
+ static <T> Stream<T> generate(Supplier<T> s) {
+ return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE,
+ Spliterator.IMMUTABLE | Spliterator.ORDERED) {
+ @Override
+ public boolean tryAdvance(Consumer<? super T> action) {
+ action.accept(s.get());
+ return true;
+ }
+ }, false);
+ }
+
+ static <T> Stream<T> iterate(T seed, UnaryOperator<T> f) {
+ return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE,
+ Spliterator.IMMUTABLE | Spliterator.ORDERED) {
+ private T next = seed;
+
+ @Override
+ public boolean tryAdvance(Consumer<? super T> action) {
+ action.accept(next);
+ next = f.apply(next);
+ return true;
+ }
+ }, false);
+ }
+
+ static <T> Stream<T> of(T t) {
+ // TODO consider a splittable that returns only a single value, either for use here or in the
+ // singleton collection types
+ return Collections.singleton(t).stream();
+ }
+
+ static <T> Stream<T> of(T... values) {
+ return Arrays.stream(values);
+ }
+
+ /**
+ * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.Builder.html">
+ * the official Java API doc</a> for details.
+ */
+ public interface Builder<T> extends Consumer<T> {
+ @Override
+ void accept(T t);
+
+ default Stream.Builder<T> add(T t) {
+ accept(t);
+ return this;
+ }
+
+ Stream<T> build();
+ }
+
+ boolean allMatch(Predicate<? super T> predicate);
+
+ boolean anyMatch(Predicate<? super T> predicate);
+
+ <R,A> R collect(Collector<? super T,A,R> collector);
+
+ <R> R collect(Supplier<R> supplier,
+ BiConsumer<R,? super T> accumulator,
+ BiConsumer<R,R> combiner);
+
+ long count();
+
+ Stream<T> distinct();
+
+ Stream<T> filter(Predicate<? super T> predicate);
+
+ Optional<T> findAny();
+
+ Optional<T> findFirst();
+
+ <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper);
+
+ DoubleStream flatMapToDouble(Function<? super T,? extends DoubleStream> mapper);
+
+ IntStream flatMapToInt(Function<? super T,? extends IntStream> mapper);
+
+ LongStream flatMapToLong(Function<? super T,? extends LongStream> mapper);
+
+ void forEach(Consumer<? super T> action);
+
+ void forEachOrdered(Consumer<? super T> action);
+
+ Stream<T> limit(long maxSize);
+
+ <R> Stream<R> map(Function<? super T,? extends R> mapper);
+
+ DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
+
+ IntStream mapToInt(ToIntFunction<? super T> mapper);
+
+ LongStream mapToLong(ToLongFunction<? super T> mapper);
+
+ Optional<T> max(Comparator<? super T> comparator);
+
+ Optional<T> min(Comparator<? super T> comparator);
+
+ boolean noneMatch(Predicate<? super T> predicate);
+
+ Stream<T> peek(Consumer<? super T> action);
+
+ Optional<T> reduce(BinaryOperator<T> accumulator);
+
+ T reduce(T identity, BinaryOperator<T> accumulator);
+
+ <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner);
+
+ Stream<T> skip(long n);
+
+ Stream<T> sorted();
+
+ Stream<T> sorted(Comparator<? super T> comparator);
+
+ Object[] toArray();
+
+ <A> A[] toArray(IntFunction<A[]> generator);
+
+ /**
+ * Represents an empty stream, doing nothing for all methods.
+ */
+ static class EmptyStreamSource<T> extends TerminatableStream<EmptyStreamSource<T>>
+ implements Stream<T> {
+
+ public EmptyStreamSource(TerminatableStream<?> previous) {
+ super(previous);
+ }
+
+ @Override
+ public Stream<T> filter(Predicate<? super T> predicate) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public <R> Stream<R> map(Function<? super T, ? extends R> mapper) {
+ throwIfTerminated();
+ return (Stream) this;
+ }
+
+ @Override
+ public IntStream mapToInt(ToIntFunction<? super T> mapper) {
+ throwIfTerminated();
+ return new IntStream.EmptyIntStreamSource(this);
+ }
+
+ @Override
+ public LongStream mapToLong(ToLongFunction<? super T> mapper) {
+ throwIfTerminated();
+ return new LongStream.EmptyLongStreamSource(this);
+ }
+
+ @Override
+ public DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) {
+ throwIfTerminated();
+ return new DoubleStream.EmptyDoubleStreamSource(this);
+ }
+
+ @Override
+ public <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) {
+ throwIfTerminated();
+ return (Stream) this;
+ }
+
+ @Override
+ public IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper) {
+ throwIfTerminated();
+ return new IntStream.EmptyIntStreamSource(this);
+ }
+
+ @Override
+ public LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper) {
+ throwIfTerminated();
+ return new LongStream.EmptyLongStreamSource(this);
+ }
+
+ @Override
+ public DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper) {
+ throwIfTerminated();
+ return new DoubleStream.EmptyDoubleStreamSource(this);
+ }
+
+ @Override
+ public Stream<T> distinct() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public Stream<T> sorted() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public Stream<T> sorted(Comparator<? super T> comparator) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public Stream<T> peek(Consumer<? super T> action) {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public Stream<T> limit(long maxSize) {
+ throwIfTerminated();
+ checkState(maxSize >= 0, "maxSize may not be negative");
+ return this;
+ }
+
+ @Override
+ public Stream<T> skip(long n) {
+ throwIfTerminated();
+ checkState(n >= 0, "n may not be negative");
+ return this;
+ }
+
+ @Override
+ public void forEach(Consumer<? super T> action) {
+ terminate();
+ // nothing to do
+ }
+
+ @Override
+ public void forEachOrdered(Consumer<? super T> action) {
+ terminate();
+ // nothing to do
+ }
+
+ @Override
+ public Object[] toArray() {
+ terminate();
+ return new Object[0];
+ }
+
+ @Override
+ public <A> A[] toArray(IntFunction<A[]> generator) {
+ terminate();
+ return generator.apply(0);
+ }
+
+ @Override
+ public T reduce(T identity, BinaryOperator<T> accumulator) {
+ terminate();
+ return identity;
+ }
+
+ @Override
+ public Optional<T> reduce(BinaryOperator<T> accumulator) {
+ terminate();
+ return Optional.empty();
+ }
+
+ @Override
+ public <U> U reduce(U identity,
+ BiFunction<U, ? super T, U> accumulator,
+ BinaryOperator<U> combiner) {
+ terminate();
+ return identity;
+ }
+
+ @Override
+ public <R> R collect(Supplier<R> supplier,
+ BiConsumer<R, ? super T> accumulator,
+ BiConsumer<R, R> combiner) {
+ terminate();
+ return supplier.get();
+ }
+
+ @Override
+ public <R, A> R collect(Collector<? super T, A, R> collector) {
+ terminate();
+ return collector.finisher().apply(collector.supplier().get());
+ }
+
+ @Override
+ public Optional<T> min(Comparator<? super T> comparator) {
+ terminate();
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<T> max(Comparator<? super T> comparator) {
+ terminate();
+ return Optional.empty();
+ }
+
+ @Override
+ public long count() {
+ terminate();
+ return 0;
+ }
+
+ @Override
+ public boolean anyMatch(Predicate<? super T> predicate) {
+ terminate();
+ return false;
+ }
+
+ @Override
+ public boolean allMatch(Predicate<? super T> predicate) {
+ terminate();
+ return true;
+ }
+
+ @Override
+ public boolean noneMatch(Predicate<? super T> predicate) {
+ terminate();
+ return true;
+ }
+
+ @Override
+ public Optional<T> findFirst() {
+ terminate();
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<T> findAny() {
+ terminate();
+ return Optional.empty();
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ terminate();
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Spliterator<T> spliterator() {
+ terminate();
+ return Spliterators.emptySpliterator();
+ }
+
+ @Override
+ public boolean isParallel() {
+ throwIfTerminated();
+ return false;
+ }
+
+ @Override
+ public Stream<T> sequential() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public Stream<T> parallel() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public Stream<T> unordered() {
+ throwIfTerminated();
+ return this;
+ }
+ }
+
+ /**
+ * Object to Object map spliterator.
+ * @param <U> the input type
+ * @param <T> the output type
+ */
+ static final class MapToObjSpliterator<U, T> extends Spliterators.AbstractSpliterator<T> {
+ private final Function<? super U, ? extends T> map;
+ private final Spliterator<U> original;
+
+ public MapToObjSpliterator(Function<? super U, ? extends T> map, Spliterator<U> original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final Consumer<? super T> action) {
+ return original.tryAdvance(u -> action.accept(map.apply(u)));
+ }
+ }
+
+ /**
+ * Object to Int map spliterator.
+ * @param <T> the input type
+ */
+ static final class MapToIntSpliterator<T> extends Spliterators.AbstractIntSpliterator {
+ private final ToIntFunction<? super T> map;
+ private final Spliterator<T> original;
+
+ public MapToIntSpliterator(ToIntFunction<? super T> map, Spliterator<T> original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final IntConsumer action) {
+ return original.tryAdvance(u -> action.accept(map.applyAsInt(u)));
+ }
+ }
+
+ /**
+ * Object to Long map spliterator.
+ * @param <T> the input type
+ */
+ static final class MapToLongSpliterator<T> extends Spliterators.AbstractLongSpliterator {
+ private final ToLongFunction<? super T> map;
+ private final Spliterator<T> original;
+
+ public MapToLongSpliterator(ToLongFunction<? super T> map, Spliterator<T> original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final LongConsumer action) {
+ return original.tryAdvance(u -> action.accept(map.applyAsLong(u)));
+ }
+ }
+
+ /**
+ * Object to Double map spliterator.
+ * @param <T> the input type
+ */
+ static final class MapToDoubleSpliterator<T> extends Spliterators.AbstractDoubleSpliterator {
+ private final ToDoubleFunction<? super T> map;
+ private final Spliterator<T> original;
+
+ public MapToDoubleSpliterator(ToDoubleFunction<? super T> map, Spliterator<T> original) {
+ super(
+ original.estimateSize(),
+ original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT)
+ );
+ checkNotNull(map);
+ this.map = map;
+ this.original = original;
+ }
+
+ @Override
+ public boolean tryAdvance(final DoubleConsumer action) {
+ return original.tryAdvance(u -> action.accept(map.applyAsDouble(u)));
+ }
+ }
+
+ /**
+ * Object filter spliterator.
+ * @param <T> the type of data to iterate over
+ */
+ static final class FilterSpliterator<T> extends Spliterators.AbstractSpliterator<T> {
+ private final Predicate<? super T> filter;
+ private final Spliterator<T> original;
+
+ private boolean found;
+
+ public FilterSpliterator(Predicate<? super T> filter, Spliterator<T> original) {
+ super(original.estimateSize(), original.characteristics() & ~Spliterator.SIZED);
+ checkNotNull(filter);
+ this.filter = filter;
+ this.original = original;
+ }
+
+ @Override
+ public Comparator<? super T> getComparator() {
+ return original.getComparator();
+ }
+
+ @Override
+ public boolean tryAdvance(final Consumer<? super T> action) {
+ found = false;
+ while (!found && original.tryAdvance(item -> {
+ if (filter.test(item)) {
+ found = true;
+ action.accept(item);
+ }
+ })) {
+ // do nothing, work is done in tryAdvance
+ }
+
+ return found;
+ }
+ }
+
+ /**
+ * Object skip spliterator.
+ * @param <T> the type of data to iterate over
+ */
+ static final class SkipSpliterator<T> extends Spliterators.AbstractSpliterator<T> {
+ private long skip;
+ private final Spliterator<T> original;
+
+ public SkipSpliterator(long skip, Spliterator<T> original) {
+ super(
+ original.hasCharacteristics(Spliterator.SIZED)
+ ? Math.max(0, original.estimateSize() - skip)
+ : Long.MAX_VALUE,
+ original.characteristics()
+ );
+ this.skip = skip;
+ this.original = original;
+ }
+
+ @Override
+ public Comparator<? super T> getComparator() {
+ return original.getComparator();
+ }
+
+ @Override
+ public boolean tryAdvance(Consumer<? super T> action) {
+ while (skip > 0) {
+ if (!original.tryAdvance(ignore -> { })) {
+ return false;
+ }
+ skip--;
+ }
+ return original.tryAdvance(action);
+ }
+ }
+
+ /**
+ * Object limit spliterator.
+ * @param <T> the type of data to iterate over
+ */
+ static final class LimitSpliterator<T> extends Spliterators.AbstractSpliterator<T> {
+ private final long limit;
+ private final Spliterator<T> original;
+ private int position = 0;
+
+ public LimitSpliterator(long limit, Spliterator<T> original) {
+ super(
+ original.hasCharacteristics(Spliterator.SIZED)
+ ? Math.min(original.estimateSize(), limit)
+ : Long.MAX_VALUE,
+ original.characteristics()
+ );
+ this.limit = limit;
+ this.original = original;
+ }
+
+ @Override
+ public Comparator<? super T> getComparator() {
+ return original.getComparator();
+ }
+
+ @Override
+ public boolean tryAdvance(Consumer<? super T> action) {
+ if (limit <= position) {
+ return false;
+ }
+ boolean result = original.tryAdvance(action);
+ position++;
+ return result;
+ }
+ }
+
+ /**
+ * Main implementation of Stream, wrapping a single spliterator and an optional parent stream.
+ * @param <T>
+ */
+ static class StreamSource<T> extends TerminatableStream<StreamSource<T>> implements Stream<T> {
+ private final Spliterator<T> spliterator;
+
+ public StreamSource(TerminatableStream<?> prev, Spliterator<T> spliterator) {
+ super(prev);
+ this.spliterator = spliterator;
+ }
+
+ // terminal
+ @Override
+ public Spliterator<T> spliterator() {
+ terminate();
+ return spliterator;
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return Spliterators.iterator(spliterator());
+ }
+
+ @Override
+ public long count() {
+ terminate();
+ long count = 0;
+ while (spliterator.tryAdvance(a -> { })) {
+ count++;
+ }
+ return count;
+ }
+
+ @Override
+ public void forEach(Consumer<? super T> action) {
+ forEachOrdered(action);
+ }
+
+ @Override
+ public void forEachOrdered(Consumer<? super T> action) {
+ terminate();
+ spliterator.forEachRemaining(action);
+ }
+
+ @Override
+ public Object[] toArray() {
+ return toArray(Object[]::new);
+ }
+
+ @Override
+ public <A> A[] toArray(IntFunction<A[]> generator) {
+ List<T> collected = collect(Collectors.toList());
+ return collected.toArray(generator.apply(collected.size()));
+ }
+
+ @Override
+ public <R> R collect(Supplier<R> supplier,
+ BiConsumer<R, ? super T> accumulator,
+ BiConsumer<R, R> combiner) {
+ return collect(Collector.of(supplier, accumulator, (a, b) -> {
+ combiner.accept(a, b);
+ return a;
+ }));
+ }
+
+ @Override
+ public <R, A> R collect(final Collector<? super T, A, R> collector) {
+ return collector.finisher().apply(reduce(
+ collector.supplier().get(),
+ (a, t) -> {
+ collector.accumulator().accept(a, t);
+ return a;
+ },
+ collector.combiner()
+ ));
+ }
+
+ @Override
+ public Optional<T> findFirst() {
+ terminate();
+ ValueConsumer<T> holder = new ValueConsumer<T>();
+ if (spliterator.tryAdvance(holder)) {
+ return Optional.of(holder.value);
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<T> findAny() {
+ return findFirst();
+ }
+
+ @Override
+ public boolean anyMatch(Predicate<? super T> predicate) {
+ return filter(predicate).findFirst().isPresent();
+ }
+
+ @Override
+ public boolean allMatch(final Predicate<? super T> predicate) {
+ return !anyMatch(predicate.negate());
+ }
+
+ @Override
+ public boolean noneMatch(final Predicate<? super T> predicate) {
+ return !anyMatch(predicate);
+ }
+
+ @Override
+ public Optional<T> min(final Comparator<? super T> comparator) {
+ return reduce(BinaryOperator.minBy(comparator));
+ }
+
+ @Override
+ public Optional<T> max(final Comparator<? super T> comparator) {
+ return reduce(BinaryOperator.maxBy(comparator));
+ }
+
+ @Override
+ public T reduce(T identity, BinaryOperator<T> accumulator) {
+ return reduce(identity, accumulator, accumulator);
+ }
+
+ @Override
+ public Optional<T> reduce(BinaryOperator<T> accumulator) {
+ ValueConsumer<T> consumer = new ValueConsumer<T>();
+ if (!spliterator.tryAdvance(consumer)) {
+ terminate();
+ return Optional.empty();
+ }
+ return Optional.of(reduce(consumer.value, accumulator));
+ }
+
+ // combiner is ignored, since we don't parallelize
+ @Override
+ public <U> U reduce(U identity,
+ BiFunction<U, ? super T, U> accumulator,
+ BinaryOperator<U> combiner) {
+ terminate();
+ final ValueConsumer<U> consumer = new ValueConsumer<U>();
+ consumer.value = identity;
+ spliterator.forEachRemaining(item -> {
+ consumer.accept(accumulator.apply(consumer.value, item));
+ });
+ return consumer.value;
+ }
+ // end terminal
+
+ // intermediate
+ @Override
+ public Stream<T> filter(Predicate<? super T> predicate) {
+ throwIfTerminated();
+ return new StreamSource<>(this, new FilterSpliterator<>(predicate, spliterator));
+ }
+
+ @Override
+ public <R> Stream<R> map(Function<? super T, ? extends R> mapper) {
+ throwIfTerminated();
+ return new StreamSource<>(this, new MapToObjSpliterator<>(mapper, spliterator));
+ }
+
+ @Override
+ public IntStream mapToInt(ToIntFunction<? super T> mapper) {
+ throwIfTerminated();
+ return new IntStream.IntStreamSource(this, new MapToIntSpliterator<>(mapper, spliterator));
+ }
+
+ @Override
+ public LongStream mapToLong(ToLongFunction<? super T> mapper) {
+ throwIfTerminated();
+ return new LongStream.LongStreamSource(this, new MapToLongSpliterator<>(mapper, spliterator));
+ }
+
+ @Override
+ public DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) {
+ throwIfTerminated();
+ return new DoubleStream.DoubleStreamSource(
+ this,
+ new MapToDoubleSpliterator<>(mapper, spliterator)
+ );
+ }
+
+ @Override
+ public <R> Stream<R> flatMap(final Function<? super T, ? extends Stream<? extends R>> mapper) {
+ throwIfTerminated();
+ final Spliterator<? extends Stream<? extends R>> spliteratorOfStreams =
+ new MapToObjSpliterator<>(mapper, spliterator);
+ return new StreamSource<R>(this, new Spliterators.AbstractSpliterator<R>(Long.MAX_VALUE, 0) {
+ Stream<? extends R> nextStream;
+ Spliterator<? extends R> next;
+
+ @Override
+ public boolean tryAdvance(Consumer<? super R> action) {
+ // look for a new spliterator
+ while (advanceToNextSpliterator()) {
+ // if we have one, try to read and use it
+ if (next.tryAdvance(action)) {
+ return true;
+ } else {
+ nextStream.close();
+ nextStream = null;
+ // failed, null it out so we can find another
+ next = null;
+ }
+ }
+ return false;
+ }
+
+ private boolean advanceToNextSpliterator() {
+ while (next == null) {
+ if (!spliteratorOfStreams.tryAdvance(n -> {
+ if (n != null) {
+ nextStream = n;
+ next = n.spliterator();
+ }
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+ }
+
+ @Override
+ public IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper) {
+ throwIfTerminated();
+ final Spliterator<? extends IntStream> spliteratorOfStreams =
+ new MapToObjSpliterator<>(mapper, spliterator);
+ return new IntStream.IntStreamSource(
+ this,
+ new Spliterators.AbstractIntSpliterator(Long.MAX_VALUE, 0) {
+ IntStream nextStream;
+ Spliterator.OfInt next;
+
+ @Override
+ public boolean tryAdvance(IntConsumer action) {
+ // look for a new spliterator
+ while (advanceToNextSpliterator()) {
+ // if we have one, try to read and use it
+ if (next.tryAdvance(action)) {
+ return true;
+ } else {
+ nextStream.close();
+ nextStream = null;
+ // failed, null it out so we can find another
+ next = null;
+ }
+ }
+ return false;
+ }
+
+ private boolean advanceToNextSpliterator() {
+ while (next == null) {
+ if (!spliteratorOfStreams.tryAdvance(n -> {
+ if (n != null) {
+ nextStream = n;
+ next = n.spliterator();
+ }
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ );
+ }
+
+ @Override
+ public LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper) {
+ throwIfTerminated();
+ final Spliterator<? extends LongStream> spliteratorOfStreams =
+ new MapToObjSpliterator<>(mapper, spliterator);
+ return new LongStream.LongStreamSource(
+ this,
+ new Spliterators.AbstractLongSpliterator(Long.MAX_VALUE, 0) {
+ LongStream nextStream;
+ Spliterator.OfLong next;
+
+ @Override
+ public boolean tryAdvance(LongConsumer action) {
+ // look for a new spliterator
+ while (advanceToNextSpliterator()) {
+ // if we have one, try to read and use it
+ if (next.tryAdvance(action)) {
+ return true;
+ } else {
+ nextStream.close();
+ nextStream = null;
+ // failed, null it out so we can find another
+ next = null;
+ }
+ }
+ return false;
+ }
+
+ private boolean advanceToNextSpliterator() {
+ while (next == null) {
+ if (!spliteratorOfStreams.tryAdvance(n -> {
+ if (n != null) {
+ nextStream = n;
+ next = n.spliterator();
+ }
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ );
+ }
+
+ @Override
+ public DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper) {
+ throwIfTerminated();
+ final Spliterator<? extends DoubleStream> spliteratorOfStreams =
+ new MapToObjSpliterator<>(mapper, spliterator);
+ return new DoubleStream.DoubleStreamSource(
+ this,
+ new Spliterators.AbstractDoubleSpliterator(Long.MAX_VALUE, 0) {
+ DoubleStream nextStream;
+ Spliterator.OfDouble next;
+
+ @Override
+ public boolean tryAdvance(DoubleConsumer action) {
+ // look for a new spliterator
+ while (advanceToNextSpliterator()) {
+ // if we have one, try to read and use it
+ if (next.tryAdvance(action)) {
+ return true;
+ } else {
+ nextStream.close();
+ nextStream = null;
+ // failed, null it out so we can find another
+ next = null;
+ }
+ }
+ return false;
+ }
+
+ private boolean advanceToNextSpliterator() {
+ while (next == null) {
+ if (!spliteratorOfStreams.tryAdvance(n -> {
+ if (n != null) {
+ nextStream = n;
+ next = n.spliterator();
+ }
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ );
+ }
+
+ @Override
+ public Stream<T> distinct() {
+ throwIfTerminated();
+ HashSet<T> seen = new HashSet<>();
+ return filter(seen::add);
+ }
+
+ @Override
+ public Stream<T> sorted() {
+ throwIfTerminated();
+ Comparator<T> c = (Comparator) Comparator.naturalOrder();
+ return sorted(c);
+ }
+
+ @Override
+ public Stream<T> sorted(final Comparator<? super T> comparator) {
+ throwIfTerminated();
+ return new StreamSource<>(
+ this,
+ new Spliterators.AbstractSpliterator<T>(
+ spliterator.estimateSize(),
+ spliterator.characteristics() | Spliterator.SORTED
+ ) {
+ Spliterator<T> ordered = null;
+
+ @Override
+ public Comparator<? super T> getComparator() {
+ return comparator == Comparator.naturalOrder() ? null : comparator;
+ }
+
+ @Override
+ public boolean tryAdvance(Consumer<? super T> action) {
+ if (ordered == null) {
+ List<T> list = new ArrayList<>();
+ spliterator.forEachRemaining(list::add);
+ Collections.sort(list, comparator);
+ ordered = list.spliterator();
+ }
+ return ordered.tryAdvance(action);
+ }
+ }
+ );
+ }
+
+ @Override
+ public Stream<T> peek(final Consumer<? super T> action) {
+ checkNotNull(action);
+ throwIfTerminated();
+ return new StreamSource<>(
+ this,
+ new Spliterators.AbstractSpliterator<T>(
+ spliterator.estimateSize(),
+ spliterator.characteristics()
+ ) {
+ @Override
+ public boolean tryAdvance(final Consumer<? super T> innerAction) {
+ return spliterator.tryAdvance(item -> {
+ action.accept(item);
+ innerAction.accept(item);
+ });
+ }
+ }
+ );
+ }
+
+ @Override
+ public Stream<T> limit(long maxSize) {
+ throwIfTerminated();
+ checkState(maxSize >= 0, "maxSize may not be negative");
+ return new StreamSource<>(this, new LimitSpliterator<>(maxSize, spliterator));
+ }
+
+ @Override
+ public Stream<T> skip(long n) {
+ throwIfTerminated();
+ checkState(n >= 0, "n may not be negative");
+ if (n == 0) {
+ return this;
+ }
+ return new StreamSource<>(this, new SkipSpliterator<>(n, spliterator));
+ }
+
+ @Override
+ public boolean isParallel() {
+ throwIfTerminated();
+ return false;
+ }
+
+ @Override
+ public Stream<T> sequential() {
+ throwIfTerminated();
+ return this;
+ }
+
+ @Override
+ public Stream<T> parallel() {
+ throwIfTerminated();
+ // do nothing, no such thing as gwt+parallel
+ return this;
+ }
+
+ @Override
+ public Stream<T> unordered() {
+ throwIfTerminated();
+ return this;
+ }
+ }
+}
diff --git a/user/super/com/google/gwt/emul/java/util/stream/StreamSupport.java b/user/super/com/google/gwt/emul/java/util/stream/StreamSupport.java
new file mode 100644
index 0000000..12b34e3
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/stream/StreamSupport.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.function.Supplier;
+
+/**
+ * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/StreamSupport.html">
+ * the official Java API doc</a> for details.
+ */
+public final class StreamSupport {
+
+ public static DoubleStream doubleStream(Spliterator.OfDouble spliterator, boolean parallel) {
+ return new DoubleStream.DoubleStreamSource(null, spliterator);
+ }
+
+ public static DoubleStream doubleStream(Supplier<? extends Spliterator.OfDouble> supplier,
+ int characteristics,
+ boolean parallel) {
+ // TODO this is somewhat convoluted, and would be better served by a lazy singleton spliterator
+ return Stream.of(supplier).map(Supplier::get).flatMapToDouble(doubleSpliterator -> {
+ return doubleStream(doubleSpliterator, parallel);
+ });
+ }
+
+ public static IntStream intStream(Spliterator.OfInt spliterator, boolean parallel) {
+ return new IntStream.IntStreamSource(null, spliterator);
+ }
+
+ public static IntStream intStream(Supplier<? extends Spliterator.OfInt> supplier,
+ int characteristics,
+ boolean parallel) {
+ // TODO this is somewhat convoluted, and would be better served by a lazy singleton spliterator
+ return Stream.of(supplier).map(Supplier::get).flatMapToInt(intSpliterator -> {
+ return intStream(intSpliterator, parallel);
+ });
+ }
+
+ public static LongStream longStream(Spliterator.OfLong spliterator, boolean parallel) {
+ return new LongStream.LongStreamSource(null, spliterator);
+ }
+
+ public static LongStream longStream(Supplier<? extends Spliterator.OfLong> supplier,
+ int characteristics,
+ final boolean parallel) {
+ // TODO this is somewhat convoluted, and would be better served by a lazy singleton spliterator
+ return Stream.of(supplier).map(Supplier::get).flatMapToLong(longSpliterator -> {
+ return longStream(longSpliterator, parallel);
+ });
+ }
+
+ public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
+ return new Stream.StreamSource<T>(null, spliterator);
+ }
+
+ public static <T> Stream<T> stream(Supplier<? extends Spliterator<T>> supplier,
+ int characteristics,
+ final boolean parallel) {
+ // TODO this is somewhat convoluted, and would be better served by a lazy singleton spliterator
+ return Stream.of(supplier).map(Supplier::get).flatMap(spliterator -> {
+ return stream(spliterator, parallel);
+ });
+ }
+
+ private StreamSupport() {
+ // prevent instantiation
+ }
+
+}
diff --git a/user/super/com/google/gwt/emul/java/util/stream/TerminatableStream.java b/user/super/com/google/gwt/emul/java/util/stream/TerminatableStream.java
new file mode 100644
index 0000000..018331f
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/stream/TerminatableStream.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+// package protected, as not part of jre
+class TerminatableStream<T extends TerminatableStream<T>> {
+ // root-only fields, ignored for non-root instances
+ private boolean terminated = false;
+ private final List<Runnable> onClose;
+
+ private final TerminatableStream<?> root;
+
+ public TerminatableStream(TerminatableStream<?> previous) {
+ if (previous == null) {
+ root = null;
+ onClose = new ArrayList<>();
+ } else {
+ root = previous;
+ onClose = null;
+ }
+ }
+
+ void throwIfTerminated() {
+ if (root != null) {
+ root.throwIfTerminated();
+ } else if (terminated) {
+ throw new IllegalStateException("Stream already terminated, can't be modified or used");
+ }
+ }
+
+ // note that not all terminals directly call this, but they must use it indirectly
+ void terminate() {
+ if (root == null) {
+ throwIfTerminated();
+ terminated = true;
+ } else {
+ root.terminate();
+ }
+ }
+
+ public T onClose(Runnable closeHandler) {
+ if (root == null) {
+ onClose.add(closeHandler);
+ } else {
+ root.onClose(closeHandler);
+ }
+
+ return (T) this;
+ }
+
+ public void close() {
+ if (root == null) {
+ terminated = true;
+
+ // TODO this might not be quite right, make sure that it behaves the same way when throwing
+ // the same exception multiple times as JDK does.
+ LinkedHashSet<Throwable> throwables = new LinkedHashSet<>();
+ onClose.forEach((runnable) -> {
+ try {
+ runnable.run();
+ } catch (Throwable e) {
+ throwables.add(e);
+ }
+ });
+ onClose.clear();
+ if (!throwables.isEmpty()) {
+ Iterator<Throwable> iterator = throwables.iterator();
+ Throwable outer = iterator.next();
+ iterator.forEachRemaining(outer::addSuppressed);
+
+ if (outer instanceof RuntimeException) {
+ throw (RuntimeException) outer;
+ }
+ if (outer instanceof Error) {
+ throw (Error) outer;
+ }
+ assert false : "Couldn't have caught this exception from a Runnable! " + outer;
+ }
+ } else {
+ root.close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/user/test/com/google/gwt/emultest/EmulJava8Suite.java b/user/test/com/google/gwt/emultest/EmulJava8Suite.java
index e898b30..572eb86 100644
--- a/user/test/com/google/gwt/emultest/EmulJava8Suite.java
+++ b/user/test/com/google/gwt/emultest/EmulJava8Suite.java
@@ -43,6 +43,11 @@
import com.google.gwt.emultest.java8.util.TreeMapTest;
import com.google.gwt.emultest.java8.util.VectorTest;
import com.google.gwt.emultest.java8.util.stream.CollectorsTest;
+import com.google.gwt.emultest.java8.util.stream.DoubleStreamTest;
+import com.google.gwt.emultest.java8.util.stream.IntStreamTest;
+import com.google.gwt.emultest.java8.util.stream.LongStreamTest;
+import com.google.gwt.emultest.java8.util.stream.StreamSupportTest;
+import com.google.gwt.emultest.java8.util.stream.StreamTest;
import com.google.gwt.junit.tools.GWTTestSuite;
import junit.framework.Test;
@@ -90,6 +95,11 @@
//-- java.util.stream
suite.addTestSuite(CollectorsTest.class);
+ suite.addTestSuite(DoubleStreamTest.class);
+ suite.addTestSuite(IntStreamTest.class);
+ suite.addTestSuite(LongStreamTest.class);
+ suite.addTestSuite(StreamTest.class);
+ suite.addTestSuite(StreamSupportTest.class);
return suite;
}
diff --git a/user/test/com/google/gwt/emultest/java/util/EmulTestBase.java b/user/test/com/google/gwt/emultest/java/util/EmulTestBase.java
index a3babcc..c1fc5de 100644
--- a/user/test/com/google/gwt/emultest/java/util/EmulTestBase.java
+++ b/user/test/com/google/gwt/emultest/java/util/EmulTestBase.java
@@ -17,6 +17,7 @@
import com.google.gwt.junit.client.GWTTestCase;
+import java.util.Arrays;
import java.util.List;
/**
@@ -41,6 +42,21 @@
}
}
+ public static void assertEquals(int[] expected, int[] actual) {
+ assertTrue("expected: " + Arrays.toString(expected) + ", actual: " + Arrays.toString(actual),
+ Arrays.equals(expected, actual));
+ }
+
+ public static void assertEquals(long[] expected, long[] actual) {
+ assertTrue("expected: " + Arrays.toString(expected) + ", actual: " + Arrays.toString(actual),
+ Arrays.equals(expected, actual));
+ }
+
+ public static void assertEquals(double[] expected, double[] actual) {
+ assertTrue("expected: " + Arrays.toString(expected) + ", actual: " + Arrays.toString(actual),
+ Arrays.equals(expected, actual));
+ }
+
@Override
public String getModuleName() {
return "com.google.gwt.emultest.EmulSuite";
diff --git a/user/test/com/google/gwt/emultest/java8/util/ArraysTest.java b/user/test/com/google/gwt/emultest/java8/util/ArraysTest.java
index 3a4d42b..ffb42dd 100644
--- a/user/test/com/google/gwt/emultest/java8/util/ArraysTest.java
+++ b/user/test/com/google/gwt/emultest/java8/util/ArraysTest.java
@@ -135,4 +135,156 @@
Arrays.setAll(array, i -> "" + (i + 1));
assertEquals(new String[]{"1", "2", "3"}, array);
}
+
+ public void testArrayStreamInt() {
+ int[] six = {1, 2, 3, 4, 5, 6};
+
+ // zero entries
+ assertEquals(new int[]{}, Arrays.stream(six, 0, 0).toArray());
+ assertEquals(new int[]{}, Arrays.stream(six, 1, 1).toArray());
+
+ // single entry
+ assertEquals(new int[]{1}, Arrays.stream(six, 0, 1).toArray());
+ assertEquals(new int[]{2}, Arrays.stream(six, 1, 2).toArray());
+
+ // multiple entries
+ assertEquals(new int[]{1, 2, 3}, Arrays.stream(six, 0, 3).toArray());
+ assertEquals(new int[]{4, 5, 6}, Arrays.stream(six, 3, 6).toArray());
+
+ try {
+ // start < 0
+ Arrays.stream(six, -1, 1);
+ fail("expected aioobe");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ try {
+ // end < start
+ Arrays.stream(six, 2, 1);
+ fail("expected aioobe");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ try {
+ // end > size
+ Arrays.stream(six, 0, 7);
+ fail("expected aioobe");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ }
+
+ public void testArrayStreamLong() {
+ long[] six = {1, 2, 3, 4, 5, 6};
+
+ // zero entries
+ assertEquals(new long[]{}, Arrays.stream(six, 0, 0).toArray());
+ assertEquals(new long[]{}, Arrays.stream(six, 1, 1).toArray());
+
+ // single entry
+ assertEquals(new long[]{1}, Arrays.stream(six, 0, 1).toArray());
+ assertEquals(new long[]{2}, Arrays.stream(six, 1, 2).toArray());
+
+ // multiple entries
+ assertEquals(new long[]{1, 2, 3}, Arrays.stream(six, 0, 3).toArray());
+ assertEquals(new long[]{4, 5, 6}, Arrays.stream(six, 3, 6).toArray());
+
+ try {
+ // start < 0
+ Arrays.stream(six, -1, 1);
+ fail("expected aioobe");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ try {
+ // end < start
+ Arrays.stream(six, 2, 1);
+ fail("expected aioobe");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ try {
+ // end > size
+ Arrays.stream(six, 0, 7);
+ fail("expected aioobe");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ }
+
+ public void testArrayStreamDouble() {
+ double[] six = {1, 2, 3, 4, 5, 6};
+
+ // zero entries
+ assertEquals(new double[]{}, Arrays.stream(six, 0, 0).toArray());
+ assertEquals(new double[]{}, Arrays.stream(six, 1, 1).toArray());
+
+ // single entry
+ assertEquals(new double[]{1}, Arrays.stream(six, 0, 1).toArray());
+ assertEquals(new double[]{2}, Arrays.stream(six, 1, 2).toArray());
+
+ // multiple entries
+ assertEquals(new double[]{1, 2, 3}, Arrays.stream(six, 0, 3).toArray());
+ assertEquals(new double[]{4, 5, 6}, Arrays.stream(six, 3, 6).toArray());
+
+ try {
+ // start < 0
+ Arrays.stream(six, -1, 1);
+ fail("expected aioobe");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ try {
+ // end < start
+ Arrays.stream(six, 2, 1);
+ fail("expected aioobe");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ try {
+ // end > size
+ Arrays.stream(six, 0, 7);
+ fail("expected aioobe");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ }
+
+ public void testArrayStreamObject() {
+ String[] six = {"1", "2", "3", "4", "5", "6"};
+
+ // zero entries
+ assertEquals(new String[]{}, Arrays.stream(six, 0, 0).toArray());
+ assertEquals(new String[]{}, Arrays.stream(six, 1, 1).toArray());
+
+ // single entry
+ assertEquals(new String[]{"1"}, Arrays.stream(six, 0, 1).toArray());
+ assertEquals(new String[]{"2"}, Arrays.stream(six, 1, 2).toArray());
+
+ // multiple entries
+ assertEquals(new String[]{"1", "2", "3"}, Arrays.stream(six, 0, 3).toArray());
+ assertEquals(new String[]{"4", "5", "6"}, Arrays.stream(six, 3, 6).toArray());
+
+ try {
+ // start < 0
+ Arrays.stream(six, -1, 1);
+ fail("expected aioobe");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ try {
+ // end < start
+ Arrays.stream(six, 2, 1);
+ fail("expected aioobe");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ try {
+ // end > size
+ Arrays.stream(six, 0, 7);
+ fail("expected aioobe");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ }
}
diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/DoubleStreamTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/DoubleStreamTest.java
new file mode 100644
index 0000000..fb0cc17
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java8/util/stream/DoubleStreamTest.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.emultest.java8.util.stream;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.DoubleSummaryStatistics;
+import java.util.Iterator;
+import java.util.List;
+import java.util.OptionalDouble;
+import java.util.Spliterator;
+import java.util.function.DoubleSupplier;
+import java.util.function.Supplier;
+import java.util.stream.DoubleStream;
+import java.util.stream.Stream;
+
+/**
+ * Tests {@link DoubleStream}.
+ */
+public class DoubleStreamTest extends EmulTestBase {
+
+ public void testEmptyStream() {
+ DoubleStream empty = DoubleStream.empty();
+ assertEquals(0, empty.count());
+ try {
+ empty.count();
+ fail("second terminal operation should have thrown IllegalStateEx");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+
+ assertEquals(0, DoubleStream.empty().limit(2).toArray().length);
+ assertEquals(0L, DoubleStream.empty().count());
+ assertEquals(0L, DoubleStream.empty().limit(2).count());
+
+ assertFalse(DoubleStream.empty().findFirst().isPresent());
+ assertFalse(DoubleStream.empty().findAny().isPresent());
+ assertFalse(DoubleStream.empty().max().isPresent());
+ assertFalse(DoubleStream.empty().min().isPresent());
+ assertTrue(DoubleStream.empty().noneMatch(item -> true));
+ assertTrue(DoubleStream.empty().allMatch(item -> true));
+ assertFalse(DoubleStream.empty().anyMatch(item -> true));
+ assertEquals(new double[0], DoubleStream.empty().toArray());
+ }
+
+ public void testStreamOfOne() {
+ Supplier<DoubleStream> one = () -> DoubleStream.of(1);
+ assertEquals(new double[]{1d}, one.get().toArray());
+ assertEquals(1L, one.get().count());
+ assertEquals(1d, one.get().findFirst().getAsDouble(), 0d);
+ assertEquals(1d, one.get().findAny().getAsDouble(), 0d);
+ }
+
+ public void testBuilder() {
+ DoubleStream s = DoubleStream.builder()
+ .add(1d)
+ .add(3d)
+ .add(2d)
+ .build();
+
+ assertEquals(
+ new double[] {1d, 3d, 2d},
+ s.toArray()
+ );
+
+ DoubleStream.Builder builder = DoubleStream.builder();
+ DoubleStream built = builder.build();
+ assertEquals(0, built.count());
+ try {
+ builder.build();
+ fail("build() after build() should fail");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+ try {
+ builder.add(10d);
+ fail("add() after build() should fail");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+ }
+
+ public void testConcat() {
+ Supplier<DoubleStream> adbc = () -> {
+ return DoubleStream.concat(DoubleStream.of(1, 4), DoubleStream.of(2, 3));
+ };
+
+ assertEquals(new double[]{1d, 4d, 2d, 3d}, adbc.get().toArray());
+ assertEquals(new double[]{1d, 2d, 3d, 4d}, adbc.get().sorted().toArray());
+
+ List<String> closed = new ArrayList<>();
+ DoubleStream first = DoubleStream.of(1d).onClose(() -> closed.add("first"));
+ DoubleStream second = DoubleStream.of(2d).onClose(() -> closed.add("second"));
+
+ DoubleStream concat = DoubleStream.concat(first, second);
+
+ // read everything, make sure we saw it all and didn't close automatically
+ double collectedAll = concat.sum();
+ assertEquals(3d, collectedAll);
+ assertEquals(0, closed.size());
+
+ concat.close();
+ assertEquals(Arrays.asList("first", "second"), closed);
+ }
+
+ public void testIterate() {
+ assertEquals(
+ new double[]{10d, 11d, 12d, 13d, 14d},
+ DoubleStream.iterate(0d, l -> l + 1d)
+ .skip(10)
+ .limit(5)
+ .toArray()
+ );
+ }
+
+ public void testGenerate() {
+ // infinite, but if you limit it is already too short to skip much
+ assertEquals(new double[0], DoubleStream.generate(makeGenerator()).limit(4).skip(5).toArray());
+
+ assertEquals(
+ new double[]{10d, 11d, 12d, 13d, 14d},
+ DoubleStream.generate(makeGenerator())
+ .skip(10)
+ .limit(5)
+ .toArray()
+ );
+ }
+
+ private DoubleSupplier makeGenerator() {
+ return new DoubleSupplier() {
+ double next = 0d;
+
+ @Override
+ public double getAsDouble() {
+ return next++;
+ }
+ };
+ }
+
+ public void testToArray() {
+ assertEquals(new double[0], DoubleStream.of().toArray());
+ assertEquals(new double[] {1d}, DoubleStream.of(1d).toArray());
+ assertEquals(new double[] {3d, 2d, 0d}, DoubleStream.of(3d, 2d, 0d).toArray());
+ }
+
+ public void testReduce() {
+ double reduced = DoubleStream.of(1d, 2d, 4d).reduce(0, Double::sum);
+ assertEquals(7d, reduced, 0d);
+
+ reduced = DoubleStream.of().reduce(0, Double::sum);
+ assertEquals(0d, reduced, 0d);
+
+ OptionalDouble maybe = DoubleStream.of(1d, 4d, 8d).reduce(Double::sum);
+ assertTrue(maybe.isPresent());
+ assertEquals(13, maybe.getAsDouble(), 0d);
+ maybe = DoubleStream.of().reduce(Double::sum);
+ assertFalse(maybe.isPresent());
+ }
+
+ public void testFilter() {
+ // unconsumed stream never runs filter
+ boolean[] data = {false};
+ DoubleStream.of(1d, 2d, 3d).filter(i -> data[0] |= true);
+ assertFalse(data[0]);
+
+ // one result
+ assertEquals(
+ new double[]{1d},
+ DoubleStream.of(1d, 2d, 3d, 4d, 3d).filter(a -> a == 1).toArray()
+ );
+ // zero results
+ assertEquals(
+ new double[0],
+ DoubleStream.of(1d, 2d, 3d, 4d, 3d).filter(a -> false).toArray()
+ );
+ // two results
+ assertEquals(
+ new double[] {2d, 4d},
+ DoubleStream.of(1d, 2d, 3d, 4d, 3d).filter(a -> a % 2 == 0).toArray()
+ );
+ // all
+ assertEquals(
+ new double[] {1d, 2d, 3d, 4d, 3d},
+ DoubleStream.of(1d, 2d, 3d, 4d, 3d).filter(a -> true).toArray()
+ );
+ }
+
+ public void testMap() {
+ // unconsumed stream never runs map
+ int[] data = {0};
+ DoubleStream.of(1d, 2d, 3d).map(i -> data[0]++);
+ assertEquals(0, data[0]);
+
+ assertEquals(
+ new double[] {2d, 4d, 6d},
+ DoubleStream.of(1d, 2d, 3d).map(i -> i * 2).toArray()
+ );
+ }
+
+ public void testPeek() {
+ // unconsumed stream never peeks
+ boolean[] data = {false};
+ DoubleStream.of(1d, 2d, 3d).peek(i -> data[0] |= true);
+ assertFalse(data[0]);
+
+ // make sure we saw it all in order
+ double[] items = new double[] {1d, 2d, 3d};
+ List<Double> peeked = new ArrayList<>();
+ DoubleStream.of(items).peek(peeked::add).forEach(item -> {
+ // do nothing, just run
+ });
+ assertEquals(items.length, peeked.size());
+ for (int i = 0; i < items.length; i++) {
+ assertEquals(items[i], peeked.get(i), 0d);
+ }
+ }
+
+ // same impl, no parallel in browser
+ public void testFindFirstOrAny() {
+ OptionalDouble any = DoubleStream.of(1d, 2d).findAny();
+ assertTrue(any.isPresent());
+ assertEquals(1d, any.getAsDouble(), 0d);
+ }
+
+ public void testAnyMatch() {
+ // all
+ assertTrue(DoubleStream.of(1d, 2d).anyMatch(s -> true));
+
+ // some
+ assertTrue(DoubleStream.of(1d, 2d).anyMatch(s -> s == 1d));
+
+ // none
+ assertFalse(DoubleStream.of(1d, 2d).anyMatch(s -> false));
+ }
+
+ public void testAllMatch() {
+ // all
+ assertTrue(DoubleStream.of(1d, 2d).allMatch(s -> true));
+
+ // some
+ assertFalse(DoubleStream.of(1d, 2d).allMatch(s -> s == 1d));
+
+ // none
+ assertFalse(DoubleStream.of(1d, 2d).allMatch(s -> false));
+ }
+
+ public void testNoneMatch() {
+ // all
+ assertFalse(DoubleStream.of(1d, 2d).noneMatch(s -> true));
+
+ // some
+ assertFalse(DoubleStream.of(1d, 2d).noneMatch(s -> s == 1d));
+
+ // none
+ assertTrue(DoubleStream.of(1d, 2d).noneMatch(s -> false));
+ }
+
+ public void testFlatMap() {
+ assertEquals(0L, DoubleStream.empty().flatMap(value -> DoubleStream.of(1d)).count());
+ assertEquals(0L, DoubleStream.of(1d).flatMap(value -> DoubleStream.empty()).count());
+ assertEquals(0L, DoubleStream.of(1d).flatMap(value -> DoubleStream.of()).count());
+ assertEquals(0L, DoubleStream.of().flatMap(value -> DoubleStream.of(1d)).count());
+ assertEquals(1L, DoubleStream.of(1d).flatMap(value -> DoubleStream.of(1d)).count());
+
+ DoubleStream values = DoubleStream.of(1d, 2d, 3d);
+
+ assertEquals(
+ new double[] {1d, 2d, 2d, 4d, 3d, 6d},
+ values.flatMap(i -> DoubleStream.of(i, i * 2d)).toArray()
+ );
+ }
+
+ public void testMapToOthers() {
+ Supplier<DoubleStream> s = () -> DoubleStream.of(1d, 2d, 10d);
+
+ assertEquals(
+ new String[]{"1", "2", "10"},
+ s.get().mapToObj(DoubleStreamTest::toIntegralString).toArray(String[]::new)
+ );
+
+ assertEquals(
+ new long[]{1L, 2L, 10L},
+ s.get().mapToLong(i -> (long) i).toArray()
+ );
+
+ assertEquals(
+ new int[] {1, 2, 10},
+ s.get().mapToInt(i -> (int) i).toArray()
+ );
+ }
+
+ public void testDistinct() {
+ double[] distinct = DoubleStream.of(1d, 2d, 3d, 2d).distinct().toArray();
+ assertEquals(3, distinct.length);
+ assertEquals(1d + 2d + 3d, distinct[0] + distinct[1] + distinct[2], 0d);
+ }
+
+ public void testSorted() {
+ double[] sorted = DoubleStream.of(3d, 1d, 2d).sorted().toArray();
+ assertEquals(new double[] {1d, 2d, 3d}, sorted);
+ }
+
+ public void testMinMax() {
+ Supplier<DoubleStream> stream = () -> DoubleStream.of(2d, 3d, 4d, 1d);
+
+ assertEquals(1d, stream.get().min().orElse(0), 0d);
+ assertEquals(4d, stream.get().max().orElse(0), 0d);
+
+ assertFalse(stream.get().filter(a -> false).max().isPresent());
+ assertFalse(stream.get().filter(a -> false).min().isPresent());
+ }
+
+ public void testCountLimitSkip() {
+ Supplier<DoubleStream> stream = () -> DoubleStream.of(1d, 2d, 3d, 4d);
+
+ assertEquals(4L, stream.get().count());
+
+ assertEquals(4L, stream.get().limit(4).count());
+ assertEquals(4L, stream.get().limit(5).count());
+ assertEquals(3L, stream.get().limit(3).count());
+
+ assertEquals(3L, stream.get().skip(1).limit(3).count());
+
+ assertEquals(2L, stream.get().limit(3).skip(1).count());
+
+ assertEquals(1L, stream.get().skip(3).count());
+
+ assertEquals(new double[] {3d, 4d}, stream.get().skip(2).limit(3).toArray());
+ assertEquals(new double[] {3d}, stream.get().skip(2).limit(1).toArray());
+
+ assertEquals(new double[] {4d}, stream.get().skip(3).toArray());
+ assertEquals(new double[] {}, stream.get().skip(5).toArray());
+
+ assertEquals(new double[] {1d, 2d}, stream.get().limit(2).toArray());
+
+ assertEquals(new double[] {2d}, stream.get().limit(2).skip(1).toArray());
+ }
+
+ public void testBoxed() {
+ Supplier<DoubleStream> stream = () -> DoubleStream.of(1d, 2d);
+ Stream<Double> expected = stream.get().mapToObj(Double::valueOf);
+ assertEquals(expected.toArray(), stream.get().boxed().toArray());
+ }
+
+ public void testSummaryStats() {
+ Supplier<DoubleStream> stream = () -> DoubleStream.of(1d, 2d, 3d);
+ DoubleSummaryStatistics summaryStats = stream.get().summaryStatistics();
+ assertEquals(3L, summaryStats.getCount());
+ assertEquals(1d, summaryStats.getMin(), 0d);
+ assertEquals(2d, summaryStats.getAverage(), 0d);
+ assertEquals(3d, summaryStats.getMax(), 0d);
+ assertEquals(6d, summaryStats.getSum(), 0d);
+
+ summaryStats.accept(6L);
+ assertEquals(4L, summaryStats.getCount());
+ assertEquals(1d, summaryStats.getMin(), 0d);
+ assertEquals(3d, summaryStats.getAverage(), 0d);
+ assertEquals(6d, summaryStats.getMax(), 0d);
+ assertEquals(12d, summaryStats.getSum(), 0d);
+
+ DoubleSummaryStatistics combinedSumStats = stream.get().summaryStatistics();
+ combinedSumStats.combine(DoubleStream.of(4d, 5d, 6d, 0d).summaryStatistics());
+ assertEquals(7L, combinedSumStats.getCount());
+ assertEquals(0d, combinedSumStats.getMin(), 0d);
+ assertEquals(3d, combinedSumStats.getAverage(), 0d);
+ assertEquals(6d, combinedSumStats.getMax(), 0d);
+ assertEquals(21d, combinedSumStats.getSum(), 0d);
+ }
+
+ public void testAverage() {
+ assertFalse(DoubleStream.empty().average().isPresent());
+ assertEquals(2.0d, DoubleStream.of(1d, 2d, 3d).average().getAsDouble(), 0d);
+ assertEquals(0d, DoubleStream.of(1d, 2d, -3d).average().getAsDouble(), 0d);
+ assertEquals(-2.0d, DoubleStream.of(-1d, -2d, -3d).average().getAsDouble(), 0d);
+ }
+
+ public void testSum() {
+ assertEquals(6d, DoubleStream.of(1d, 2d, 3d).sum(), 0d);
+ assertEquals(0d, DoubleStream.of(1d, 2d, -3d).sum(), 0d);
+ assertEquals(-6d, DoubleStream.of(-1d, -2d, -3d).sum(), 0d);
+ }
+
+ public void testCollect() {
+ // noinspection StringConcatenationInsideStringBufferAppend
+ String val = DoubleStream.of(1d, 2d, 3d, 4d, 5d).collect(StringBuilder::new,
+ (stringBuilder, d) -> stringBuilder.append(toIntegralString(d)),
+ StringBuilder::append).toString();
+
+ assertEquals("12345", val);
+ }
+
+ public void testForEach() {
+ List<Double> vals = new ArrayList<>();
+ DoubleStream.of(1d, 2d, 3d, 4d, 5d).forEach(vals::add);
+ assertEquals(5, vals.size());
+ assertEquals(new Double[] {1d, 2d, 3d, 4d, 5d}, vals.toArray(new Double[vals.size()]));
+ }
+
+ public void testIterator() {
+ List<Double> vals = new ArrayList<>();
+ Iterator<Double> iterator = DoubleStream.of(1d, 2d, 3d, 4d, 5d).iterator();
+ while (iterator.hasNext()) {
+ vals.add(iterator.next());
+ }
+ assertEquals(5, vals.size());
+ assertEquals(new Double[] {1d, 2d, 3d, 4d, 5d}, vals.toArray(new Double[vals.size()]));
+ }
+
+ public void testSpliterator() {
+ Spliterator<Double> spliterator = DoubleStream.of(1d, 2d, 3d, 4d, 5d).spliterator();
+ assertEquals(5, spliterator.estimateSize());
+ assertEquals(5, spliterator.getExactSizeIfKnown());
+
+ List<Double> vals = new ArrayList<>();
+ while (spliterator.tryAdvance(vals::add)) {
+ // work is all done in the condition
+ }
+
+ assertEquals(5, vals.size());
+ assertEquals(new Double[] {1d, 2d, 3d, 4d, 5d}, vals.toArray(new Double[vals.size()]));
+ }
+
+ // See https://github.com/gwtproject/gwt/issues/8615
+ private static String toIntegralString(double value) {
+ return "" + (int) value;
+ }
+}
diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/IntStreamTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/IntStreamTest.java
new file mode 100644
index 0000000..232aebe
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java8/util/stream/IntStreamTest.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.emultest.java8.util.stream;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.IntSummaryStatistics;
+import java.util.Iterator;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.Spliterator;
+import java.util.function.IntSupplier;
+import java.util.function.Supplier;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+
+/**
+ * Tests {@link IntStream}.
+ */
+public class IntStreamTest extends EmulTestBase {
+
+ public void testEmptyStream() {
+ IntStream empty = IntStream.empty();
+ assertEquals(0, empty.count());
+ try {
+ empty.count();
+ fail("second terminal operation should have thrown IllegalStateEx");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+
+ assertEquals(0, IntStream.empty().limit(2).toArray().length);
+ assertEquals(0L, IntStream.empty().count());
+ assertEquals(0L, IntStream.empty().limit(2).count());
+
+ assertFalse(IntStream.empty().findFirst().isPresent());
+ assertFalse(IntStream.empty().findAny().isPresent());
+ assertFalse(IntStream.empty().max().isPresent());
+ assertFalse(IntStream.empty().min().isPresent());
+ assertTrue(IntStream.empty().noneMatch(item -> true));
+ assertTrue(IntStream.empty().allMatch(item -> true));
+ assertFalse(IntStream.empty().anyMatch(item -> true));
+ assertEquals(new int[0], IntStream.empty().toArray());
+ }
+
+ public void testStreamOfOne() {
+ Supplier<IntStream> one = () -> IntStream.of(1);
+ assertEquals(new int[]{1}, one.get().toArray());
+ assertEquals(1L, one.get().count());
+ assertEquals(1, one.get().findFirst().getAsInt());
+ assertEquals(1, one.get().findAny().getAsInt());
+ }
+
+ public void testBuilder() {
+ IntStream s = IntStream.builder()
+ .add(1)
+ .add(3)
+ .add(2)
+ .build();
+
+ assertEquals(
+ new int[] {1, 3, 2},
+ s.toArray()
+ );
+
+ IntStream.Builder builder = IntStream.builder();
+ IntStream built = builder.build();
+ assertEquals(0, built.count());
+ try {
+ builder.build();
+ fail("build() after build() should fail");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+ try {
+ builder.add(10);
+ fail("add() after build() should fail");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+ }
+
+ public void testConcat() {
+ Supplier<IntStream> adbc = () -> IntStream.concat(IntStream.of(1, 4), IntStream.of(2, 3));
+
+ assertEquals(new int[]{1, 4, 2, 3}, adbc.get().toArray());
+ assertEquals(new int[]{1, 2, 3, 4}, adbc.get().sorted().toArray());
+
+ List<String> closed = new ArrayList<>();
+ IntStream first = IntStream.of(1).onClose(() -> closed.add("first"));
+ IntStream second = IntStream.of(2).onClose(() -> closed.add("second"));
+
+ IntStream concat = IntStream.concat(first, second);
+
+ // read everything, make sure we saw it all and didn't close automatically
+ int collectedAll = concat.sum();
+ assertEquals(3, collectedAll);
+ assertEquals(0, closed.size());
+
+ concat.close();
+ assertEquals(Arrays.asList("first", "second"), closed);
+ }
+
+ public void testIterate() {
+ assertEquals(
+ new int[]{10, 11, 12, 13, 14},
+ IntStream.iterate(0, i -> i + 1)
+ .skip(10)
+ .limit(5)
+ .toArray()
+ );
+ }
+
+ public void testGenerate() {
+ // infinite, but if you limit it is already too short to skip much
+ assertEquals(new int[0], IntStream.generate(makeGenerator()).limit(4).skip(5).toArray());
+
+ assertEquals(
+ new int[] {10, 11, 12, 13, 14},
+ IntStream.generate(makeGenerator())
+ .skip(10)
+ .limit(5)
+ .toArray()
+ );
+ }
+
+ private IntSupplier makeGenerator() {
+ return new IntSupplier() {
+ int next = 0;
+
+ @Override
+ public int getAsInt() {
+ return next++;
+ }
+ };
+ }
+
+ public void testRange() {
+ assertEquals(new int[] {1, 2, 3, 4}, IntStream.range(1, 5).toArray());
+ assertEquals(new int[] {-1, 0, 1, 2, 3, 4}, IntStream.range(-1, 5).toArray());
+ assertEquals(new int[] {}, IntStream.range(1, -5).toArray());
+ assertEquals(new int[] {}, IntStream.range(-1, -5).toArray());
+ }
+
+ public void testRangeClosed() {
+ assertEquals(new int[] {1, 2, 3, 4, 5}, IntStream.rangeClosed(1, 5).toArray());
+ assertEquals(new int[] {-1, 0, 1, 2, 3, 4, 5}, IntStream.rangeClosed(-1, 5).toArray());
+ assertEquals(new int[] {}, IntStream.rangeClosed(1, -5).toArray());
+ assertEquals(new int[] {}, IntStream.rangeClosed(-1, -5).toArray());
+ }
+
+ public void testToArray() {
+ assertEquals(new int[0], IntStream.of().toArray());
+ assertEquals(new int[] {1}, IntStream.of(1).toArray());
+ assertEquals(new int[] {3,2,0}, IntStream.of(3,2,0).toArray());
+ }
+
+ public void testReduce() {
+ int reduced = IntStream.of(1, 2, 4).reduce(0, Integer::sum);
+ assertEquals(7, reduced);
+
+ reduced = IntStream.of().reduce(0, Integer::sum);
+ assertEquals(0, reduced);
+
+ OptionalInt maybe = IntStream.of(1, 4, 8).reduce(Integer::sum);
+ assertTrue(maybe.isPresent());
+ assertEquals(13, maybe.getAsInt());
+ maybe = IntStream.of().reduce(Integer::sum);
+ assertFalse(maybe.isPresent());
+ }
+
+ public void testFilter() {
+ // unconsumed stream never runs filter
+ boolean[] data = {false};
+ IntStream.of(1, 2, 3).filter(i -> data[0] |= true);
+ assertFalse(data[0]);
+
+ // one result
+ assertEquals(
+ new int[] {1},
+ IntStream.of(1, 2, 3, 4, 3).filter(a -> a == 1).toArray()
+ );
+ // zero results
+ assertEquals(
+ new int[0],
+ IntStream.of(1, 2, 3, 4, 3).filter(a -> false).toArray()
+ );
+ // two results
+ assertEquals(
+ new int[] {2, 4},
+ IntStream.of(1, 2, 3, 4, 3).filter(a -> a % 2 == 0).toArray()
+ );
+ // all
+ assertEquals(
+ new int[] {1, 2, 3, 4, 3},
+ IntStream.of(1, 2, 3, 4, 3).filter(a -> true).toArray()
+ );
+ }
+
+ public void testMap() {
+ // unconsumed stream never runs map
+ int[] data = {0};
+ IntStream.of(1, 2, 3).map(i -> data[0]++);
+ assertEquals(0, data[0]);
+
+ assertEquals(
+ new int[] {2, 4, 6},
+ IntStream.of(1, 2, 3).map(i -> i * 2).toArray()
+ );
+ }
+
+ public void testPeek() {
+ // unconsumed stream never peeks
+ boolean[] data = {false};
+ IntStream.of(1, 2, 3).peek(i -> data[0] |= true);
+ assertFalse(data[0]);
+
+ // make sure we saw it all in order
+ int[] items = new int[] {1, 2, 3};
+ List<Integer> peeked = new ArrayList<>();
+ IntStream.of(items).peek(peeked::add).forEach(item -> {
+ // do nothing, just run
+ });
+ assertEquals(items.length, peeked.size());
+ for (int i = 0; i < items.length; i++) {
+ assertEquals(items[i], (int) peeked.get(i));
+ }
+ }
+
+ // same impl, no parallel in browser
+ public void testFindFirstOrAny() {
+ OptionalInt any = IntStream.of(1, 2).findAny();
+ assertTrue(any.isPresent());
+ assertEquals(1, any.getAsInt());
+ }
+
+ public void testAnyMatch() {
+ // all
+ assertTrue(IntStream.of(1, 2).anyMatch(s -> true));
+
+ // some
+ assertTrue(IntStream.of(1, 2).anyMatch(s -> s == 1));
+
+ // none
+ assertFalse(IntStream.of(1, 2).anyMatch(s -> false));
+ }
+
+ public void testAllMatch() {
+ // all
+ assertTrue(IntStream.of(1, 2).allMatch(s -> true));
+
+ // some
+ assertFalse(IntStream.of(1, 2).allMatch(s -> s == 1));
+
+ // none
+ assertFalse(IntStream.of(1, 2).allMatch(s -> false));
+ }
+
+ public void testNoneMatch() {
+ // all
+ assertFalse(IntStream.of(1, 2).noneMatch(s -> true));
+
+ // some
+ assertFalse(IntStream.of(1, 2).noneMatch(s -> s == 1));
+
+ // none
+ assertTrue(IntStream.of(1, 2).noneMatch(s -> false));
+ }
+
+ public void testFlatMap() {
+ assertEquals(0, IntStream.empty().flatMap(value -> IntStream.of(1)).count());
+ assertEquals(0, IntStream.of(1).flatMap(value -> IntStream.empty()).count());
+ assertEquals(0, IntStream.of(1).flatMap(value -> IntStream.of()).count());
+ assertEquals(0, IntStream.of().flatMap(value -> IntStream.of(1)).count());
+ assertEquals(1, IntStream.of(1).flatMap(value -> IntStream.of(1)).count());
+
+ IntStream values = IntStream.of(1, 2, 3);
+
+ assertEquals(
+ new int[] {1, 2, 2, 4, 3, 6},
+ values.flatMap(i -> IntStream.of(i, i * 2)).toArray()
+ );
+ }
+
+ public void testMapToOthers() {
+ Supplier<IntStream> s = () -> IntStream.of(1, 2, 10);
+
+ assertEquals(
+ new String[] {"1", "2", "10"},
+ s.get().mapToObj(String::valueOf).toArray(String[]::new)
+ );
+
+ assertEquals(
+ new long[] {1, 2, 10},
+ s.get().mapToLong(i -> (long) i).toArray()
+ );
+
+ assertEquals(
+ new double[] {1, 2, 10},
+ s.get().mapToDouble(i -> (double) i).toArray()
+ );
+ }
+
+ public void testDistinct() {
+ int[] distinct = IntStream.of(1, 2, 3, 2).distinct().toArray();
+ assertEquals(3, distinct.length);
+ assertEquals(1 + 2 + 3, distinct[0] + distinct[1] + distinct[2]);
+ }
+
+ public void testSorted() {
+ int[] sorted = IntStream.of(3, 1, 2).sorted().toArray();
+ assertEquals(new int[] {1, 2, 3}, sorted);
+ }
+
+ public void testMinMax() {
+ Supplier<IntStream> stream = () -> IntStream.of(2, 3, 4, 1);
+
+ assertEquals(1, stream.get().min().orElse(0));
+ assertEquals(4, stream.get().max().orElse(0));
+
+ assertFalse(stream.get().filter(a -> false).max().isPresent());
+ assertFalse(stream.get().filter(a -> false).min().isPresent());
+ }
+
+ public void testCountLimitSkip() {
+ Supplier<IntStream> stream = () -> IntStream.of(1, 2, 3, 4);
+
+ assertEquals(4, stream.get().count());
+
+ assertEquals(4, stream.get().limit(4).count());
+ assertEquals(4, stream.get().limit(5).count());
+ assertEquals(3, stream.get().limit(3).count());
+
+ assertEquals(3, stream.get().skip(1).limit(3).count());
+
+ assertEquals(2, stream.get().limit(3).skip(1).count());
+
+ assertEquals(1, stream.get().skip(3).count());
+
+ assertEquals(new int[] {3, 4}, stream.get().skip(2).limit(3).toArray());
+ assertEquals(new int[] {3}, stream.get().skip(2).limit(1).toArray());
+
+ assertEquals(new int[] {4}, stream.get().skip(3).toArray());
+ assertEquals(new int[] {}, stream.get().skip(5).toArray());
+
+ assertEquals(new int[] {1, 2}, stream.get().limit(2).toArray());
+
+ assertEquals(new int[] {2}, stream.get().limit(2).skip(1).toArray());
+ }
+
+ public void testBoxed() {
+ Supplier<IntStream> stream = () -> IntStream.of(1, 2);
+ Stream<Integer> expected = stream.get().mapToObj(Integer::valueOf);
+ assertEquals(expected.toArray(), stream.get().boxed().toArray());
+ }
+
+ public void testAsOtherPrimitive() {
+ Supplier<IntStream> stream = () -> IntStream.of(1, 2);
+
+ DoubleStream actualDoubleStream = stream.get().asDoubleStream();
+ assertEquals(new double[]{1, 2}, actualDoubleStream.toArray());
+
+ LongStream actualLongStream = stream.get().asLongStream();
+ assertEquals(new long[] {1, 2}, actualLongStream.toArray());
+ }
+
+ public void testSummaryStats() {
+ Supplier<IntStream> stream = () -> IntStream.of(1, 2, 3);
+ IntSummaryStatistics summaryStats = stream.get().summaryStatistics();
+ assertEquals(3, summaryStats.getCount());
+ assertEquals(1, summaryStats.getMin());
+ assertEquals(2, summaryStats.getAverage(), 0d);
+ assertEquals(3, summaryStats.getMax());
+ assertEquals(6, summaryStats.getSum());
+
+ summaryStats.accept(6);
+ assertEquals(4, summaryStats.getCount());
+ assertEquals(1, summaryStats.getMin());
+ assertEquals(3, summaryStats.getAverage(), 0d);
+ assertEquals(6, summaryStats.getMax());
+ assertEquals(12, summaryStats.getSum());
+
+ IntSummaryStatistics combinedSumStats = stream.get().summaryStatistics();
+ combinedSumStats.combine(IntStream.of(4, 5, 6, 0).summaryStatistics());
+ assertEquals(7, combinedSumStats.getCount());
+ assertEquals(0, combinedSumStats.getMin());
+ assertEquals(3, combinedSumStats.getAverage(), 0d);
+ assertEquals(6, combinedSumStats.getMax());
+ assertEquals(21, combinedSumStats.getSum());
+ }
+
+ public void testAverage() {
+ assertFalse(IntStream.empty().average().isPresent());
+ assertEquals(2.0d, IntStream.of(1, 2, 3).average().getAsDouble(), 0d);
+ assertEquals(0d, IntStream.of(1, 2, -3).average().getAsDouble(), 0d);
+ assertEquals(-2.0d, IntStream.of(-1, -2, -3).average().getAsDouble(), 0d);
+ }
+
+ public void testSum() {
+ assertEquals(6, IntStream.of(1, 2, 3).sum());
+ assertEquals(0, IntStream.of(1, 2, -3).sum());
+ assertEquals(-6, IntStream.of(-1, -2, -3).sum());
+ }
+
+ public void testCollect() {
+ String val = IntStream.of(1, 2, 3, 4, 5).collect(StringBuilder::new,
+ // TODO switch to a lambda reference once #9340 is fixed
+ (stringBuilder, i) -> stringBuilder.append(i),
+ StringBuilder::append).toString();
+
+ assertEquals("12345", val);
+ }
+
+ public void testForEach() {
+ List<Integer> vals = new ArrayList<>();
+ IntStream.of(1, 2, 3, 4, 5).forEach(vals::add);
+ assertEquals(5, vals.size());
+ assertEquals(new Integer[] {1, 2, 3, 4, 5}, vals.toArray(new Integer[vals.size()]));
+ }
+
+ public void testIterator() {
+ List<Integer> vals = new ArrayList<>();
+ Iterator<Integer> iterator = IntStream.of(1, 2, 3, 4, 5).iterator();
+ while (iterator.hasNext()) {
+ vals.add(iterator.next());
+ }
+ assertEquals(5, vals.size());
+ assertEquals(new Integer[] {1, 2, 3, 4, 5}, vals.toArray(new Integer[vals.size()]));
+ }
+
+ public void testSpliterator() {
+ Spliterator<Integer> spliterator = IntStream.of(1, 2, 3, 4, 5).spliterator();
+ assertEquals(5, spliterator.estimateSize());
+ assertEquals(5, spliterator.getExactSizeIfKnown());
+
+ List<Integer> vals = new ArrayList<>();
+ while (spliterator.tryAdvance(vals::add)) {
+ // work is all done in the condition
+ }
+
+ assertEquals(5, vals.size());
+ assertEquals(new Integer[] {1, 2, 3, 4, 5}, vals.toArray(new Integer[vals.size()]));
+ }
+}
diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/LongStreamTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/LongStreamTest.java
new file mode 100644
index 0000000..407f4bf
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java8/util/stream/LongStreamTest.java
@@ -0,0 +1,457 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.emultest.java8.util.stream;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.LongSummaryStatistics;
+import java.util.OptionalLong;
+import java.util.Spliterator;
+import java.util.function.LongSupplier;
+import java.util.function.Supplier;
+import java.util.stream.DoubleStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+
+/**
+ * Tests {@link LongStream}.
+ */
+public class LongStreamTest extends EmulTestBase {
+
+ public void testEmptyStream() {
+ LongStream empty = LongStream.empty();
+ assertEquals(0, empty.count());
+ try {
+ empty.count();
+ fail("second terminal operation should have thrown IllegalStateEx");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+
+ assertEquals(0, LongStream.empty().limit(2).toArray().length);
+ assertEquals(0L, LongStream.empty().count());
+ assertEquals(0L, LongStream.empty().limit(2).count());
+
+ assertFalse(LongStream.empty().findFirst().isPresent());
+ assertFalse(LongStream.empty().findAny().isPresent());
+ assertFalse(LongStream.empty().max().isPresent());
+ assertFalse(LongStream.empty().min().isPresent());
+ assertTrue(LongStream.empty().noneMatch(item -> true));
+ assertTrue(LongStream.empty().allMatch(item -> true));
+ assertFalse(LongStream.empty().anyMatch(item -> true));
+ assertEquals(new long[0], LongStream.empty().toArray());
+ }
+
+ public void testStreamOfOne() {
+ Supplier<LongStream> one = () -> LongStream.of(1);
+ assertEquals(new long[]{1L}, one.get().toArray());
+ assertEquals(1L, one.get().count());
+ assertEquals(1, one.get().findFirst().getAsLong());
+ assertEquals(1, one.get().findAny().getAsLong());
+ }
+
+ public void testBuilder() {
+ LongStream s = LongStream.builder()
+ .add(1L)
+ .add(3L)
+ .add(2L)
+ .build();
+
+ assertEquals(
+ new long[] {1L, 3L, 2L},
+ s.toArray()
+ );
+
+ LongStream.Builder builder = LongStream.builder();
+ LongStream built = builder.build();
+ assertEquals(0L, built.count());
+ try {
+ builder.build();
+ fail("build() after build() should fail");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+ try {
+ builder.add(10L);
+ fail("add() after build() should fail");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+ }
+
+ public void testConcat() {
+ Supplier<LongStream> adbc = () -> LongStream.concat(LongStream.of(1, 4), LongStream.of(2, 3));
+
+ assertEquals(new long[]{1L, 4L, 2L, 3L}, adbc.get().toArray());
+ assertEquals(new long[]{1L, 2L, 3L, 4L}, adbc.get().sorted().toArray());
+
+ List<String> closed = new ArrayList<>();
+ LongStream first = LongStream.of(1L).onClose(() -> closed.add("first"));
+ LongStream second = LongStream.of(2L).onClose(() -> closed.add("second"));
+
+ LongStream concat = LongStream.concat(first, second);
+
+ // read everything, make sure we saw it all and didn't close automatically
+ long collectedAll = concat.sum();
+ assertEquals(3L, collectedAll);
+ assertEquals(0, closed.size());
+
+ concat.close();
+ assertEquals(Arrays.asList("first", "second"), closed);
+ }
+
+ public void testIterate() {
+ assertEquals(
+ new long[]{10L, 11L, 12L, 13L, 14L},
+ LongStream.iterate(0L, l -> l + 1L)
+ .skip(10)
+ .limit(5)
+ .toArray()
+ );
+ }
+
+ public void testGenerate() {
+ // infinite, but if you limit it is already too short to skip much
+ assertEquals(new long[0], LongStream.generate(makeGenerator()).limit(4).skip(5).toArray());
+
+ assertEquals(
+ new long[]{10L, 11L, 12L, 13L, 14L},
+ LongStream.generate(makeGenerator())
+ .skip(10)
+ .limit(5)
+ .toArray()
+ );
+ }
+
+ private LongSupplier makeGenerator() {
+ return new LongSupplier() {
+ long next = 0L;
+
+ @Override
+ public long getAsLong() {
+ return next++;
+ }
+ };
+ }
+
+ public void testRange() {
+ assertEquals(new long[] {1L, 2L, 3L, 4L}, LongStream.range(1, 5).toArray());
+ assertEquals(new long[] {-1L, 0L, 1L, 2L, 3L, 4L}, LongStream.range(-1, 5).toArray());
+ assertEquals(new long[] {}, LongStream.range(1, -5).toArray());
+ assertEquals(new long[] {}, LongStream.range(-1, -5).toArray());
+ }
+
+ public void testRangeClosed() {
+ assertEquals(new long[] {1L, 2L, 3L, 4L, 5L}, LongStream.rangeClosed(1, 5).toArray());
+ assertEquals(new long[] {-1L, 0L, 1L, 2L, 3L, 4L, 5L}, LongStream.rangeClosed(-1, 5).toArray());
+ assertEquals(new long[] {}, LongStream.rangeClosed(1, -5).toArray());
+ assertEquals(new long[] {}, LongStream.rangeClosed(-1, -5).toArray());
+ }
+
+ public void testToArray() {
+ assertEquals(new long[0], LongStream.of().toArray());
+ assertEquals(new long[] {1L}, LongStream.of(1L).toArray());
+ assertEquals(new long[] {3L, 2L, 0L}, LongStream.of(3L,2L,0L).toArray());
+ }
+
+ public void testReduce() {
+ long reduced = LongStream.of(1L, 2L, 4L).reduce(0, Long::sum);
+ assertEquals(7, reduced);
+
+ reduced = LongStream.of().reduce(0, Long::sum);
+ assertEquals(0L, reduced);
+
+ OptionalLong maybe = LongStream.of(1L, 4L, 8L).reduce(Long::sum);
+ assertTrue(maybe.isPresent());
+ assertEquals(13L, maybe.getAsLong());
+ maybe = LongStream.of().reduce(Long::sum);
+ assertFalse(maybe.isPresent());
+ }
+
+ public void testFilter() {
+ // unconsumed stream never runs filter
+ boolean[] data = {false};
+ LongStream.of(1L, 2L, 3L).filter(i -> data[0] |= true);
+ assertFalse(data[0]);
+
+ // one result
+ assertEquals(
+ new long[] {1L},
+ LongStream.of(1L, 2L, 3L, 4L, 3L).filter(a -> a == 1).toArray()
+ );
+ // zero results
+ assertEquals(
+ new long[0],
+ LongStream.of(1L, 2L, 3L, 4L, 3L).filter(a -> false).toArray()
+ );
+ // two results
+ assertEquals(
+ new long[] {2L, 4L},
+ LongStream.of(1L, 2L, 3L, 4L, 3L).filter(a -> a % 2 == 0).toArray()
+ );
+ // all
+ assertEquals(
+ new long[] {1L, 2L, 3L, 4L, 3L},
+ LongStream.of(1L, 2L, 3L, 4L, 3L).filter(a -> true).toArray()
+ );
+ }
+
+ public void testMap() {
+ // unconsumed stream never runs map
+ int[] data = {0};
+ LongStream.of(1L, 2L, 3L).map(i -> data[0]++);
+ assertEquals(0, data[0]);
+
+ assertEquals(
+ new long[] {2L, 4L, 6L},
+ LongStream.of(1L, 2L, 3L).map(i -> i * 2).toArray()
+ );
+ }
+
+ public void testPeek() {
+ // unconsumed stream never peeks
+ boolean[] data = {false};
+ LongStream.of(1L, 2L, 3L).peek(i -> data[0] |= true);
+ assertFalse(data[0]);
+
+ // make sure we saw it all in order
+ long[] items = new long[] {1L, 2L, 3L};
+ List<Long> peeked = new ArrayList<>();
+ LongStream.of(items).peek(peeked::add).forEach(item -> {
+ // do nothing, just run
+ });
+ assertEquals(items.length, peeked.size());
+ for (int i = 0; i < items.length; i++) {
+ assertEquals(items[i], (long) peeked.get(i));
+ }
+ }
+
+ // same impl, no parallel in browser
+ public void testFindFirstOrAny() {
+ OptionalLong any = LongStream.of(1L, 2L).findAny();
+ assertTrue(any.isPresent());
+ assertEquals(1L, any.getAsLong());
+ }
+
+ public void testAnyMatch() {
+ // all
+ assertTrue(LongStream.of(1L, 2L).anyMatch(s -> true));
+
+ // some
+ assertTrue(LongStream.of(1L, 2L).anyMatch(s -> s == 1L));
+
+ // none
+ assertFalse(LongStream.of(1L, 2L).anyMatch(s -> false));
+ }
+
+ public void testAllMatch() {
+ // all
+ assertTrue(LongStream.of(1L, 2L).allMatch(s -> true));
+
+ // some
+ assertFalse(LongStream.of(1L, 2L).allMatch(s -> s == 1L));
+
+ // none
+ assertFalse(LongStream.of(1L, 2L).allMatch(s -> false));
+ }
+
+ public void testNoneMatch() {
+ // all
+ assertFalse(LongStream.of(1L, 2L).noneMatch(s -> true));
+
+ // some
+ assertFalse(LongStream.of(1L, 2L).noneMatch(s -> s == 1L));
+
+ // none
+ assertTrue(LongStream.of(1L, 2L).noneMatch(s -> false));
+ }
+
+ public void testFlatMap() {
+ assertEquals(0L, LongStream.empty().flatMap(value -> LongStream.of(1L)).count());
+ assertEquals(0L, LongStream.of(1L).flatMap(value -> LongStream.empty()).count());
+ assertEquals(0L, LongStream.of(1L).flatMap(value -> LongStream.of()).count());
+ assertEquals(0L, LongStream.of().flatMap(value -> LongStream.of(1L)).count());
+ assertEquals(1L, LongStream.of(1L).flatMap(value -> LongStream.of(1L)).count());
+
+ LongStream values = LongStream.of(1L, 2L, 3L);
+
+ assertEquals(
+ new long[] {1L, 2L, 2L, 4L, 3L, 6L},
+ values.flatMap(i -> LongStream.of(i, i * 2)).toArray()
+ );
+ }
+
+ public void testMapToOthers() {
+ Supplier<LongStream> s = () -> LongStream.of(1, 2, 10);
+
+ assertEquals(
+ new String[] {"1", "2", "10"},
+ s.get().mapToObj(String::valueOf).toArray(String[]::new)
+ );
+
+ assertEquals(
+ new int[] {1, 2, 10},
+ s.get().mapToInt(i -> (int) i).toArray()
+ );
+
+ assertEquals(
+ new double[] {1d, 2d, 10d},
+ s.get().mapToDouble(i -> (double) i).toArray()
+ );
+ }
+
+ public void testDistinct() {
+ long[] distinct = LongStream.of(1L, 2L, 3L, 2L).distinct().toArray();
+ assertEquals(3, distinct.length);
+ assertEquals(1L + 2L + 3L, distinct[0] + distinct[1] + distinct[2]);
+ }
+
+ public void testSorted() {
+ long[] sorted = LongStream.of(3L, 1L, 2L).sorted().toArray();
+ assertEquals(new long[] {1L, 2L, 3L}, sorted);
+ }
+
+ public void testMinMax() {
+ Supplier<LongStream> stream = () -> LongStream.of(2L, 3L, 4L, 1L);
+
+ assertEquals(1L, stream.get().min().orElse(0));
+ assertEquals(4L, stream.get().max().orElse(0));
+
+ assertFalse(stream.get().filter(a -> false).max().isPresent());
+ assertFalse(stream.get().filter(a -> false).min().isPresent());
+ }
+
+ public void testCountLimitSkip() {
+ Supplier<LongStream> stream = () -> LongStream.of(1L, 2L, 3L, 4L);
+
+ assertEquals(4L, stream.get().count());
+
+ assertEquals(4L, stream.get().limit(4).count());
+ assertEquals(4L, stream.get().limit(5).count());
+ assertEquals(3L, stream.get().limit(3).count());
+
+ assertEquals(3L, stream.get().skip(1).limit(3).count());
+
+ assertEquals(2L, stream.get().limit(3).skip(1).count());
+
+ assertEquals(1L, stream.get().skip(3).count());
+
+ assertEquals(new long[] {3L, 4L}, stream.get().skip(2).limit(3).toArray());
+ assertEquals(new long[] {3L}, stream.get().skip(2).limit(1).toArray());
+
+ assertEquals(new long[] {4L}, stream.get().skip(3).toArray());
+ assertEquals(new long[] {}, stream.get().skip(5).toArray());
+
+ assertEquals(new long[] {1L, 2L}, stream.get().limit(2).toArray());
+
+ assertEquals(new long[] {2L}, stream.get().limit(2).skip(1).toArray());
+ }
+
+ public void testBoxed() {
+ Supplier<LongStream> stream = () -> LongStream.of(1L, 2L);
+ Stream<Long> expected = stream.get().mapToObj(Long::valueOf);
+ assertEquals(expected.toArray(), stream.get().boxed().toArray());
+ }
+
+ public void testAsOtherPrimitive() {
+ Supplier<LongStream> stream = () -> LongStream.of(1L, 2L);
+ DoubleStream actualDoubleStream = stream.get().asDoubleStream();
+ assertEquals(new double[]{1, 2}, actualDoubleStream.toArray());
+ }
+
+ public void testSummaryStats() {
+ Supplier<LongStream> stream = () -> LongStream.of(1L, 2L, 3L);
+ LongSummaryStatistics summaryStats = stream.get().summaryStatistics();
+ assertEquals(3L, summaryStats.getCount());
+ assertEquals(1L, summaryStats.getMin());
+ assertEquals(2L, summaryStats.getAverage(), 0d);
+ assertEquals(3L, summaryStats.getMax());
+ assertEquals(6L, summaryStats.getSum());
+
+ summaryStats.accept(6L);
+ assertEquals(4L, summaryStats.getCount());
+ assertEquals(1L, summaryStats.getMin());
+ assertEquals(3L, summaryStats.getAverage(), 0d);
+ assertEquals(6L, summaryStats.getMax());
+ assertEquals(12L, summaryStats.getSum());
+
+ LongSummaryStatistics combinedSumStats = stream.get().summaryStatistics();
+ combinedSumStats.combine(LongStream.of(4L, 5L, 6L, 0L).summaryStatistics());
+ assertEquals(7L, combinedSumStats.getCount());
+ assertEquals(0L, combinedSumStats.getMin());
+ assertEquals(3L, combinedSumStats.getAverage(), 0d);
+ assertEquals(6L, combinedSumStats.getMax());
+ assertEquals(21L, combinedSumStats.getSum());
+ }
+
+ public void testAverage() {
+ assertFalse(LongStream.empty().average().isPresent());
+ assertEquals(2.0d, LongStream.of(1L, 2L, 3L).average().getAsDouble(), 0d);
+ assertEquals(0d, LongStream.of(1L, 2L, -3L).average().getAsDouble(), 0d);
+ assertEquals(-2.0d, LongStream.of(-1L, -2L, -3L).average().getAsDouble(), 0d);
+ }
+
+ public void testSum() {
+ assertEquals(6L, LongStream.of(1L, 2L, 3L).sum());
+ assertEquals(0L, LongStream.of(1L, 2L, -3L).sum());
+ assertEquals(-6L, LongStream.of(-1L, -2L, -3L).sum());
+ }
+
+ public void testCollect() {
+ String val = LongStream.of(1L, 2L, 3L, 4L, 5L).collect(StringBuilder::new,
+ // TODO switch to a lambda reference once #9340 is fixed
+ (stringBuilder, lng) -> stringBuilder.append(lng),
+ StringBuilder::append).toString();
+
+ assertEquals("12345", val);
+ }
+
+ public void testForEach() {
+ List<Long> vals = new ArrayList<>();
+ LongStream.of(1L, 2L, 3L, 4L, 5L).forEach(vals::add);
+ assertEquals(5, vals.size());
+ assertEquals(new Long[] {1L, 2L, 3L, 4L, 5L}, vals.toArray(new Long[vals.size()]));
+ }
+
+ public void testIterator() {
+ List<Long> vals = new ArrayList<>();
+ Iterator<Long> iterator = LongStream.of(1L, 2L, 3L, 4L, 5L).iterator();
+ while (iterator.hasNext()) {
+ vals.add(iterator.next());
+ }
+ assertEquals(5, vals.size());
+ assertEquals(new Long[] {1L, 2L, 3L, 4L, 5L}, vals.toArray(new Long[vals.size()]));
+ }
+
+ public void testSpliterator() {
+ Spliterator<Long> spliterator = LongStream.of(1L, 2L, 3L, 4L, 5L).spliterator();
+ assertEquals(5, spliterator.estimateSize());
+ assertEquals(5, spliterator.getExactSizeIfKnown());
+
+ List<Long> vals = new ArrayList<>();
+ while (spliterator.tryAdvance(vals::add)) {
+ // work is all done in the condition
+ }
+
+ assertEquals(5, vals.size());
+ assertEquals(new Long[] {1L, 2L, 3L, 4L, 5L}, vals.toArray(new Long[vals.size()]));
+ }
+}
diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/StreamSupportTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/StreamSupportTest.java
new file mode 100644
index 0000000..0ff6331
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java8/util/stream/StreamSupportTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.emultest.java8.util.stream;
+
+import static java.util.stream.StreamSupport.doubleStream;
+import static java.util.stream.StreamSupport.intStream;
+import static java.util.stream.StreamSupport.longStream;
+import static java.util.stream.StreamSupport.stream;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.util.Spliterators;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+
+/**
+ * Tests {@link java.util.stream.StreamSupport}.
+ */
+public class StreamSupportTest extends EmulTestBase {
+
+ public void testDoubleStream() {
+ DoubleStream doubles = doubleStream(
+ Spliterators.spliterator(new double[] {1d, 2d, 3d, 4d}, 0),
+ false
+ );
+
+ assertNotNull(doubles);
+ assertEquals(new double[]{1d, 2d, 3d}, doubles.limit(3).toArray());
+
+ doubles = doubleStream(() -> Spliterators.spliterator(new double[] {1d, 2d, 3d, 4d}, 0), 0,
+ false);
+
+ assertNotNull(doubles);
+ assertEquals(
+ new double[] {2d, 3d},
+ doubles.skip(1).limit(2).toArray()
+ );
+ }
+
+ public void testIntStream() {
+ IntStream ints = intStream(
+ Spliterators.spliterator(new int[] {1, 2, 3, 4}, 0),
+ false
+ );
+
+ assertNotNull(ints);
+ assertEquals(new int[] {1, 2, 3}, ints.limit(3).toArray());
+
+ ints = intStream(() -> Spliterators.spliterator(new int[] {1, 2, 3, 4}, 0), 0, false);
+
+ assertNotNull(ints);
+ assertEquals(
+ new int[] {2, 3},
+ ints.skip(1).limit(2).toArray()
+ );
+ }
+
+ public void testLongStream() {
+ LongStream longs = longStream(
+ Spliterators.spliterator(new long[] {1L, 2L, 3L, 4L}, 0),
+ false
+ );
+
+ assertNotNull(longs);
+ assertEquals(new long[] {1L, 2L, 3L}, longs.limit(3).toArray());
+
+ longs = longStream(() -> Spliterators.spliterator(new long[] {1L, 2L, 3L, 4L}, 0), 0, false);
+
+ assertNotNull(longs);
+ assertEquals(
+ new long[] {2L, 3L},
+ longs.skip(1).limit(2).toArray()
+ );
+ }
+
+ public void testStream() {
+ Stream<String> strings = stream(
+ Spliterators.spliterator(new String[] {"a", "b", "c", "d"}, 0),
+ false
+ );
+
+ assertNotNull(strings);
+ assertEquals(new String[] {"a", "b", "c"}, strings.limit(3).toArray());
+
+ strings = stream(() -> Spliterators.spliterator(new String[] {"a", "b", "c", "d"}, 0), 0, false);
+
+ assertNotNull(strings);
+ assertEquals(
+ new String[] {"b", "c"},
+ strings.skip(1).limit(2).toArray()
+ );
+ }
+}
diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/StreamTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/StreamTest.java
new file mode 100644
index 0000000..d46bfaf
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java8/util/stream/StreamTest.java
@@ -0,0 +1,627 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.emultest.java8.util.stream;
+
+import static java.util.Arrays.asList;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.Spliterator;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+
+/**
+ * Tests {@link Stream}.
+ */
+public class StreamTest extends EmulTestBase {
+
+ public void testEmptyStream() {
+ Stream<Object> empty = Stream.empty();
+ assertEquals(0, empty.count());
+ try {
+ empty.count();
+ fail("second terminal operation should have thrown IllegalStateEx");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+
+ assertEquals(0, Stream.empty().limit(2).collect(Collectors.toList()).size());
+ assertEquals(0, Stream.empty().count());
+ assertEquals(0, Stream.empty().limit(2).count());
+
+ assertFalse(Stream.empty().findFirst().isPresent());
+ assertFalse(Stream.empty().findAny().isPresent());
+ assertFalse(Stream.<String>empty().max(Comparator.naturalOrder()).isPresent());
+ assertFalse(Stream.<String>empty().min(Comparator.naturalOrder()).isPresent());
+ assertTrue(Stream.empty().allMatch(item -> true));
+ assertFalse(Stream.empty().anyMatch(item -> true));
+ assertTrue(Stream.empty().noneMatch(item -> false));
+ assertFalse(Stream.empty().iterator().hasNext());
+ assertFalse(Stream.empty().spliterator().tryAdvance(a -> fail("should not advance")));
+ Stream.empty().spliterator().forEachRemaining(a -> fail("should not advance"));
+ assertEquals(new Object[0], Stream.empty().toArray());
+ assertEquals(new Object[0], Stream.empty().toArray(Object[]::new));
+ }
+
+ public void testStreamOfOne() {
+ Supplier<Stream<String>> one = () -> Stream.of("");
+ assertEquals(Collections.singletonList(""), one.get().collect(Collectors.toList()));
+ assertEquals(1L, one.get().count());
+ assertEquals("", one.get().findFirst().get());
+ assertEquals("", one.get().findAny().get());
+ }
+
+ public void testBuilder() {
+ Supplier<Stream<String>> s = () -> Stream.<String>builder()
+ .add("1")
+ .add("3")
+ .add("2")
+ .build();
+
+ Optional<String> max = s.get().filter(str -> !str.equals("3")).max(Comparator.naturalOrder());
+ assertTrue(max.isPresent());
+ assertEquals("2", max.get());
+
+ max = s.get().max(Comparator.reverseOrder());
+ assertTrue(max.isPresent());
+ assertEquals("1", max.get());
+
+ Stream.Builder<Object> builder = Stream.builder();
+ Stream<Object> built = builder.build();
+ assertEquals(0, built.count());
+ try {
+ builder.build();
+ fail("build() after build() should fail");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+ try {
+ builder.add("asdf");
+ fail("add() after build() should fail");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+ }
+
+ public void testConcat() {
+ Supplier<Stream<String>> adbc = () -> Stream.concat(Stream.of("a", "d"), Stream.of("b", "c"));
+
+ assertEquals(new String[]{"a", "d", "b", "c"}, adbc.get().toArray(String[]::new));
+ assertEquals(new String[]{"a", "b", "c", "d"}, adbc.get().sorted().toArray(String[]::new));
+
+ List<String> closed = new ArrayList<>();
+ Stream<String> first = Stream.of("first").onClose(() -> closed.add("first"));
+ Stream<String> second = Stream.of("second").onClose(() -> closed.add("second"));
+
+ Stream<String> concat = Stream.concat(first, second);
+
+ // read everything, make sure we saw it all and didn't close automatically
+ String collectedAll = concat.collect(Collectors.joining());
+ assertEquals("firstsecond", collectedAll);
+ assertEquals(0, closed.size());
+
+ concat.close();
+ assertEquals(Arrays.asList("first", "second"), closed);
+ }
+
+ public void testIterate() {
+ assertEquals(
+ new Integer[]{10, 11, 12, 13, 14},
+ Stream.iterate(0, i -> i + 1)
+ .skip(10)
+ .limit(5)
+ .toArray(Integer[]::new)
+ );
+ }
+
+ public void testGenerate() {
+ // infinite, but if you limit it is already too short to skip much
+ assertEquals(new Integer[]{}, Stream.generate(makeGenerator())
+ .limit(4)
+ .skip(5)
+ .toArray(Integer[]::new));
+
+ assertEquals(new Integer[]{10, 11, 12, 13, 14}, Stream.generate(makeGenerator())
+ .skip(10)
+ .limit(5)
+ .toArray(Integer[]::new));
+ }
+
+ private Supplier<Integer> makeGenerator() {
+ return new Supplier<Integer>() {
+ int next = 0;
+
+ @Override
+ public Integer get() {
+ return next++;
+ }
+ };
+ }
+
+ public void testSpliterator() {
+ final String[] values = new String[] {"a", "b", "c"};
+
+ Spliterator<String> spliterator = Stream.of(values).spliterator();
+ assertEquals(3, spliterator.estimateSize());
+ assertEquals(3, spliterator.getExactSizeIfKnown());
+
+ List<String> actualValues = new ArrayList<>();
+ while (spliterator.tryAdvance(actualValues::add)) {
+ // work is all done in the condition
+ }
+
+ assertEquals(asList(values), actualValues);
+ }
+
+ public void testIterator() {
+ final String[] values = new String[] {"a", "b", "c"};
+
+ List<String> actualValues = new ArrayList<String>();
+ Iterator<String> iterator = Stream.of(values).iterator();
+ while (iterator.hasNext()) {
+ actualValues.add(iterator.next());
+ }
+ assertEquals(asList(values), actualValues);
+ }
+
+ public void testForEach() {
+ final String[] values = new String[] {"a", "b", "c"};
+
+ List<String> actualValues = new ArrayList<>();
+ Stream.of(values).forEach(actualValues::add);
+ assertEquals(asList(values), actualValues);
+ }
+
+ // toArray
+ public void testToArray() {
+ assertEquals(
+ new Object[]{"a", "b"},
+ asList("a", "b").stream().toArray()
+ );
+ assertEquals(
+ new String[]{"a", "b"},
+ asList("a", "b").stream().toArray(String[]::new)
+ );
+ }
+
+ // reduce
+ public void testReduce() {
+ String reduced = Stream.of("a", "b", "c").reduce("", String::concat);
+ assertEquals("abc", reduced);
+
+ reduced = Stream.<String>of().reduce("initial", String::concat);
+ assertEquals("initial", reduced);
+
+ Optional<String> maybe = Stream.of("a", "b", "c").reduce(String::concat);
+ assertTrue(maybe.isPresent());
+ assertEquals("abc", maybe.get());
+ maybe = Stream.<String>of().reduce(String::concat);
+ assertFalse(maybe.isPresent());
+
+ reduced = Stream.of("a", "b", "c").reduce("", String::concat, String::concat);
+ assertEquals("abc", reduced);
+ }
+
+ public void testCollect() {
+ final String[] values = new String[] {"a", "b", "c"};
+
+ String collectedString = Stream.of(values).collect(StringBuilder::new,
+ StringBuilder::append,
+ StringBuilder::append).toString();
+ assertEquals("abc", collectedString);
+
+ List<String> collectedList = Stream.of(values).collect(Collectors.toList());
+ assertEquals(asList(values), collectedList);
+ }
+
+ public void testFilter() {
+ // unconsumed stream never runs filter
+ boolean[] data = {false};
+ Stream.of(1, 2, 3).filter(i -> data[0] |= true);
+ assertFalse(data[0]);
+
+ // one result
+ assertEquals(
+ Collections.singletonList("a"),
+ Stream.of("a", "b", "c", "d", "c").filter(a -> a.equals("a")).collect(Collectors.toList())
+ );
+ // zero results
+ assertEquals(
+ Collections.emptyList(),
+ Stream.of("a", "b", "c", "d", "c").filter(a -> false).collect(Collectors.toList())
+ );
+ // two results
+ assertEquals(
+ asList("c3", "c5"),
+ Stream.of("a1", "b2", "c3", "d4", "c5")
+ .filter(a -> a.startsWith("c"))
+ .collect(Collectors.toList())
+ );
+ // all
+ assertEquals(
+ asList("a", "b", "c", "d", "c"),
+ Stream.of("a", "b", "c", "d", "c").filter(a -> true).collect(Collectors.toList())
+ );
+ }
+
+ public void testMap() {
+ // unconsumed stream never runs map
+ boolean[] data = {false};
+ Stream.of(1, 2, 3).map(i -> data[0] |= true);
+ assertFalse(data[0]);
+
+ assertEquals(
+ asList("#1", "#2", "#3"),
+ Stream.of(1, 2, 3).map(i -> "#" + i).collect(Collectors.toList())
+ );
+ }
+
+ public void testPeek() {
+ // unconsumed stream never peeks
+ boolean[] data = {false};
+ Stream.of(1, 2, 3).peek(i -> data[0] |= true);
+ assertFalse(data[0]);
+
+ // make sure we saw it all in order
+ List<String> items = asList("a", "b", "c");
+ List<String> peeked = new ArrayList<>();
+ items.stream().peek(peeked::add).forEach(item -> {
+ // deliberately do nothing, just run
+ });
+ assertEquals(items, peeked);
+ }
+
+ // same impl, no parallel in browser
+ public void testFindFirstOrAny() {
+ Optional<String> any = Stream.of("a", "b").findAny();
+ assertTrue(any.isPresent());
+ assertEquals("a", any.get());
+ }
+
+ public void testAnyMatch() {
+ // all
+ assertTrue(Stream.of("a", "b").anyMatch(s -> true));
+
+ // some
+ assertTrue(Stream.of("a", "b").anyMatch(s -> s.equals("a")));
+
+ // none
+ assertFalse(Stream.of("a", "b").anyMatch(s -> false));
+ }
+
+ public void testAllMatch() {
+ // all
+ assertTrue(Stream.of("a", "b").allMatch(s -> true));
+
+ // some
+ assertFalse(Stream.of("a", "b").allMatch(s -> s.equals("a")));
+
+ // none
+ assertFalse(Stream.of("a", "b").allMatch(s -> false));
+ }
+
+ public void testNoneMatch() {
+ // all
+ assertFalse(Stream.of("a", "b").noneMatch(s -> true));
+
+ // some
+ assertFalse(Stream.of("a", "b").noneMatch(s -> s.equals("a")));
+
+ // none
+ assertTrue(Stream.of("a", "b").noneMatch(s -> false));
+ }
+
+ public void testFlatMap() {
+ assertEquals(0, Stream.<Stream<String>>empty().flatMap(Function.identity()).count());
+ assertEquals(0, Stream.of(Stream.<String>empty()).flatMap(Function.identity()).count());
+ assertEquals(0, Stream.of(Stream.of()).flatMap(Function.identity()).count());
+ assertEquals(1, Stream.of(Stream.of("")).flatMap(Function.identity()).count());
+
+ Stream<Stream<String>> strings = Stream.of(Stream.of("a", "b"), Stream.empty(), Stream.of("c"));
+
+ assertEquals(
+ asList("a", "b", "c"),
+ strings.flatMap(Function.identity()).collect(Collectors.toList())
+ );
+ }
+ public void testMapToPrimitives() {
+ Supplier<Stream<String>> s = () -> Stream.of("1", "2", "10");
+
+ assertEquals(
+ new int[]{1, 2, 10},
+ s.get().mapToInt(Integer::parseInt).toArray()
+ );
+
+ assertEquals(
+ new long[]{1, 2, 10},
+ s.get().mapToLong(Long::parseLong).toArray()
+ );
+
+ assertEquals(
+ new double[]{1, 2, 10},
+ s.get().mapToDouble(Double::parseDouble).toArray()
+ );
+ }
+
+ public void testFlatMapToPrimitives() {
+ assertEquals(0, Stream.<IntStream>empty().flatMapToInt(Function.identity()).count());
+ assertEquals(0, Stream.of(IntStream.empty()).flatMapToInt(Function.identity()).count());
+ assertEquals(0, Stream.of(IntStream.of()).flatMapToInt(Function.identity()).count());
+ assertEquals(1, Stream.of(IntStream.of(0)).flatMapToInt(Function.identity()).count());
+
+ Stream<IntStream> intStreams = Stream.of(
+ IntStream.of(1, 2),
+ IntStream.empty(),
+ IntStream.of(5)
+ );
+ assertEquals(
+ new int[]{1, 2, 5},
+ intStreams.flatMapToInt(Function.identity()).toArray()
+ );
+
+ Stream<LongStream> longStreams = Stream.of(
+ LongStream.of(1, 2),
+ LongStream.empty(),
+ LongStream.of(5)
+ );
+ assertEquals(
+ new long[]{1, 2, 5},
+ longStreams.flatMapToLong(Function.identity()).toArray()
+ );
+
+ Stream<DoubleStream> doubleStreams = Stream.of(
+ DoubleStream.of(1, 2),
+ DoubleStream.empty(),
+ DoubleStream.of(5)
+ );
+ assertEquals(
+ new double[]{1, 2, 5},
+ doubleStreams.flatMapToDouble(Function.identity()).toArray()
+ );
+ }
+
+ public void testDistinct() {
+ List<String> distinct = asList("a", "b", "c", "b").stream()
+ .distinct()
+ .collect(Collectors.toList());
+ assertEquals(3, distinct.size());
+ assertTrue(distinct.contains("a"));
+ assertTrue(distinct.contains("b"));
+ assertTrue(distinct.contains("c"));
+ }
+
+ public void testSorted() {
+ List<String> sorted = asList("c", "a", "b").stream().sorted().collect(Collectors.toList());
+ List<String> reversed = asList("c", "a", "b").stream()
+ .sorted(Comparator.reverseOrder())
+ .collect(Collectors.toList());
+
+ assertEquals(asList("a", "b", "c"), sorted);
+ assertEquals(asList("c", "b", "a"), reversed);
+ }
+
+ public void testMinMax() {
+ Supplier<Stream<String>> stream = () -> Stream.of("b", "c", "d", "a");
+
+ assertEquals("a", stream.get().min(Comparator.naturalOrder()).orElse(null));
+ assertEquals("d", stream.get().min(Comparator.reverseOrder()).orElse(null));
+ assertEquals("a", stream.get().max(Comparator.reverseOrder()).orElse(null));
+ assertEquals("d", stream.get().max(Comparator.naturalOrder()).orElse(null));
+
+ assertFalse(stream.get().filter(a -> false).max(Comparator.naturalOrder()).isPresent());
+ assertFalse(stream.get().filter(a -> false).min(Comparator.naturalOrder()).isPresent());
+ }
+
+ public void testCountLimitSkip() {
+ Supplier<Stream<String>> stream = () -> asList("a", "b", "c", "d").stream();
+
+ assertEquals(4, stream.get().count());
+
+ assertEquals(4, stream.get().limit(4).count());
+ assertEquals(4, stream.get().limit(5).count());
+ assertEquals(3, stream.get().limit(3).count());
+
+ assertEquals(3, stream.get().skip(1).limit(3).count());
+
+ assertEquals(2, stream.get().limit(3).skip(1).count());
+
+ assertEquals(1, stream.get().skip(3).count());
+
+ assertEquals(asList("c", "d"), stream.get().skip(2).limit(3).collect(Collectors.toList()));
+ assertEquals(Collections.singletonList("c"), stream.get()
+ .skip(2)
+ .limit(1)
+ .collect(Collectors.toList()));
+
+ assertEquals(Collections.singletonList("d"), stream.get()
+ .skip(3)
+ .collect(Collectors.toList()));
+ assertEquals(Collections.emptyList(), stream.get()
+ .skip(5)
+ .collect(Collectors.toList()));
+
+ assertEquals(asList("a", "b"), stream.get()
+ .limit(2)
+ .collect(Collectors.toList()));
+
+ assertEquals(Collections.singletonList("b"), stream.get()
+ .limit(2)
+ .skip(1)
+ .collect(Collectors.toList()));
+ }
+
+ // This frustrating test was written first on the JVM stream to discover the basic behavior before
+ // trying to implement it in GWT. As far as I can tell, none of this is clearly described in
+ // javadoc. Also note that it is *not* required to use the returned stream from calling onClose
+ public void testCloseQuirks() {
+ // all subclasses use the same close()/onClose(...) impl, just test once with Stream.empty()
+
+ Stream<Object> s = Stream.of(1);
+ s.close();
+ // allow multiple close
+ s.close();
+
+ // Add a handler, close, and attempt to re-close - handler only runs the one time
+ int[] calledCount = {0};
+ s = Stream.empty();
+ s.onClose(() -> calledCount[0]++);
+ // shouldn't have been called yet
+ assertEquals(0, calledCount[0]);
+ s.close();
+ // called once
+ assertEquals(1, calledCount[0]);
+ s.close();
+ // not called again on subsequent closes
+ assertEquals(1, calledCount[0]);
+
+ // Add a handler after close, and re-close, the handler will only go off after the _second_
+ // close
+ calledCount[0] = 0;
+ s = Stream.of(1);
+ s.close();
+ s = s.onClose(() -> calledCount[0]++);
+ // shouldn't have been called yet
+ assertEquals(0, calledCount[0]);
+ s.close();
+ // frustratingly, the JVM apparently permits each handler when added to let the stream be closed
+ // _again_
+ assertEquals(1, calledCount[0]);
+
+ // Adding yet another runnable and closing again demonstrates this - only the new one is run,
+ // the old ones are not
+ s = s.onClose(() -> calledCount[0]++);
+ s.close();
+ assertEquals(2, calledCount[0]);
+
+ // Add two handlers, ensure both are called, and neither called the second time the stream is
+ // closed
+ calledCount[0] = 0;
+ s = Stream.empty();
+ s = s.onClose(() -> calledCount[0]++);
+ s = s.onClose(() -> calledCount[0]++);
+ s.close();
+ assertEquals(2, calledCount[0]);
+ s.close();
+ assertEquals(2, calledCount[0]);
+ }
+
+ public void testClose() {
+ // terminate stream before closing, confirm that handler is called
+ Stream<Object> s = Stream.of("a", "b", "c");
+ int[] calledCount = {0};
+ s = s.onClose(() -> calledCount[0]++);
+
+ long count = s.count();
+ assertEquals(3, count);
+ assertEquals(0, calledCount[0]);
+
+ s.close();
+ assertEquals(1, calledCount[0]);
+
+ // terminate stream after closing, confirm that handler is called, and terminating fails
+ s = Stream.of("a", "b", "c");
+ calledCount[0] = 0;
+ s = s.onClose(() -> calledCount[0]++);
+
+ s.close();
+ assertEquals(1, calledCount[0]);
+
+ try {
+ s.count();
+ fail("Expected IllegalStateException");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+ assertEquals(1, calledCount[0]);
+ }
+
+ public void testCloseException() {
+ // Try a single exception, confirm we catch it
+ Stream<Object> s = Stream.of(1, 2, 3);
+
+ RuntimeException a = new RuntimeException("a");
+ s.onClose(() -> {
+ throw a;
+ });
+ try {
+ s.close();
+ fail("RuntimeException expected");
+ } catch (RuntimeException expected) {
+ assertSame(a, expected);
+ assertEquals(0, expected.getSuppressed().length);
+ }
+
+ // Throw an exception in two of the three handlers, confirm both arrive and the third was called
+ // correctly
+ s = Stream.of(1, 2, 3);
+
+ RuntimeException a2 = new RuntimeException("a");
+ IllegalStateException b = new IllegalStateException("b");
+ int[] calledCount = {0};
+ s
+ .onClose(() -> {
+ throw a2;
+ })
+ .onClose(() -> {
+ throw b;
+ })
+ .onClose(() -> calledCount[0]++);
+
+ try {
+ s.close();
+ fail("RuntimeException expected");
+ } catch (RuntimeException expected) {
+ assertSame(a2, expected);
+ assertEquals(1, expected.getSuppressed().length);
+ Throwable firstSuppressed = expected.getSuppressed()[0];
+ assertSame(b, firstSuppressed);
+ }
+ assertEquals(1, calledCount[0]);
+
+ // Throw the same exception instance twice, ensure it only arrives once
+ s = Stream.of(1, 2, 3);
+
+ RuntimeException t = new RuntimeException("a");
+ s
+ .onClose(() -> {
+ throw t;
+ })
+ .onClose(() -> {
+ throw t;
+ });
+
+ try {
+ s.close();
+ fail("RuntimeException expected");
+ } catch (RuntimeException expected) {
+ assertSame(t, expected);
+ assertEquals(0, expected.getSuppressed().length);
+ }
+ }
+}
\ No newline at end of file