From 37dc5e9844c6e74d2124658e0aacc982e0be4c5d Mon Sep 17 00:00:00 2001 From: cpovirk Date: Tue, 11 Feb 2025 13:44:40 -0800 Subject: [PATCH] DO NOT MERGE Demo of Guava changes for https://github.com/openjdk/jdk/pull/23461. This change pre-sizes collectors for which the size of the output collection must match the size of the input stream. It omits cases like `ImmutableSet` (which deduplicates), but it includes cases `ImmutableList` (obviously) and `ImmutableMap`/`ImmutableBiMap` (which rejects duplicate keys). RELNOTES=`collect`: Changed `toImmutableList`, `toImmutableMap`, and `toImmutableBiMap` to internally pre-size their collections when possible. PiperOrigin-RevId: 725756865 --- .../common/collect/CollectCollectors.java | 70 ++++++++++++++++++- .../common/collect/CollectCollectors.java | 70 ++++++++++++++++++- 2 files changed, 134 insertions(+), 6 deletions(-) diff --git a/android/guava/src/com/google/common/collect/CollectCollectors.java b/android/guava/src/com/google/common/collect/CollectCollectors.java index f12c882093ce..864def06dc01 100644 --- a/android/guava/src/com/google/common/collect/CollectCollectors.java +++ b/android/guava/src/com/google/common/collect/CollectCollectors.java @@ -17,6 +17,8 @@ package com.google.common.collect; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Sets.immutableEnumSet; +import static java.util.Arrays.asList; import static java.util.Collections.singletonMap; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toMap; @@ -24,17 +26,21 @@ import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; import com.google.common.base.Preconditions; +import com.google.common.primitives.Ints; import java.util.Collection; import java.util.Comparator; import java.util.EnumMap; import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.TreeMap; +import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Function; +import java.util.function.LongFunction; import java.util.function.Supplier; import java.util.function.ToIntFunction; import java.util.stream.Collector; +import java.util.stream.Collector.Characteristics; import java.util.stream.Stream; import org.jspecify.annotations.Nullable; @@ -43,10 +49,60 @@ @SuppressWarnings("Java7ApiChecker") @IgnoreJRERequirement // used only from APIs with Java 8 types in them final class CollectCollectors { + private static < + T extends @Nullable Object, A extends @Nullable Object, R extends @Nullable Object> + Collector sizedCollector( + Supplier supplier, + LongFunction sizedSupplier, + BiConsumer accumulator, + BinaryOperator combiner, + Function finisher, + Characteristics... characteristics) { + ImmutableSet characteristicsSet = immutableEnumSet(asList(characteristics)); + return new Collector() { + @Override + public Supplier supplier() { + return supplier; + } + + // only an override under some future version of Java? + @SuppressWarnings({ + "MissingOverride", + "UnusedMethod", + }) + public LongFunction sizedSupplier() { + return sizedSupplier; + } + + @Override + public BiConsumer accumulator() { + return accumulator; + } + + @Override + public BinaryOperator combiner() { + return combiner; + } + + @Override + public Function finisher() { + return finisher; + } + + @Override + public ImmutableSet characteristics() { + return characteristicsSet; + } + }; + } private static final Collector> TO_IMMUTABLE_LIST = - Collector.of( + sizedCollector( ImmutableList::builder, + size -> + size == -1 + ? ImmutableList.builder() + : ImmutableList.builderWithExpectedSize(Ints.checkedCast(size)), ImmutableList.Builder::add, ImmutableList.Builder::combine, ImmutableList.Builder::build); @@ -191,8 +247,12 @@ ImmutableSet toImmutableSet() { Function valueFunction) { checkNotNull(keyFunction); checkNotNull(valueFunction); - return Collector.of( + return sizedCollector( ImmutableMap.Builder::new, + size -> + size == -1 + ? new ImmutableMap.Builder() + : new ImmutableMap.Builder(Ints.checkedCast(size)), (builder, input) -> builder.put(keyFunction.apply(input), valueFunction.apply(input)), ImmutableMap.Builder::combine, ImmutableMap.Builder::buildOrThrow); @@ -249,8 +309,12 @@ ImmutableSet toImmutableSet() { Function valueFunction) { checkNotNull(keyFunction); checkNotNull(valueFunction); - return Collector.of( + return sizedCollector( ImmutableBiMap.Builder::new, + size -> + size == -1 + ? new ImmutableBiMap.Builder() + : new ImmutableBiMap.Builder(Ints.checkedCast(size)), (builder, input) -> builder.put(keyFunction.apply(input), valueFunction.apply(input)), ImmutableBiMap.Builder::combine, ImmutableBiMap.Builder::buildOrThrow, diff --git a/guava/src/com/google/common/collect/CollectCollectors.java b/guava/src/com/google/common/collect/CollectCollectors.java index a18c7f724f4b..bc4778d92b64 100644 --- a/guava/src/com/google/common/collect/CollectCollectors.java +++ b/guava/src/com/google/common/collect/CollectCollectors.java @@ -17,6 +17,8 @@ package com.google.common.collect; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Sets.immutableEnumSet; +import static java.util.Arrays.asList; import static java.util.Collections.singletonMap; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toMap; @@ -24,27 +26,81 @@ import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; import com.google.common.base.Preconditions; +import com.google.common.primitives.Ints; import java.util.Collection; import java.util.Comparator; import java.util.EnumMap; import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.TreeMap; +import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Function; +import java.util.function.LongFunction; import java.util.function.Supplier; import java.util.function.ToIntFunction; import java.util.stream.Collector; +import java.util.stream.Collector.Characteristics; import java.util.stream.Stream; import org.jspecify.annotations.Nullable; /** Collectors utilities for {@code common.collect} internals. */ @GwtCompatible final class CollectCollectors { + private static < + T extends @Nullable Object, A extends @Nullable Object, R extends @Nullable Object> + Collector sizedCollector( + Supplier supplier, + LongFunction sizedSupplier, + BiConsumer accumulator, + BinaryOperator combiner, + Function finisher, + Characteristics... characteristics) { + ImmutableSet characteristicsSet = immutableEnumSet(asList(characteristics)); + return new Collector() { + @Override + public Supplier supplier() { + return supplier; + } + + // only an override under some future version of Java? + @SuppressWarnings({ + "MissingOverride", + "UnusedMethod", + }) + public LongFunction sizedSupplier() { + return sizedSupplier; + } + + @Override + public BiConsumer accumulator() { + return accumulator; + } + + @Override + public BinaryOperator combiner() { + return combiner; + } + + @Override + public Function finisher() { + return finisher; + } + + @Override + public ImmutableSet characteristics() { + return characteristicsSet; + } + }; + } private static final Collector> TO_IMMUTABLE_LIST = - Collector.of( + sizedCollector( ImmutableList::builder, + size -> + size == -1 + ? ImmutableList.builder() + : ImmutableList.builderWithExpectedSize(Ints.checkedCast(size)), ImmutableList.Builder::add, ImmutableList.Builder::combine, ImmutableList.Builder::build); @@ -188,8 +244,12 @@ ImmutableSet toImmutableSet() { Function valueFunction) { checkNotNull(keyFunction); checkNotNull(valueFunction); - return Collector.of( + return sizedCollector( ImmutableMap.Builder::new, + size -> + size == -1 + ? new ImmutableMap.Builder() + : new ImmutableMap.Builder(Ints.checkedCast(size)), (builder, input) -> builder.put(keyFunction.apply(input), valueFunction.apply(input)), ImmutableMap.Builder::combine, ImmutableMap.Builder::buildOrThrow); @@ -246,8 +306,12 @@ ImmutableSet toImmutableSet() { Function valueFunction) { checkNotNull(keyFunction); checkNotNull(valueFunction); - return Collector.of( + return sizedCollector( ImmutableBiMap.Builder::new, + size -> + size == -1 + ? new ImmutableBiMap.Builder() + : new ImmutableBiMap.Builder(Ints.checkedCast(size)), (builder, input) -> builder.put(keyFunction.apply(input), valueFunction.apply(input)), ImmutableBiMap.Builder::combine, ImmutableBiMap.Builder::buildOrThrow,