From 8b9d39dbb84a4494ed6a93e76df25cbdb713d086 Mon Sep 17 00:00:00 2001 From: Ivan Hetman Date: Wed, 7 Jun 2023 11:18:37 +0300 Subject: [PATCH] classlib: additional collectors for streams --- .../java/util/TDoubleSummaryStatistics.java | 90 +++++++++++++++++++ .../java/util/TIntSummaryStatistics.java | 84 +++++++++++++++++ .../java/util/TLongSummaryStatistics.java | 88 ++++++++++++++++++ .../java/util/stream/TCollectors.java | 90 +++++++++++++++++++ .../java/util/stream/TDoubleStream.java | 3 + .../classlib/java/util/stream/TIntStream.java | 3 + .../java/util/stream/TLongStream.java | 3 + .../doubleimpl/TSimpleDoubleStreamImpl.java | 10 +++ .../doubleimpl/TSummaryDoubleConsumer.java | 29 ++++++ .../stream/intimpl/TSimpleIntStreamImpl.java | 10 +++ .../stream/intimpl/TSummaryIntConsumer.java | 29 ++++++ .../longimpl/TSimpleLongStreamImpl.java | 10 +++ .../stream/longimpl/TSummaryLongConsumer.java | 29 ++++++ .../java/util/stream/CollectorsTest.java | 63 +++++++++++++ .../java/util/stream/DoubleStreamTest.java | 17 ++++ .../java/util/stream/IntStreamTest.java | 17 ++++ .../java/util/stream/LongStreamTest.java | 17 ++++ 17 files changed, 592 insertions(+) create mode 100644 classlib/src/main/java/org/teavm/classlib/java/util/TDoubleSummaryStatistics.java create mode 100644 classlib/src/main/java/org/teavm/classlib/java/util/TIntSummaryStatistics.java create mode 100644 classlib/src/main/java/org/teavm/classlib/java/util/TLongSummaryStatistics.java create mode 100644 classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSummaryDoubleConsumer.java create mode 100644 classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSummaryIntConsumer.java create mode 100644 classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSummaryLongConsumer.java diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TDoubleSummaryStatistics.java b/classlib/src/main/java/org/teavm/classlib/java/util/TDoubleSummaryStatistics.java new file mode 100644 index 000000000..78422a2d7 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TDoubleSummaryStatistics.java @@ -0,0 +1,90 @@ +/* + * 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; + +import org.teavm.classlib.java.util.function.TDoubleConsumer; + +public class TDoubleSummaryStatistics implements TDoubleConsumer { + private long count; + private double sum; + private double min = Double.POSITIVE_INFINITY; + private double max = Double.NEGATIVE_INFINITY; + + public TDoubleSummaryStatistics() { } + + public TDoubleSummaryStatistics(long count, double min, double max, double sum) + throws IllegalArgumentException { + if (count < 0L || count > 0L && min > max) { + throw new IllegalArgumentException(); + } + if (count == 0L) { + return; + } + boolean minNan = Double.isNaN(min); + boolean maxNan = Double.isNaN(max); + boolean sumNan = Double.isNaN(sum); + if ((!minNan || !maxNan || !sumNan) && (minNan || maxNan || sumNan)) { + throw new IllegalArgumentException(); + } + + this.count = count; + this.sum = sum; + this.min = min; + this.max = max; + } + + @Override + public void accept(double value) { + ++count; + sum = sum + value; + min = Math.min(min, value); + max = Math.max(max, value); + } + + public void combine(TDoubleSummaryStatistics that) { + this.count = this.count + that.count; + this.sum = this.sum + that.sum; + + this.min = Math.min(this.min, that.min); + this.max = Math.max(this.max, that.max); + } + + public final long getCount() { + return count; + } + + public final double getSum() { + return sum; + } + + public final double getMin() { + return min; + } + + public final double getMax() { + return max; + } + + public final double getAverage() { + return count > 0 ? sum / count : 0.0d; + } + + @Override + public String toString() { + return "DoubleSummaryStatistics{" + "count=" + count + ", sum=" + sum + ", min=" + min + + ", max=" + max + ", avg=" + getAverage() + "}"; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TIntSummaryStatistics.java b/classlib/src/main/java/org/teavm/classlib/java/util/TIntSummaryStatistics.java new file mode 100644 index 000000000..faee8cb54 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TIntSummaryStatistics.java @@ -0,0 +1,84 @@ +/* + * 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; + +import org.teavm.classlib.java.util.function.TIntConsumer; + +public class TIntSummaryStatistics implements TIntConsumer { + private long count; + private long sum; + private int min = Integer.MAX_VALUE; + private int max = Integer.MIN_VALUE; + + public TIntSummaryStatistics() { + + } + + public TIntSummaryStatistics(long count, int min, int max, long sum) + throws IllegalArgumentException { + if (count < 0L || count > 0L && min > max) { + throw new IllegalArgumentException(); + } + if (count == 0L) { + return; + } + this.count = count; + this.sum = sum; + this.min = min; + this.max = max; + } + + @Override + public void accept(int value) { + ++count; + sum = sum + value; + min = Math.min(min, value); + max = Math.max(max, value); + } + + public void combine(TIntSummaryStatistics that) { + this.count = this.count + that.count; + this.sum = this.sum + that.sum; + this.min = Math.min(this.min, that.min); + this.max = Math.max(this.max, that.max); + } + + public final long getCount() { + return count; + } + + public final long getSum() { + return sum; + } + + public final int getMin() { + return min; + } + + public final int getMax() { + return max; + } + + public final double getAverage() { + return count > 0 ? (double) sum / count : 0.0d; + } + + @Override + public String toString() { + return "IntSummaryStatistics{" + "count=" + count + ", sum=" + sum + ", min=" + min + + ", max=" + max + ", avg=" + getAverage() + "}"; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TLongSummaryStatistics.java b/classlib/src/main/java/org/teavm/classlib/java/util/TLongSummaryStatistics.java new file mode 100644 index 000000000..3a6ed7ec8 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TLongSummaryStatistics.java @@ -0,0 +1,88 @@ +/* + * 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; + +import org.teavm.classlib.java.util.function.TIntConsumer; +import org.teavm.classlib.java.util.function.TLongConsumer; + +public class TLongSummaryStatistics implements TLongConsumer, TIntConsumer { + private long count; + private long sum; + private long min = Long.MAX_VALUE; + private long max = Long.MIN_VALUE; + + public TLongSummaryStatistics() { } + + public TLongSummaryStatistics(long count, long min, long max, long sum) + throws IllegalArgumentException { + if (count < 0L || count > 0L && min > max) { + throw new IllegalArgumentException(); + } + if (count == 0L) { + return; + } + this.count = count; + this.sum = sum; + this.min = min; + this.max = max; + } + + @Override + public void accept(int value) { + accept((long) value); + } + + @Override + public void accept(long value) { + ++count; + sum = sum + value; + min = Math.min(min, value); + max = Math.max(max, value); + } + + public void combine(TLongSummaryStatistics that) { + this.count = that.count; + this.sum = this.sum + that.sum; + this.min = Math.min(this.min, that.min); + this.max = Math.max(this.max, that.max); + } + + public final long getCount() { + return count; + } + + public final long getSum() { + return sum; + } + + public final long getMin() { + return min; + } + + public final long getMax() { + return max; + } + + public final double getAverage() { + return count > 0 ? (double) sum / count : 0.0d; + } + + @Override + public String toString() { + return "LongSummaryStatistics{" + "count=" + count + ", sum=" + sum + ", min=" + min + + ", max=" + max + ", avg=" + getAverage() + "}"; + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/TCollectors.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/TCollectors.java index cc4c95005..7c9702ffc 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/TCollectors.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/TCollectors.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.DoubleSummaryStatistics; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; @@ -27,9 +28,18 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; +import java.util.function.BiFunction; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.Supplier; +import java.util.function.ToDoubleFunction; +import java.util.function.ToIntFunction; +import java.util.function.ToLongFunction; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import org.teavm.classlib.java.util.TDoubleSummaryStatistics; +import org.teavm.classlib.java.util.TIntSummaryStatistics; +import org.teavm.classlib.java.util.TLongSummaryStatistics; import org.teavm.classlib.java.util.TObjects; public final class TCollectors { @@ -253,4 +263,84 @@ public final class TCollectors { public static TCollector counting() { return reducing(0L, e -> 1L, Long::sum); } + + public static TCollector summingInt(ToIntFunction mapper) { + return TCollector.of( + () -> new int[1], + (a, t) -> a[0] = a[0] + mapper.applyAsInt(t), + (a, b) -> { + a[0] = a[0] + b[0]; + return a; + }, + a -> a[0]); + } + + public static TCollector summingLong(ToLongFunction mapper) { + return collectingAndThen(summarizingLong(mapper), TLongSummaryStatistics::getSum); + } + + public static TCollector summingDouble(ToDoubleFunction mapper) { + return collectingAndThen(summarizingDouble(mapper), TDoubleSummaryStatistics::getSum); + } + + public static TCollector averagingInt(ToIntFunction mapper) { + return collectingAndThen(summarizingInt(mapper), TIntSummaryStatistics::getAverage); + } + + public static TCollector averagingLong(ToLongFunction mapper) { + return collectingAndThen(summarizingLong(mapper), TLongSummaryStatistics::getAverage); + } + + public static TCollector averagingDouble(ToDoubleFunction mapper) { + return collectingAndThen(summarizingDouble(mapper), TDoubleSummaryStatistics::getAverage); + } + + public static TCollector summarizingInt(ToIntFunction mapper) { + return TCollector.of( + TIntSummaryStatistics::new, + (r, t) -> r.accept(mapper.applyAsInt(t)), + (l, r) -> { l.combine(r); return l; }, TCollector.Characteristics.IDENTITY_FINISH); + } + + public static TCollector summarizingLong(ToLongFunction mapper) { + return TCollector.of( + TLongSummaryStatistics::new, + (r, t) -> r.accept(mapper.applyAsLong(t)), + (l, r) -> { l.combine(r); return l; }, TCollector.Characteristics.IDENTITY_FINISH); + } + + public static TCollector summarizingDouble(ToDoubleFunction mapper) { + return TCollector.of( + TDoubleSummaryStatistics::new, + (r, t) -> r.accept(mapper.applyAsDouble(t)), + (l, r) -> { l.combine(r); return l; }, TCollector.Characteristics.IDENTITY_FINISH); + } + + private static TCollector teeingUnwrap(TCollector left, + TCollector right, BiFunction merger) { + return TCollector.of(() -> new Pair<>(left.supplier().get(), right.supplier().get()), + (p, t) -> { + left.accumulator().accept(p.a, t); + right.accumulator().accept(p.b, t); + }, (p1, p2) -> { + p1.a = left.combiner().apply(p1.a, p2.a); + p2.b = right.combiner().apply(p1.b, p2.b); + return p1; + }, p -> merger.apply(left.finisher().apply(p.a), right.finisher().apply(p.b))); + } + + public static TCollector teeing(TCollector left, + TCollector right, BiFunction merger) { + return teeingUnwrap(left, right, merger); + } + + private static class Pair { + private A a; + private B b; + + private Pair(A a, B b) { + this.a = a; + this.b = b; + } + } } 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 f801fa8e3..95ce1c0fe 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 @@ -29,6 +29,7 @@ import java.util.function.DoubleToLongFunction; import java.util.function.DoubleUnaryOperator; import java.util.function.ObjDoubleConsumer; import java.util.function.Supplier; +import org.teavm.classlib.java.util.TDoubleSummaryStatistics; import org.teavm.classlib.java.util.stream.doubleimpl.TArrayDoubleStreamImpl; import org.teavm.classlib.java.util.stream.doubleimpl.TDoubleStreamBuilder; import org.teavm.classlib.java.util.stream.doubleimpl.TEmptyDoubleStreamImpl; @@ -95,6 +96,8 @@ public interface TDoubleStream extends TBaseStream { OptionalDouble average(); + TDoubleSummaryStatistics summaryStatistics(); + boolean anyMatch(DoublePredicate predicate); boolean allMatch(DoublePredicate predicate); 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 3f44e8cfe..7796d6575 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 @@ -30,6 +30,7 @@ import java.util.function.IntToLongFunction; import java.util.function.IntUnaryOperator; import java.util.function.ObjIntConsumer; import java.util.function.Supplier; +import org.teavm.classlib.java.util.TIntSummaryStatistics; import org.teavm.classlib.java.util.stream.intimpl.TArrayIntStreamImpl; import org.teavm.classlib.java.util.stream.intimpl.TEmptyIntStreamImpl; import org.teavm.classlib.java.util.stream.intimpl.TGenerateIntStream; @@ -97,6 +98,8 @@ public interface TIntStream extends TBaseStream { OptionalDouble average(); + TIntSummaryStatistics summaryStatistics(); + boolean anyMatch(IntPredicate predicate); boolean allMatch(IntPredicate predicate); 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 2b32a18db..6db9ce723 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 @@ -30,6 +30,7 @@ import java.util.function.LongToIntFunction; import java.util.function.LongUnaryOperator; import java.util.function.ObjLongConsumer; import java.util.function.Supplier; +import org.teavm.classlib.java.util.TLongSummaryStatistics; import org.teavm.classlib.java.util.stream.longimpl.TArrayLongStreamImpl; import org.teavm.classlib.java.util.stream.longimpl.TEmptyLongStreamImpl; import org.teavm.classlib.java.util.stream.longimpl.TGenerateLongStream; @@ -97,6 +98,8 @@ public interface TLongStream extends TBaseStream { OptionalDouble average(); + TLongSummaryStatistics summaryStatistics(); + boolean anyMatch(LongPredicate predicate); boolean allMatch(LongPredicate predicate); 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 560049887..d2963c014 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 @@ -31,6 +31,7 @@ import java.util.function.DoubleToLongFunction; import java.util.function.DoubleUnaryOperator; import java.util.function.ObjDoubleConsumer; import java.util.function.Supplier; +import org.teavm.classlib.java.util.TDoubleSummaryStatistics; import org.teavm.classlib.java.util.stream.TDoubleStream; import org.teavm.classlib.java.util.stream.TIntStream; import org.teavm.classlib.java.util.stream.TLongStream; @@ -208,6 +209,15 @@ public abstract class TSimpleDoubleStreamImpl implements TDoubleStream { return consumer.count > 0 ? OptionalDouble.of(consumer.sum / consumer.count) : OptionalDouble.empty(); } + @Override + public TDoubleSummaryStatistics summaryStatistics() { + TSummaryDoubleConsumer consumer = new TSummaryDoubleConsumer(); + while (next(consumer)) { + // go on + } + return consumer.stat; + } + @Override public boolean anyMatch(DoublePredicate predicate) { TAnyMatchConsumer consumer = new TAnyMatchConsumer(predicate); diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSummaryDoubleConsumer.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSummaryDoubleConsumer.java new file mode 100644 index 000000000..bebd2c7d6 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/doubleimpl/TSummaryDoubleConsumer.java @@ -0,0 +1,29 @@ +/* + * 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; +import org.teavm.classlib.java.util.TDoubleSummaryStatistics; + +public class TSummaryDoubleConsumer implements DoublePredicate { + final TDoubleSummaryStatistics stat = new TDoubleSummaryStatistics(); + + @Override + public boolean test(double value) { + stat.accept(value); + return true; + } +} 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 287fcde67..e44ff529a 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 @@ -32,6 +32,7 @@ import java.util.function.IntToLongFunction; import java.util.function.IntUnaryOperator; import java.util.function.ObjIntConsumer; import java.util.function.Supplier; +import org.teavm.classlib.java.util.TIntSummaryStatistics; import org.teavm.classlib.java.util.stream.TDoubleStream; import org.teavm.classlib.java.util.stream.TIntStream; import org.teavm.classlib.java.util.stream.TLongStream; @@ -209,6 +210,15 @@ public abstract class TSimpleIntStreamImpl implements TIntStream { return consumer.count > 0 ? OptionalDouble.of(consumer.sum / consumer.count) : OptionalDouble.empty(); } + @Override + public TIntSummaryStatistics summaryStatistics() { + TSummaryIntConsumer consumer = new TSummaryIntConsumer(); + while (next(consumer)) { + // go on + } + return consumer.stat; + } + @Override public boolean anyMatch(IntPredicate predicate) { TAnyMatchConsumer consumer = new TAnyMatchConsumer(predicate); diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSummaryIntConsumer.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSummaryIntConsumer.java new file mode 100644 index 000000000..c33ed2b35 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TSummaryIntConsumer.java @@ -0,0 +1,29 @@ +/* + * 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; +import org.teavm.classlib.java.util.TIntSummaryStatistics; + +public class TSummaryIntConsumer implements IntPredicate { + final TIntSummaryStatistics stat = new TIntSummaryStatistics(); + + @Override + public boolean test(int value) { + stat.accept(value); + return true; + } +} 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 8a3de4df4..58d98252f 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 @@ -32,6 +32,7 @@ import java.util.function.LongToIntFunction; import java.util.function.LongUnaryOperator; import java.util.function.ObjLongConsumer; import java.util.function.Supplier; +import org.teavm.classlib.java.util.TLongSummaryStatistics; import org.teavm.classlib.java.util.stream.TDoubleStream; import org.teavm.classlib.java.util.stream.TIntStream; import org.teavm.classlib.java.util.stream.TLongStream; @@ -209,6 +210,15 @@ public abstract class TSimpleLongStreamImpl implements TLongStream { return consumer.count > 0 ? OptionalDouble.of(consumer.sum / consumer.count) : OptionalDouble.empty(); } + @Override + public TLongSummaryStatistics summaryStatistics() { + TSummaryLongConsumer consumer = new TSummaryLongConsumer(); + while (next(consumer)) { + // go on + } + return consumer.stat; + } + @Override public boolean anyMatch(LongPredicate predicate) { TAnyMatchConsumer consumer = new TAnyMatchConsumer(predicate); diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSummaryLongConsumer.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSummaryLongConsumer.java new file mode 100644 index 000000000..6eda6dc8b --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/longimpl/TSummaryLongConsumer.java @@ -0,0 +1,29 @@ +/* + * 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; +import org.teavm.classlib.java.util.TLongSummaryStatistics; + +public class TSummaryLongConsumer implements LongPredicate { + final TLongSummaryStatistics stat = new TLongSummaryStatistics(); + + @Override + public boolean test(long value) { + stat.accept(value); + return true; + } +} diff --git a/tests/src/test/java/org/teavm/classlib/java/util/stream/CollectorsTest.java b/tests/src/test/java/org/teavm/classlib/java/util/stream/CollectorsTest.java index 832c6c9a0..71a3f0126 100644 --- a/tests/src/test/java/org/teavm/classlib/java/util/stream/CollectorsTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/util/stream/CollectorsTest.java @@ -19,9 +19,12 @@ import static org.junit.Assert.assertEquals; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.DoubleSummaryStatistics; import java.util.HashMap; import java.util.HashSet; +import java.util.IntSummaryStatistics; import java.util.List; +import java.util.LongSummaryStatistics; import java.util.Map; import java.util.Optional; import java.util.function.Function; @@ -114,4 +117,64 @@ public class CollectorsTest { assertEquals(Optional.empty(), Stream.empty() .collect(Collectors.minBy(Comparator.naturalOrder()))); } + + @Test + public void summaryInt() { + assertEquals(Integer.valueOf(6), Stream.of("a", "bb", "ccc").collect(Collectors.summingInt(String::length))); + assertEquals(Double.valueOf(2.0), Stream.of("a", "bb", "ccc").collect(Collectors.averagingInt(String::length))); + IntSummaryStatistics statistics = Stream.of("a", "bb", "ccc").collect(Collectors.summarizingInt(String::length)); + assertEquals(3L, statistics.getCount()); + assertEquals(2.0, statistics.getAverage(), 0.0); + assertEquals(1, statistics.getMin()); + assertEquals(3, statistics.getMax()); + assertEquals(6L, statistics.getSum()); + IntSummaryStatistics empty = Stream.of().collect(Collectors.summarizingInt(String::length)); + assertEquals(0L, empty.getCount()); + assertEquals(0.0, empty.getAverage(), 0.0); + assertEquals(Integer.MAX_VALUE, empty.getMin()); + assertEquals(Integer.MIN_VALUE, empty.getMax()); + assertEquals(0L, empty.getSum()); + } + + @Test + public void summaryLong() { + assertEquals(Long.valueOf(6L), Stream.of("a", "bb", "ccc").collect(Collectors.summingLong(String::length))); + assertEquals(Double.valueOf(2.0), Stream.of("a", "bb", "ccc").collect(Collectors.averagingLong(String::length))); + LongSummaryStatistics statistics = Stream.of("a", "bb", "ccc").collect(Collectors.summarizingLong(String::length)); + assertEquals(3L, statistics.getCount()); + assertEquals(2.0, statistics.getAverage(), 0.0); + assertEquals(1L, statistics.getMin()); + assertEquals(3L, statistics.getMax()); + assertEquals(6L, statistics.getSum()); + LongSummaryStatistics empty = Stream.of().collect(Collectors.summarizingLong(String::length)); + assertEquals(0L, empty.getCount()); + assertEquals(0.0, empty.getAverage(), 0.0); + assertEquals(Long.MAX_VALUE, empty.getMin()); + assertEquals(Long.MIN_VALUE, empty.getMax()); + assertEquals(0L, empty.getSum()); + } + + @Test + public void summaryDouble() { + assertEquals(Double.valueOf(6.0), Stream.of("a", "bb", "ccc").collect(Collectors.summingDouble(String::length))); + assertEquals(Double.valueOf(2.0), Stream.of("a", "bb", "ccc").collect(Collectors.averagingDouble(String::length))); + DoubleSummaryStatistics statistics = Stream.of("a", "bb", "ccc").collect(Collectors.summarizingDouble(String::length)); + assertEquals(3L, statistics.getCount()); + assertEquals(2.0, statistics.getAverage(), 0.0); + assertEquals(1.0, statistics.getMin(), 0.0); + assertEquals(3.0, statistics.getMax(), 0.0); + assertEquals(6.0, statistics.getSum(), 0.0); + DoubleSummaryStatistics empty = Stream.of().collect(Collectors.summarizingDouble(String::length)); + assertEquals(0L, empty.getCount()); + assertEquals(0.0, empty.getAverage(), 0.0); + assertEquals(Double.POSITIVE_INFINITY, empty.getMin(), 0.0); + assertEquals(Double.NEGATIVE_INFINITY, empty.getMax(), 0.0); + assertEquals(0.0, empty.getSum(), 0.0); + } + + @Test + public void teeing() { + assertEquals(Double.valueOf(3.0d), Stream.of("a", "bb", "ccc").collect(Collectors.teeing(Collectors.summingInt(String::length), + Collectors.averagingInt(String::length), (sum, avg) -> sum / avg))); + } } 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 580fa4649..69dbbe2f1 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 @@ -24,6 +24,7 @@ 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.DoubleSummaryStatistics; import java.util.PrimitiveIterator; import java.util.Spliterator; import java.util.stream.DoubleStream; @@ -334,4 +335,20 @@ public class DoubleStreamTest { assertEquals(2.5, DoubleStream.of(1, 2, 3, 4).average().getAsDouble(), 0.001); assertFalse(DoubleStream.empty().average().isPresent()); } + + @Test + public void summaryStatistics() { + DoubleSummaryStatistics statistics = DoubleStream.of(1.0, 2.0, 3.0).summaryStatistics(); + assertEquals(3L, statistics.getCount()); + assertEquals(2.0, statistics.getAverage(), 0.0); + assertEquals(1.0, statistics.getMin(), 0.0); + assertEquals(3.0, statistics.getMax(), 0.0); + assertEquals(6.0, statistics.getSum(), 0.0); + DoubleSummaryStatistics empty = DoubleStream.empty().summaryStatistics(); + assertEquals(0L, empty.getCount()); + assertEquals(0.0, empty.getAverage(), 0.0); + assertEquals(Double.POSITIVE_INFINITY, empty.getMin(), 0.0); + assertEquals(Double.NEGATIVE_INFINITY, empty.getMax(), 0.0); + assertEquals(0.0, empty.getSum(), 0.0); + } } 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 a949778e3..f1835d25e 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 @@ -24,6 +24,7 @@ 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.IntSummaryStatistics; import java.util.PrimitiveIterator; import java.util.Spliterator; import java.util.stream.IntStream; @@ -327,4 +328,20 @@ public class IntStreamTest { IntStream.rangeClosed(1, 4).forEach(appendIntNumbersTo(sb)); assertEquals("1;2;3;4;", sb.toString()); } + + @Test + public void summaryStatistics() { + IntSummaryStatistics statistics = IntStream.of(1, 2, 3).summaryStatistics(); + assertEquals(3L, statistics.getCount()); + assertEquals(2.0, statistics.getAverage(), 0.0); + assertEquals(1, statistics.getMin()); + assertEquals(3, statistics.getMax()); + assertEquals(6L, statistics.getSum()); + IntSummaryStatistics empty = IntStream.empty().summaryStatistics(); + assertEquals(0L, empty.getCount()); + assertEquals(0.0, empty.getAverage(), 0.0); + assertEquals(Integer.MAX_VALUE, empty.getMin()); + assertEquals(Integer.MIN_VALUE, empty.getMax()); + assertEquals(0L, empty.getSum()); + } } 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 37abfbd61..cd8104746 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 @@ -24,6 +24,7 @@ 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.LongSummaryStatistics; import java.util.PrimitiveIterator; import java.util.Spliterator; import java.util.stream.LongStream; @@ -331,4 +332,20 @@ public class LongStreamTest { LongStream.rangeClosed(1, 4).forEach(appendLongNumbersTo(sb)); assertEquals("1;2;3;4;", sb.toString()); } + + @Test + public void summaryStatistics() { + LongSummaryStatistics statistics = LongStream.of(1L, 2L, 3L).summaryStatistics(); + assertEquals(3L, statistics.getCount()); + assertEquals(2.0, statistics.getAverage(), 0.0); + assertEquals(1L, statistics.getMin()); + assertEquals(3L, statistics.getMax()); + assertEquals(6L, statistics.getSum()); + LongSummaryStatistics empty = LongStream.empty().summaryStatistics(); + assertEquals(0L, empty.getCount()); + assertEquals(0.0, empty.getAverage(), 0.0); + assertEquals(Long.MAX_VALUE, empty.getMin()); + assertEquals(Long.MIN_VALUE, empty.getMax()); + assertEquals(0L, empty.getSum()); + } }