From 084998ce5a8078d317380ff531b662c70b28b294 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Fri, 27 Jan 2023 06:36:27 -0500 Subject: [PATCH] Add additional bool-only ToFrozenDictionary/Set overloads (#81256) API review decided to include additional overloads to enable only specifying the bool. --- .../ref/System.Collections.Immutable.cs | 2 ++ .../System/Collections/Frozen/FrozenDictionary.cs | 27 ++++++++++++++++++++++ .../src/System/Collections/Frozen/FrozenSet.cs | 19 +++++++++++++++ .../tests/Frozen/FrozenDictionaryTests.cs | 16 +++++++++++++ .../tests/Frozen/FrozenSetTests.cs | 20 ++++++++++++++++ 5 files changed, 84 insertions(+) diff --git a/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs b/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs index 4641aa6..bb9e96e 100644 --- a/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs +++ b/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs @@ -10,6 +10,7 @@ namespace System.Collections.Frozen { public static System.Collections.Frozen.FrozenDictionary ToFrozenDictionary(this System.Collections.Generic.IEnumerable> source, System.Collections.Generic.IEqualityComparer? comparer = null) where TKey : notnull { throw null; } public static System.Collections.Frozen.FrozenDictionary ToFrozenDictionary(this System.Collections.Generic.IEnumerable> source, System.Collections.Generic.IEqualityComparer? comparer, bool optimizeForReading) where TKey : notnull { throw null; } + public static System.Collections.Frozen.FrozenDictionary ToFrozenDictionary(this System.Collections.Generic.IEnumerable> source, bool optimizeForReading) where TKey : notnull { throw null; } public static System.Collections.Frozen.FrozenDictionary ToFrozenDictionary(this System.Collections.Generic.IEnumerable source, System.Func keySelector, System.Collections.Generic.IEqualityComparer? comparer = null) where TKey : notnull { throw null; } public static System.Collections.Frozen.FrozenDictionary ToFrozenDictionary(this System.Collections.Generic.IEnumerable source, System.Func keySelector, System.Func elementSelector, System.Collections.Generic.IEqualityComparer? comparer = null) where TKey : notnull { throw null; } } @@ -73,6 +74,7 @@ namespace System.Collections.Frozen { public static System.Collections.Frozen.FrozenSet ToFrozenSet(this System.Collections.Generic.IEnumerable source, System.Collections.Generic.IEqualityComparer? comparer = null) { throw null; } public static System.Collections.Frozen.FrozenSet ToFrozenSet(this System.Collections.Generic.IEnumerable source, System.Collections.Generic.IEqualityComparer? comparer, bool optimizeForReading) { throw null; } + public static System.Collections.Frozen.FrozenSet ToFrozenSet(this System.Collections.Generic.IEnumerable source, bool optimizeForReading) { throw null; } } public abstract partial class FrozenSet : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.ISet, System.Collections.ICollection, System.Collections.IEnumerable { diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenDictionary.cs index 79c65f8..65de1ad 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenDictionary.cs @@ -40,6 +40,33 @@ namespace System.Collections.Frozen /// Creates a with the specified key/value pairs. /// The key/value pairs to use to populate the dictionary. + /// + /// to do more work as part of dictionary construction to optimize for subsequent reading of the data; + /// to prefer making construction more efficient. The default is . + /// + /// The type of the keys in the dictionary. + /// The type of the values in the dictionary. + /// + /// + /// Frozen collections are immutable and may be optimized for situations where a collection is created very infrequently but + /// is used very frequently at runtime. Setting to will result in a + /// relatively high cost to create the collection in exchange for improved performance when subsequently using the collection. + /// Using is ideal for collections that are created once, potentially at the startup of a service, and then + /// used throughout the remainder of the lifetime of the service. Because of the high cost of creation, frozen collections should + /// only be initialized with trusted input. + /// + /// + /// If the same key appears multiple times in the input, the latter one in the sequence takes precedence. This differs from + /// , with which multiple duplicate keys will result in an exception. + /// + /// + /// A that contains the specified keys and values. + public static FrozenDictionary ToFrozenDictionary(this IEnumerable> source, bool optimizeForReading) + where TKey : notnull => + ToFrozenDictionary(source, null, optimizeForReading); + + /// Creates a with the specified key/value pairs. + /// The key/value pairs to use to populate the dictionary. /// The comparer implementation to use to compare keys for equality. If null, is used. /// /// to do more work as part of dictionary construction to optimize for subsequent reading of the data; diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs index 47efdd7..d057036 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs @@ -33,6 +33,25 @@ namespace System.Collections.Frozen /// Creates a with the specified values. /// The values to use to populate the set. + /// + /// to do more work as part of set construction to optimize for subsequent reading of the data; + /// to prefer making construction more efficient. The default is . + /// + /// The type of the values in the set. + /// A frozen set. + /// + /// Frozen collections are immutable and may be optimized for situations where a collection is created very infrequently but + /// is used very frequently at runtime. Setting to will result in a + /// relatively high cost to create the collection in exchange for improved performance when subsequently using the collection. + /// Using is ideal for collections that are created once, potentially at the startup of a service, and then + /// used throughout the remainder of the lifetime of the service. Because of the high cost of creation, frozen collections should + /// only be initialized with trusted input. + /// + public static FrozenSet ToFrozenSet(this IEnumerable source, bool optimizeForReading) => + ToFrozenSet(source, null, optimizeForReading); + + /// Creates a with the specified values. + /// The values to use to populate the set. /// The comparer implementation to use to compare values for equality. If null, is used. /// /// to do more work as part of set construction to optimize for subsequent reading of the data; diff --git a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenDictionaryTests.cs b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenDictionaryTests.cs index ae1fa7f..12e218f 100644 --- a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenDictionaryTests.cs +++ b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenDictionaryTests.cs @@ -57,6 +57,8 @@ namespace System.Collections.Frozen.Tests AssertExtensions.Throws("source", () => ((Dictionary)null).ToFrozenDictionary()); AssertExtensions.Throws("source", () => ((Dictionary)null).ToFrozenDictionary(null)); AssertExtensions.Throws("source", () => ((Dictionary)null).ToFrozenDictionary(EqualityComparer.Default)); + AssertExtensions.Throws("source", () => ((Dictionary)null).ToFrozenDictionary(null, false)); + AssertExtensions.Throws("source", () => ((Dictionary)null).ToFrozenDictionary(null, true)); AssertExtensions.Throws("keySelector", () => Enumerable.Empty().ToFrozenDictionary((Func)null)); AssertExtensions.Throws("keySelector", () => Enumerable.Empty().ToFrozenDictionary((Func)null, EqualityComparer.Default)); @@ -148,6 +150,8 @@ namespace System.Collections.Frozen.Tests Assert.Same(FrozenDictionary.Empty, FrozenDictionary.Empty.ToFrozenDictionary(null)); Assert.Same(FrozenDictionary.Empty, FrozenDictionary.Empty.ToFrozenDictionary(null, false)); Assert.Same(FrozenDictionary.Empty, FrozenDictionary.Empty.ToFrozenDictionary(null, true)); + Assert.Same(FrozenDictionary.Empty, FrozenDictionary.Empty.ToFrozenDictionary(false)); + Assert.Same(FrozenDictionary.Empty, FrozenDictionary.Empty.ToFrozenDictionary(true)); Assert.Same(FrozenDictionary.Empty, FrozenDictionary.Empty.ToFrozenDictionary(EqualityComparer.Default)); Assert.Same(FrozenDictionary.Empty, FrozenDictionary.Empty.ToFrozenDictionary(EqualityComparer.Default, false)); Assert.Same(FrozenDictionary.Empty, FrozenDictionary.Empty.ToFrozenDictionary(EqualityComparer.Default, true)); @@ -161,6 +165,18 @@ namespace System.Collections.Frozen.Tests Assert.NotSame(frozen, frozen.ToFrozenDictionary(NonDefaultEqualityComparer.Instance)); } + [Theory] + [InlineData(false)] + [InlineData(true)] + public void ToFrozenDictionary_BoolArg_UsesDefaultComparer(bool optimizeForReading) + { + Dictionary source = Enumerable.Range(0, 4).ToDictionary(CreateTKey, CreateTValue); + + FrozenDictionary frozen1 = source.ToFrozenDictionary(optimizeForReading); + + Assert.Same(EqualityComparer.Default, frozen1.Comparer); + } + [Fact] public void ToFrozenDictionary_KeySelector_ResultsAreUsed() { diff --git a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenSetTests.cs b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenSetTests.cs index f37774d..a1190c0 100644 --- a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenSetTests.cs +++ b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenSetTests.cs @@ -55,8 +55,14 @@ namespace System.Collections.Frozen.Tests public void NullSource_ThrowsException() { AssertExtensions.Throws("source", () => ((HashSet)null).ToFrozenSet()); + AssertExtensions.Throws("source", () => ((HashSet)null).ToFrozenSet(false)); + AssertExtensions.Throws("source", () => ((HashSet)null).ToFrozenSet(true)); AssertExtensions.Throws("source", () => ((HashSet)null).ToFrozenSet(null)); + AssertExtensions.Throws("source", () => ((HashSet)null).ToFrozenSet(null, false)); + AssertExtensions.Throws("source", () => ((HashSet)null).ToFrozenSet(null, true)); AssertExtensions.Throws("source", () => ((HashSet)null).ToFrozenSet(EqualityComparer.Default)); + AssertExtensions.Throws("source", () => ((HashSet)null).ToFrozenSet(EqualityComparer.Default, false)); + AssertExtensions.Throws("source", () => ((HashSet)null).ToFrozenSet(EqualityComparer.Default, true)); } [Fact] @@ -136,6 +142,8 @@ namespace System.Collections.Frozen.Tests Assert.Same(FrozenSet.Empty, FrozenSet.Empty.ToFrozenSet(null)); Assert.Same(FrozenSet.Empty, FrozenSet.Empty.ToFrozenSet(null, false)); Assert.Same(FrozenSet.Empty, FrozenSet.Empty.ToFrozenSet(null, true)); + Assert.Same(FrozenSet.Empty, FrozenSet.Empty.ToFrozenSet(false)); + Assert.Same(FrozenSet.Empty, FrozenSet.Empty.ToFrozenSet(true)); Assert.Same(FrozenSet.Empty, FrozenSet.Empty.ToFrozenSet(EqualityComparer.Default)); Assert.Same(FrozenSet.Empty, FrozenSet.Empty.ToFrozenSet(EqualityComparer.Default, false)); Assert.Same(FrozenSet.Empty, FrozenSet.Empty.ToFrozenSet(EqualityComparer.Default, true)); @@ -149,6 +157,18 @@ namespace System.Collections.Frozen.Tests Assert.NotSame(frozen, frozen.ToFrozenSet(NonDefaultEqualityComparer.Instance)); } + [Theory] + [InlineData(false)] + [InlineData(true)] + public void ToFrozenSet_BoolArg_UsesDefaultComparer(bool optimizeForReading) + { + HashSet source = new HashSet(Enumerable.Range(0, 4).Select(CreateT)); + + FrozenSet frozen = source.ToFrozenSet(optimizeForReading); + + Assert.Same(EqualityComparer.Default, frozen.Comparer); + } + public static IEnumerable LookupItems_AllItemsFoundAsExpected_MemberData() => from size in new[] { 0, 1, 2, 10, 999, 1024 } from comparer in new IEqualityComparer[] { null, EqualityComparer.Default, NonDefaultEqualityComparer.Instance } -- 2.7.4