From c066864c6842b7a92bf70e653af3df311d8b3236 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 26 Apr 2024 21:30:13 +0200 Subject: [PATCH] classlib: fix bug in Stream.takeWhile Fix #913 --- .../doubleimpl/TTakeWhileDoubleStream.java | 29 ++++++++++--------- .../util/stream/impl/TTakeWhileStream.java | 29 ++++++++++--------- .../stream/intimpl/TTakeWhileIntStream.java | 29 ++++++++++--------- .../stream/longimpl/TTakeWhileLongStream.java | 27 +++++++++-------- .../java/util/stream/IntStreamTest.java | 18 ++++++++++++ .../classlib/java/util/stream/StreamTest.java | 19 ++++++++++++ 6 files changed, 100 insertions(+), 51 deletions(-) diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TTakeWhileDoubleStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TTakeWhileDoubleStream.java index 50eb1553c..8c4bb42b7 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TTakeWhileDoubleStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TTakeWhileDoubleStream.java @@ -17,30 +17,33 @@ package org.teavm.classlib.java.util.stream.doubleimpl; import java.util.function.DoublePredicate; -public class TTakeWhileDoubleStream extends TWrappingDoubleStreamImpl { +public class TTakeWhileDoubleStream extends TSimpleDoubleStreamImpl { + private TSimpleDoubleStreamImpl sourceStream; private DoublePredicate predicate; /* set to `true` as soon as we see a value `v` in the source stream for which `predicate.test(v)` is false */ private boolean isStopped; - TTakeWhileDoubleStream(TSimpleDoubleStreamImpl innerStream, DoublePredicate predicate) { - super(innerStream); + TTakeWhileDoubleStream(TSimpleDoubleStreamImpl sourceStream, DoublePredicate predicate) { + this.sourceStream = sourceStream; this.predicate = predicate; } @Override - protected DoublePredicate wrap(DoublePredicate consumer) { - return t -> { - if (isStopped) { - return false; - } - - if (predicate.test(t)) { - return consumer.test(t); - } else { + public boolean next(DoublePredicate consumer) { + if (isStopped) { + return false; + } + var result = sourceStream.next(e -> { + if (!predicate.test(e)) { isStopped = true; return false; } - }; + return consumer.test(e); + }); + if (!result) { + isStopped = true; + } + return result; } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TTakeWhileStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TTakeWhileStream.java index 18fb24164..787be7118 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TTakeWhileStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TTakeWhileStream.java @@ -17,30 +17,33 @@ package org.teavm.classlib.java.util.stream.impl; import java.util.function.Predicate; -public class TTakeWhileStream extends TWrappingStreamImpl { +public class TTakeWhileStream extends TSimpleStreamImpl { + private TSimpleStreamImpl sourceStream; private Predicate predicate; /* set to `true` as soon as we see a value `v` in the source stream for which `predicate.test(v)` is false */ private boolean isStopped; - TTakeWhileStream(TSimpleStreamImpl innerStream, Predicate predicate) { - super(innerStream); + TTakeWhileStream(TSimpleStreamImpl sourceStream, Predicate predicate) { + this.sourceStream = sourceStream; this.predicate = predicate; } @Override - protected Predicate wrap(Predicate consumer) { - return t -> { - if (isStopped) { - return false; - } - - if (predicate.test(t)) { - return consumer.test(t); - } else { + public boolean next(Predicate consumer) { + if (isStopped) { + return false; + } + var result = sourceStream.next(e -> { + if (!predicate.test(e)) { isStopped = true; return false; } - }; + return consumer.test(e); + }); + if (!result) { + isStopped = true; + } + return result; } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TTakeWhileIntStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TTakeWhileIntStream.java index 56419b43e..506177df1 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TTakeWhileIntStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TTakeWhileIntStream.java @@ -17,30 +17,33 @@ package org.teavm.classlib.java.util.stream.intimpl; import java.util.function.IntPredicate; -public class TTakeWhileIntStream extends TWrappingIntStreamImpl { +public class TTakeWhileIntStream extends TSimpleIntStreamImpl { + private TSimpleIntStreamImpl sourceStream; private IntPredicate predicate; /* set to `true` as soon as we see a value `v` in the source stream for which `predicate.test(v)` is false */ private boolean isStopped; - TTakeWhileIntStream(TSimpleIntStreamImpl innerStream, IntPredicate predicate) { - super(innerStream); + TTakeWhileIntStream(TSimpleIntStreamImpl sourceStream, IntPredicate predicate) { + this.sourceStream = sourceStream; this.predicate = predicate; } @Override - protected IntPredicate wrap(IntPredicate consumer) { - return t -> { - if (isStopped) { - return false; - } - - if (predicate.test(t)) { - return consumer.test(t); - } else { + public boolean next(IntPredicate consumer) { + if (isStopped) { + return false; + } + var result = sourceStream.next(e -> { + if (!predicate.test(e)) { isStopped = true; return false; } - }; + return consumer.test(e); + }); + if (!result) { + isStopped = true; + } + return result; } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TTakeWhileLongStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TTakeWhileLongStream.java index 513a59168..45bb02b31 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TTakeWhileLongStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TTakeWhileLongStream.java @@ -17,30 +17,33 @@ package org.teavm.classlib.java.util.stream.longimpl; import java.util.function.LongPredicate; -public class TTakeWhileLongStream extends TWrappingLongStreamImpl { +public class TTakeWhileLongStream extends TSimpleLongStreamImpl { + private TSimpleLongStreamImpl sourceStream; private LongPredicate predicate; /* set to `true` as soon as we see a value `v` in the source stream for which `predicate.test(v)` is false */ private boolean isStopped; TTakeWhileLongStream(TSimpleLongStreamImpl innerStream, LongPredicate predicate) { - super(innerStream); + this.sourceStream = innerStream; this.predicate = predicate; } @Override - protected LongPredicate wrap(LongPredicate consumer) { - return t -> { - if (isStopped) { - return false; - } - - if (predicate.test(t)) { - return consumer.test(t); - } else { + public boolean next(LongPredicate consumer) { + if (isStopped) { + return false; + } + var result = sourceStream.next(e -> { + if (!predicate.test(e)) { isStopped = true; return false; } - }; + return consumer.test(e); + }); + if (!result) { + isStopped = true; + } + return result; } } 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 24fb08292..1e0addaa3 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 @@ -27,6 +27,7 @@ import static org.teavm.classlib.java.util.stream.Helper.testLongStream; import java.util.IntSummaryStatistics; import java.util.PrimitiveIterator; import java.util.Spliterator; +import java.util.function.IntSupplier; import java.util.stream.IntStream; import org.junit.Test; import org.junit.runner.RunWith; @@ -112,6 +113,23 @@ public class IntStreamTest { public void takeWhileWorks() { assertArrayEquals(new int[] { 1, 2, 3 }, IntStream.of(1, 2, 3, 4, 0, 5, 6).takeWhile(n -> n < 4).toArray()); + + class ForeverIncreasingSupplier implements IntSupplier { + int value = 1; + + @Override + public int getAsInt() { + return value++; + } + } + + testIntStream( + () -> IntStream.concat( + IntStream.generate(new ForeverIncreasingSupplier()).takeWhile(n -> n < 4), + IntStream.generate(new ForeverIncreasingSupplier()).takeWhile(n -> n < 3) + ), + 1, 2, 3, 1, 2 + ); } @Test 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 0a17f0848..5ac1a876f 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 @@ -33,6 +33,7 @@ import java.util.Iterator; import java.util.List; import java.util.Spliterator; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.DoubleStream; import java.util.stream.IntStream; import java.util.stream.LongStream; @@ -394,6 +395,23 @@ public class StreamTest { var sb = new StringBuilder(); Stream.of(1, 2, 3, 4, 0, 5, 6).takeWhile(n -> n < 4).forEach(sb::append); assertEquals("123", sb.toString()); + + class ForeverIncreasingSupplier implements Supplier { + int value = 1; + + @Override + public Integer get() { + return value++; + } + } + + testIntegerStream( + () -> Stream.concat( + Stream.generate(new ForeverIncreasingSupplier()).takeWhile(n -> n < 4), + Stream.generate(new ForeverIncreasingSupplier()).takeWhile(n -> n < 3) + ), + 1, 2, 3, 1, 2 + ); } @Test @@ -488,4 +506,5 @@ public class StreamTest { List repetitions = Stream.iterate("", s -> s.length() < 5, s -> s + "a").toList(); assertEquals(List.of("", "a", "aa", "aaa", "aaaa"), repetitions); } + } \ No newline at end of file