diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TAllMatchConsumer.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TAllMatchConsumer.java new file mode 100644 index 000000000..aa012e832 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TAllMatchConsumer.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Alexey Andreev. + * + * 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 org.teavm.classlib.java.util.stream.doubleimpl; + +import java.util.function.DoublePredicate; + +public class TAllMatchConsumer implements DoublePredicate { + public boolean matched = true; + private DoublePredicate predicate; + + public TAllMatchConsumer(DoublePredicate predicate) { + this.predicate = predicate; + } + + @Override + public boolean test(double t) { + if (!predicate.test(t)) { + matched = false; + } + return matched; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TAnyMatchConsumer.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TAnyMatchConsumer.java new file mode 100644 index 000000000..9be7efccb --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TAnyMatchConsumer.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019 Alexey Andreev. + * + * 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 org.teavm.classlib.java.util.stream.doubleimpl; + +import java.util.function.DoublePredicate; + +public class TAnyMatchConsumer implements DoublePredicate { + public boolean matched; + private DoublePredicate predicate; + + public TAnyMatchConsumer(DoublePredicate predicate) { + this.predicate = predicate; + } + + @Override + public boolean test(double t) { + matched = predicate.test(t); + return !matched; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TEmptyDoubleStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TEmptyDoubleStreamImpl.java index 3b5a99d41..f23016c5a 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TEmptyDoubleStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TEmptyDoubleStreamImpl.java @@ -30,6 +30,6 @@ public class TEmptyDoubleStreamImpl extends TSimpleDoubleStreamImpl { @Override public long count() { - return 1; + return 0; } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TFlatMappingDoubleStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TFlatMappingDoubleStreamImpl.java index 984f951ba..9f1e2c2d9 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TFlatMappingDoubleStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TFlatMappingDoubleStreamImpl.java @@ -22,6 +22,7 @@ import org.teavm.classlib.java.util.stream.TDoubleStream; public class TFlatMappingDoubleStreamImpl extends TSimpleDoubleStreamImpl { private TSimpleDoubleStreamImpl sourceStream; + private boolean currentSet; private TDoubleStream current; private PrimitiveIterator.OfDouble iterator; private DoubleFunction mapper; @@ -35,42 +36,44 @@ public class TFlatMappingDoubleStreamImpl extends TSimpleDoubleStreamImpl { @Override public boolean next(DoublePredicate consumer) { - while (true) { - if (current == null) { - if (done) { - return false; - } + if (current == null) { + if (done) { + return false; + } + currentSet = false; + while (!currentSet) { boolean hasMore = sourceStream.next(e -> { current = mapper.apply(e); + currentSet = true; return false; }); if (!hasMore) { done = true; - } - if (current == null) { - done = true; - return false; + break; } } - if (current instanceof TSimpleDoubleStreamImpl) { - @SuppressWarnings("unchecked") - TSimpleDoubleStreamImpl castCurrent = (TSimpleDoubleStreamImpl) current; - if (castCurrent.next(consumer)) { - return true; - } - current = null; - } else { - iterator = current.iterator(); - while (iterator.hasNext()) { - double e = iterator.nextDouble(); - if (!consumer.test(e)) { - return true; - } - } - iterator = null; - current = null; + if (current == null) { + return false; } } + if (current instanceof TSimpleDoubleStreamImpl) { + TSimpleDoubleStreamImpl castCurrent = (TSimpleDoubleStreamImpl) current; + if (castCurrent.next(consumer)) { + return true; + } + current = null; + } else { + iterator = current.iterator(); + while (iterator.hasNext()) { + double e = iterator.next(); + if (!consumer.test(e)) { + return true; + } + } + iterator = null; + current = null; + } + return true; } @Override diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSimpleDoubleStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSimpleDoubleStreamImpl.java index e58e95fa6..560049887 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSimpleDoubleStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSimpleDoubleStreamImpl.java @@ -101,10 +101,15 @@ public abstract class TSimpleDoubleStreamImpl implements TDoubleStream { @Override public void forEachOrdered(DoubleConsumer action) { - next(e -> { - action.accept(e); - return true; - }); + while (true) { + boolean hasMore = next(e -> { + action.accept(e); + return true; + }); + if (!hasMore) { + return; + } + } } @Override @@ -112,7 +117,9 @@ public abstract class TSimpleDoubleStreamImpl implements TDoubleStream { int estimatedSize = estimateSize(); if (estimatedSize < 0) { List list = new ArrayList<>(); - next(list::add); + while (next(list::add)) { + // go on + } double[] array = new double[list.size()]; for (int i = 0; i < array.length; ++i) { array[i] = list.get(i); @@ -121,8 +128,9 @@ public abstract class TSimpleDoubleStreamImpl implements TDoubleStream { } else { double[] array = new double[estimatedSize]; ArrayFillingConsumer consumer = new ArrayFillingConsumer(array); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have reported done status"; + while (next(consumer)) { + // go on + } if (consumer.index < array.length) { array = Arrays.copyOf(array, consumer.index); } @@ -133,26 +141,33 @@ public abstract class TSimpleDoubleStreamImpl implements TDoubleStream { @Override public double reduce(double identity, DoubleBinaryOperator accumulator) { TReducingDoubleConsumer consumer = new TReducingDoubleConsumer(accumulator, identity, true); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have returned true"; + while (next(consumer)) { + // go on + } return consumer.result; } @Override public OptionalDouble reduce(DoubleBinaryOperator accumulator) { TReducingDoubleConsumer consumer = new TReducingDoubleConsumer(accumulator, 0, false); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have returned true"; + while (next(consumer)) { + // go on + } return consumer.initialized ? OptionalDouble.of(consumer.result) : OptionalDouble.empty(); } @Override public R collect(Supplier supplier, ObjDoubleConsumer accumulator, BiConsumer combiner) { R collection = supplier.get(); - next(e -> { - accumulator.accept(collection, e); - return true; - }); + while (true) { + boolean hasMore = next(e -> { + accumulator.accept(collection, e); + return true; + }); + if (!hasMore) { + break; + } + } return collection; } @@ -169,32 +184,46 @@ public abstract class TSimpleDoubleStreamImpl implements TDoubleStream { @Override public long count() { TCountingDoubleConsumer consumer = new TCountingDoubleConsumer(); - next(consumer); + while (next(consumer)) { + // go on + } return consumer.count; } @Override public double sum() { TSumDoubleConsumer consumer = new TSumDoubleConsumer(); - next(consumer); + while (next(consumer)) { + // go on + } return consumer.sum; } @Override public OptionalDouble average() { TAverageDoubleConsumer consumer = new TAverageDoubleConsumer(); - next(consumer); + while (next(consumer)) { + // go on + } return consumer.count > 0 ? OptionalDouble.of(consumer.sum / consumer.count) : OptionalDouble.empty(); } @Override public boolean anyMatch(DoublePredicate predicate) { - return next(predicate.negate()); + TAnyMatchConsumer consumer = new TAnyMatchConsumer(predicate); + while (!consumer.matched && next(consumer)) { + // go on + } + return consumer.matched; } @Override public boolean allMatch(DoublePredicate predicate) { - return !next(predicate); + TAllMatchConsumer consumer = new TAllMatchConsumer(predicate); + while (consumer.matched && next(consumer)) { + // go on + } + return consumer.matched; } @Override @@ -205,7 +234,9 @@ public abstract class TSimpleDoubleStreamImpl implements TDoubleStream { @Override public OptionalDouble findFirst() { TFindFirstDoubleConsumer consumer = new TFindFirstDoubleConsumer(); - next(consumer); + while (!consumer.hasAny && next(consumer)) { + // go on + } return consumer.hasAny ? OptionalDouble.of(consumer.result) : OptionalDouble.empty(); } @@ -264,7 +295,7 @@ public abstract class TSimpleDoubleStreamImpl implements TDoubleStream { public abstract boolean next(DoublePredicate consumer); - class ArrayFillingConsumer implements DoublePredicate { + static class ArrayFillingConsumer implements DoublePredicate { double[] array; int index; diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSimpleDoubleStreamIterator.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSimpleDoubleStreamIterator.java index ea26850a9..86acc852a 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSimpleDoubleStreamIterator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSimpleDoubleStreamIterator.java @@ -53,13 +53,21 @@ public class TSimpleDoubleStreamIterator implements PrimitiveIterator.OfDouble { if (state != NEEDS_MORE) { return; } - boolean hasMore = stream.next(e -> { - lastElement = e; - return false; - }); - state = hasMore ? HAS_DATA : LAST_ELEMENT; - if (state == LAST_ELEMENT) { - stream = null; + state = NEEDS_MORE; + while (state == NEEDS_MORE) { + boolean hasMore = stream.next(e -> { + lastElement = e; + state = HAS_DATA; + return false; + }); + if (!hasMore) { + if (state == NEEDS_MORE) { + state = DONE; + } else { + state = LAST_ELEMENT; + } + stream = null; + } } } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSimpleDoubleStreamSpliterator.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSimpleDoubleStreamSpliterator.java index dbe2748ba..d510e846c 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSimpleDoubleStreamSpliterator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSimpleDoubleStreamSpliterator.java @@ -20,6 +20,7 @@ import java.util.function.DoubleConsumer; public class TSimpleDoubleStreamSpliterator implements Spliterator.OfDouble { private TSimpleDoubleStreamImpl stream; + private boolean foundItems; private boolean done; public TSimpleDoubleStreamSpliterator(TSimpleDoubleStreamImpl stream) { @@ -39,10 +40,14 @@ public class TSimpleDoubleStreamSpliterator implements Spliterator.OfDouble { if (done) { return false; } - done = !stream.next(x -> { - action.accept(x); - return false; - }); + foundItems = false; + while (!foundItems && !done) { + done = !stream.next(x -> { + action.accept(x); + foundItems = true; + return false; + }); + } return true; } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSkippingDoubleStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSkippingDoubleStreamImpl.java index 75e0a4267..a2e83bf9f 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSkippingDoubleStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSkippingDoubleStreamImpl.java @@ -30,7 +30,7 @@ public class TSkippingDoubleStreamImpl extends TSimpleDoubleStreamImpl { @Override public boolean next(DoublePredicate consumer) { - if (remaining > 0) { + while (remaining > 0) { if (!sourceStream.next(e -> --remaining > 0)) { return false; } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSpecializedConcatDoubleStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSpecializedConcatDoubleStream.java index 38ac89ed2..4d64d745e 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSpecializedConcatDoubleStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSpecializedConcatDoubleStream.java @@ -33,16 +33,15 @@ public class TSpecializedConcatDoubleStream extends TSimpleDoubleStreamImpl { if (current == null) { return false; } - while (true) { - if (current.next(consumer)) { - return true; - } - if (current == first) { - current = second; - } else { - current = null; - return false; - } + if (current.next(consumer)) { + return true; + } + if (current == first) { + current = second; + return true; + } else { + current = null; + return false; } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TAllMatchConsumer.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TAllMatchConsumer.java new file mode 100644 index 000000000..d93f40bca --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TAllMatchConsumer.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Alexey Andreev. + * + * 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 org.teavm.classlib.java.util.stream.impl; + +import java.util.function.Predicate; + +public class TAllMatchConsumer implements Predicate { + public boolean matched = true; + private Predicate predicate; + + public TAllMatchConsumer(Predicate predicate) { + this.predicate = predicate; + } + + @Override + public boolean test(T t) { + if (!predicate.test(t)) { + matched = false; + } + return matched; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TAnyMatchConsumer.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TAnyMatchConsumer.java new file mode 100644 index 000000000..3e61f5cca --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TAnyMatchConsumer.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019 Alexey Andreev. + * + * 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 org.teavm.classlib.java.util.stream.impl; + +import java.util.function.Predicate; + +public class TAnyMatchConsumer implements Predicate { + public boolean matched; + private Predicate predicate; + + public TAnyMatchConsumer(Predicate predicate) { + this.predicate = predicate; + } + + @Override + public boolean test(T t) { + matched = predicate.test(t); + return !matched; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TEmptyStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TEmptyStreamImpl.java index 563b5d35d..1dea8866a 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TEmptyStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TEmptyStreamImpl.java @@ -30,6 +30,6 @@ public class TEmptyStreamImpl extends TSimpleStreamImpl { @Override public long count() { - return 1; + return 0; } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingStreamImpl.java index 953be0db0..1ce808b62 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingStreamImpl.java @@ -22,6 +22,7 @@ import org.teavm.classlib.java.util.stream.TStream; public class TFlatMappingStreamImpl extends TSimpleStreamImpl { private TSimpleStreamImpl sourceStream; + private boolean currentSet; private TStream current; private Iterator iterator; private Function> mapper; @@ -35,42 +36,45 @@ public class TFlatMappingStreamImpl extends TSimpleStreamImpl { @Override public boolean next(Predicate consumer) { - while (true) { - if (current == null) { - if (done) { - return false; - } + if (current == null) { + if (done) { + return false; + } + currentSet = false; + while (!currentSet) { boolean hasMore = sourceStream.next(e -> { current = mapper.apply(e); + currentSet = true; return false; }); if (!hasMore) { done = true; - } - if (current == null) { - done = true; - return false; + break; } } - if (current instanceof TSimpleStreamImpl) { - @SuppressWarnings("unchecked") - TSimpleStreamImpl castCurrent = (TSimpleStreamImpl) current; - if (castCurrent.next(consumer)) { - return true; - } - current = null; - } else { - iterator = current.iterator(); - while (iterator.hasNext()) { - T e = iterator.next(); - if (!consumer.test(e)) { - return true; - } - } - iterator = null; - current = null; + if (current == null) { + return false; } } + if (current instanceof TSimpleStreamImpl) { + @SuppressWarnings("unchecked") + TSimpleStreamImpl castCurrent = (TSimpleStreamImpl) current; + if (castCurrent.next(consumer)) { + return true; + } + current = null; + } else { + iterator = current.iterator(); + while (iterator.hasNext()) { + T e = iterator.next(); + if (!consumer.test(e)) { + return true; + } + } + iterator = null; + current = null; + } + return true; } @Override diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingToDoubleStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingToDoubleStreamImpl.java index f32fb25bb..3cd53ce6d 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingToDoubleStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingToDoubleStreamImpl.java @@ -24,6 +24,7 @@ import org.teavm.classlib.java.util.stream.doubleimpl.TSimpleDoubleStreamImpl; public class TFlatMappingToDoubleStreamImpl extends TSimpleDoubleStreamImpl { private TSimpleStreamImpl sourceStream; private TDoubleStream current; + private boolean currentSet; private PrimitiveIterator.OfDouble iterator; private Function mapper; private boolean done; @@ -36,42 +37,44 @@ public class TFlatMappingToDoubleStreamImpl extends TSimpleDoubleStreamImpl { @Override public boolean next(DoublePredicate consumer) { - while (true) { - if (current == null) { - if (done) { - return false; - } + if (current == null) { + if (done) { + return false; + } + currentSet = false; + while (!currentSet) { boolean hasMore = sourceStream.next(e -> { current = mapper.apply(e); + currentSet = true; return false; }); if (!hasMore) { done = true; - } - if (current == null) { - done = true; - return false; + break; } } - if (current instanceof TSimpleDoubleStreamImpl) { - @SuppressWarnings("unchecked") - TSimpleDoubleStreamImpl castCurrent = (TSimpleDoubleStreamImpl) current; - if (castCurrent.next(consumer)) { - return true; - } - current = null; - } else { - iterator = current.iterator(); - while (iterator.hasNext()) { - double e = iterator.nextDouble(); - if (!consumer.test(e)) { - return true; - } - } - iterator = null; - current = null; + if (current == null) { + return false; } } + if (current instanceof TSimpleDoubleStreamImpl) { + TSimpleDoubleStreamImpl castCurrent = (TSimpleDoubleStreamImpl) current; + if (castCurrent.next(consumer)) { + return true; + } + current = null; + } else { + iterator = current.iterator(); + while (iterator.hasNext()) { + double e = iterator.next(); + if (!consumer.test(e)) { + return true; + } + } + iterator = null; + current = null; + } + return true; } @Override diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingToIntStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingToIntStreamImpl.java index 423b6cdde..6e870a7b7 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingToIntStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingToIntStreamImpl.java @@ -24,6 +24,7 @@ import org.teavm.classlib.java.util.stream.intimpl.TSimpleIntStreamImpl; public class TFlatMappingToIntStreamImpl extends TSimpleIntStreamImpl { private TSimpleStreamImpl sourceStream; private TIntStream current; + private boolean currentSet; private PrimitiveIterator.OfInt iterator; private Function mapper; private boolean done; @@ -36,42 +37,44 @@ public class TFlatMappingToIntStreamImpl extends TSimpleIntStreamImpl { @Override public boolean next(IntPredicate consumer) { - while (true) { - if (current == null) { - if (done) { - return false; - } + if (current == null) { + if (done) { + return false; + } + currentSet = false; + while (!currentSet) { boolean hasMore = sourceStream.next(e -> { current = mapper.apply(e); + currentSet = true; return false; }); if (!hasMore) { done = true; - } - if (current == null) { - done = true; - return false; + break; } } - if (current instanceof TSimpleIntStreamImpl) { - @SuppressWarnings("unchecked") - TSimpleIntStreamImpl castCurrent = (TSimpleIntStreamImpl) current; - if (castCurrent.next(consumer)) { - return true; - } - current = null; - } else { - iterator = current.iterator(); - while (iterator.hasNext()) { - int e = iterator.nextInt(); - if (!consumer.test(e)) { - return true; - } - } - iterator = null; - current = null; + if (current == null) { + return false; } } + if (current instanceof TSimpleIntStreamImpl) { + TSimpleIntStreamImpl castCurrent = (TSimpleIntStreamImpl) current; + if (castCurrent.next(consumer)) { + return true; + } + current = null; + } else { + iterator = current.iterator(); + while (iterator.hasNext()) { + int e = iterator.next(); + if (!consumer.test(e)) { + return true; + } + } + iterator = null; + current = null; + } + return true; } @Override diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingToLongStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingToLongStreamImpl.java index 9183fa208..09c6ef3cb 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingToLongStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TFlatMappingToLongStreamImpl.java @@ -24,6 +24,7 @@ import org.teavm.classlib.java.util.stream.longimpl.TSimpleLongStreamImpl; public class TFlatMappingToLongStreamImpl extends TSimpleLongStreamImpl { private TSimpleStreamImpl sourceStream; private TLongStream current; + private boolean currentSet; private PrimitiveIterator.OfLong iterator; private Function mapper; private boolean done; @@ -36,42 +37,44 @@ public class TFlatMappingToLongStreamImpl extends TSimpleLongStreamImpl { @Override public boolean next(LongPredicate consumer) { - while (true) { - if (current == null) { - if (done) { - return false; - } + if (current == null) { + if (done) { + return false; + } + currentSet = false; + while (!currentSet) { boolean hasMore = sourceStream.next(e -> { current = mapper.apply(e); + currentSet = true; return false; }); if (!hasMore) { done = true; - } - if (current == null) { - done = true; - return false; + break; } } - if (current instanceof TSimpleLongStreamImpl) { - @SuppressWarnings("unchecked") - TSimpleLongStreamImpl castCurrent = (TSimpleLongStreamImpl) current; - if (castCurrent.next(consumer)) { - return true; - } - current = null; - } else { - iterator = current.iterator(); - while (iterator.hasNext()) { - long e = iterator.nextLong(); - if (!consumer.test(e)) { - return true; - } - } - iterator = null; - current = null; + if (current == null) { + return false; } } + if (current instanceof TSimpleLongStreamImpl) { + TSimpleLongStreamImpl castCurrent = (TSimpleLongStreamImpl) current; + if (castCurrent.next(consumer)) { + return true; + } + current = null; + } else { + iterator = current.iterator(); + while (iterator.hasNext()) { + long e = iterator.next(); + if (!consumer.test(e)) { + return true; + } + } + iterator = null; + current = null; + } + return true; } @Override diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSimpleStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSimpleStreamImpl.java index ff37e066a..00068b078 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSimpleStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSimpleStreamImpl.java @@ -123,10 +123,15 @@ public abstract class TSimpleStreamImpl implements TStream { @Override public void forEachOrdered(Consumer action) { - next(e -> { - action.accept(e); - return true; - }); + while (true) { + boolean hasMore = next(e -> { + action.accept(e); + return true; + }); + if (!hasMore) { + return; + } + } } @Override @@ -140,7 +145,9 @@ public abstract class TSimpleStreamImpl implements TStream { int estimatedSize = estimateSize(); if (estimatedSize < 0) { List list = new ArrayList<>(); - next(list::add); + while (next(list::add)) { + // go on + } A[] array = generator.apply(list.size()); for (int i = 0; i < array.length; ++i) { array[i] = (A) list.get(i); @@ -148,9 +155,10 @@ public abstract class TSimpleStreamImpl implements TStream { return array; } else { A[] array = generator.apply(estimatedSize); - ArrayFillingConsumer consumer = new ArrayFillingConsumer<>(array); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have reported done status"; + ArrayFillingConsumer consumer = new ArrayFillingConsumer<>(array); + while (next(consumer)) { + // go on + } if (consumer.index < array.length) { array = Arrays.copyOf(array, consumer.index); } @@ -161,34 +169,42 @@ public abstract class TSimpleStreamImpl implements TStream { @Override public T reduce(T identity, BinaryOperator accumulator) { TReducingConsumer consumer = new TReducingConsumer<>(accumulator, identity, true); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have returned true"; + while (next(consumer)) { + // go on + } return consumer.result; } @Override public Optional reduce(BinaryOperator accumulator) { TReducingConsumer consumer = new TReducingConsumer<>(accumulator, null, false); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have returned true"; + while (next(consumer)) { + // go on + } return Optional.ofNullable(consumer.result); } @Override public U reduce(U identity, BiFunction accumulator, BinaryOperator combiner) { TReducingConsumer2 consumer = new TReducingConsumer2<>(accumulator, identity); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have returned true"; + while (next(consumer)) { + // go on + } return consumer.result; } @Override public R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner) { R collection = supplier.get(); - next(e -> { - accumulator.accept(collection, e); - return true; - }); + while (true) { + boolean hasMore = next(e -> { + accumulator.accept(collection, e); + return true; + }); + if (!hasMore) { + break; + } + } return collection; } @@ -216,18 +232,28 @@ public abstract class TSimpleStreamImpl implements TStream { @Override public long count() { TCountingConsumer consumer = new TCountingConsumer<>(); - next(consumer); + while (next(consumer)) { + // go on + } return consumer.count; } @Override public boolean anyMatch(Predicate predicate) { - return next(predicate.negate()); + TAnyMatchConsumer consumer = new TAnyMatchConsumer<>(predicate); + while (!consumer.matched && next(consumer)) { + // go on + } + return consumer.matched; } @Override public boolean allMatch(Predicate predicate) { - return !next(predicate); + TAllMatchConsumer consumer = new TAllMatchConsumer<>(predicate); + while (consumer.matched && next(consumer)) { + // go on + } + return consumer.matched; } @Override @@ -238,7 +264,9 @@ public abstract class TSimpleStreamImpl implements TStream { @Override public Optional findFirst() { TFindFirstConsumer consumer = new TFindFirstConsumer<>(); - next(consumer); + while (consumer.result == null && next(consumer)) { + // go on + } return Optional.ofNullable(consumer.result); } @@ -292,7 +320,7 @@ public abstract class TSimpleStreamImpl implements TStream { public abstract boolean next(Predicate consumer); - class ArrayFillingConsumer implements Predicate { + static class ArrayFillingConsumer implements Predicate { A[] array; int index; diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSimpleStreamIterator.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSimpleStreamIterator.java index 6b4659802..72e0eaf88 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSimpleStreamIterator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSimpleStreamIterator.java @@ -63,13 +63,21 @@ public class TSimpleStreamIterator implements Iterator { if (state != NEEDS_MORE) { return; } - boolean hasMore = stream.next(e -> { - lastElement = e; - return false; - }); - state = hasMore ? HAS_DATA : LAST_ELEMENT; - if (state == LAST_ELEMENT) { - stream = null; + state = NEEDS_MORE; + while (state == NEEDS_MORE) { + boolean hasMore = stream.next(e -> { + lastElement = e; + state = HAS_DATA; + return false; + }); + if (!hasMore) { + if (state == NEEDS_MORE) { + state = DONE; + } else { + state = LAST_ELEMENT; + } + stream = null; + } } } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSimpleStreamSpliterator.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSimpleStreamSpliterator.java index 45a0cdee5..25c294e16 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSimpleStreamSpliterator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSimpleStreamSpliterator.java @@ -20,6 +20,7 @@ import java.util.function.Consumer; public class TSimpleStreamSpliterator implements Spliterator { private TSimpleStreamImpl stream; + private boolean foundItems; private boolean done; public TSimpleStreamSpliterator(TSimpleStreamImpl stream) { @@ -28,10 +29,15 @@ public class TSimpleStreamSpliterator implements Spliterator { @Override public void forEachRemaining(Consumer action) { - stream.next(x -> { - action.accept(x); - return true; - }); + while (true) { + boolean hasMore = stream.next(x -> { + action.accept(x); + return true; + }); + if (!hasMore) { + break; + } + } } @Override @@ -39,10 +45,14 @@ public class TSimpleStreamSpliterator implements Spliterator { if (done) { return false; } - done = !stream.next(x -> { - action.accept(x); - return false; - }); + foundItems = false; + while (!foundItems && !done) { + done = !stream.next(x -> { + action.accept(x); + foundItems = true; + return false; + }); + } return true; } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSkippingStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSkippingStreamImpl.java index 20c6b944d..fffb57d98 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSkippingStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSkippingStreamImpl.java @@ -30,7 +30,7 @@ public class TSkippingStreamImpl extends TSimpleStreamImpl { @Override public boolean next(Predicate consumer) { - if (remaining > 0) { + while (remaining > 0) { if (!sourceStream.next(e -> --remaining > 0)) { return false; } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSpecializedConcatStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSpecializedConcatStream.java index 5b9e3ded4..74326bb3b 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSpecializedConcatStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TSpecializedConcatStream.java @@ -33,16 +33,15 @@ public class TSpecializedConcatStream extends TSimpleStreamImpl { if (current == null) { return false; } - while (true) { - if (current.next(consumer)) { - return true; - } - if (current == first) { - current = second; - } else { - current = null; - return false; - } + if (current.next(consumer)) { + return true; + } + if (current == first) { + current = second; + return true; + } else { + current = null; + return false; } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TAllMatchConsumer.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TAllMatchConsumer.java new file mode 100644 index 000000000..c0ac87d03 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TAllMatchConsumer.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Alexey Andreev. + * + * 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 org.teavm.classlib.java.util.stream.intimpl; + +import java.util.function.IntPredicate; + +public class TAllMatchConsumer implements IntPredicate { + public boolean matched = true; + private IntPredicate predicate; + + public TAllMatchConsumer(IntPredicate predicate) { + this.predicate = predicate; + } + + @Override + public boolean test(int t) { + if (!predicate.test(t)) { + matched = false; + } + return matched; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TAnyMatchConsumer.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TAnyMatchConsumer.java new file mode 100644 index 000000000..834c49cae --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TAnyMatchConsumer.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019 Alexey Andreev. + * + * 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 org.teavm.classlib.java.util.stream.intimpl; + +import java.util.function.IntPredicate; + +public class TAnyMatchConsumer implements IntPredicate { + public boolean matched; + private IntPredicate predicate; + + public TAnyMatchConsumer(IntPredicate predicate) { + this.predicate = predicate; + } + + @Override + public boolean test(int t) { + matched = predicate.test(t); + return !matched; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TEmptyIntStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TEmptyIntStreamImpl.java index ad8beacb6..57b6a3115 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TEmptyIntStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TEmptyIntStreamImpl.java @@ -30,6 +30,6 @@ public class TEmptyIntStreamImpl extends TSimpleIntStreamImpl { @Override public long count() { - return 1; + return 0; } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TFlatMappingIntStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TFlatMappingIntStreamImpl.java index 06f48ac41..39aca329f 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TFlatMappingIntStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TFlatMappingIntStreamImpl.java @@ -22,6 +22,7 @@ import org.teavm.classlib.java.util.stream.TIntStream; public class TFlatMappingIntStreamImpl extends TSimpleIntStreamImpl { private TSimpleIntStreamImpl sourceStream; + private boolean currentSet; private TIntStream current; private PrimitiveIterator.OfInt iterator; private IntFunction mapper; @@ -34,42 +35,44 @@ public class TFlatMappingIntStreamImpl extends TSimpleIntStreamImpl { @Override public boolean next(IntPredicate consumer) { - while (true) { - if (current == null) { - if (done) { - return false; - } + if (current == null) { + if (done) { + return false; + } + currentSet = false; + while (!currentSet) { boolean hasMore = sourceStream.next(e -> { current = mapper.apply(e); + currentSet = true; return false; }); if (!hasMore) { done = true; - } - if (current == null) { - done = true; - return false; + break; } } - if (current instanceof TSimpleIntStreamImpl) { - @SuppressWarnings("unchecked") - TSimpleIntStreamImpl castCurrent = (TSimpleIntStreamImpl) current; - if (castCurrent.next(consumer)) { - return true; - } - current = null; - } else { - iterator = current.iterator(); - while (iterator.hasNext()) { - int e = iterator.nextInt(); - if (!consumer.test(e)) { - return true; - } - } - iterator = null; - current = null; + if (current == null) { + return false; } } + if (current instanceof TSimpleIntStreamImpl) { + TSimpleIntStreamImpl castCurrent = (TSimpleIntStreamImpl) current; + if (castCurrent.next(consumer)) { + return true; + } + current = null; + } else { + iterator = current.iterator(); + while (iterator.hasNext()) { + int e = iterator.next(); + if (!consumer.test(e)) { + return true; + } + } + iterator = null; + current = null; + } + return true; } @Override diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSimpleIntStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSimpleIntStreamImpl.java index d938fc7cb..287fcde67 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSimpleIntStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSimpleIntStreamImpl.java @@ -102,10 +102,15 @@ public abstract class TSimpleIntStreamImpl implements TIntStream { @Override public void forEachOrdered(IntConsumer action) { - next(e -> { - action.accept(e); - return true; - }); + while (true) { + boolean hasMore = next(e -> { + action.accept(e); + return true; + }); + if (!hasMore) { + return; + } + } } @Override @@ -113,7 +118,9 @@ public abstract class TSimpleIntStreamImpl implements TIntStream { int estimatedSize = estimateSize(); if (estimatedSize < 0) { List list = new ArrayList<>(); - next(list::add); + while (next(list::add)) { + // go on + } int[] array = new int[list.size()]; for (int i = 0; i < array.length; ++i) { array[i] = list.get(i); @@ -122,8 +129,9 @@ public abstract class TSimpleIntStreamImpl implements TIntStream { } else { int[] array = new int[estimatedSize]; ArrayFillingConsumer consumer = new ArrayFillingConsumer(array); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have reported done status"; + while (next(consumer)) { + // go on + } if (consumer.index < array.length) { array = Arrays.copyOf(array, consumer.index); } @@ -134,26 +142,33 @@ public abstract class TSimpleIntStreamImpl implements TIntStream { @Override public int reduce(int identity, IntBinaryOperator accumulator) { TReducingIntConsumer consumer = new TReducingIntConsumer(accumulator, identity, true); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have returned true"; + while (next(consumer)) { + // go on + } return consumer.result; } @Override public OptionalInt reduce(IntBinaryOperator accumulator) { TReducingIntConsumer consumer = new TReducingIntConsumer(accumulator, 0, false); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have returned true"; + while (next(consumer)) { + // go on + } return consumer.initialized ? OptionalInt.of(consumer.result) : OptionalInt.empty(); } @Override public R collect(Supplier supplier, ObjIntConsumer accumulator, BiConsumer combiner) { R collection = supplier.get(); - next(e -> { - accumulator.accept(collection, e); - return true; - }); + while (true) { + boolean hasMore = next(e -> { + accumulator.accept(collection, e); + return true; + }); + if (!hasMore) { + break; + } + } return collection; } @@ -170,32 +185,46 @@ public abstract class TSimpleIntStreamImpl implements TIntStream { @Override public long count() { TCountingIntConsumer consumer = new TCountingIntConsumer(); - next(consumer); + while (next(consumer)) { + // go on + } return consumer.count; } @Override public int sum() { TSumIntConsumer consumer = new TSumIntConsumer(); - next(consumer); + while (next(consumer)) { + // go on + } return consumer.sum; } @Override public OptionalDouble average() { TSumIntAsDoubleConsumer consumer = new TSumIntAsDoubleConsumer(); - next(consumer); + while (next(consumer)) { + // go on + } return consumer.count > 0 ? OptionalDouble.of(consumer.sum / consumer.count) : OptionalDouble.empty(); } @Override public boolean anyMatch(IntPredicate predicate) { - return next(predicate.negate()); + TAnyMatchConsumer consumer = new TAnyMatchConsumer(predicate); + while (!consumer.matched && next(consumer)) { + // go on + } + return consumer.matched; } @Override public boolean allMatch(IntPredicate predicate) { - return !next(predicate); + TAllMatchConsumer consumer = new TAllMatchConsumer(predicate); + while (consumer.matched && next(consumer)) { + // go on + } + return consumer.matched; } @Override @@ -206,7 +235,9 @@ public abstract class TSimpleIntStreamImpl implements TIntStream { @Override public OptionalInt findFirst() { TFindFirstIntConsumer consumer = new TFindFirstIntConsumer(); - next(consumer); + while (!consumer.hasAny && next(consumer)) { + // go on + } return consumer.hasAny ? OptionalInt.of(consumer.result) : OptionalInt.empty(); } @@ -275,7 +306,7 @@ public abstract class TSimpleIntStreamImpl implements TIntStream { public abstract boolean next(IntPredicate consumer); - class ArrayFillingConsumer implements IntPredicate { + static class ArrayFillingConsumer implements IntPredicate { int[] array; int index; diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSimpleIntStreamIterator.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSimpleIntStreamIterator.java index c6dd23c7c..8dd0052ae 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSimpleIntStreamIterator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSimpleIntStreamIterator.java @@ -53,13 +53,21 @@ public class TSimpleIntStreamIterator implements PrimitiveIterator.OfInt { if (state != NEEDS_MORE) { return; } - boolean hasMore = stream.next(e -> { - lastElement = e; - return false; - }); - state = hasMore ? HAS_DATA : LAST_ELEMENT; - if (state == LAST_ELEMENT) { - stream = null; + state = NEEDS_MORE; + while (state == NEEDS_MORE) { + boolean hasMore = stream.next(e -> { + lastElement = e; + state = HAS_DATA; + return false; + }); + if (!hasMore) { + if (state == NEEDS_MORE) { + state = DONE; + } else { + state = LAST_ELEMENT; + } + stream = null; + } } } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSimpleIntStreamSpliterator.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSimpleIntStreamSpliterator.java index ed99714e7..6913c94a8 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSimpleIntStreamSpliterator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSimpleIntStreamSpliterator.java @@ -20,6 +20,7 @@ import java.util.function.IntConsumer; public class TSimpleIntStreamSpliterator implements Spliterator.OfInt { private TSimpleIntStreamImpl stream; + private boolean foundItems; private boolean done; public TSimpleIntStreamSpliterator(TSimpleIntStreamImpl stream) { @@ -39,10 +40,14 @@ public class TSimpleIntStreamSpliterator implements Spliterator.OfInt { if (done) { return false; } - done = !stream.next(x -> { - action.accept(x); - return false; - }); + foundItems = false; + while (!foundItems && !done) { + done = !stream.next(x -> { + action.accept(x); + foundItems = true; + return false; + }); + } return true; } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSkippingIntStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSkippingIntStreamImpl.java index c9cd9d9d8..17e1b8055 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSkippingIntStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSkippingIntStreamImpl.java @@ -30,7 +30,7 @@ public class TSkippingIntStreamImpl extends TSimpleIntStreamImpl { @Override public boolean next(IntPredicate consumer) { - if (remaining > 0) { + while (remaining > 0) { if (!sourceStream.next(e -> --remaining > 0)) { return false; } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSpecializedConcatIntStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSpecializedConcatIntStream.java index 37e7d4484..b0b55f5ca 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSpecializedConcatIntStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSpecializedConcatIntStream.java @@ -33,16 +33,15 @@ public class TSpecializedConcatIntStream extends TSimpleIntStreamImpl { if (current == null) { return false; } - while (true) { - if (current.next(consumer)) { - return true; - } - if (current == first) { - current = second; - } else { - current = null; - return false; - } + if (current.next(consumer)) { + return true; + } + if (current == first) { + current = second; + return true; + } else { + current = null; + return false; } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TAllMatchConsumer.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TAllMatchConsumer.java new file mode 100644 index 000000000..acadb3436 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TAllMatchConsumer.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Alexey Andreev. + * + * 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 org.teavm.classlib.java.util.stream.longimpl; + +import java.util.function.LongPredicate; + +public class TAllMatchConsumer implements LongPredicate { + public boolean matched = true; + private LongPredicate predicate; + + public TAllMatchConsumer(LongPredicate predicate) { + this.predicate = predicate; + } + + @Override + public boolean test(long t) { + if (!predicate.test(t)) { + matched = false; + } + return matched; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TAnyMatchConsumer.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TAnyMatchConsumer.java new file mode 100644 index 000000000..476dd3618 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TAnyMatchConsumer.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019 Alexey Andreev. + * + * 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 org.teavm.classlib.java.util.stream.longimpl; + +import java.util.function.LongPredicate; + +public class TAnyMatchConsumer implements LongPredicate { + public boolean matched; + private LongPredicate predicate; + + public TAnyMatchConsumer(LongPredicate predicate) { + this.predicate = predicate; + } + + @Override + public boolean test(long t) { + matched = predicate.test(t); + return !matched; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TEmptyLongStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TEmptyLongStreamImpl.java index 96ec04b0f..b0c336e68 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TEmptyLongStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TEmptyLongStreamImpl.java @@ -30,6 +30,6 @@ public class TEmptyLongStreamImpl extends TSimpleLongStreamImpl { @Override public long count() { - return 1; + return 0; } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TFlatMappingLongStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TFlatMappingLongStreamImpl.java index cd5709a24..a0ec84c6c 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TFlatMappingLongStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TFlatMappingLongStreamImpl.java @@ -22,6 +22,7 @@ import org.teavm.classlib.java.util.stream.TLongStream; public class TFlatMappingLongStreamImpl extends TSimpleLongStreamImpl { private TSimpleLongStreamImpl sourceStream; + private boolean currentSet; private TLongStream current; private PrimitiveIterator.OfLong iterator; private LongFunction mapper; @@ -34,42 +35,44 @@ public class TFlatMappingLongStreamImpl extends TSimpleLongStreamImpl { @Override public boolean next(LongPredicate consumer) { - while (true) { - if (current == null) { - if (done) { - return false; - } + if (current == null) { + if (done) { + return false; + } + currentSet = false; + while (!currentSet) { boolean hasMore = sourceStream.next(e -> { current = mapper.apply(e); + currentSet = true; return false; }); if (!hasMore) { done = true; - } - if (current == null) { - done = true; - return false; + break; } } - if (current instanceof TSimpleLongStreamImpl) { - @SuppressWarnings("unchecked") - TSimpleLongStreamImpl castCurrent = (TSimpleLongStreamImpl) current; - if (castCurrent.next(consumer)) { - return true; - } - current = null; - } else { - iterator = current.iterator(); - while (iterator.hasNext()) { - long e = iterator.nextLong(); - if (!consumer.test(e)) { - return true; - } - } - iterator = null; - current = null; + if (current == null) { + return false; } } + if (current instanceof TSimpleLongStreamImpl) { + TSimpleLongStreamImpl castCurrent = (TSimpleLongStreamImpl) current; + if (castCurrent.next(consumer)) { + return true; + } + current = null; + } else { + iterator = current.iterator(); + while (iterator.hasNext()) { + long e = iterator.next(); + if (!consumer.test(e)) { + return true; + } + } + iterator = null; + current = null; + } + return true; } @Override diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSimpleLongStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSimpleLongStreamImpl.java index dd4462ac4..8a3de4df4 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSimpleLongStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSimpleLongStreamImpl.java @@ -102,10 +102,15 @@ public abstract class TSimpleLongStreamImpl implements TLongStream { @Override public void forEachOrdered(LongConsumer action) { - next(e -> { - action.accept(e); - return true; - }); + while (true) { + boolean hasMore = next(e -> { + action.accept(e); + return true; + }); + if (!hasMore) { + return; + } + } } @Override @@ -113,7 +118,9 @@ public abstract class TSimpleLongStreamImpl implements TLongStream { int estimatedSize = estimateSize(); if (estimatedSize < 0) { List list = new ArrayList<>(); - next(list::add); + while (next(list::add)) { + // go on + } long[] array = new long[list.size()]; for (int i = 0; i < array.length; ++i) { array[i] = list.get(i); @@ -122,8 +129,9 @@ public abstract class TSimpleLongStreamImpl implements TLongStream { } else { long[] array = new long[estimatedSize]; ArrayFillingConsumer consumer = new ArrayFillingConsumer(array); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have reported done status"; + while (next(consumer)) { + // go on + } if (consumer.index < array.length) { array = Arrays.copyOf(array, consumer.index); } @@ -134,26 +142,33 @@ public abstract class TSimpleLongStreamImpl implements TLongStream { @Override public long reduce(long identity, LongBinaryOperator accumulator) { TReducingLongConsumer consumer = new TReducingLongConsumer(accumulator, identity, true); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have returned true"; + while (next(consumer)) { + // go on + } return consumer.result; } @Override public OptionalLong reduce(LongBinaryOperator accumulator) { TReducingLongConsumer consumer = new TReducingLongConsumer(accumulator, 0, false); - boolean wantsMore = next(consumer); - assert !wantsMore : "next() should have returned true"; + while (next(consumer)) { + // go on + } return consumer.initialized ? OptionalLong.of(consumer.result) : OptionalLong.empty(); } @Override public R collect(Supplier supplier, ObjLongConsumer accumulator, BiConsumer combiner) { R collection = supplier.get(); - next(e -> { - accumulator.accept(collection, e); - return true; - }); + while (true) { + boolean hasMore = next(e -> { + accumulator.accept(collection, e); + return true; + }); + if (!hasMore) { + break; + } + } return collection; } @@ -170,32 +185,46 @@ public abstract class TSimpleLongStreamImpl implements TLongStream { @Override public long count() { TCountingLongConsumer consumer = new TCountingLongConsumer(); - next(consumer); + while (next(consumer)) { + // go on + } return consumer.count; } @Override public long sum() { TSumLongConsumer consumer = new TSumLongConsumer(); - next(consumer); + while (next(consumer)) { + // go on + } return consumer.sum; } @Override public OptionalDouble average() { TSumLongAsDoubleConsumer consumer = new TSumLongAsDoubleConsumer(); - next(consumer); + while (next(consumer)) { + // go on + } return consumer.count > 0 ? OptionalDouble.of(consumer.sum / consumer.count) : OptionalDouble.empty(); } @Override public boolean anyMatch(LongPredicate predicate) { - return next(predicate.negate()); + TAnyMatchConsumer consumer = new TAnyMatchConsumer(predicate); + while (!consumer.matched && next(consumer)) { + // go on + } + return consumer.matched; } @Override public boolean allMatch(LongPredicate predicate) { - return !next(predicate); + TAllMatchConsumer consumer = new TAllMatchConsumer(predicate); + while (consumer.matched && next(consumer)) { + // go on + } + return consumer.matched; } @Override @@ -206,7 +235,9 @@ public abstract class TSimpleLongStreamImpl implements TLongStream { @Override public OptionalLong findFirst() { TFindFirstLongConsumer consumer = new TFindFirstLongConsumer(); - next(consumer); + while (!consumer.hasAny && next(consumer)) { + // go on + } return consumer.hasAny ? OptionalLong.of(consumer.result) : OptionalLong.empty(); } @@ -270,7 +301,7 @@ public abstract class TSimpleLongStreamImpl implements TLongStream { public abstract boolean next(LongPredicate consumer); - class ArrayFillingConsumer implements LongPredicate { + static class ArrayFillingConsumer implements LongPredicate { long[] array; int index; diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSimpleLongStreamIterator.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSimpleLongStreamIterator.java index 7f9e0bb45..20f8b7724 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSimpleLongStreamIterator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSimpleLongStreamIterator.java @@ -53,13 +53,21 @@ public class TSimpleLongStreamIterator implements PrimitiveIterator.OfLong { if (state != NEEDS_MORE) { return; } - boolean hasMore = stream.next(e -> { - lastElement = e; - return false; - }); - state = hasMore ? HAS_DATA : LAST_ELEMENT; - if (state == LAST_ELEMENT) { - stream = null; + state = NEEDS_MORE; + while (state == NEEDS_MORE) { + boolean hasMore = stream.next(e -> { + lastElement = e; + state = HAS_DATA; + return false; + }); + if (!hasMore) { + if (state == NEEDS_MORE) { + state = DONE; + } else { + state = LAST_ELEMENT; + } + stream = null; + } } } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSimpleLongStreamSpliterator.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSimpleLongStreamSpliterator.java index 8e0df0cb3..bfa2f8d8a 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSimpleLongStreamSpliterator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSimpleLongStreamSpliterator.java @@ -20,6 +20,7 @@ import java.util.function.LongConsumer; public class TSimpleLongStreamSpliterator implements Spliterator.OfLong { private TSimpleLongStreamImpl stream; + private boolean foundItems; private boolean done; public TSimpleLongStreamSpliterator(TSimpleLongStreamImpl stream) { @@ -39,10 +40,14 @@ public class TSimpleLongStreamSpliterator implements Spliterator.OfLong { if (done) { return false; } - done = !stream.next(x -> { - action.accept(x); - return false; - }); + foundItems = false; + while (!foundItems && !done) { + done = !stream.next(x -> { + action.accept(x); + foundItems = true; + return false; + }); + } return true; } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSkippingLongStreamImpl.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSkippingLongStreamImpl.java index 1a9b560da..e7aa3a188 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSkippingLongStreamImpl.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSkippingLongStreamImpl.java @@ -30,7 +30,7 @@ public class TSkippingLongStreamImpl extends TSimpleLongStreamImpl { @Override public boolean next(LongPredicate consumer) { - if (remaining > 0) { + while (remaining > 0) { if (!sourceStream.next(e -> --remaining > 0)) { return false; } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSpecializedConcatLongStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSpecializedConcatLongStream.java index 00ac7a5e8..c1314d436 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSpecializedConcatLongStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSpecializedConcatLongStream.java @@ -33,16 +33,15 @@ public class TSpecializedConcatLongStream extends TSimpleLongStreamImpl { if (current == null) { return false; } - while (true) { - if (current.next(consumer)) { - return true; - } - if (current == first) { - current = second; - } else { - current = null; - return false; - } + if (current.next(consumer)) { + return true; + } + if (current == first) { + current = second; + return true; + } else { + current = null; + return false; } } diff --git a/tests/src/test/java/org/teavm/classlib/java/util/stream/DoubleStreamTest.java b/tests/src/test/java/org/teavm/classlib/java/util/stream/DoubleStreamTest.java index baee5ead5..580fa4649 100644 --- a/tests/src/test/java/org/teavm/classlib/java/util/stream/DoubleStreamTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/util/stream/DoubleStreamTest.java @@ -19,13 +19,15 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.teavm.classlib.java.util.stream.Helper.appendDoubleNumbersTo; +import static org.teavm.classlib.java.util.stream.Helper.testDoubleStream; +import static org.teavm.classlib.java.util.stream.Helper.testIntStream; +import static org.teavm.classlib.java.util.stream.Helper.testIntegerStream; +import static org.teavm.classlib.java.util.stream.Helper.testLongStream; import java.util.PrimitiveIterator; import java.util.Spliterator; -import java.util.function.DoubleConsumer; -import java.util.function.IntConsumer; -import java.util.function.LongConsumer; -import java.util.stream.Collectors; import java.util.stream.DoubleStream; +import java.util.stream.LongStream; import org.junit.Test; import org.junit.runner.RunWith; import org.teavm.junit.TeaVMTestRunner; @@ -34,85 +36,94 @@ import org.teavm.junit.TeaVMTestRunner; public class DoubleStreamTest { @Test public void forEachWorks() { - StringBuilder sb = new StringBuilder(); - DoubleStream.of(1, 2, 3).forEach(appendNumbersTo(sb)); - assertEquals("1.0;2.0;3.0;", sb.toString()); + testDoubleStream(() -> DoubleStream.of(1, 2, 3), 1, 2, 3); + testDoubleStream(() -> DoubleStream.concat(DoubleStream.of(1), DoubleStream.of(2, 3)), 1, 2, 3); + testDoubleStream(() -> DoubleStream.concat(DoubleStream.empty(), DoubleStream.of(1, 2, 3)), 1, 2, 3); } @Test public void mapWorks() { - StringBuilder sb = new StringBuilder(); - DoubleStream.of(1, 2, 3).map(n -> n * n).forEach(appendNumbersTo(sb)); - assertEquals("1.0;4.0;9.0;", sb.toString()); + testDoubleStream(() -> DoubleStream.of(1, 2, 3).map(n -> n * n), 1, 4, 9); + testDoubleStream(() -> DoubleStream.concat(DoubleStream.of(1), DoubleStream.of(2, 3)) + .map(n -> n * n), 1, 4, 9); + testDoubleStream(() -> DoubleStream.concat(DoubleStream.empty(), DoubleStream.of(1, 2, 3)) + .map(n -> n * n), 1, 4, 9); } @Test public void mapToObjWorks() { - String result = DoubleStream.of(1, 2, 3).mapToObj(n -> String.valueOf(n * n)).collect(Collectors.joining(";")); - assertEquals("1.0;4.0;9.0", result); + testIntegerStream(() -> DoubleStream.of(1, 2, 3).mapToObj(n -> (int) (n * n)), 1, 4, 9); + testIntegerStream(() -> DoubleStream.concat(DoubleStream.of(1), DoubleStream.of(2, 3)) + .mapToObj(n -> (int) (n * n)), 1, 4, 9); + testIntegerStream(() -> DoubleStream.concat(DoubleStream.empty(), DoubleStream.of(1, 2, 3)) + .mapToObj(n -> (int) (n * n)), 1, 4, 9); } @Test public void mapToIntWorks() { - StringBuilder sb = new StringBuilder(); - DoubleStream.of(1, 2, 3).mapToInt(n -> (int) (n * n)).forEach(appendIntNumbersTo(sb)); - assertEquals("1;4;9;", sb.toString()); + testIntStream(() -> DoubleStream.of(1, 2, 3).mapToInt(n -> (int) (n * n)), 1, 4, 9); + testIntStream(() -> DoubleStream.concat(DoubleStream.of(1), DoubleStream.of(2, 3)) + .mapToInt(n -> (int) (n * n)), 1, 4, 9); + testIntStream(() -> DoubleStream.concat(DoubleStream.empty(), DoubleStream.of(1, 2, 3)) + .mapToInt(n -> (int) (n * n)), 1, 4, 9); } @Test public void mapToLongWorks() { - StringBuilder sb = new StringBuilder(); - DoubleStream.of(1, 2, 3).mapToLong(n -> (long) (n * n)).forEach(appendLongNumbersTo(sb)); - assertEquals("1;4;9;", sb.toString()); + testLongStream(() -> DoubleStream.of(1, 2, 3).mapToLong(n -> (long) (n * n)), 1, 4, 9); + testLongStream(() -> DoubleStream.concat(DoubleStream.of(1), DoubleStream.of(2, 3)) + .mapToLong(n -> (long) (n * n)), 1, 4, 9); + testLongStream(() -> DoubleStream.concat(DoubleStream.empty(), DoubleStream.of(1, 2, 3)) + .mapToLong(n -> (long) (n * n)), 1, 4, 9); } @Test public void filterWorks() { - StringBuilder sb = new StringBuilder(); - DoubleStream.of(1, 2, 3, 4, 5, 6).filter(n -> (n % 2) == 0).forEach(appendNumbersTo(sb)); - assertEquals("2.0;4.0;6.0;", sb.toString()); + testDoubleStream(() -> DoubleStream.of(1, 2, 3, 4, 5, 6).filter(n -> (n % 2) == 0), 2, 4, 6); + testDoubleStream(() -> DoubleStream.concat(DoubleStream.of(1), DoubleStream.of(2, 3, 4, 5, 6)) + .filter(n -> ((int) n & 1) == 0), 2, 4, 6); + testDoubleStream(() -> DoubleStream.concat(DoubleStream.empty(), DoubleStream.of(1, 2, 3, 4, 5, 6)) + .filter(n -> ((int) n & 1) == 0), 2, 4, 6); } @Test public void flatMapWorks() { - StringBuilder sb = new StringBuilder(); - DoubleStream.of(1, 3).flatMap(n -> DoubleStream.of(n, n + 1)).forEach(appendNumbersTo(sb)); - assertEquals("1.0;2.0;3.0;4.0;", sb.toString()); + testDoubleStream(() -> DoubleStream.of(1, 3).flatMap(n -> DoubleStream.of(n, n + 1)), 1, 2, 3, 4); + testDoubleStream(() -> DoubleStream.of(1, 3).flatMap(n -> DoubleStream.of(n, n + 1)).skip(1), 2, 3, 4); + testDoubleStream(() -> DoubleStream.of(1, 4).flatMap(n -> DoubleStream.of(n, n + 1, n + 2)).skip(3), 4, 5, 6); - sb.setLength(0); - DoubleStream.of(1, 3).flatMap(n -> DoubleStream.of(n, n + 1)).skip(1).forEach(appendNumbersTo(sb)); - assertEquals("2.0;3.0;4.0;", sb.toString()); - - sb.setLength(0); - DoubleStream.of(1, 4).flatMap(n -> DoubleStream.of(n, n + 1, n + 2)).skip(4).forEach(appendNumbersTo(sb)); - assertEquals("5.0;6.0;", sb.toString()); + testDoubleStream(() -> DoubleStream.of(1, 3, 100) + .flatMap(n -> n < 100 ? DoubleStream.of(n, n + 1) : DoubleStream.empty()), 1, 2, 3, 4); + testDoubleStream(() -> DoubleStream.of(100, 1, 3) + .flatMap(n -> n < 100 ? DoubleStream.of(n, n + 1) : DoubleStream.empty()), 1, 2, 3, 4); } @Test public void skipWorks() { - for (int i = 0; i <= 6; ++i) { - StringBuilder sb = new StringBuilder(); - DoubleStream.iterate(1, n -> n + 1).limit(5).skip(i).forEach(appendNumbersTo(sb)); - - StringBuilder expected = new StringBuilder(); + for (int i = 0; i <= 5; ++i) { + int index = i; + double[] expected = new double[5 - i]; for (int j = i; j < 5; ++j) { - expected.append((double) j + 1).append(';'); + expected[j - i] = j + 1; } - assertEquals("Error skipping " + i + " elements", expected.toString(), sb.toString()); + testDoubleStream(() -> DoubleStream.iterate(1, n -> n + 1).limit(5).skip(index), expected); + testDoubleStream(() -> DoubleStream.concat(DoubleStream.of(1), DoubleStream.iterate(2, n -> n + 1) + .limit(4)).skip(index), expected); + testDoubleStream(() -> DoubleStream.concat(DoubleStream.empty(), DoubleStream.iterate(1, n -> n + 1) + .limit(5)).skip(index), expected); } } @Test public void limitWorks() { for (int i = 0; i <= 3; ++i) { - StringBuilder sb = new StringBuilder(); - DoubleStream.iterate(1, n -> n + 1).limit(i).forEach(appendNumbersTo(sb)); - - StringBuilder expected = new StringBuilder(); - for (int j = 0; j < i; ++j) { - expected.append((double) j + 1).append(';'); + int index = i; + long[] expected = new long[i]; + for (int j = 0; j < expected.length; ++j) { + expected[j] = j + 1; } - assertEquals("Error limiting to " + i + " elements", expected.toString(), sb.toString()); + + testLongStream(() -> LongStream.iterate(1, n -> n + 1).limit(index), expected); } } @@ -135,19 +146,19 @@ public class DoubleStreamTest { @Test public void distinctWorks() { StringBuilder sb = new StringBuilder(); - DoubleStream.of(2, 3, 2, 3).distinct().forEach(appendNumbersTo(sb)); + DoubleStream.of(2, 3, 2, 3).distinct().forEach(appendDoubleNumbersTo(sb)); assertEquals("2.0;3.0;", sb.toString()); sb.setLength(0); - DoubleStream.of(2, 3, 2, 3).skip(1).distinct().forEach(appendNumbersTo(sb)); + DoubleStream.of(2, 3, 2, 3).skip(1).distinct().forEach(appendDoubleNumbersTo(sb)); assertEquals("3.0;2.0;", sb.toString()); sb.setLength(0); - DoubleStream.of(2, 3, 2, 3).limit(2).distinct().forEach(appendNumbersTo(sb)); + DoubleStream.of(2, 3, 2, 3).limit(2).distinct().forEach(appendDoubleNumbersTo(sb)); assertEquals("2.0;3.0;", sb.toString()); sb.setLength(0); - DoubleStream.of(2, 2, 3, 2, 4, 3, 1).distinct().forEach(appendNumbersTo(sb)); + DoubleStream.of(2, 2, 3, 2, 4, 3, 1).distinct().forEach(appendDoubleNumbersTo(sb)); assertEquals("2.0;3.0;4.0;1.0;", sb.toString()); } @@ -164,22 +175,22 @@ public class DoubleStreamTest { @Test public void concatWorks() { StringBuilder sb = new StringBuilder(); - DoubleStream.concat(DoubleStream.of(1, 2), DoubleStream.of(3, 4)).forEach(appendNumbersTo(sb)); + DoubleStream.concat(DoubleStream.of(1, 2), DoubleStream.of(3, 4)).forEach(appendDoubleNumbersTo(sb)); assertEquals("1.0;2.0;3.0;4.0;", sb.toString()); sb.setLength(0); - DoubleStream.concat(DoubleStream.of(1, 2), DoubleStream.of(3, 4)).skip(1).forEach(appendNumbersTo(sb)); + DoubleStream.concat(DoubleStream.of(1, 2), DoubleStream.of(3, 4)).skip(1).forEach(appendDoubleNumbersTo(sb)); assertEquals("2.0;3.0;4.0;", sb.toString()); sb.setLength(0); - DoubleStream.concat(DoubleStream.of(1, 2), DoubleStream.of(3, 4, 5)).skip(3).forEach(appendNumbersTo(sb)); + DoubleStream.concat(DoubleStream.of(1, 2), DoubleStream.of(3, 4, 5)).skip(3).forEach(appendDoubleNumbersTo(sb)); assertEquals("4.0;5.0;", sb.toString()); } @Test public void peekWorks() { StringBuilder sb = new StringBuilder(); - DoubleStream.of(1, 2, 3).peek(appendNumbersTo(sb)).map(n -> n + 10).forEach(appendNumbersTo(sb)); + DoubleStream.of(1, 2, 3).peek(appendDoubleNumbersTo(sb)).map(n -> n + 10).forEach(appendDoubleNumbersTo(sb)); assertEquals("1.0;11.0;2.0;12.0;3.0;13.0;", sb.toString()); } @@ -196,31 +207,31 @@ public class DoubleStreamTest { @Test public void streamOfOneElement() { StringBuilder sb = new StringBuilder(); - DoubleStream.of(5).forEach(appendNumbersTo(sb)); + DoubleStream.of(5).forEach(appendDoubleNumbersTo(sb)); assertEquals("5.0;", sb.toString()); sb.setLength(0); - DoubleStream.of(5).skip(1).forEach(appendNumbersTo(sb)); + DoubleStream.of(5).skip(1).forEach(appendDoubleNumbersTo(sb)); assertEquals("", sb.toString()); sb.setLength(0); - DoubleStream.concat(DoubleStream.of(5), DoubleStream.of(6)).forEach(appendNumbersTo(sb)); + DoubleStream.concat(DoubleStream.of(5), DoubleStream.of(6)).forEach(appendDoubleNumbersTo(sb)); assertEquals("5.0;6.0;", sb.toString()); } @Test public void sortedStream() { StringBuilder sb = new StringBuilder(); - DoubleStream.of(5, 7, 1, 2, 4, 3).sorted().forEach(appendNumbersTo(sb)); + DoubleStream.of(5, 7, 1, 2, 4, 3).sorted().forEach(appendDoubleNumbersTo(sb)); assertEquals("1.0;2.0;3.0;4.0;5.0;7.0;", sb.toString()); sb.setLength(0); - DoubleStream.of(2, 3, 1).peek(appendNumbersTo(sb)).sorted().limit(2).map(n -> n + 10) - .forEach(appendNumbersTo(sb)); + DoubleStream.of(2, 3, 1).peek(appendDoubleNumbersTo(sb)).sorted().limit(2).map(n -> n + 10) + .forEach(appendDoubleNumbersTo(sb)); assertEquals("2.0;3.0;1.0;11.0;12.0;", sb.toString()); sb.setLength(0); - DoubleStream.of(2, 3, 1).peek(appendNumbersTo(sb)).sorted().limit(0).forEach(appendNumbersTo(sb)); + DoubleStream.of(2, 3, 1).peek(appendDoubleNumbersTo(sb)).sorted().limit(0).forEach(appendDoubleNumbersTo(sb)); assertEquals("2.0;3.0;1.0;", sb.toString()); } @@ -299,7 +310,7 @@ public class DoubleStreamTest { sb.setLength(0); iterator = DoubleStream.of(1, 2, 3).iterator(); - iterator.forEachRemaining(appendNumbersTo(sb)); + iterator.forEachRemaining(appendDoubleNumbersTo(sb)); assertEquals("1.0;2.0;3.0;", sb.toString()); } @@ -307,14 +318,14 @@ public class DoubleStreamTest { public void spliterator() { StringBuilder sb = new StringBuilder(); Spliterator.OfDouble spliterator = DoubleStream.of(1, 2, 3).spliterator(); - while (spliterator.tryAdvance(appendNumbersTo(sb))) { + while (spliterator.tryAdvance(appendDoubleNumbersTo(sb))) { // continue } assertEquals("1.0;2.0;3.0;", sb.toString()); sb.setLength(0); spliterator = DoubleStream.of(1, 2, 3).spliterator(); - spliterator.forEachRemaining(appendNumbersTo(sb)); + spliterator.forEachRemaining(appendDoubleNumbersTo(sb)); assertEquals("1.0;2.0;3.0;", sb.toString()); } @@ -323,16 +334,4 @@ public class DoubleStreamTest { assertEquals(2.5, DoubleStream.of(1, 2, 3, 4).average().getAsDouble(), 0.001); assertFalse(DoubleStream.empty().average().isPresent()); } - - private DoubleConsumer appendNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } - - private IntConsumer appendIntNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } - - private LongConsumer appendLongNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } } diff --git a/tests/src/test/java/org/teavm/classlib/java/util/stream/Helper.java b/tests/src/test/java/org/teavm/classlib/java/util/stream/Helper.java new file mode 100644 index 000000000..c794735d2 --- /dev/null +++ b/tests/src/test/java/org/teavm/classlib/java/util/stream/Helper.java @@ -0,0 +1,208 @@ +/* + * Copyright 2019 Alexey Andreev. + * + * 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 org.teavm.classlib.java.util.stream; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import java.util.Iterator; +import java.util.PrimitiveIterator; +import java.util.function.Consumer; +import java.util.function.DoubleConsumer; +import java.util.function.IntConsumer; +import java.util.function.LongConsumer; +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; + +final class Helper { + private Helper() { + } + + static void testIntegerStream(Supplier> streamSupplier, Integer... expected) { + StringBuilder sb = new StringBuilder(); + for (Integer e : expected) { + sb.append(e).append(';'); + } + String expectedText = sb.toString(); + + sb.setLength(0); + streamSupplier.get().forEach(appendNumbersTo(sb)); + assertEquals(expectedText, sb.toString()); + + sb.setLength(0); + Iterator iter = streamSupplier.get().iterator(); + while (iter.hasNext()) { + sb.append(iter.next()).append(';'); + } + assertEquals(expectedText, sb.toString()); + + assertEquals(expected.length, streamSupplier.get().count()); + + if (expected.length > 0) { + int max = expected[0]; + for (Integer e : expected) { + max = Math.max(max, e); + } + int notInCollection = max + 1; + int inCollection = expected[0]; + assertTrue(streamSupplier.get().allMatch(e -> e < notInCollection)); + assertFalse(streamSupplier.get().allMatch(e -> e < inCollection)); + assertTrue(streamSupplier.get().anyMatch(e -> e == inCollection)); + assertFalse(streamSupplier.get().anyMatch(e -> e == notInCollection)); + } else { + assertTrue(streamSupplier.get().allMatch(e -> false)); + assertTrue(streamSupplier.get().allMatch(e -> true)); + assertFalse(streamSupplier.get().anyMatch(e -> true)); + assertFalse(streamSupplier.get().anyMatch(e -> false)); + } + } + + static void testIntStream(Supplier streamSupplier, int... expected) { + StringBuilder sb = new StringBuilder(); + for (int e : expected) { + sb.append(e).append(';'); + } + String expectedText = sb.toString(); + + sb.setLength(0); + streamSupplier.get().forEach(appendIntNumbersTo(sb)); + assertEquals(expectedText, sb.toString()); + + sb.setLength(0); + PrimitiveIterator.OfInt iter = streamSupplier.get().iterator(); + while (iter.hasNext()) { + sb.append(iter.next()).append(';'); + } + assertEquals(expectedText, sb.toString()); + + assertEquals(expected.length, streamSupplier.get().count()); + + if (expected.length > 0) { + int max = expected[0]; + for (int e : expected) { + max = Math.max(max, e); + } + int notInCollection = max + 1; + int inCollection = expected[0]; + assertTrue(streamSupplier.get().allMatch(e -> e < notInCollection)); + assertFalse(streamSupplier.get().allMatch(e -> e < inCollection)); + assertTrue(streamSupplier.get().anyMatch(e -> e == inCollection)); + assertFalse(streamSupplier.get().anyMatch(e -> e == notInCollection)); + } else { + assertTrue(streamSupplier.get().allMatch(e -> false)); + assertTrue(streamSupplier.get().allMatch(e -> true)); + assertFalse(streamSupplier.get().anyMatch(e -> true)); + assertFalse(streamSupplier.get().anyMatch(e -> false)); + } + } + + static void testLongStream(Supplier streamSupplier, long... expected) { + StringBuilder sb = new StringBuilder(); + for (long e : expected) { + sb.append(e).append(';'); + } + String expectedText = sb.toString(); + + sb.setLength(0); + streamSupplier.get().forEach(appendLongNumbersTo(sb)); + assertEquals(expectedText, sb.toString()); + + sb.setLength(0); + PrimitiveIterator.OfLong iter = streamSupplier.get().iterator(); + while (iter.hasNext()) { + sb.append(iter.next()).append(';'); + } + assertEquals(expectedText, sb.toString()); + + assertEquals(expected.length, streamSupplier.get().count()); + + if (expected.length > 0) { + long max = expected[0]; + for (long e : expected) { + max = Math.max(max, e); + } + long notInCollection = max + 1; + long inCollection = expected[0]; + assertTrue(streamSupplier.get().allMatch(e -> e < notInCollection)); + assertFalse(streamSupplier.get().allMatch(e -> e < inCollection)); + assertTrue(streamSupplier.get().anyMatch(e -> e == inCollection)); + assertFalse(streamSupplier.get().anyMatch(e -> e == notInCollection)); + } else { + assertTrue(streamSupplier.get().allMatch(e -> false)); + assertTrue(streamSupplier.get().allMatch(e -> true)); + assertFalse(streamSupplier.get().anyMatch(e -> true)); + assertFalse(streamSupplier.get().anyMatch(e -> false)); + } + } + + static void testDoubleStream(Supplier streamSupplier, double... expected) { + StringBuilder sb = new StringBuilder(); + for (double e : expected) { + sb.append(e).append(';'); + } + String expectedText = sb.toString(); + + sb.setLength(0); + streamSupplier.get().forEach(appendDoubleNumbersTo(sb)); + assertEquals(expectedText, sb.toString()); + + sb.setLength(0); + PrimitiveIterator.OfDouble iter = streamSupplier.get().iterator(); + while (iter.hasNext()) { + sb.append(iter.next()).append(';'); + } + assertEquals(expectedText, sb.toString()); + + assertEquals(expected.length, streamSupplier.get().count()); + + if (expected.length > 0) { + double max = expected[0]; + for (double e : expected) { + max = Math.max(max, e); + } + double notInCollection = max + 1; + double inCollection = expected[0]; + assertTrue(streamSupplier.get().allMatch(e -> e < notInCollection)); + assertFalse(streamSupplier.get().allMatch(e -> e < inCollection)); + assertTrue(streamSupplier.get().anyMatch(e -> e == inCollection)); + assertFalse(streamSupplier.get().anyMatch(e -> e == notInCollection)); + } else { + assertTrue(streamSupplier.get().allMatch(e -> false)); + assertTrue(streamSupplier.get().allMatch(e -> true)); + assertFalse(streamSupplier.get().anyMatch(e -> true)); + assertFalse(streamSupplier.get().anyMatch(e -> false)); + } + } + + static Consumer appendNumbersTo(StringBuilder sb) { + return n -> sb.append(n).append(';'); + } + + static IntConsumer appendIntNumbersTo(StringBuilder sb) { + return n -> sb.append(n).append(';'); + } + + static LongConsumer appendLongNumbersTo(StringBuilder sb) { + return n -> sb.append(n).append(';'); + } + + static DoubleConsumer appendDoubleNumbersTo(StringBuilder sb) { + return n -> sb.append(n).append(';'); + } +} diff --git a/tests/src/test/java/org/teavm/classlib/java/util/stream/IntStreamTest.java b/tests/src/test/java/org/teavm/classlib/java/util/stream/IntStreamTest.java index 9652771c9..a949778e3 100644 --- a/tests/src/test/java/org/teavm/classlib/java/util/stream/IntStreamTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/util/stream/IntStreamTest.java @@ -19,12 +19,13 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.teavm.classlib.java.util.stream.Helper.appendIntNumbersTo; +import static org.teavm.classlib.java.util.stream.Helper.testDoubleStream; +import static org.teavm.classlib.java.util.stream.Helper.testIntStream; +import static org.teavm.classlib.java.util.stream.Helper.testIntegerStream; +import static org.teavm.classlib.java.util.stream.Helper.testLongStream; import java.util.PrimitiveIterator; import java.util.Spliterator; -import java.util.function.DoubleConsumer; -import java.util.function.IntConsumer; -import java.util.function.LongConsumer; -import java.util.stream.Collectors; import java.util.stream.IntStream; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,85 +35,88 @@ import org.teavm.junit.TeaVMTestRunner; public class IntStreamTest { @Test public void forEachWorks() { - StringBuilder sb = new StringBuilder(); - IntStream.of(1, 2, 3).forEach(appendNumbersTo(sb)); - assertEquals("1;2;3;", sb.toString()); + testIntStream(() -> IntStream.of(1, 2, 3), 1, 2, 3); + testIntStream(() -> IntStream.concat(IntStream.of(1), IntStream.of(2, 3)), 1, 2, 3); + testIntStream(() -> IntStream.concat(IntStream.empty(), IntStream.of(1, 2, 3)), 1, 2, 3); } @Test public void mapWorks() { - StringBuilder sb = new StringBuilder(); - IntStream.of(1, 2, 3).map(n -> n * n).forEach(appendNumbersTo(sb)); - assertEquals("1;4;9;", sb.toString()); + testIntStream(() -> IntStream.of(1, 2, 3).map(n -> n * n), 1, 4, 9); + testIntStream(() -> IntStream.concat(IntStream.of(1), IntStream.of(2, 3)).map(n -> n * n), 1, 4, 9); + testIntStream(() -> IntStream.concat(IntStream.empty(), IntStream.of(1, 2, 3)).map(n -> n * n), 1, 4, 9); } @Test public void mapToObjWorks() { - String result = IntStream.of(1, 2, 3).mapToObj(n -> String.valueOf(n * n)).collect(Collectors.joining(";")); - assertEquals("1;4;9", result); + testIntegerStream(() -> IntStream.of(1, 2, 3).mapToObj(n -> n * n), 1, 4, 9); + testIntegerStream(() -> IntStream.concat(IntStream.of(1), IntStream.of(2, 3)).mapToObj(n -> n * n), 1, 4, 9); + testIntegerStream(() -> IntStream.concat(IntStream.empty(), IntStream.of(1, 2, 3)) + .mapToObj(n -> n * n), 1, 4, 9); } @Test public void mapToLongWorks() { - StringBuilder sb = new StringBuilder(); - IntStream.of(1, 2, 3).mapToLong(n -> n * n).forEach(appendLongNumbersTo(sb)); - assertEquals("1;4;9;", sb.toString()); + testLongStream(() -> IntStream.of(1, 2, 3).mapToLong(n -> n * n), 1, 4, 9); + testLongStream(() -> IntStream.concat(IntStream.of(1), IntStream.of(2, 3)).mapToLong(n -> n * n), 1, 4, 9); + testLongStream(() -> IntStream.concat(IntStream.empty(), IntStream.of(1, 2, 3)).mapToLong(n -> n * n), 1, 4, 9); } @Test public void mapToDoubleWorks() { - StringBuilder sb = new StringBuilder(); - IntStream.of(1, 2, 3).mapToDouble(n -> n * n).forEach(appendDoubleNumbersTo(sb)); - assertEquals("1.0;4.0;9.0;", sb.toString()); + testDoubleStream(() -> IntStream.of(1, 2, 3).mapToDouble(n -> n * n), 1, 4, 9); + testDoubleStream(() -> IntStream.concat(IntStream.of(1), IntStream.of(2, 3)).mapToDouble(n -> n * n), 1, 4, 9); + testDoubleStream(() -> IntStream.concat(IntStream.empty(), IntStream.of(1, 2, 3)).mapToDouble(n -> n * n), + 1, 4, 9); } @Test public void filterWorks() { - StringBuilder sb = new StringBuilder(); - IntStream.of(1, 2, 3, 4, 5, 6).filter(n -> (n & 1) == 0).forEach(appendNumbersTo(sb)); - assertEquals("2;4;6;", sb.toString()); + testIntStream(() -> IntStream.of(1, 2, 3, 4, 5, 6).filter(n -> (n & 1) == 0), 2, 4, 6); + testIntStream(() -> IntStream.concat(IntStream.of(1), IntStream.of(2, 3, 4, 5, 6)) + .filter(n -> (n & 1) == 0), 2, 4, 6); + testIntStream(() -> IntStream.concat(IntStream.empty(), IntStream.of(1, 2, 3, 4, 5, 6)) + .filter(n -> (n & 1) == 0), 2, 4, 6); } @Test public void flatMapWorks() { - StringBuilder sb = new StringBuilder(); - IntStream.of(1, 3).flatMap(n -> IntStream.of(n, n + 1)).forEach(appendNumbersTo(sb)); - assertEquals("1;2;3;4;", sb.toString()); + testIntStream(() -> IntStream.of(1, 3).flatMap(n -> IntStream.of(n, n + 1)), 1, 2, 3, 4); + testIntStream(() -> IntStream.of(1, 3).flatMap(n -> IntStream.of(n, n + 1)).skip(1), 2, 3, 4); + testIntStream(() -> IntStream.of(1, 4).flatMap(n -> IntStream.of(n, n + 1, n + 2)).skip(3), 4, 5, 6); - sb.setLength(0); - IntStream.of(1, 3).flatMap(n -> IntStream.of(n, n + 1)).skip(1).forEach(appendNumbersTo(sb)); - assertEquals("2;3;4;", sb.toString()); - - sb.setLength(0); - IntStream.of(1, 4).flatMap(n -> IntStream.of(n, n + 1, n + 2)).skip(4).forEach(appendNumbersTo(sb)); - assertEquals("5;6;", sb.toString()); + testIntStream(() -> IntStream.of(1, 3, 100) + .flatMap(n -> n < 100 ? IntStream.of(n, n + 1) : IntStream.empty()), 1, 2, 3, 4); + testIntStream(() -> IntStream.of(100, 1, 3) + .flatMap(n -> n < 100 ? IntStream.of(n, n + 1) : IntStream.empty()), 1, 2, 3, 4); } @Test public void skipWorks() { - for (int i = 0; i <= 6; ++i) { - StringBuilder sb = new StringBuilder(); - IntStream.iterate(1, n -> n + 1).limit(5).skip(i).forEach(appendNumbersTo(sb)); - - StringBuilder expected = new StringBuilder(); + for (int i = 0; i <= 5; ++i) { + int index = i; + int[] expected = new int[5 - i]; for (int j = i; j < 5; ++j) { - expected.append(j + 1).append(';'); + expected[j - i] = j + 1; } - assertEquals("Error skipping " + i + " elements", expected.toString(), sb.toString()); + testIntStream(() -> IntStream.iterate(1, n -> n + 1).limit(5).skip(index), expected); + testIntStream(() -> IntStream.concat(IntStream.of(1), IntStream.iterate(2, n -> n + 1).limit(4)) + .skip(index), expected); + testIntStream(() -> IntStream.concat(IntStream.empty(), IntStream.iterate(1, n -> n + 1).limit(5)) + .skip(index), expected); } } @Test public void limitWorks() { for (int i = 0; i <= 3; ++i) { - StringBuilder sb = new StringBuilder(); - IntStream.iterate(1, n -> n + 1).limit(i).forEach(appendNumbersTo(sb)); - - StringBuilder expected = new StringBuilder(); - for (int j = 0; j < i; ++j) { - expected.append(j + 1).append(';'); + int index = i; + int[] expected = new int[i]; + for (int j = 0; j < expected.length; ++j) { + expected[j] = j + 1; } - assertEquals("Error limiting to " + i + " elements", expected.toString(), sb.toString()); + + testIntStream(() -> IntStream.iterate(1, n -> n + 1).limit(index), expected); } } @@ -153,22 +157,22 @@ public class IntStreamTest { @Test public void concatWorks() { StringBuilder sb = new StringBuilder(); - IntStream.concat(IntStream.of(1, 2), IntStream.of(3, 4)).forEach(appendNumbersTo(sb)); + IntStream.concat(IntStream.of(1, 2), IntStream.of(3, 4)).forEach(appendIntNumbersTo(sb)); assertEquals("1;2;3;4;", sb.toString()); sb.setLength(0); - IntStream.concat(IntStream.of(1, 2), IntStream.of(3, 4)).skip(1).forEach(appendNumbersTo(sb)); + IntStream.concat(IntStream.of(1, 2), IntStream.of(3, 4)).skip(1).forEach(appendIntNumbersTo(sb)); assertEquals("2;3;4;", sb.toString()); sb.setLength(0); - IntStream.concat(IntStream.of(1, 2), IntStream.of(3, 4, 5)).skip(3).forEach(appendNumbersTo(sb)); + IntStream.concat(IntStream.of(1, 2), IntStream.of(3, 4, 5)).skip(3).forEach(appendIntNumbersTo(sb)); assertEquals("4;5;", sb.toString()); } @Test public void peekWorks() { StringBuilder sb = new StringBuilder(); - IntStream.of(1, 2, 3).peek(appendNumbersTo(sb)).map(n -> n + 10).forEach(appendNumbersTo(sb)); + IntStream.of(1, 2, 3).peek(appendIntNumbersTo(sb)).map(n -> n + 10).forEach(appendIntNumbersTo(sb)); assertEquals("1;11;2;12;3;13;", sb.toString()); } @@ -185,30 +189,31 @@ public class IntStreamTest { @Test public void streamOfOneElement() { StringBuilder sb = new StringBuilder(); - IntStream.of(5).forEach(appendNumbersTo(sb)); + IntStream.of(5).forEach(appendIntNumbersTo(sb)); assertEquals("5;", sb.toString()); sb.setLength(0); - IntStream.of(5).skip(1).forEach(appendNumbersTo(sb)); + IntStream.of(5).skip(1).forEach(appendIntNumbersTo(sb)); assertEquals("", sb.toString()); sb.setLength(0); - IntStream.concat(IntStream.of(5), IntStream.of(6)).forEach(appendNumbersTo(sb)); + IntStream.concat(IntStream.of(5), IntStream.of(6)).forEach(appendIntNumbersTo(sb)); assertEquals("5;6;", sb.toString()); } @Test public void sortedStream() { StringBuilder sb = new StringBuilder(); - IntStream.of(5, 7, 1, 2, 4, 3).sorted().forEach(appendNumbersTo(sb)); + IntStream.of(5, 7, 1, 2, 4, 3).sorted().forEach(appendIntNumbersTo(sb)); assertEquals("1;2;3;4;5;7;", sb.toString()); sb.setLength(0); - IntStream.of(2, 3, 1).peek(appendNumbersTo(sb)).sorted().limit(2).map(n -> n + 10).forEach(appendNumbersTo(sb)); + IntStream.of(2, 3, 1).peek(appendIntNumbersTo(sb)).sorted().limit(2).map(n -> n + 10) + .forEach(appendIntNumbersTo(sb)); assertEquals("2;3;1;11;12;", sb.toString()); sb.setLength(0); - IntStream.of(2, 3, 1).peek(appendNumbersTo(sb)).sorted().limit(0).forEach(appendNumbersTo(sb)); + IntStream.of(2, 3, 1).peek(appendIntNumbersTo(sb)).sorted().limit(0).forEach(appendIntNumbersTo(sb)); assertEquals("2;3;1;", sb.toString()); } @@ -287,7 +292,7 @@ public class IntStreamTest { sb.setLength(0); iterator = IntStream.of(1, 2, 3).iterator(); - iterator.forEachRemaining(appendNumbersTo(sb)); + iterator.forEachRemaining(appendIntNumbersTo(sb)); assertEquals("1;2;3;", sb.toString()); } @@ -295,14 +300,14 @@ public class IntStreamTest { public void spliterator() { StringBuilder sb = new StringBuilder(); Spliterator.OfInt spliterator = IntStream.of(1, 2, 3).spliterator(); - while (spliterator.tryAdvance(appendNumbersTo(sb))) { + while (spliterator.tryAdvance(appendIntNumbersTo(sb))) { // continue } assertEquals("1;2;3;", sb.toString()); sb.setLength(0); spliterator = IntStream.of(1, 2, 3).spliterator(); - spliterator.forEachRemaining(appendNumbersTo(sb)); + spliterator.forEachRemaining(appendIntNumbersTo(sb)); assertEquals("1;2;3;", sb.toString()); } @@ -315,23 +320,11 @@ public class IntStreamTest { @Test public void range() { StringBuilder sb = new StringBuilder(); - IntStream.range(1, 4).forEach(appendNumbersTo(sb)); + IntStream.range(1, 4).forEach(appendIntNumbersTo(sb)); assertEquals("1;2;3;", sb.toString()); sb.setLength(0); - IntStream.rangeClosed(1, 4).forEach(appendNumbersTo(sb)); + IntStream.rangeClosed(1, 4).forEach(appendIntNumbersTo(sb)); assertEquals("1;2;3;4;", sb.toString()); } - - private IntConsumer appendNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } - - private LongConsumer appendLongNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } - - private DoubleConsumer appendDoubleNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } } diff --git a/tests/src/test/java/org/teavm/classlib/java/util/stream/LongStreamTest.java b/tests/src/test/java/org/teavm/classlib/java/util/stream/LongStreamTest.java index cd18c2bf0..37abfbd61 100644 --- a/tests/src/test/java/org/teavm/classlib/java/util/stream/LongStreamTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/util/stream/LongStreamTest.java @@ -19,12 +19,13 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.teavm.classlib.java.util.stream.Helper.appendLongNumbersTo; +import static org.teavm.classlib.java.util.stream.Helper.testDoubleStream; +import static org.teavm.classlib.java.util.stream.Helper.testIntStream; +import static org.teavm.classlib.java.util.stream.Helper.testIntegerStream; +import static org.teavm.classlib.java.util.stream.Helper.testLongStream; import java.util.PrimitiveIterator; import java.util.Spliterator; -import java.util.function.DoubleConsumer; -import java.util.function.IntConsumer; -import java.util.function.LongConsumer; -import java.util.stream.Collectors; import java.util.stream.LongStream; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,85 +35,92 @@ import org.teavm.junit.TeaVMTestRunner; public class LongStreamTest { @Test public void forEachWorks() { - StringBuilder sb = new StringBuilder(); - LongStream.of(1, 2, 3).forEach(appendNumbersTo(sb)); - assertEquals("1;2;3;", sb.toString()); + testLongStream(() -> LongStream.of(1, 2, 3), 1, 2, 3); + testLongStream(() -> LongStream.concat(LongStream.of(1), LongStream.of(2, 3)), 1, 2, 3); + testLongStream(() -> LongStream.concat(LongStream.empty(), LongStream.of(1, 2, 3)), 1, 2, 3); } @Test public void mapWorks() { - StringBuilder sb = new StringBuilder(); - LongStream.of(1, 2, 3).map(n -> n * n).forEach(appendNumbersTo(sb)); - assertEquals("1;4;9;", sb.toString()); + testLongStream(() -> LongStream.of(1, 2, 3).map(n -> n * n), 1, 4, 9); + testLongStream(() -> LongStream.concat(LongStream.of(1), LongStream.of(2, 3)).map(n -> n * n), 1, 4, 9); + testLongStream(() -> LongStream.concat(LongStream.empty(), LongStream.of(1, 2, 3)).map(n -> n * n), 1, 4, 9); } @Test public void mapToObjWorks() { - String result = LongStream.of(1, 2, 3).mapToObj(n -> String.valueOf(n * n)).collect(Collectors.joining(";")); - assertEquals("1;4;9", result); + testIntegerStream(() -> LongStream.of(1, 2, 3).mapToObj(n -> (int) (n * n)), 1, 4, 9); + testIntegerStream(() -> LongStream.concat(LongStream.of(1), LongStream.of(2, 3)) + .mapToObj(n -> (int) (n * n)), 1, 4, 9); + testIntegerStream(() -> LongStream.concat(LongStream.empty(), LongStream.of(1, 2, 3)) + .mapToObj(n -> (int) (n * n)), 1, 4, 9); } @Test public void mapToIntWorks() { - StringBuilder sb = new StringBuilder(); - LongStream.of(1, 2, 3).mapToInt(n -> (int) (n * n)).forEach(appendIntNumbersTo(sb)); - assertEquals("1;4;9;", sb.toString()); + testIntStream(() -> LongStream.of(1, 2, 3).mapToInt(n -> (int) (n * n)), 1, 4, 9); + testIntStream(() -> LongStream.concat(LongStream.of(1), LongStream.of(2, 3)) + .mapToInt(n -> (int) (n * n)), 1, 4, 9); + testIntStream(() -> LongStream.concat(LongStream.empty(), LongStream.of(1, 2, 3)) + .mapToInt(n -> (int) (n * n)), 1, 4, 9); } @Test public void mapToDoubleWorks() { - StringBuilder sb = new StringBuilder(); - LongStream.of(1, 2, 3).mapToDouble(n -> n * n).forEach(appendDoubleNumbersTo(sb)); - assertEquals("1.0;4.0;9.0;", sb.toString()); + testDoubleStream(() -> LongStream.of(1, 2, 3).mapToDouble(n -> n * n), 1, 4, 9); + testDoubleStream(() -> LongStream.concat(LongStream.of(1), LongStream.of(2, 3)).mapToDouble(n -> n * n), + 1, 4, 9); + testDoubleStream(() -> LongStream.concat(LongStream.empty(), LongStream.of(1, 2, 3)).mapToDouble(n -> n * n), + 1, 4, 9); } @Test public void filterWorks() { - StringBuilder sb = new StringBuilder(); - LongStream.of(1, 2, 3, 4, 5, 6).filter(n -> (n & 1) == 0).forEach(appendNumbersTo(sb)); - assertEquals("2;4;6;", sb.toString()); + testLongStream(() -> LongStream.of(1, 2, 3, 4, 5, 6).filter(n -> (n & 1) == 0), 2, 4, 6); + testLongStream(() -> LongStream.concat(LongStream.of(1), LongStream.of(2, 3, 4, 5, 6)) + .filter(n -> (n & 1) == 0), 2, 4, 6); + testLongStream(() -> LongStream.concat(LongStream.empty(), LongStream.of(1, 2, 3, 4, 5, 6)) + .filter(n -> (n & 1) == 0), 2, 4, 6); } @Test public void flatMapWorks() { - StringBuilder sb = new StringBuilder(); - LongStream.of(1, 3).flatMap(n -> LongStream.of(n, n + 1)).forEach(appendNumbersTo(sb)); - assertEquals("1;2;3;4;", sb.toString()); + testLongStream(() -> LongStream.of(1, 3).flatMap(n -> LongStream.of(n, n + 1)), 1, 2, 3, 4); + testLongStream(() -> LongStream.of(1, 3).flatMap(n -> LongStream.of(n, n + 1)).skip(1), 2, 3, 4); + testLongStream(() -> LongStream.of(1, 4).flatMap(n -> LongStream.of(n, n + 1, n + 2)).skip(3), 4, 5, 6); - sb.setLength(0); - LongStream.of(1, 3).flatMap(n -> LongStream.of(n, n + 1)).skip(1).forEach(appendNumbersTo(sb)); - assertEquals("2;3;4;", sb.toString()); - - sb.setLength(0); - LongStream.of(1, 4).flatMap(n -> LongStream.of(n, n + 1, n + 2)).skip(4).forEach(appendNumbersTo(sb)); - assertEquals("5;6;", sb.toString()); + testLongStream(() -> LongStream.of(1, 3, 100) + .flatMap(n -> n < 100 ? LongStream.of(n, n + 1) : LongStream.empty()), 1, 2, 3, 4); + testLongStream(() -> LongStream.of(100, 1, 3) + .flatMap(n -> n < 100 ? LongStream.of(n, n + 1) : LongStream.empty()), 1, 2, 3, 4); } @Test public void skipWorks() { - for (int i = 0; i <= 6; ++i) { - StringBuilder sb = new StringBuilder(); - LongStream.iterate(1, n -> n + 1).limit(5).skip(i).forEach(appendNumbersTo(sb)); - - StringBuilder expected = new StringBuilder(); + for (int i = 0; i <= 5; ++i) { + int index = i; + long[] expected = new long[5 - i]; for (int j = i; j < 5; ++j) { - expected.append(j + 1).append(';'); + expected[j - i] = j + 1; } - assertEquals("Error skipping " + i + " elements", expected.toString(), sb.toString()); + testLongStream(() -> LongStream.iterate(1, n -> n + 1).limit(5).skip(index), expected); + testLongStream(() -> LongStream.concat(LongStream.of(1), LongStream.iterate(2, n -> n + 1).limit(4)) + .skip(index), expected); + testLongStream(() -> LongStream.concat(LongStream.empty(), LongStream.iterate(1, n -> n + 1).limit(5)) + .skip(index), expected); } } @Test public void limitWorks() { for (int i = 0; i <= 3; ++i) { - StringBuilder sb = new StringBuilder(); - LongStream.iterate(1, n -> n + 1).limit(i).forEach(appendNumbersTo(sb)); - - StringBuilder expected = new StringBuilder(); - for (int j = 0; j < i; ++j) { - expected.append(j + 1).append(';'); + int index = i; + long[] expected = new long[i]; + for (int j = 0; j < expected.length; ++j) { + expected[j] = j + 1; } - assertEquals("Error limiting to " + i + " elements", expected.toString(), sb.toString()); + + testLongStream(() -> LongStream.iterate(1, n -> n + 1).limit(index), expected); } } @@ -153,22 +161,22 @@ public class LongStreamTest { @Test public void concatWorks() { StringBuilder sb = new StringBuilder(); - LongStream.concat(LongStream.of(1, 2), LongStream.of(3, 4)).forEach(appendNumbersTo(sb)); + LongStream.concat(LongStream.of(1, 2), LongStream.of(3, 4)).forEach(appendLongNumbersTo(sb)); assertEquals("1;2;3;4;", sb.toString()); sb.setLength(0); - LongStream.concat(LongStream.of(1, 2), LongStream.of(3, 4)).skip(1).forEach(appendNumbersTo(sb)); + LongStream.concat(LongStream.of(1, 2), LongStream.of(3, 4)).skip(1).forEach(appendLongNumbersTo(sb)); assertEquals("2;3;4;", sb.toString()); sb.setLength(0); - LongStream.concat(LongStream.of(1, 2), LongStream.of(3, 4, 5)).skip(3).forEach(appendNumbersTo(sb)); + LongStream.concat(LongStream.of(1, 2), LongStream.of(3, 4, 5)).skip(3).forEach(appendLongNumbersTo(sb)); assertEquals("4;5;", sb.toString()); } @Test public void peekWorks() { StringBuilder sb = new StringBuilder(); - LongStream.of(1, 2, 3).peek(appendNumbersTo(sb)).map(n -> n + 10).forEach(appendNumbersTo(sb)); + LongStream.of(1, 2, 3).peek(appendLongNumbersTo(sb)).map(n -> n + 10).forEach(appendLongNumbersTo(sb)); assertEquals("1;11;2;12;3;13;", sb.toString()); } @@ -185,31 +193,31 @@ public class LongStreamTest { @Test public void streamOfOneElement() { StringBuilder sb = new StringBuilder(); - LongStream.of(5).forEach(appendNumbersTo(sb)); + LongStream.of(5).forEach(appendLongNumbersTo(sb)); assertEquals("5;", sb.toString()); sb.setLength(0); - LongStream.of(5).skip(1).forEach(appendNumbersTo(sb)); + LongStream.of(5).skip(1).forEach(appendLongNumbersTo(sb)); assertEquals("", sb.toString()); sb.setLength(0); - LongStream.concat(LongStream.of(5), LongStream.of(6)).forEach(appendNumbersTo(sb)); + LongStream.concat(LongStream.of(5), LongStream.of(6)).forEach(appendLongNumbersTo(sb)); assertEquals("5;6;", sb.toString()); } @Test public void sortedStream() { StringBuilder sb = new StringBuilder(); - LongStream.of(5, 7, 1, 2, 4, 3).sorted().forEach(appendNumbersTo(sb)); + LongStream.of(5, 7, 1, 2, 4, 3).sorted().forEach(appendLongNumbersTo(sb)); assertEquals("1;2;3;4;5;7;", sb.toString()); sb.setLength(0); - LongStream.of(2, 3, 1).peek(appendNumbersTo(sb)).sorted().limit(2).map(n -> n + 10) - .forEach(appendNumbersTo(sb)); + LongStream.of(2, 3, 1).peek(appendLongNumbersTo(sb)).sorted().limit(2).map(n -> n + 10) + .forEach(appendLongNumbersTo(sb)); assertEquals("2;3;1;11;12;", sb.toString()); sb.setLength(0); - LongStream.of(2, 3, 1).peek(appendNumbersTo(sb)).sorted().limit(0).forEach(appendNumbersTo(sb)); + LongStream.of(2, 3, 1).peek(appendLongNumbersTo(sb)).sorted().limit(0).forEach(appendLongNumbersTo(sb)); assertEquals("2;3;1;", sb.toString()); } @@ -288,7 +296,7 @@ public class LongStreamTest { sb.setLength(0); iterator = LongStream.of(1, 2, 3).iterator(); - iterator.forEachRemaining(appendNumbersTo(sb)); + iterator.forEachRemaining(appendLongNumbersTo(sb)); assertEquals("1;2;3;", sb.toString()); } @@ -296,14 +304,14 @@ public class LongStreamTest { public void spliterator() { StringBuilder sb = new StringBuilder(); Spliterator.OfLong spliterator = LongStream.of(1, 2, 3).spliterator(); - while (spliterator.tryAdvance(appendNumbersTo(sb))) { + while (spliterator.tryAdvance(appendLongNumbersTo(sb))) { // continue } assertEquals("1;2;3;", sb.toString()); sb.setLength(0); spliterator = LongStream.of(1, 2, 3).spliterator(); - spliterator.forEachRemaining(appendNumbersTo(sb)); + spliterator.forEachRemaining(appendLongNumbersTo(sb)); assertEquals("1;2;3;", sb.toString()); } @@ -316,23 +324,11 @@ public class LongStreamTest { @Test public void range() { StringBuilder sb = new StringBuilder(); - LongStream.range(1, 4).forEach(appendNumbersTo(sb)); + LongStream.range(1, 4).forEach(appendLongNumbersTo(sb)); assertEquals("1;2;3;", sb.toString()); sb.setLength(0); - LongStream.rangeClosed(1, 4).forEach(appendNumbersTo(sb)); + LongStream.rangeClosed(1, 4).forEach(appendLongNumbersTo(sb)); assertEquals("1;2;3;4;", sb.toString()); } - - private LongConsumer appendNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } - - private IntConsumer appendIntNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } - - private DoubleConsumer appendDoubleNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } } diff --git a/tests/src/test/java/org/teavm/classlib/java/util/stream/StreamTest.java b/tests/src/test/java/org/teavm/classlib/java/util/stream/StreamTest.java index 9c41479f9..996b5c1d7 100644 --- a/tests/src/test/java/org/teavm/classlib/java/util/stream/StreamTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/util/stream/StreamTest.java @@ -19,14 +19,15 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.teavm.classlib.java.util.stream.Helper.appendNumbersTo; +import static org.teavm.classlib.java.util.stream.Helper.testDoubleStream; +import static org.teavm.classlib.java.util.stream.Helper.testIntStream; +import static org.teavm.classlib.java.util.stream.Helper.testIntegerStream; +import static org.teavm.classlib.java.util.stream.Helper.testLongStream; import java.util.Comparator; import java.util.Iterator; import java.util.Spliterator; -import java.util.function.Consumer; -import java.util.function.DoubleConsumer; import java.util.function.Function; -import java.util.function.IntConsumer; -import java.util.function.LongConsumer; import java.util.stream.DoubleStream; import java.util.stream.IntStream; import java.util.stream.LongStream; @@ -39,137 +40,139 @@ import org.teavm.junit.TeaVMTestRunner; public class StreamTest { @Test public void forEachWorks() { - StringBuilder sb = new StringBuilder(); - Stream.of(1, 2, 3).forEach(appendNumbersTo(sb)); - assertEquals("1;2;3;", sb.toString()); + testIntegerStream(() -> Stream.of(1, 2, 3), 1, 2, 3); + testIntegerStream(() -> Stream.concat(Stream.of(1), Stream.of(2, 3)), 1, 2, 3); + testIntegerStream(() -> Stream.concat(Stream.empty(), Stream.of(1, 2, 3)), 1, 2, 3); } @Test public void mapWorks() { - StringBuilder sb = new StringBuilder(); - Stream.of(1, 2, 3).map(n -> n * n).forEach(appendNumbersTo(sb)); - assertEquals("1;4;9;", sb.toString()); + testIntegerStream(() -> Stream.of(1, 2, 3).map(n -> n * n), 1, 4, 9); + testIntegerStream(() -> Stream.concat(Stream.of(1), Stream.of(2, 3)).map(n -> n * n), 1, 4, 9); + testIntegerStream(() -> Stream.concat(Stream.empty(), Stream.of(1, 2, 3)).map(n -> n * n), 1, 4, 9); } @Test public void mapToIntWorks() { - StringBuilder sb = new StringBuilder(); - Stream.of(1, 2, 3).mapToInt(n -> n * n).forEach(appendIntNumbersTo(sb)); - assertEquals("1;4;9;", sb.toString()); + testIntStream(() -> Stream.of(1, 2, 3).mapToInt(n -> n * n), 1, 4, 9); + testIntStream(() -> Stream.concat(Stream.of(1), Stream.of(2, 3)).mapToInt(n -> n * n), 1, 4, 9); + testIntStream(() -> Stream.concat(Stream.empty(), Stream.of(1, 2, 3)).mapToInt(n -> n * n), 1, 4, 9); } @Test public void mapToLongWorks() { - StringBuilder sb = new StringBuilder(); - Stream.of(1, 2, 3).mapToLong(n -> n * n).forEach(appendLongNumbersTo(sb)); - assertEquals("1;4;9;", sb.toString()); + testLongStream(() -> Stream.of(1, 2, 3).mapToLong(n -> n * n), 1, 4, 9); + testLongStream(() -> Stream.concat(Stream.of(1), Stream.of(2, 3)).mapToLong(n -> n * n), 1, 4, 9); + testLongStream(() -> Stream.concat(Stream.empty(), Stream.of(1, 2, 3)).mapToLong(n -> n * n), 1, 4, 9); } @Test public void mapToDoubleWorks() { - StringBuilder sb = new StringBuilder(); - Stream.of(1, 2, 3).mapToDouble(n -> n * n).forEach(appendDoubleNumbersTo(sb)); - assertEquals("1.0;4.0;9.0;", sb.toString()); + testDoubleStream(() -> Stream.of(1, 2, 3).mapToDouble(n -> n * n), 1, 4, 9); + testDoubleStream(() -> Stream.concat(Stream.of(1), Stream.of(2, 3)).mapToDouble(n -> n * n), 1, 4, 9); + testDoubleStream(() -> Stream.concat(Stream.empty(), Stream.of(1, 2, 3)).mapToDouble(n -> n * n), 1, 4, 9); } @Test public void filterWorks() { - StringBuilder sb = new StringBuilder(); - Stream.of(1, 2, 3, 4, 5, 6).filter(n -> (n & 1) == 0).forEach(appendNumbersTo(sb)); - assertEquals("2;4;6;", sb.toString()); + testIntegerStream(() -> Stream.of(1, 2, 3, 4, 5, 6).filter(n -> (n & 1) == 0), 2, 4, 6); + testIntegerStream(() -> Stream.concat(Stream.of(1), Stream.of(2, 3, 4, 5, 6)).filter(n -> (n & 1) == 0), + 2, 4, 6); + testIntegerStream(() -> Stream.concat(Stream.empty(), Stream.of(1, 2, 3, 4, 5, 6)).filter(n -> (n & 1) == 0), + 2, 4, 6); } @Test public void flatMapWorks() { - StringBuilder sb = new StringBuilder(); - Stream.of(Stream.of(1, 2), Stream.of(3, 4)).flatMap(n -> n).forEach(appendNumbersTo(sb)); - assertEquals("1;2;3;4;", sb.toString()); + testIntegerStream(() -> Stream.of(Stream.of(1, 2), Stream.of(3, 4)).flatMap(n -> n), 1, 2, 3, 4); + testIntegerStream(() -> Stream.of(Stream.empty(), Stream.of(1, 2), Stream.of(3, 4)).flatMap(n -> n), + 1, 2, 3, 4); + testIntegerStream(() -> Stream.of(Stream.of(1, 2), Stream.empty(), Stream.of(3, 4)).flatMap(n -> n), + 1, 2, 3, 4); + testIntegerStream(() -> Stream.of(Stream.of(1, 2), Stream.of(3, 4), Stream.empty()).flatMap(n -> n), + 1, 2, 3, 4); - sb.setLength(0); - Stream.of(Stream.of(1, 2), Stream.of(3, 4)).flatMap(n -> n).skip(1).forEach(appendNumbersTo(sb)); - assertEquals("2;3;4;", sb.toString()); + testIntegerStream(() -> Stream.of(Stream.of(1, 2), Stream.of(3, 4)).flatMap(n -> n).skip(1), 2, 3, 4); - sb.setLength(0); - Stream.of(Stream.of(1, 2), Stream.of(3, 4, 5)).flatMap(n -> n).skip(3).forEach(appendNumbersTo(sb)); - assertEquals("4;5;", sb.toString()); + testIntegerStream(() -> Stream.of(Stream.of(1, 2), Stream.of(3, 4, 5)).flatMap(n -> n).skip(3), 4, 5); } @Test public void flatMapToIntWorks() { - StringBuilder sb = new StringBuilder(); - Stream.of(IntStream.of(1, 2), IntStream.of(3, 4)).flatMapToInt(n -> n).forEach(appendIntNumbersTo(sb)); - assertEquals("1;2;3;4;", sb.toString()); + testIntStream(() -> Stream.of(IntStream.of(1, 2), IntStream.of(3, 4)).flatMapToInt(n -> n), 1, 2, 3, 4); + testIntStream(() -> Stream.of(IntStream.empty(), IntStream.of(1, 2), IntStream.of(3, 4)).flatMapToInt(n -> n), + 1, 2, 3, 4); + testIntStream(() -> Stream.of(IntStream.of(1, 2), IntStream.empty(), IntStream.of(3, 4)).flatMapToInt(n -> n), + 1, 2, 3, 4); + testIntStream(() -> Stream.of(IntStream.of(1, 2), IntStream.of(3, 4), IntStream.empty()).flatMapToInt(n -> n), + 1, 2, 3, 4); - sb.setLength(0); - Stream.of(IntStream.of(1, 2), IntStream.of(3, 4)).flatMapToInt(n -> n).skip(1).forEach(appendIntNumbersTo(sb)); - assertEquals("2;3;4;", sb.toString()); + testIntStream(() -> Stream.of(IntStream.of(1, 2), IntStream.of(3, 4)).flatMapToInt(n -> n).skip(1), 2, 3, 4); - sb.setLength(0); - Stream.of(IntStream.of(1, 2), IntStream.of(3, 4, 5)).flatMapToInt(n -> n).skip(3) - .forEach(appendIntNumbersTo(sb)); - assertEquals("4;5;", sb.toString()); + testIntStream(() -> Stream.of(IntStream.of(1, 2), IntStream.of(3, 4, 5)).flatMapToInt(n -> n).skip(3), 4, 5); } @Test public void flatMapToLongWorks() { - StringBuilder sb = new StringBuilder(); - Stream.of(LongStream.of(1, 2), LongStream.of(3, 4)).flatMapToLong(n -> n).forEach(appendLongNumbersTo(sb)); - assertEquals("1;2;3;4;", sb.toString()); + testLongStream(() -> Stream.of(LongStream.of(1, 2), LongStream.of(3, 4)).flatMapToLong(n -> n), 1, 2, 3, 4); + testLongStream(() -> Stream.of(LongStream.empty(), LongStream.of(1, 2), LongStream.of(3, 4)) + .flatMapToLong(n -> n), 1, 2, 3, 4); + testLongStream(() -> Stream.of(LongStream.of(1, 2), LongStream.empty(), LongStream.of(3, 4)) + .flatMapToLong(n -> n), 1, 2, 3, 4); + testLongStream(() -> Stream.of(LongStream.of(1, 2), LongStream.of(3, 4), LongStream.empty()) + .flatMapToLong(n -> n), 1, 2, 3, 4); - sb.setLength(0); - Stream.of(LongStream.of(1, 2), LongStream.of(3, 4)).flatMapToLong(n -> n).skip(1) - .forEach(appendLongNumbersTo(sb)); - assertEquals("2;3;4;", sb.toString()); + testLongStream(() -> Stream.of(LongStream.of(1, 2), LongStream.of(3, 4)) + .flatMapToLong(n -> n).skip(1), 2, 3, 4); - sb.setLength(0); - Stream.of(LongStream.of(1, 2), LongStream.of(3, 4, 5)).flatMapToLong(n -> n).skip(3) - .forEach(appendLongNumbersTo(sb)); - assertEquals("4;5;", sb.toString()); + testLongStream(() -> Stream.of(LongStream.of(1, 2), LongStream.of(3, 4, 5)) + .flatMapToLong(n -> n).skip(3), 4, 5); } @Test public void flatMapToDoubleWorks() { - StringBuilder sb = new StringBuilder(); - Stream.of(DoubleStream.of(1, 2), DoubleStream.of(3, 4)).flatMapToDouble(n -> n) - .forEach(appendDoubleNumbersTo(sb)); - assertEquals("1.0;2.0;3.0;4.0;", sb.toString()); + testDoubleStream(() -> Stream.of(DoubleStream.of(1, 2), DoubleStream.of(3, 4)).flatMapToDouble(n -> n), + 1, 2, 3, 4); + testDoubleStream(() -> Stream.of(DoubleStream.empty(), DoubleStream.of(1, 2), DoubleStream.of(3, 4)) + .flatMapToDouble(n -> n), 1, 2, 3, 4); + testDoubleStream(() -> Stream.of(DoubleStream.of(1, 2), DoubleStream.empty(), DoubleStream.of(3, 4)) + .flatMapToDouble(n -> n), 1, 2, 3, 4); + testDoubleStream(() -> Stream.of(DoubleStream.of(1, 2), DoubleStream.of(3, 4), DoubleStream.empty()) + .flatMapToDouble(n -> n), 1, 2, 3, 4); - sb.setLength(0); - Stream.of(DoubleStream.of(1, 2), DoubleStream.of(3, 4)).flatMapToDouble(n -> n).skip(1) - .forEach(appendDoubleNumbersTo(sb)); - assertEquals("2.0;3.0;4.0;", sb.toString()); + testDoubleStream(() -> Stream.of(DoubleStream.of(1, 2), DoubleStream.of(3, 4)) + .flatMapToDouble(n -> n).skip(1), 2, 3, 4); - sb.setLength(0); - Stream.of(DoubleStream.of(1, 2), DoubleStream.of(3, 4, 5)).flatMapToDouble(n -> n).skip(3) - .forEach(appendDoubleNumbersTo(sb)); - assertEquals("4.0;5.0;", sb.toString()); + testDoubleStream(() -> Stream.of(DoubleStream.of(1, 2), DoubleStream.of(3, 4, 5)) + .flatMapToDouble(n -> n).skip(3), 4, 5); } @Test public void skipWorks() { - for (int i = 0; i <= 6; ++i) { - StringBuilder sb = new StringBuilder(); - Stream.iterate(1, n -> n + 1).limit(5).skip(i).forEach(appendNumbersTo(sb)); - - StringBuilder expected = new StringBuilder(); + for (int i = 0; i <= 5; ++i) { + int index = i; + Integer[] expected = new Integer[5 - i]; for (int j = i; j < 5; ++j) { - expected.append(j + 1).append(';'); + expected[j - i] = j + 1; } - assertEquals("Error skipping " + i + " elements", expected.toString(), sb.toString()); + testIntegerStream(() -> Stream.iterate(1, n -> n + 1).limit(5).skip(index), expected); + testIntegerStream(() -> Stream.concat(Stream.of(1), Stream.iterate(2, n -> n + 1).limit(4)) + .skip(index), expected); + testIntegerStream(() -> Stream.concat(Stream.empty(), Stream.iterate(1, n -> n + 1).limit(5)) + .skip(index), expected); } } @Test public void limitWorks() { for (int i = 0; i <= 3; ++i) { - StringBuilder sb = new StringBuilder(); - Stream.iterate(1, n -> n + 1).limit(i).forEach(appendNumbersTo(sb)); - - StringBuilder expected = new StringBuilder(); - for (int j = 0; j < i; ++j) { - expected.append(j + 1).append(';'); + int index = i; + Integer[] expected = new Integer[i]; + for (int j = 0; j < expected.length; ++j) { + expected[j] = j + 1; } - assertEquals("Error limiting to " + i + " elements", expected.toString(), sb.toString()); + + testIntegerStream(() -> Stream.iterate(1, n -> n + 1).limit(index), expected); } } @@ -242,26 +245,20 @@ public class StreamTest { @Test public void streamOfOneElement() { - StringBuilder sb = new StringBuilder(); - Stream.of(5).forEach(appendNumbersTo(sb)); - assertEquals("5;", sb.toString()); - - sb.setLength(0); - Stream.of(5).skip(1).forEach(appendNumbersTo(sb)); - assertEquals("", sb.toString()); - - sb.setLength(0); - Stream.concat(Stream.of(5), Stream.of(6)).forEach(appendNumbersTo(sb)); - assertEquals("5;6;", sb.toString()); + testIntegerStream(() -> Stream.of(5), 5); + testIntegerStream(() -> Stream.of(5).skip(1)); + testIntegerStream(() -> Stream.concat(Stream.of(5), Stream.of(6)), 5, 6); + testIntegerStream(() -> Stream.concat(Stream.empty(), Stream.of(5)), 5); + testIntegerStream(() -> Stream.concat(Stream.of(5), Stream.empty()), 5); } @Test public void sortedStream() { - StringBuilder sb = new StringBuilder(); - Stream.of(5, 7, 1, 2, 4, 3).sorted().forEach(appendNumbersTo(sb)); - assertEquals("1;2;3;4;5;7;", sb.toString()); + testIntegerStream(() -> Stream.of(5, 7, 1, 2, 4, 3).sorted(), 1, 2, 3, 4, 5, 7); + testIntegerStream(() -> Stream.concat(Stream.of(5), Stream.of(7, 1, 2, 4, 3)).sorted(), 1, 2, 3, 4, 5, 7); + testIntegerStream(() -> Stream.concat(Stream.empty(), Stream.of(5, 7, 1, 2, 4, 3)).sorted(), 1, 2, 3, 4, 5, 7); - sb.setLength(0); + StringBuilder sb = new StringBuilder(); Stream.of(2, 3, 1).peek(appendNumbersTo(sb)).sorted().limit(2).map(n -> n + 10).forEach(appendNumbersTo(sb)); assertEquals("2;3;1;11;12;", sb.toString()); @@ -367,20 +364,4 @@ public class StreamTest { spliterator.forEachRemaining(appendNumbersTo(sb)); assertEquals("1;2;3;", sb.toString()); } - - private Consumer appendNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } - - private IntConsumer appendIntNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } - - private LongConsumer appendLongNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } - - private DoubleConsumer appendDoubleNumbersTo(StringBuilder sb) { - return n -> sb.append(n).append(';'); - } -} +} \ No newline at end of file