diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/TDoubleStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/TDoubleStream.java index 9b5819786..6a7d2b7ac 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/TDoubleStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/TDoubleStream.java @@ -81,6 +81,10 @@ public interface TDoubleStream extends TBaseStream { TDoubleStream limit(long maxSize); + TDoubleStream takeWhile(DoublePredicate predicate); + + TDoubleStream dropWhile(DoublePredicate predicate); + TDoubleStream skip(long n); void forEach(DoubleConsumer action); diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/TIntStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/TIntStream.java index 841e07d56..97233dc69 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/TIntStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/TIntStream.java @@ -83,6 +83,10 @@ public interface TIntStream extends TBaseStream { TIntStream limit(long maxSize); + TIntStream takeWhile(IntPredicate predicate); + + TIntStream dropWhile(IntPredicate predicate); + TIntStream skip(long n); void forEach(IntConsumer action); diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/TLongStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/TLongStream.java index 88c48f06d..f80420e40 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/TLongStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/TLongStream.java @@ -83,6 +83,10 @@ public interface TLongStream extends TBaseStream { TLongStream limit(long maxSize); + TLongStream takeWhile(LongPredicate predicate); + + TLongStream dropWhile(LongPredicate predicate); + TLongStream skip(long n); void forEach(LongConsumer action); diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/TStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/TStream.java index c3a9d150a..3b62e4432 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/TStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/TStream.java @@ -119,6 +119,8 @@ public interface TStream extends TBaseStream> { TStream takeWhile(Predicate predicate); + TStream dropWhile(Predicate predicate); + TStream skip(long n); void forEach(Consumer action); diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TDropWhileDoubleStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TDropWhileDoubleStream.java new file mode 100644 index 000000000..05b67e741 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TDropWhileDoubleStream.java @@ -0,0 +1,44 @@ +/* + * Copyright 2023 ihromant. + * + * 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 TDropWhileDoubleStream extends TWrappingDoubleStreamImpl { + private DoublePredicate predicate; + + /* set to `true` as soon as we see a value `v` in the source stream for which `predicate.test(v)` is true */ + private boolean isStarted; + + TDropWhileDoubleStream(TSimpleDoubleStreamImpl innerStream, DoublePredicate predicate) { + super(innerStream); + this.predicate = predicate; + } + + @Override + protected DoublePredicate wrap(DoublePredicate consumer) { + return t -> { + if (!isStarted) { + if (predicate.test(t)) { + return true; + } else { + isStarted = true; + } + } + return consumer.test(t); + }; + } +} 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 d2963c014..f10bcef86 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 @@ -90,6 +90,16 @@ public abstract class TSimpleDoubleStreamImpl implements TDoubleStream { return new TLimitingDoubleStreamImpl(this, (int) maxSize); } + @Override + public TDoubleStream takeWhile(DoublePredicate predicate) { + return new TTakeWhileDoubleStream(this, predicate); + } + + @Override + public TDoubleStream dropWhile(DoublePredicate predicate) { + return new TDropWhileDoubleStream(this, predicate); + } + @Override public TDoubleStream skip(long n) { return new TSkippingDoubleStreamImpl(this, (int) n); 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 new file mode 100644 index 000000000..50eb1553c --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TTakeWhileDoubleStream.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023 ihromant. + * + * 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 TTakeWhileDoubleStream extends TWrappingDoubleStreamImpl { + 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); + this.predicate = predicate; + } + + @Override + protected DoublePredicate wrap(DoublePredicate consumer) { + return t -> { + if (isStopped) { + return false; + } + + if (predicate.test(t)) { + return consumer.test(t); + } else { + isStopped = true; + return false; + } + }; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TDropWhileStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TDropWhileStream.java new file mode 100644 index 000000000..c34535f8f --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/impl/TDropWhileStream.java @@ -0,0 +1,44 @@ +/* + * Copyright 2023 ihromant. + * + * 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 TDropWhileStream extends TWrappingStreamImpl { + private Predicate predicate; + + /* set to `true` as soon as we see a value `v` in the source stream for which `predicate.test(v)` is true */ + private boolean isStarted; + + TDropWhileStream(TSimpleStreamImpl innerStream, Predicate predicate) { + super(innerStream); + this.predicate = predicate; + } + + @Override + protected Predicate wrap(Predicate consumer) { + return t -> { + if (!isStarted) { + if (predicate.test(t)) { + return true; + } else { + isStarted = true; + } + } + return consumer.test(t); + }; + } +} 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 10f839089..98c78faf9 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 @@ -116,6 +116,11 @@ public abstract class TSimpleStreamImpl implements TStream { return new TTakeWhileStream<>(this, predicate); } + @Override + public TStream dropWhile(Predicate predicate) { + return new TDropWhileStream<>(this, predicate); + } + @Override public TStream skip(long n) { return new TSkippingStreamImpl<>(this, (int) n); diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TDropWhileIntStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TDropWhileIntStream.java new file mode 100644 index 000000000..b03aace3d --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TDropWhileIntStream.java @@ -0,0 +1,44 @@ +/* + * Copyright 2023 ihromant. + * + * 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 TDropWhileIntStream extends TWrappingIntStreamImpl { + private IntPredicate predicate; + + /* set to `true` as soon as we see a value `v` in the source stream for which `predicate.test(v)` is true */ + private boolean isStarted; + + TDropWhileIntStream(TSimpleIntStreamImpl innerStream, IntPredicate predicate) { + super(innerStream); + this.predicate = predicate; + } + + @Override + protected IntPredicate wrap(IntPredicate consumer) { + return t -> { + if (!isStarted) { + if (predicate.test(t)) { + return true; + } else { + isStarted = true; + } + } + return consumer.test(t); + }; + } +} 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 e44ff529a..ee002c222 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 @@ -91,6 +91,16 @@ public abstract class TSimpleIntStreamImpl implements TIntStream { return new TLimitingIntStreamImpl(this, (int) maxSize); } + @Override + public TIntStream takeWhile(IntPredicate predicate) { + return new TTakeWhileIntStream(this, predicate); + } + + @Override + public TIntStream dropWhile(IntPredicate predicate) { + return new TDropWhileIntStream(this, predicate); + } + @Override public TIntStream skip(long n) { return new TSkippingIntStreamImpl(this, (int) n); 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 new file mode 100644 index 000000000..56419b43e --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TTakeWhileIntStream.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023 ihromant. + * + * 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 TTakeWhileIntStream extends TWrappingIntStreamImpl { + 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); + this.predicate = predicate; + } + + @Override + protected IntPredicate wrap(IntPredicate consumer) { + return t -> { + if (isStopped) { + return false; + } + + if (predicate.test(t)) { + return consumer.test(t); + } else { + isStopped = true; + return false; + } + }; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TDropWhileLongStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TDropWhileLongStream.java new file mode 100644 index 000000000..e822e9b34 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TDropWhileLongStream.java @@ -0,0 +1,44 @@ +/* + * Copyright 2023 ihromant. + * + * 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 TDropWhileLongStream extends TWrappingLongStreamImpl { + private LongPredicate predicate; + + /* set to `true` as soon as we see a value `v` in the source stream for which `predicate.test(v)` is true */ + private boolean isStarted; + + TDropWhileLongStream(TSimpleLongStreamImpl innerStream, LongPredicate predicate) { + super(innerStream); + this.predicate = predicate; + } + + @Override + protected LongPredicate wrap(LongPredicate consumer) { + return t -> { + if (!isStarted) { + if (predicate.test(t)) { + return true; + } else { + isStarted = true; + } + } + return consumer.test(t); + }; + } +} 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 58d98252f..827a67a1f 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 @@ -91,6 +91,16 @@ public abstract class TSimpleLongStreamImpl implements TLongStream { return new TLimitingLongStreamImpl(this, (int) maxSize); } + @Override + public TLongStream takeWhile(LongPredicate predicate) { + return new TTakeWhileLongStream(this, predicate); + } + + @Override + public TLongStream dropWhile(LongPredicate predicate) { + return new TDropWhileLongStream(this, predicate); + } + @Override public TLongStream skip(long n) { return new TSkippingLongStreamImpl(this, (int) n); 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 new file mode 100644 index 000000000..513a59168 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TTakeWhileLongStream.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023 ihromant. + * + * 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 TTakeWhileLongStream extends TWrappingLongStreamImpl { + 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.predicate = predicate; + } + + @Override + protected LongPredicate wrap(LongPredicate consumer) { + return t -> { + if (isStopped) { + return false; + } + + if (predicate.test(t)) { + return consumer.test(t); + } else { + isStopped = true; + return false; + } + }; + } +} 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 1fbc7a668..24fb08292 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 @@ -108,6 +108,34 @@ public class IntStreamTest { } } + @Test + public void takeWhileWorks() { + assertArrayEquals(new int[] { 1, 2, 3 }, + IntStream.of(1, 2, 3, 4, 0, 5, 6).takeWhile(n -> n < 4).toArray()); + } + + @Test + public void dropWhileWorks() { + assertArrayEquals(new int[] { 4, 0, 5, 6 }, + IntStream.of(1, 2, 3, 4, 0, 5, 6).dropWhile(n -> n < 4).toArray()); + assertArrayEquals(new int[] {}, + IntStream.of(1, 2, 3, 4, 0, 5, 6).dropWhile(n -> n < 7).toArray()); + } + + @Test + public void takeWhileWithOtherStreamOps() { + assertArrayEquals(new int[] { 1, 3 }, + IntStream.of(1, 2, 3, 4, 0, 5, 6).takeWhile(i -> i < 4).filter(i -> i % 2 != 0).toArray()); + } + + @Test + public void dropWhileWithOtherStreamOps() { + assertArrayEquals(new int[] { 4, 0, 6 }, + IntStream.of(1, 2, 3, 4, 0, 5, 6).dropWhile(i -> i < 4).filter(i -> i % 2 == 0).toArray()); + assertArrayEquals(new int[] {}, + IntStream.of(1, 2, 3, 4, 0, 5, 6).dropWhile(i -> i < 7).filter(i -> i % 2 == 0).toArray()); + } + @Test public void limitWorks() { for (int i = 0; i <= 3; ++i) { 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 09ac579d7..0a17f0848 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 @@ -396,6 +396,16 @@ public class StreamTest { assertEquals("123", sb.toString()); } + @Test + public void dropWhileWorks() { + var sb = new StringBuilder(); + Stream.of(1, 2, 3, 4, 0, 5, 6).dropWhile(n -> n < 4).forEach(sb::append); + assertEquals("4056", sb.toString()); + sb = new StringBuilder(); + Stream.of(1, 2, 3, 4, 0, 5, 6).dropWhile(n -> n < 7).forEach(sb::append); + assertEquals("", sb.toString()); + } + @Test public void takeWhileWithOtherStreamOps() { var sb = new StringBuilder(); @@ -403,6 +413,16 @@ public class StreamTest { assertEquals("13", sb.toString()); } + @Test + public void dropWhileWithOtherStreamOps() { + var sb = new StringBuilder(); + Stream.of(1, 2, 3, 4, 0, 5, 6).dropWhile(i -> i < 4).filter(i -> i % 2 == 0).forEach(sb::append); + assertEquals("406", sb.toString()); + sb = new StringBuilder(); + Stream.of(1, 2, 3, 4, 0, 5, 6).dropWhile(i -> i < 7).filter(i -> i % 2 == 0).forEach(sb::append); + assertEquals("", sb.toString()); + } + @Test public void toList() { List list = Stream.of(1, 2, 3, 4, 5).filter(i -> i % 2 == 0).toList();