From 204e1752d828fac0f772d144b0daaf7dd4ab93ec Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Wed, 14 Jun 2023 18:30:58 +0200 Subject: [PATCH 1/5] use stackalloc for smaller sizes --- .../Collections/Frozen/FrozenHashTable.cs | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs index 72cf9adb16a2..620e7e842473 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs @@ -48,13 +48,21 @@ private FrozenHashTable(int[] hashCodes, Bucket[] buckets, ulong fastModMultipli /// then uses this index to reference individual entries by indexing into . /// /// A frozen hash table. +#if NET6_0_OR_GREATER + [System.Runtime.CompilerServices.SkipLocalsInitAttribute] +#endif public static FrozenHashTable Create(int entriesLength, Func hashAtIndex, Action storeDestIndexFromSrcIndex, bool optimizeForReading = true) { Debug.Assert(entriesLength != 0); // Calculate the hashcodes for every entry. - int[] arrayPoolHashCodes = ArrayPool.Shared.Rent(entriesLength); - Span hashCodes = arrayPoolHashCodes.AsSpan(0, entriesLength); + int[]? arrayPoolHashCodes = null, arrayPoolBuckets = null; + + Span hashCodes = entriesLength <= 256 + ? stackalloc int[256] + : (arrayPoolHashCodes = ArrayPool.Shared.Rent(entriesLength)); + hashCodes = hashCodes.Slice(0, entriesLength); + for (int i = 0; i < entriesLength; i++) { hashCodes[i] = hashAtIndex(i); @@ -70,9 +78,12 @@ public static FrozenHashTable Create(int entriesLength, Func hashAtInd // - bucketStarts: initially filled with all -1s, the ith element stores the index // into hashCodes of the head element of that bucket's chain. // - nexts: the ith element stores the index of the next item in the chain. - int[] arrayPoolBuckets = ArrayPool.Shared.Rent(numBuckets + hashCodes.Length); - Span bucketStarts = arrayPoolBuckets.AsSpan(0, numBuckets); - Span nexts = arrayPoolBuckets.AsSpan(numBuckets, hashCodes.Length); + Span buckets = numBuckets + hashCodes.Length <= 256 + ? stackalloc int[256] + : (arrayPoolBuckets = ArrayPool.Shared.Rent(numBuckets + hashCodes.Length)); + + Span bucketStarts = buckets.Slice(0, numBuckets); + Span nexts = buckets.Slice(numBuckets, hashCodes.Length); bucketStarts.Fill(-1); // Populate the bucket entries and starts. For each hash code, compute its bucket, @@ -123,8 +134,14 @@ public static FrozenHashTable Create(int entriesLength, Func hashAtInd } Debug.Assert(count == hashtableHashcodes.Length); - ArrayPool.Shared.Return(arrayPoolBuckets); - ArrayPool.Shared.Return(arrayPoolHashCodes); + if (arrayPoolBuckets is not null) + { + ArrayPool.Shared.Return(arrayPoolBuckets); + } + if (arrayPoolHashCodes is not null) + { + ArrayPool.Shared.Return(arrayPoolHashCodes); + } return new FrozenHashTable(hashtableHashcodes, hashtableBuckets, fastModMultiplier); } From d2adef7e916b26fe88c44bd1fae5d977b9dbb5e7 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Wed, 14 Jun 2023 18:31:06 +0200 Subject: [PATCH 2/5] Revert "use stackalloc for smaller sizes", it did not help much This reverts commit 204e1752d828fac0f772d144b0daaf7dd4ab93ec. --- .../Collections/Frozen/FrozenHashTable.cs | 31 +++++-------------- 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs index 620e7e842473..72cf9adb16a2 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs @@ -48,21 +48,13 @@ private FrozenHashTable(int[] hashCodes, Bucket[] buckets, ulong fastModMultipli /// then uses this index to reference individual entries by indexing into . /// /// A frozen hash table. -#if NET6_0_OR_GREATER - [System.Runtime.CompilerServices.SkipLocalsInitAttribute] -#endif public static FrozenHashTable Create(int entriesLength, Func hashAtIndex, Action storeDestIndexFromSrcIndex, bool optimizeForReading = true) { Debug.Assert(entriesLength != 0); // Calculate the hashcodes for every entry. - int[]? arrayPoolHashCodes = null, arrayPoolBuckets = null; - - Span hashCodes = entriesLength <= 256 - ? stackalloc int[256] - : (arrayPoolHashCodes = ArrayPool.Shared.Rent(entriesLength)); - hashCodes = hashCodes.Slice(0, entriesLength); - + int[] arrayPoolHashCodes = ArrayPool.Shared.Rent(entriesLength); + Span hashCodes = arrayPoolHashCodes.AsSpan(0, entriesLength); for (int i = 0; i < entriesLength; i++) { hashCodes[i] = hashAtIndex(i); @@ -78,12 +70,9 @@ public static FrozenHashTable Create(int entriesLength, Func hashAtInd // - bucketStarts: initially filled with all -1s, the ith element stores the index // into hashCodes of the head element of that bucket's chain. // - nexts: the ith element stores the index of the next item in the chain. - Span buckets = numBuckets + hashCodes.Length <= 256 - ? stackalloc int[256] - : (arrayPoolBuckets = ArrayPool.Shared.Rent(numBuckets + hashCodes.Length)); - - Span bucketStarts = buckets.Slice(0, numBuckets); - Span nexts = buckets.Slice(numBuckets, hashCodes.Length); + int[] arrayPoolBuckets = ArrayPool.Shared.Rent(numBuckets + hashCodes.Length); + Span bucketStarts = arrayPoolBuckets.AsSpan(0, numBuckets); + Span nexts = arrayPoolBuckets.AsSpan(numBuckets, hashCodes.Length); bucketStarts.Fill(-1); // Populate the bucket entries and starts. For each hash code, compute its bucket, @@ -134,14 +123,8 @@ public static FrozenHashTable Create(int entriesLength, Func hashAtInd } Debug.Assert(count == hashtableHashcodes.Length); - if (arrayPoolBuckets is not null) - { - ArrayPool.Shared.Return(arrayPoolBuckets); - } - if (arrayPoolHashCodes is not null) - { - ArrayPool.Shared.Return(arrayPoolHashCodes); - } + ArrayPool.Shared.Return(arrayPoolBuckets); + ArrayPool.Shared.Return(arrayPoolHashCodes); return new FrozenHashTable(hashtableHashcodes, hashtableBuckets, fastModMultiplier); } From d43e99a809b5cd0d5b1171ac3fa4c83f2a2f52a8 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Thu, 15 Jun 2023 08:46:49 +0200 Subject: [PATCH 3/5] let the caller of FrozenHashTable.Create provide the hashcodes, it avoids a closure, index boundary checks and helps with inlining (7% gain) in case of hash set of integers it avoids renting and copying all integers to just have a copy of them --- .../System/Collections/Frozen/FrozenHashTable.cs | 13 ++----------- .../Frozen/Int32/Int32FrozenDictionary.cs | 12 +++++++++++- .../Collections/Frozen/Int32/Int32FrozenSet.cs | 4 ++-- .../src/System/Collections/Frozen/ItemsFrozenSet.cs | 12 +++++++++++- .../Frozen/KeysAndValuesFrozenDictionary.cs | 12 +++++++++++- .../Frozen/String/OrdinalStringFrozenDictionary.cs | 12 +++++++++++- .../Frozen/String/OrdinalStringFrozenSet.cs | 12 +++++++++++- 7 files changed, 59 insertions(+), 18 deletions(-) diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs index 72cf9adb16a2..0ad7063d2a18 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs @@ -37,7 +37,7 @@ private FrozenHashTable(int[] hashCodes, Bucket[] buckets, ulong fastModMultipli /// Initializes a frozen hash table. /// The number of entries to track from the hash table. - /// A delegate that produces a hash code for a given entry. It's passed the index of the entry and returns that entry's hash code. + /// Pre-calculated hash codes. /// A delegate that assigns the index to a specific entry. It's passed the destination and source indices. /// true to spend additional effort tuning for subsequent read speed on the table; false to prioritize construction time. /// @@ -48,18 +48,10 @@ private FrozenHashTable(int[] hashCodes, Bucket[] buckets, ulong fastModMultipli /// then uses this index to reference individual entries by indexing into . /// /// A frozen hash table. - public static FrozenHashTable Create(int entriesLength, Func hashAtIndex, Action storeDestIndexFromSrcIndex, bool optimizeForReading = true) + public static FrozenHashTable Create(int entriesLength, ReadOnlySpan hashCodes, Action storeDestIndexFromSrcIndex, bool optimizeForReading = true) { Debug.Assert(entriesLength != 0); - // Calculate the hashcodes for every entry. - int[] arrayPoolHashCodes = ArrayPool.Shared.Rent(entriesLength); - Span hashCodes = arrayPoolHashCodes.AsSpan(0, entriesLength); - for (int i = 0; i < entriesLength; i++) - { - hashCodes[i] = hashAtIndex(i); - } - // Determine how many buckets to use. This might be fewer than the number of entries // if any entries have identical hashcodes (not just different hashcodes that might // map to the same bucket). @@ -124,7 +116,6 @@ public static FrozenHashTable Create(int entriesLength, Func hashAtInd Debug.Assert(count == hashtableHashcodes.Length); ArrayPool.Shared.Return(arrayPoolBuckets); - ArrayPool.Shared.Return(arrayPoolHashCodes); return new FrozenHashTable(hashtableHashcodes, hashtableBuckets, fastModMultiplier); } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenDictionary.cs index bedcbb6bd080..32390a7e41fd 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenDictionary.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; @@ -27,10 +28,19 @@ internal Int32FrozenDictionary(Dictionary source) : base(EqualityCo _values = new TValue[entries.Length]; + int[] arrayPoolHashCodes = ArrayPool.Shared.Rent(entries.Length); + Span hashCodes = arrayPoolHashCodes.AsSpan(0, entries.Length); + for (int i = 0; i < entries.Length; i++) + { + hashCodes[i] = entries[i].Key; + } + _hashTable = FrozenHashTable.Create( entries.Length, - index => entries[index].Key, + hashCodes, (destIndex, srcIndex) => _values[destIndex] = entries[srcIndex].Value); + + ArrayPool.Shared.Return(arrayPoolHashCodes); } /// diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenSet.cs index 7f1da9dfa552..810a0f71bf99 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenSet.cs @@ -27,8 +27,8 @@ internal Int32FrozenSet(HashSet source) : base(EqualityComparer.Defaul _hashTable = FrozenHashTable.Create( count, - index => entries[index], - delegate { }); + new ReadOnlySpan(entries, 0, count), + static delegate { }); ArrayPool.Shared.Return(entries); } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/ItemsFrozenSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/ItemsFrozenSet.cs index abf91889fe46..ffebd7e6ea25 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/ItemsFrozenSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/ItemsFrozenSet.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; @@ -22,11 +23,20 @@ protected ItemsFrozenSet(HashSet source, bool optimizeForReading = true) : ba _items = new T[entries.Length]; + int[] arrayPoolHashCodes = ArrayPool.Shared.Rent(entries.Length); + Span hashCodes = arrayPoolHashCodes.AsSpan(0, entries.Length); + for (int i = 0; i < entries.Length; i++) + { + hashCodes[i] = entries[i] is T t ? Comparer.GetHashCode(t) : 0; + } + _hashTable = FrozenHashTable.Create( entries.Length, - index => entries[index] is T t ? Comparer.GetHashCode(t) : 0, + hashCodes, (destIndex, srcIndex) => _items[destIndex] = entries[srcIndex], optimizeForReading); + + ArrayPool.Shared.Return(arrayPoolHashCodes); } /// diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/KeysAndValuesFrozenDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/KeysAndValuesFrozenDictionary.cs index fb168cf1b65e..bc9ae1e1c1d2 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/KeysAndValuesFrozenDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/KeysAndValuesFrozenDictionary.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; @@ -24,15 +25,24 @@ protected KeysAndValuesFrozenDictionary(Dictionary source, bool op _keys = new TKey[entries.Length]; _values = new TValue[entries.Length]; + int[] arrayPoolHashCodes = ArrayPool.Shared.Rent(entries.Length); + Span hashCodes = arrayPoolHashCodes.AsSpan(0, entries.Length); + for (int i = 0; i < entries.Length; i++) + { + hashCodes[i] = Comparer.GetHashCode(entries[i].Key); + } + _hashTable = FrozenHashTable.Create( entries.Length, - index => Comparer.GetHashCode(entries[index].Key), + hashCodes, (destIndex, srcIndex) => { _keys[destIndex] = entries[srcIndex].Key; _values[destIndex] = entries[srcIndex].Value; }, optimizeForReading); + + ArrayPool.Shared.Return(arrayPoolHashCodes); } /// diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary.cs index b9f7dfd89cd1..ffc624a172eb 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; @@ -40,14 +41,23 @@ internal abstract class OrdinalStringFrozenDictionary : FrozenDictionary HashIndex = hashIndex; HashCount = hashCount; + int[] arrayPoolHashCodes = ArrayPool.Shared.Rent(entries.Length); + Span hashCodes = arrayPoolHashCodes.AsSpan(0, entries.Length); + for (int i = 0; i < entries.Length; i++) + { + hashCodes[i] = GetHashCode(entries[i].Key); + } + _hashTable = FrozenHashTable.Create( entries.Length, - index => GetHashCode(entries[index].Key), + hashCodes, (destIndex, srcIndex) => { _keys[destIndex] = entries[srcIndex].Key; _values[destIndex] = entries[srcIndex].Value; }); + + ArrayPool.Shared.Return(arrayPoolHashCodes); } private protected int HashIndex { get; } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet.cs index f4c7700f0dd8..abb741ed22a0 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -30,10 +31,19 @@ internal abstract class OrdinalStringFrozenSet : FrozenSetInternalBase.Shared.Rent(entries.Length); + Span hashCodes = arrayPoolHashCodes.AsSpan(0, entries.Length); + for (int i = 0; i < entries.Length; i++) + { + hashCodes[i] = GetHashCode(entries[i]); + } + _hashTable = FrozenHashTable.Create( entries.Length, - index => GetHashCode(entries[index]), + hashCodes, (destIndex, srcIndex) => _items[destIndex] = entries[srcIndex]); + + ArrayPool.Shared.Return(arrayPoolHashCodes); } private protected int HashIndex { get; } From d4ff38ff106603cf3c3a43fb7458dba47f8f93c6 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Thu, 15 Jun 2023 11:06:00 +0200 Subject: [PATCH 4/5] keys and values are needed for every strategy, lets create them up-front (2-4% gain) * in CreateLengthBucketsFrozenDictionaryIfAppropriate iterate over array rather than dictionary * in OrdinalStringFrozenDictionary ctor avoid creating a copy of all entires (we already have a copy of keys) --- .../Collections/Frozen/FrozenDictionary.cs | 34 +++++++++---------- .../String/LengthBucketsFrozenDictionary.cs | 13 ++++--- .../String/OrdinalStringFrozenDictionary.cs | 25 +++++++------- .../OrdinalStringFrozenDictionary_Full.cs | 4 +-- ...ingFrozenDictionary_FullCaseInsensitive.cs | 4 +-- ...ozenDictionary_FullCaseInsensitiveAscii.cs | 4 +-- ...tJustifiedCaseInsensitiveAsciiSubstring.cs | 4 +-- ...y_LeftJustifiedCaseInsensitiveSubstring.cs | 4 +-- ...rozenDictionary_LeftJustifiedSingleChar.cs | 4 +-- ...FrozenDictionary_LeftJustifiedSubstring.cs | 4 +-- ...tJustifiedCaseInsensitiveAsciiSubstring.cs | 4 +-- ..._RightJustifiedCaseInsensitiveSubstring.cs | 4 +-- ...ozenDictionary_RightJustifiedSingleChar.cs | 4 +-- ...rozenDictionary_RightJustifiedSubstring.cs | 4 +-- 14 files changed, 57 insertions(+), 59 deletions(-) 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 8582703ffdcb..11a2db81912d 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 @@ -229,15 +229,15 @@ public static class FrozenDictionary if (typeof(TKey) == typeof(string) && (ReferenceEquals(comparer, EqualityComparer.Default) || ReferenceEquals(comparer, StringComparer.Ordinal) || ReferenceEquals(comparer, StringComparer.OrdinalIgnoreCase))) { - Dictionary stringEntries = (Dictionary)(object)source; IEqualityComparer stringComparer = (IEqualityComparer)(object)comparer; - // this array is needed for every strategy - string[] entries = (string[])(object)source.Keys.ToArray(); + // keys and values are needed for every strategy + string[] keys = (string[])(object)source.Keys.ToArray(); + TValue[] values = source.Values.ToArray(); // Calculate the minimum and maximum lengths of the strings in the dictionary. Several of the analyses need this. int minLength = int.MaxValue, maxLength = 0; - foreach (string key in entries) + foreach (string key in keys) { if (key.Length < minLength) minLength = key.Length; if (key.Length > maxLength) maxLength = key.Length; @@ -245,14 +245,14 @@ public static class FrozenDictionary Debug.Assert(minLength >= 0 && maxLength >= minLength); // Try to create an implementation that uses length buckets, where each bucket contains up to only a few strings of the same length. - FrozenDictionary? frozenDictionary = LengthBucketsFrozenDictionary.CreateLengthBucketsFrozenDictionaryIfAppropriate(stringEntries, stringComparer, minLength, maxLength, entries); + FrozenDictionary? frozenDictionary = LengthBucketsFrozenDictionary.CreateLengthBucketsFrozenDictionaryIfAppropriate(keys, values, stringComparer, minLength, maxLength); if (frozenDictionary is not null) { return (FrozenDictionary)(object)frozenDictionary; } // Analyze the keys for unique substrings and create an implementation that minimizes the cost of hashing keys. - KeyAnalyzer.AnalysisResults analysis = KeyAnalyzer.Analyze(entries, ReferenceEquals(stringComparer, StringComparer.OrdinalIgnoreCase), minLength, maxLength); + KeyAnalyzer.AnalysisResults analysis = KeyAnalyzer.Analyze(keys, ReferenceEquals(stringComparer, StringComparer.OrdinalIgnoreCase), minLength, maxLength); if (analysis.SubstringHashing) { if (analysis.RightJustifiedSubstring) @@ -260,14 +260,14 @@ public static class FrozenDictionary if (analysis.IgnoreCase) { frozenDictionary = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring(stringEntries, entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring(stringEntries, entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount) + : new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); } else { frozenDictionary = analysis.HashCount == 1 - ? new OrdinalStringFrozenDictionary_RightJustifiedSingleChar(stringEntries, entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex) - : new OrdinalStringFrozenDictionary_RightJustifiedSubstring(stringEntries, entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenDictionary_RightJustifiedSingleChar(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex) + : new OrdinalStringFrozenDictionary_RightJustifiedSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); } } else @@ -275,14 +275,14 @@ public static class FrozenDictionary if (analysis.IgnoreCase) { frozenDictionary = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring(stringEntries, entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring(stringEntries, entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount) + : new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); } else { frozenDictionary = analysis.HashCount == 1 - ? new OrdinalStringFrozenDictionary_LeftJustifiedSingleChar(stringEntries, entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex) - : new OrdinalStringFrozenDictionary_LeftJustifiedSubstring(stringEntries, entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenDictionary_LeftJustifiedSingleChar(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex) + : new OrdinalStringFrozenDictionary_LeftJustifiedSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); } } } @@ -291,12 +291,12 @@ public static class FrozenDictionary if (analysis.IgnoreCase) { frozenDictionary = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii(stringEntries, entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff) - : new OrdinalStringFrozenDictionary_FullCaseInsensitive(stringEntries, entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff); + ? new OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff) + : new OrdinalStringFrozenDictionary_FullCaseInsensitive(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff); } else { - frozenDictionary = new OrdinalStringFrozenDictionary_Full(stringEntries, entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff); + frozenDictionary = new OrdinalStringFrozenDictionary_Full(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff); } } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/LengthBucketsFrozenDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/LengthBucketsFrozenDictionary.cs index 4a83ac05485b..ce0687b2e8c4 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/LengthBucketsFrozenDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/LengthBucketsFrozenDictionary.cs @@ -36,25 +36,25 @@ internal sealed class LengthBucketsFrozenDictionary : FrozenDictionary? CreateLengthBucketsFrozenDictionaryIfAppropriate( - Dictionary source, IEqualityComparer comparer, int minLength, int maxLength, string[] keys) + string[] keys, TValue[] values, IEqualityComparer comparer, int minLength, int maxLength) { - Debug.Assert(source.Count != 0); + Debug.Assert(keys.Length != 0 && keys.Length == values.Length); Debug.Assert(comparer == EqualityComparer.Default || comparer == StringComparer.Ordinal || comparer == StringComparer.OrdinalIgnoreCase); Debug.Assert(minLength >= 0 && maxLength >= minLength); // If without even looking at the keys we know that some bucket will exceed the max per-bucket // limit (pigeon hole principle), we can early-exit out without doing any further work. int spread = maxLength - minLength + 1; - if (source.Count / spread > MaxPerLength) + if (keys.Length / spread > MaxPerLength) { return null; } // Iterate through all of the inputs, bucketing them based on the length of the string. var groupedByLength = new Dictionary>>(); - foreach (KeyValuePair pair in source) + for (int i = 0; i < keys.Length; i++) { - string s = pair.Key; + string s = keys[i]; Debug.Assert(s.Length >= minLength && s.Length <= maxLength); #if NET6_0_OR_GREATER @@ -72,7 +72,7 @@ internal sealed class LengthBucketsFrozenDictionary : FrozenDictionary(s, values[i])); } // If there would be too much empty space in the lookup array, bail. @@ -81,7 +81,6 @@ internal sealed class LengthBucketsFrozenDictionary : FrozenDictionary[spread][]; // Iterate through each bucket, filling the keys/values arrays, and creating a lookup array such that diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary.cs index ffc624a172eb..8db9454c5b66 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary.cs @@ -18,8 +18,8 @@ internal abstract class OrdinalStringFrozenDictionary : FrozenDictionary private readonly int _maximumLengthDiff; internal OrdinalStringFrozenDictionary( - Dictionary source, string[] keys, + TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, @@ -27,34 +27,33 @@ internal abstract class OrdinalStringFrozenDictionary : FrozenDictionary int hashCount = -1) : base(comparer) { - Debug.Assert(source.Count != 0); + Debug.Assert(keys.Length != 0 && keys.Length == values.Length); Debug.Assert(comparer == EqualityComparer.Default || comparer == StringComparer.Ordinal || comparer == StringComparer.OrdinalIgnoreCase); - var entries = new KeyValuePair[source.Count]; - ((ICollection>)source).CopyTo(entries, 0); + // we need an extra copy, as the order of items will change + _keys = new string[keys.Length]; + _values = new TValue[values.Length]; - _keys = keys; - _values = new TValue[entries.Length]; _minimumLength = minimumLength; _maximumLengthDiff = maximumLengthDiff; HashIndex = hashIndex; HashCount = hashCount; - int[] arrayPoolHashCodes = ArrayPool.Shared.Rent(entries.Length); - Span hashCodes = arrayPoolHashCodes.AsSpan(0, entries.Length); - for (int i = 0; i < entries.Length; i++) + int[] arrayPoolHashCodes = ArrayPool.Shared.Rent(keys.Length); + Span hashCodes = arrayPoolHashCodes.AsSpan(0, keys.Length); + for (int i = 0; i < keys.Length; i++) { - hashCodes[i] = GetHashCode(entries[i].Key); + hashCodes[i] = GetHashCode(keys[i]); } _hashTable = FrozenHashTable.Create( - entries.Length, + keys.Length, hashCodes, (destIndex, srcIndex) => { - _keys[destIndex] = entries[srcIndex].Key; - _values[destIndex] = entries[srcIndex].Value; + _keys[destIndex] = keys[srcIndex]; + _values[destIndex] = values[srcIndex]; }); ArrayPool.Shared.Return(arrayPoolHashCodes); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_Full.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_Full.cs index 9ef93cac7fb0..56ce7ff720bd 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_Full.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_Full.cs @@ -8,12 +8,12 @@ namespace System.Collections.Frozen internal sealed class OrdinalStringFrozenDictionary_Full : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_Full( - Dictionary source, string[] keys, + TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff) - : base(source, keys, comparer, minimumLength, maximumLengthDiff) + : base(keys, values, comparer, minimumLength, maximumLengthDiff) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_FullCaseInsensitive.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_FullCaseInsensitive.cs index 0ec65c06b1d6..3f09ba59dc7e 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_FullCaseInsensitive.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_FullCaseInsensitive.cs @@ -8,12 +8,12 @@ namespace System.Collections.Frozen internal sealed class OrdinalStringFrozenDictionary_FullCaseInsensitive : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_FullCaseInsensitive( - Dictionary source, string[] keys, + TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff) - : base(source, keys, comparer, minimumLength, maximumLengthDiff) + : base(keys, values, comparer, minimumLength, maximumLengthDiff) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii.cs index c814f2b3f955..b029567243ce 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii.cs @@ -8,12 +8,12 @@ namespace System.Collections.Frozen internal sealed class OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii( - Dictionary source, string[] keys, + TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff) - : base(source, keys, comparer, minimumLength, maximumLengthDiff) + : base(keys, values, comparer, minimumLength, maximumLengthDiff) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring.cs index 166ae6a02598..401b0f2dc0b1 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring.cs @@ -8,14 +8,14 @@ namespace System.Collections.Frozen internal sealed class OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring( - Dictionary source, string[] keys, + TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) - : base(source, keys, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring.cs index dad71c443e93..c53344113991 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring.cs @@ -8,14 +8,14 @@ namespace System.Collections.Frozen internal sealed class OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring( - Dictionary source, string[] keys, + TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) - : base(source, keys, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSingleChar.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSingleChar.cs index ca03320c8dde..b2bb0bb97b1a 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSingleChar.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSingleChar.cs @@ -8,13 +8,13 @@ namespace System.Collections.Frozen internal sealed class OrdinalStringFrozenDictionary_LeftJustifiedSingleChar : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_LeftJustifiedSingleChar( - Dictionary source, string[] keys, + TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex) - : base(source, keys, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSubstring.cs index d48e4738e9aa..2812dde4f102 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSubstring.cs @@ -8,14 +8,14 @@ namespace System.Collections.Frozen internal sealed class OrdinalStringFrozenDictionary_LeftJustifiedSubstring : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_LeftJustifiedSubstring( - Dictionary source, string[] keys, + TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) - : base(source, keys, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring.cs index b26d2a1abe72..22cf6b640af6 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring.cs @@ -8,14 +8,14 @@ namespace System.Collections.Frozen internal sealed class OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring( - Dictionary source, string[] keys, + TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) - : base(source, keys, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring.cs index fc348bc437b9..a2fec247a287 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring.cs @@ -8,14 +8,14 @@ namespace System.Collections.Frozen internal sealed class OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring( - Dictionary source, string[] keys, + TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) - : base(source, keys, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSingleChar.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSingleChar.cs index 60c8ecc0180b..cb7ae5fda7b4 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSingleChar.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSingleChar.cs @@ -8,13 +8,13 @@ namespace System.Collections.Frozen internal sealed class OrdinalStringFrozenDictionary_RightJustifiedSingleChar : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_RightJustifiedSingleChar( - Dictionary source, string[] keys, + TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex) - : base(source, keys, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSubstring.cs index f4dd7ad7bb5b..cd8fe0602ef7 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSubstring.cs @@ -8,14 +8,14 @@ namespace System.Collections.Frozen internal sealed class OrdinalStringFrozenDictionary_RightJustifiedSubstring : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_RightJustifiedSubstring( - Dictionary source, string[] keys, + TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) - : base(source, keys, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } From 393c27e97158019e3557d7131430b44565720010 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Thu, 15 Jun 2023 15:05:22 +0200 Subject: [PATCH 5/5] refactor: there is no need to pass entriesLength anymore (hashCodes.Length is the replacement) --- .../src/System/Collections/Frozen/FrozenHashTable.cs | 5 +---- .../System/Collections/Frozen/Int32/Int32FrozenDictionary.cs | 1 - .../src/System/Collections/Frozen/Int32/Int32FrozenSet.cs | 1 - .../src/System/Collections/Frozen/ItemsFrozenSet.cs | 1 - .../Collections/Frozen/KeysAndValuesFrozenDictionary.cs | 1 - .../src/System/Collections/Frozen/String/KeyAnalyzer.cs | 2 +- .../Frozen/String/OrdinalStringFrozenDictionary.cs | 1 - .../Collections/Frozen/String/OrdinalStringFrozenSet.cs | 1 - 8 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs index 0ad7063d2a18..15ba7478de23 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs @@ -36,7 +36,6 @@ private FrozenHashTable(int[] hashCodes, Bucket[] buckets, ulong fastModMultipli } /// Initializes a frozen hash table. - /// The number of entries to track from the hash table. /// Pre-calculated hash codes. /// A delegate that assigns the index to a specific entry. It's passed the destination and source indices. /// true to spend additional effort tuning for subsequent read speed on the table; false to prioritize construction time. @@ -48,10 +47,8 @@ private FrozenHashTable(int[] hashCodes, Bucket[] buckets, ulong fastModMultipli /// then uses this index to reference individual entries by indexing into . /// /// A frozen hash table. - public static FrozenHashTable Create(int entriesLength, ReadOnlySpan hashCodes, Action storeDestIndexFromSrcIndex, bool optimizeForReading = true) + public static FrozenHashTable Create(ReadOnlySpan hashCodes, Action storeDestIndexFromSrcIndex, bool optimizeForReading = true) { - Debug.Assert(entriesLength != 0); - // Determine how many buckets to use. This might be fewer than the number of entries // if any entries have identical hashcodes (not just different hashcodes that might // map to the same bucket). diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenDictionary.cs index 32390a7e41fd..e98715887add 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenDictionary.cs @@ -36,7 +36,6 @@ internal Int32FrozenDictionary(Dictionary source) : base(EqualityCo } _hashTable = FrozenHashTable.Create( - entries.Length, hashCodes, (destIndex, srcIndex) => _values[destIndex] = entries[srcIndex].Value); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenSet.cs index 810a0f71bf99..4317b319abfc 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Int32/Int32FrozenSet.cs @@ -26,7 +26,6 @@ internal Int32FrozenSet(HashSet source) : base(EqualityComparer.Defaul source.CopyTo(entries); _hashTable = FrozenHashTable.Create( - count, new ReadOnlySpan(entries, 0, count), static delegate { }); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/ItemsFrozenSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/ItemsFrozenSet.cs index ffebd7e6ea25..db94a1a8e38f 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/ItemsFrozenSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/ItemsFrozenSet.cs @@ -31,7 +31,6 @@ protected ItemsFrozenSet(HashSet source, bool optimizeForReading = true) : ba } _hashTable = FrozenHashTable.Create( - entries.Length, hashCodes, (destIndex, srcIndex) => _items[destIndex] = entries[srcIndex], optimizeForReading); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/KeysAndValuesFrozenDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/KeysAndValuesFrozenDictionary.cs index bc9ae1e1c1d2..ab0cba77c2f1 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/KeysAndValuesFrozenDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/KeysAndValuesFrozenDictionary.cs @@ -33,7 +33,6 @@ protected KeysAndValuesFrozenDictionary(Dictionary source, bool op } _hashTable = FrozenHashTable.Create( - entries.Length, hashCodes, (destIndex, srcIndex) => { diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/KeyAnalyzer.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/KeyAnalyzer.cs index 9da8b3c61e57..51e70f3f63ba 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/KeyAnalyzer.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/KeyAnalyzer.cs @@ -225,7 +225,7 @@ private static bool HasSufficientUniquenessFactor(HashSet set, ReadOnlyS { set.Clear(); - // SufficientUniquenessFactor of 95% is good enough. + // Sufficient uniqueness factor of 95% is good enough. // Instead of ensuring that 95% of data is good, we stop when we know that at least 5% is bad. int acceptableNonUniqueCount = uniqueStrings.Length / 20; diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary.cs index 8db9454c5b66..2cb519ead452 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary.cs @@ -48,7 +48,6 @@ internal abstract class OrdinalStringFrozenDictionary : FrozenDictionary } _hashTable = FrozenHashTable.Create( - keys.Length, hashCodes, (destIndex, srcIndex) => { diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet.cs index abb741ed22a0..1ee4b277b211 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet.cs @@ -39,7 +39,6 @@ internal abstract class OrdinalStringFrozenSet : FrozenSetInternalBase _items[destIndex] = entries[srcIndex]);