From d209a5f02eed225872da42481d442b0eca81e980 Mon Sep 17 00:00:00 2001 From: Ivan Hetman Date: Tue, 6 Jun 2023 12:08:15 +0300 Subject: [PATCH] classlib: add Collectors.reducing (#704) --- .../org/teavm/classlib/java/lang/TString.java | 17 +++++ .../java/util/stream/TCollectors.java | 66 +++++++++++++++++++ .../java/util/stream/CollectorsTest.java | 24 +++++++ 3 files changed, 107 insertions(+) diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TString.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TString.java index be541ea68..16c7d6dd3 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TString.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TString.java @@ -749,4 +749,21 @@ public class TString extends TObject implements TSerializable, TComparable { + private final BinaryOperator op; + private boolean present; + private T value; + + private Reducer(BinaryOperator op) { + this.op = op; + } + + private Reducer(BinaryOperator op, T value) { + this.op = op; + consume(value); + } + + private void consume(T t) { + if (present) { + value = op.apply(value, t); + } else { + value = t; + present = true; + } + } + + private Reducer merge(Reducer other) { + if (other.present) { + consume(other.value); + } + return this; + } + + private Optional getOpt() { + return present ? Optional.of(value) : Optional.empty(); + } + + private T get() { + return value; + } + } + + public static TCollector> reducing(BinaryOperator op) { + return TCollector.of(() -> new Reducer<>(op), Reducer::consume, Reducer::merge, Reducer::getOpt); + } + + public static TCollector reducing(T identity, BinaryOperator op) { + return TCollector.of(() -> new Reducer<>(op, identity), Reducer::consume, Reducer::merge, Reducer::get); + } + + public static TCollector reducing(U identity, + Function mapper, BinaryOperator op) { + return TCollector.of(() -> new Reducer<>(op, identity), + (red, t) -> red.consume(mapper.apply(t)), Reducer::merge, Reducer::get); + } + + public static TCollector> minBy(Comparator comparator) { + return reducing(BinaryOperator.minBy(comparator)); + } + + public static TCollector> maxBy(Comparator comparator) { + return reducing(BinaryOperator.maxBy(comparator)); + } + + public static TCollector counting() { + return reducing(0L, e -> 1L, Long::sum); + } } 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 c249ce4d0..832c6c9a0 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 @@ -18,10 +18,12 @@ package org.teavm.classlib.java.util.stream; import static org.junit.Assert.assertEquals; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -90,4 +92,26 @@ public class CollectorsTest { Collectors.collectingAndThen(Collectors.toList(), l -> l.stream().mapToInt(i -> i).sum())))); } + + @Test + public void reducing() { + assertEquals(Optional.of("abc"), Stream.of("a", "b", "c") + .collect(Collectors.reducing(String::concat))); + assertEquals(Optional.empty(), Stream.empty() + .collect(Collectors.reducing(String::concat))); + assertEquals("abc", Stream.of("a", "b", "c") + .collect(Collectors.reducing("", String::concat))); + assertEquals("aabbcc", Stream.of("a", "b", "c") + .collect(Collectors.reducing("", s -> s.repeat(2), String::concat))); + } + + @Test + public void minMax() { + assertEquals(Optional.of("a"), Stream.of("a", "bb", "ccc") + .collect(Collectors.minBy(Comparator.comparing(String::length)))); + assertEquals(Optional.of("ccc"), Stream.of("a", "bb", "ccc") + .collect(Collectors.maxBy(Comparator.naturalOrder()))); + assertEquals(Optional.empty(), Stream.empty() + .collect(Collectors.minBy(Comparator.naturalOrder()))); + } }