From 189615d5ddbaa032ee75d66e0e338ff0022ea3b9 Mon Sep 17 00:00:00 2001 From: Andrew J Said Date: Sat, 23 Sep 2023 23:56:02 +0100 Subject: [PATCH 1/6] Add an additional length check to FrozenDictionary and FrozenSet On construction of the collection, we compute an unsigned long which is effectively 64 boolean flags, each representing the presence of a key string of a particular length (mod 64). When reading from the collection, we can exit early if the key being tested does not map to a bit which has been switched on by the original compuation. I believe this has similarities to how Bloom Filters work. This adds a relatively small cost on creation of the collection as small cost to each read operation. However it can speed up reads with certain data patterns especially when the difference between the maximum and minimum key length is large but there aren't many different lengths. --- .../Collections/Frozen/FrozenDictionary.cs | 22 ++++++++--------- .../System/Collections/Frozen/FrozenSet.cs | 22 ++++++++--------- .../Collections/Frozen/String/KeyAnalyzer.cs | 12 ++++++++-- .../String/OrdinalStringFrozenDictionary.cs | 24 ++++++++++++------- .../OrdinalStringFrozenDictionary_Full.cs | 5 ++-- ...ingFrozenDictionary_FullCaseInsensitive.cs | 5 ++-- ...ozenDictionary_FullCaseInsensitiveAscii.cs | 5 ++-- ...tJustifiedCaseInsensitiveAsciiSubstring.cs | 3 ++- ...y_LeftJustifiedCaseInsensitiveSubstring.cs | 3 ++- ...rozenDictionary_LeftJustifiedSingleChar.cs | 3 ++- ...FrozenDictionary_LeftJustifiedSubstring.cs | 3 ++- ...tJustifiedCaseInsensitiveAsciiSubstring.cs | 3 ++- ..._RightJustifiedCaseInsensitiveSubstring.cs | 3 ++- ...ozenDictionary_RightJustifiedSingleChar.cs | 3 ++- ...rozenDictionary_RightJustifiedSubstring.cs | 3 ++- .../Frozen/String/OrdinalStringFrozenSet.cs | 24 ++++++++++++------- .../String/OrdinalStringFrozenSet_Full.cs | 5 ++-- ...inalStringFrozenSet_FullCaseInsensitive.cs | 5 ++-- ...tringFrozenSet_FullCaseInsensitiveAscii.cs | 5 ++-- ...tJustifiedCaseInsensitiveAsciiSubstring.cs | 3 ++- ...t_LeftJustifiedCaseInsensitiveSubstring.cs | 3 ++- ...StringFrozenSet_LeftJustifiedSingleChar.cs | 3 ++- ...lStringFrozenSet_LeftJustifiedSubstring.cs | 3 ++- ...tJustifiedCaseInsensitiveAsciiSubstring.cs | 3 ++- ..._RightJustifiedCaseInsensitiveSubstring.cs | 3 ++- ...tringFrozenSet_RightJustifiedSingleChar.cs | 3 ++- ...StringFrozenSet_RightJustifiedSubstring.cs | 3 ++- 27 files changed, 112 insertions(+), 70 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 e4fbdcef00b3c..e27789d42ec59 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 @@ -184,14 +184,14 @@ private static FrozenDictionary CreateFromDictionary if (analysis.IgnoreCase) { frozenDictionary = analysis.AllAsciiIfIgnoreCase - ? 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); + ? new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount) + : new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); } else { frozenDictionary = analysis.HashCount == 1 - ? 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); + ? new OrdinalStringFrozenDictionary_RightJustifiedSingleChar(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex) + : new OrdinalStringFrozenDictionary_RightJustifiedSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); } } else @@ -199,14 +199,14 @@ private static FrozenDictionary CreateFromDictionary if (analysis.IgnoreCase) { frozenDictionary = analysis.AllAsciiIfIgnoreCase - ? 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); + ? new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount) + : new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); } else { frozenDictionary = analysis.HashCount == 1 - ? 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); + ? new OrdinalStringFrozenDictionary_LeftJustifiedSingleChar(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex) + : new OrdinalStringFrozenDictionary_LeftJustifiedSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); } } } @@ -215,12 +215,12 @@ private static FrozenDictionary CreateFromDictionary if (analysis.IgnoreCase) { frozenDictionary = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff) - : new OrdinalStringFrozenDictionary_FullCaseInsensitive(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff); + ? new OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter) + : new OrdinalStringFrozenDictionary_FullCaseInsensitive(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter); } else { - frozenDictionary = new OrdinalStringFrozenDictionary_Full(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff); + frozenDictionary = new OrdinalStringFrozenDictionary_Full(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter); } } 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 8c315f214fe03..1fd1ec0649a8c 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 @@ -132,14 +132,14 @@ private static FrozenSet CreateFromSet(HashSet source) if (analysis.IgnoreCase) { frozenSet = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount) + : new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); } else { frozenSet = analysis.HashCount == 1 - ? new OrdinalStringFrozenSet_RightJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex) - : new OrdinalStringFrozenSet_RightJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenSet_RightJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex) + : new OrdinalStringFrozenSet_RightJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); } } else @@ -147,14 +147,14 @@ private static FrozenSet CreateFromSet(HashSet source) if (analysis.IgnoreCase) { frozenSet = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount) + : new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); } else { frozenSet = analysis.HashCount == 1 - ? new OrdinalStringFrozenSet_LeftJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex) - : new OrdinalStringFrozenSet_LeftJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenSet_LeftJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex) + : new OrdinalStringFrozenSet_LeftJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); } } } @@ -163,12 +163,12 @@ private static FrozenSet CreateFromSet(HashSet source) if (analysis.IgnoreCase) { frozenSet = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenSet_FullCaseInsensitiveAscii(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff) - : new OrdinalStringFrozenSet_FullCaseInsensitive(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff); + ? new OrdinalStringFrozenSet_FullCaseInsensitiveAscii(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter) + : new OrdinalStringFrozenSet_FullCaseInsensitive(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter); } else { - frozenSet = new OrdinalStringFrozenSet_Full(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff); + frozenSet = new OrdinalStringFrozenSet_Full(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter); } } 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 da050f12a83cb..dd2d01ff6d489 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 @@ -154,8 +154,14 @@ private static AnalysisResults CreateAnalysisResults( } } + ulong lengthFilter = 0; + foreach (string s in uniqueStrings) + { + lengthFilter |= (1UL << (s.Length % 64)); + } + // Return the analysis results. - return new AnalysisResults(ignoreCase, allAsciiIfIgnoreCase, index, count, minLength, maxLength); + return new AnalysisResults(ignoreCase, allAsciiIfIgnoreCase, index, count, minLength, maxLength, lengthFilter); } private delegate ReadOnlySpan GetSpan(string s, int index, int count); @@ -242,7 +248,7 @@ private static bool HasSufficientUniquenessFactor(HashSet set, ReadOnlyS internal readonly struct AnalysisResults { - public AnalysisResults(bool ignoreCase, bool allAsciiIfIgnoreCase, int hashIndex, int hashCount, int minLength, int maxLength) + public AnalysisResults(bool ignoreCase, bool allAsciiIfIgnoreCase, int hashIndex, int hashCount, int minLength, int maxLength, ulong lengthFilter) { IgnoreCase = ignoreCase; AllAsciiIfIgnoreCase = allAsciiIfIgnoreCase; @@ -250,6 +256,7 @@ public AnalysisResults(bool ignoreCase, bool allAsciiIfIgnoreCase, int hashIndex HashCount = hashCount; MinimumLength = minLength; MaximumLengthDiff = maxLength - minLength; + LengthFilter = lengthFilter; } public bool IgnoreCase { get; } @@ -258,6 +265,7 @@ public AnalysisResults(bool ignoreCase, bool allAsciiIfIgnoreCase, int hashIndex public int HashCount { get; } public int MinimumLength { get; } public int MaximumLengthDiff { get; } + public ulong LengthFilter { get; } public bool SubstringHashing => HashCount != 0; public bool RightJustifiedSubstring => HashIndex < 0; 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 e510954f7c333..6e27d5bb34afa 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 @@ -16,6 +16,7 @@ internal abstract class OrdinalStringFrozenDictionary : FrozenDictionary private readonly TValue[] _values; private readonly int _minimumLength; private readonly int _maximumLengthDiff; + private readonly ulong _lengthFilter; internal OrdinalStringFrozenDictionary( string[] keys, @@ -23,6 +24,7 @@ internal OrdinalStringFrozenDictionary( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex = -1, int hashCount = -1) : base(comparer) @@ -36,6 +38,7 @@ internal OrdinalStringFrozenDictionary( _minimumLength = minimumLength; _maximumLengthDiff = maximumLengthDiff; + _lengthFilter = lengthFilter; HashIndex = hashIndex; HashCount = hashCount; @@ -74,20 +77,23 @@ private protected override ref readonly TValue GetValueRefOrNullRefCore(string k { if ((uint)(key.Length - _minimumLength) <= (uint)_maximumLengthDiff) { - int hashCode = GetHashCode(key); - _hashTable.FindMatchingEntries(hashCode, out int index, out int endIndex); - - while (index <= endIndex) + if ((_lengthFilter & (1UL << (key.Length % 64))) > 0) { - if (hashCode == _hashTable.HashCodes[index]) + int hashCode = GetHashCode(key); + _hashTable.FindMatchingEntries(hashCode, out int index, out int endIndex); + + while (index <= endIndex) { - if (Equals(key, _keys[index])) + if (hashCode == _hashTable.HashCodes[index]) { - return ref _values[index]; + if (Equals(key, _keys[index])) + { + return ref _values[index]; + } } - } - index++; + index++; + } } } 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 56ce7ff720bd5..335dfb60ed7da 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 @@ -12,8 +12,9 @@ internal OrdinalStringFrozenDictionary_Full( TValue[] values, IEqualityComparer comparer, int minimumLength, - int maximumLengthDiff) - : base(keys, values, comparer, minimumLength, maximumLengthDiff) + int maximumLengthDiff, + ulong lengthFilter) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter) { } 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 3f09ba59dc7ee..46f2954855c6d 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 @@ -12,8 +12,9 @@ internal OrdinalStringFrozenDictionary_FullCaseInsensitive( TValue[] values, IEqualityComparer comparer, int minimumLength, - int maximumLengthDiff) - : base(keys, values, comparer, minimumLength, maximumLengthDiff) + int maximumLengthDiff, + ulong lengthFilter) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter) { } 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 b029567243ced..1fa0434b53ffc 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 @@ -12,8 +12,9 @@ internal OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii( TValue[] values, IEqualityComparer comparer, int minimumLength, - int maximumLengthDiff) - : base(keys, values, comparer, minimumLength, maximumLengthDiff) + int maximumLengthDiff, + ulong lengthFilter) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter) { } 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 401b0f2dc0b12..fb57a616f8fac 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 @@ -13,9 +13,10 @@ internal OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstrin IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex, int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 c533441139918..aad28ee370d64 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 @@ -13,9 +13,10 @@ internal OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex, int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 b2bb0bb97b1a6..724b0a9e525bc 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 @@ -13,8 +13,9 @@ internal OrdinalStringFrozenDictionary_LeftJustifiedSingleChar( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 2812dde4f1027..0a11358198457 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 @@ -13,9 +13,10 @@ internal OrdinalStringFrozenDictionary_LeftJustifiedSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex, int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 22cf6b640af67..4aa83f6230e86 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 @@ -13,9 +13,10 @@ internal OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstri IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex, int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 a2fec247a2873..99bba0ab662b7 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 @@ -13,9 +13,10 @@ internal OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex, int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 cb7ae5fda7b4d..8c1099fc5f63d 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 @@ -13,8 +13,9 @@ internal OrdinalStringFrozenDictionary_RightJustifiedSingleChar( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 cd8fe0602ef7b..da286e7228988 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 @@ -13,9 +13,10 @@ internal OrdinalStringFrozenDictionary_RightJustifiedSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex, int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) { } 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 62ce56ee3472e..b70aa92e053f7 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 @@ -14,12 +14,14 @@ internal abstract class OrdinalStringFrozenSet : FrozenSetInternalBase comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex = -1, int hashCount = -1) : base(comparer) @@ -27,6 +29,7 @@ internal OrdinalStringFrozenSet( _items = new string[entries.Length]; _minimumLength = minimumLength; _maximumLengthDiff = maximumLengthDiff; + _lengthFilter = lengthFilter; HashIndex = hashIndex; HashCount = hashCount; @@ -64,20 +67,23 @@ private protected override int FindItemIndex(string item) if (item is not null && // this implementation won't be used for null values (uint)(item.Length - _minimumLength) <= (uint)_maximumLengthDiff) { - int hashCode = GetHashCode(item); - _hashTable.FindMatchingEntries(hashCode, out int index, out int endIndex); - - while (index <= endIndex) + if ((_lengthFilter & (1UL << (item.Length % 64))) > 0) { - if (hashCode == _hashTable.HashCodes[index]) + int hashCode = GetHashCode(item); + _hashTable.FindMatchingEntries(hashCode, out int index, out int endIndex); + + while (index <= endIndex) { - if (Equals(item, _items[index])) + if (hashCode == _hashTable.HashCodes[index]) { - return index; + if (Equals(item, _items[index])) + { + return index; + } } - } - index++; + index++; + } } } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_Full.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_Full.cs index 9c10bb2dd9b74..81b5de69ad469 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_Full.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_Full.cs @@ -11,8 +11,9 @@ internal OrdinalStringFrozenSet_Full( string[] entries, IEqualityComparer comparer, int minimumLength, - int maximumLengthDiff) - : base(entries, comparer, minimumLength, maximumLengthDiff) + int maximumLengthDiff, + ulong lengthFilter) + : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitive.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitive.cs index 345121f202159..9ef6609281b1a 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitive.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitive.cs @@ -11,8 +11,9 @@ internal OrdinalStringFrozenSet_FullCaseInsensitive( string[] entries, IEqualityComparer comparer, int minimumLength, - int maximumLengthDiff) - : base(entries, comparer, minimumLength, maximumLengthDiff) + int maximumLengthDiff, + ulong lengthFilter) + : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitiveAscii.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitiveAscii.cs index b032da0e7778c..ddf16bd69ef57 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitiveAscii.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitiveAscii.cs @@ -11,8 +11,9 @@ internal OrdinalStringFrozenSet_FullCaseInsensitiveAscii( string[] entries, IEqualityComparer comparer, int minimumLength, - int maximumLengthDiff) - : base(entries, comparer, minimumLength, maximumLengthDiff) + int maximumLengthDiff, + ulong lengthFilter) + : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring.cs index b89d19a745b9a..eca02415ddfe9 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring.cs @@ -12,9 +12,10 @@ internal OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex, int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring.cs index 548173ea43f07..8f507f27717d8 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring.cs @@ -12,9 +12,10 @@ internal OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex, int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSingleChar.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSingleChar.cs index b47deeac04da9..504f391a15e97 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSingleChar.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSingleChar.cs @@ -12,8 +12,9 @@ internal OrdinalStringFrozenSet_LeftJustifiedSingleChar( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex) - : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) + : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, 1) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSubstring.cs index bec754e9491b3..a6555751538f5 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSubstring.cs @@ -12,9 +12,10 @@ internal OrdinalStringFrozenSet_LeftJustifiedSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex, int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring.cs index 3020cfd6bdc81..d4d83ceeab049 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring.cs @@ -12,9 +12,10 @@ internal OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex, int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring.cs index e1a658d6141eb..934618cbe8b54 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring.cs @@ -12,9 +12,10 @@ internal OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex, int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSingleChar.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSingleChar.cs index d9f510ea9a6c7..14caff3b27a0a 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSingleChar.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSingleChar.cs @@ -12,8 +12,9 @@ internal OrdinalStringFrozenSet_RightJustifiedSingleChar( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex) - : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) + : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, 1) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSubstring.cs index 4cb73df17c7ac..97674902e67b2 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSubstring.cs @@ -12,9 +12,10 @@ internal OrdinalStringFrozenSet_RightJustifiedSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, + ulong lengthFilter, int hashIndex, int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) + : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) { } From 39a44df6543565a74e2a3f236f79b44ab097abd5 Mon Sep 17 00:00:00 2001 From: Andrew J Said Date: Fri, 20 Oct 2023 19:48:15 +0100 Subject: [PATCH 2/6] Colocate length filter calculations to avoid repeat enumeration --- .../Collections/Frozen/FrozenDictionary.cs | 24 ++++++++------- .../System/Collections/Frozen/FrozenSet.cs | 30 ++++++++++--------- .../Collections/Frozen/String/KeyAnalyzer.cs | 12 ++------ 3 files changed, 31 insertions(+), 35 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 e27789d42ec59..d1d0c4a8c27f5 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 @@ -161,10 +161,12 @@ private static FrozenDictionary CreateFromDictionary // Calculate the minimum and maximum lengths of the strings in the dictionary. Several of the analyses need this. int minLength = int.MaxValue, maxLength = 0; + ulong lengthFilter = 0; foreach (string key in keys) { if (key.Length < minLength) minLength = key.Length; if (key.Length > maxLength) maxLength = key.Length; + lengthFilter |= (1UL << (key.Length % 64)); } Debug.Assert(minLength >= 0 && maxLength >= minLength); @@ -184,14 +186,14 @@ private static FrozenDictionary CreateFromDictionary if (analysis.IgnoreCase) { frozenDictionary = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount) + : new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount); } else { frozenDictionary = analysis.HashCount == 1 - ? new OrdinalStringFrozenDictionary_RightJustifiedSingleChar(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex) - : new OrdinalStringFrozenDictionary_RightJustifiedSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenDictionary_RightJustifiedSingleChar(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex) + : new OrdinalStringFrozenDictionary_RightJustifiedSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount); } } else @@ -199,14 +201,14 @@ private static FrozenDictionary CreateFromDictionary if (analysis.IgnoreCase) { frozenDictionary = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount) + : new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount); } else { frozenDictionary = analysis.HashCount == 1 - ? new OrdinalStringFrozenDictionary_LeftJustifiedSingleChar(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex) - : new OrdinalStringFrozenDictionary_LeftJustifiedSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenDictionary_LeftJustifiedSingleChar(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex) + : new OrdinalStringFrozenDictionary_LeftJustifiedSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount); } } } @@ -215,12 +217,12 @@ private static FrozenDictionary CreateFromDictionary if (analysis.IgnoreCase) { frozenDictionary = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter) - : new OrdinalStringFrozenDictionary_FullCaseInsensitive(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter); + ? new OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter) + : new OrdinalStringFrozenDictionary_FullCaseInsensitive(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter); } else { - frozenDictionary = new OrdinalStringFrozenDictionary_Full(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter); + frozenDictionary = new OrdinalStringFrozenDictionary_Full(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter); } } 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 1fd1ec0649a8c..df643f41a8e00 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 @@ -109,10 +109,12 @@ private static FrozenSet CreateFromSet(HashSet source) // Calculate the minimum and maximum lengths of the strings in the set. Several of the analyses need this. int minLength = int.MaxValue, maxLength = 0; - foreach (string s in entries) + ulong lengthFilter = 0; + foreach (string key in entries) { - if (s.Length < minLength) minLength = s.Length; - if (s.Length > maxLength) maxLength = s.Length; + if (key.Length < minLength) minLength = key.Length; + if (key.Length > maxLength) maxLength = key.Length; + lengthFilter |= (1UL << (key.Length % 64)); } Debug.Assert(minLength >= 0 && maxLength >= minLength); @@ -132,14 +134,14 @@ private static FrozenSet CreateFromSet(HashSet source) if (analysis.IgnoreCase) { frozenSet = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount) + : new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount); } else { frozenSet = analysis.HashCount == 1 - ? new OrdinalStringFrozenSet_RightJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex) - : new OrdinalStringFrozenSet_RightJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenSet_RightJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex) + : new OrdinalStringFrozenSet_RightJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount); } } else @@ -147,14 +149,14 @@ private static FrozenSet CreateFromSet(HashSet source) if (analysis.IgnoreCase) { frozenSet = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount) + : new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount); } else { frozenSet = analysis.HashCount == 1 - ? new OrdinalStringFrozenSet_LeftJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex) - : new OrdinalStringFrozenSet_LeftJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenSet_LeftJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex) + : new OrdinalStringFrozenSet_LeftJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount); } } } @@ -163,12 +165,12 @@ private static FrozenSet CreateFromSet(HashSet source) if (analysis.IgnoreCase) { frozenSet = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenSet_FullCaseInsensitiveAscii(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter) - : new OrdinalStringFrozenSet_FullCaseInsensitive(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter); + ? new OrdinalStringFrozenSet_FullCaseInsensitiveAscii(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter) + : new OrdinalStringFrozenSet_FullCaseInsensitive(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter); } else { - frozenSet = new OrdinalStringFrozenSet_Full(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.LengthFilter); + frozenSet = new OrdinalStringFrozenSet_Full(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter); } } 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 f8024558db2cd..f6907367d8b9a 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 @@ -159,14 +159,8 @@ private static AnalysisResults CreateAnalysisResults( } } - ulong lengthFilter = 0; - foreach (string s in uniqueStrings) - { - lengthFilter |= (1UL << (s.Length % 64)); - } - // Return the analysis results. - return new AnalysisResults(ignoreCase, allAsciiIfIgnoreCase, index, count, minLength, maxLength, lengthFilter); + return new AnalysisResults(ignoreCase, allAsciiIfIgnoreCase, index, count, minLength, maxLength); } private delegate ReadOnlySpan GetSpan(string s, int index, int count); @@ -249,7 +243,7 @@ internal static bool HasSufficientUniquenessFactor(HashSet set, ReadOnly internal readonly struct AnalysisResults { - public AnalysisResults(bool ignoreCase, bool allAsciiIfIgnoreCase, int hashIndex, int hashCount, int minLength, int maxLength, ulong lengthFilter) + public AnalysisResults(bool ignoreCase, bool allAsciiIfIgnoreCase, int hashIndex, int hashCount, int minLength, int maxLength) { IgnoreCase = ignoreCase; AllAsciiIfIgnoreCase = allAsciiIfIgnoreCase; @@ -257,7 +251,6 @@ public AnalysisResults(bool ignoreCase, bool allAsciiIfIgnoreCase, int hashIndex HashCount = hashCount; MinimumLength = minLength; MaximumLengthDiff = maxLength - minLength; - LengthFilter = lengthFilter; } public bool IgnoreCase { get; } @@ -266,7 +259,6 @@ public AnalysisResults(bool ignoreCase, bool allAsciiIfIgnoreCase, int hashIndex public int HashCount { get; } public int MinimumLength { get; } public int MaximumLengthDiff { get; } - public ulong LengthFilter { get; } public bool SubstringHashing => HashCount != 0; public bool RightJustifiedSubstring => HashIndex < 0; From 18c48f8bef9aac137b81e25ccb9a78f4f334a1da Mon Sep 17 00:00:00 2001 From: Andrew J Said Date: Sat, 21 Oct 2023 01:31:14 +0100 Subject: [PATCH 3/6] Use bitwise operation instead of rem 64 --- .../src/System/Collections/Frozen/FrozenDictionary.cs | 2 +- .../src/System/Collections/Frozen/FrozenSet.cs | 2 +- .../Collections/Frozen/String/OrdinalStringFrozenDictionary.cs | 2 +- .../System/Collections/Frozen/String/OrdinalStringFrozenSet.cs | 2 +- 4 files changed, 4 insertions(+), 4 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 d1d0c4a8c27f5..08555b10ee403 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 @@ -166,7 +166,7 @@ private static FrozenDictionary CreateFromDictionary { if (key.Length < minLength) minLength = key.Length; if (key.Length > maxLength) maxLength = key.Length; - lengthFilter |= (1UL << (key.Length % 64)); + lengthFilter |= (1UL << (key.Length & 0x3F)); } Debug.Assert(minLength >= 0 && maxLength >= minLength); 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 df643f41a8e00..8a173a9dddd95 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 @@ -114,7 +114,7 @@ private static FrozenSet CreateFromSet(HashSet source) { if (key.Length < minLength) minLength = key.Length; if (key.Length > maxLength) maxLength = key.Length; - lengthFilter |= (1UL << (key.Length % 64)); + lengthFilter |= (1UL << (key.Length & 0x3F)); } Debug.Assert(minLength >= 0 && maxLength >= minLength); 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 6e27d5bb34afa..d9e298e0eb934 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 @@ -77,7 +77,7 @@ private protected override ref readonly TValue GetValueRefOrNullRefCore(string k { if ((uint)(key.Length - _minimumLength) <= (uint)_maximumLengthDiff) { - if ((_lengthFilter & (1UL << (key.Length % 64))) > 0) + if ((_lengthFilter & (1UL << (key.Length & 0x3F))) > 0) { int hashCode = GetHashCode(key); _hashTable.FindMatchingEntries(hashCode, out int index, out int endIndex); 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 b70aa92e053f7..4590e51e82913 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 @@ -67,7 +67,7 @@ private protected override int FindItemIndex(string item) if (item is not null && // this implementation won't be used for null values (uint)(item.Length - _minimumLength) <= (uint)_maximumLengthDiff) { - if ((_lengthFilter & (1UL << (item.Length % 64))) > 0) + if ((_lengthFilter & (1UL << (item.Length & 0x3F))) > 0) { int hashCode = GetHashCode(item); _hashTable.FindMatchingEntries(hashCode, out int index, out int endIndex); From ad4592725e4b9b11d0ef09b2b659500b46cef9c4 Mon Sep 17 00:00:00 2001 From: Andrew J Said Date: Sun, 22 Oct 2023 01:06:12 +0100 Subject: [PATCH 4/6] Revert false optimisation --- .../src/System/Collections/Frozen/FrozenDictionary.cs | 2 +- .../src/System/Collections/Frozen/FrozenSet.cs | 2 +- .../Collections/Frozen/String/OrdinalStringFrozenDictionary.cs | 2 +- .../System/Collections/Frozen/String/OrdinalStringFrozenSet.cs | 2 +- 4 files changed, 4 insertions(+), 4 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 08555b10ee403..d1d0c4a8c27f5 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 @@ -166,7 +166,7 @@ private static FrozenDictionary CreateFromDictionary { if (key.Length < minLength) minLength = key.Length; if (key.Length > maxLength) maxLength = key.Length; - lengthFilter |= (1UL << (key.Length & 0x3F)); + lengthFilter |= (1UL << (key.Length % 64)); } Debug.Assert(minLength >= 0 && maxLength >= minLength); 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 8a173a9dddd95..df643f41a8e00 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 @@ -114,7 +114,7 @@ private static FrozenSet CreateFromSet(HashSet source) { if (key.Length < minLength) minLength = key.Length; if (key.Length > maxLength) maxLength = key.Length; - lengthFilter |= (1UL << (key.Length & 0x3F)); + lengthFilter |= (1UL << (key.Length % 64)); } Debug.Assert(minLength >= 0 && maxLength >= minLength); 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 d9e298e0eb934..6e27d5bb34afa 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 @@ -77,7 +77,7 @@ private protected override ref readonly TValue GetValueRefOrNullRefCore(string k { if ((uint)(key.Length - _minimumLength) <= (uint)_maximumLengthDiff) { - if ((_lengthFilter & (1UL << (key.Length & 0x3F))) > 0) + if ((_lengthFilter & (1UL << (key.Length % 64))) > 0) { int hashCode = GetHashCode(key); _hashTable.FindMatchingEntries(hashCode, out int index, out int endIndex); 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 4590e51e82913..b70aa92e053f7 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 @@ -67,7 +67,7 @@ private protected override int FindItemIndex(string item) if (item is not null && // this implementation won't be used for null values (uint)(item.Length - _minimumLength) <= (uint)_maximumLengthDiff) { - if ((_lengthFilter & (1UL << (item.Length & 0x3F))) > 0) + if ((_lengthFilter & (1UL << (item.Length % 64))) > 0) { int hashCode = GetHashCode(item); _hashTable.FindMatchingEntries(hashCode, out int index, out int endIndex); From 96962d793eb2daea299ead44dca8ff5f1adcde62 Mon Sep 17 00:00:00 2001 From: Andrew J Said Date: Sun, 22 Oct 2023 12:39:09 +0100 Subject: [PATCH 5/6] Undo changing variable name It is probably an opinionated change which isn't right. --- .../src/System/Collections/Frozen/FrozenSet.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 df643f41a8e00..10b4846e9e2e6 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 @@ -110,11 +110,11 @@ private static FrozenSet CreateFromSet(HashSet source) // Calculate the minimum and maximum lengths of the strings in the set. Several of the analyses need this. int minLength = int.MaxValue, maxLength = 0; ulong lengthFilter = 0; - foreach (string key in entries) + foreach (string s in entries) { - if (key.Length < minLength) minLength = key.Length; - if (key.Length > maxLength) maxLength = key.Length; - lengthFilter |= (1UL << (key.Length % 64)); + if (s.Length < minLength) minLength = s.Length; + if (s.Length > maxLength) maxLength = s.Length; + lengthFilter |= (1UL << (s.Length % 64)); } Debug.Assert(minLength >= 0 && maxLength >= minLength); From 8841016c7243ed387e5037914df21a33adea0ef6 Mon Sep 17 00:00:00 2001 From: Andrew J Said Date: Sat, 18 Nov 2023 01:35:59 +0000 Subject: [PATCH 6/6] Only use length filter when substring analysis yielded no results --- .../Collections/Frozen/FrozenDictionary.cs | 16 ++++++++-------- .../src/System/Collections/Frozen/FrozenSet.cs | 16 ++++++++-------- .../String/OrdinalStringFrozenDictionary.cs | 6 ++---- .../String/OrdinalStringFrozenDictionary_Full.cs | 6 +++++- ...StringFrozenDictionary_FullCaseInsensitive.cs | 6 +++++- ...gFrozenDictionary_FullCaseInsensitiveAscii.cs | 6 +++++- ...LeftJustifiedCaseInsensitiveAsciiSubstring.cs | 3 +-- ...nary_LeftJustifiedCaseInsensitiveSubstring.cs | 3 +-- ...ngFrozenDictionary_LeftJustifiedSingleChar.cs | 3 +-- ...ingFrozenDictionary_LeftJustifiedSubstring.cs | 3 +-- ...ightJustifiedCaseInsensitiveAsciiSubstring.cs | 3 +-- ...ary_RightJustifiedCaseInsensitiveSubstring.cs | 3 +-- ...gFrozenDictionary_RightJustifiedSingleChar.cs | 3 +-- ...ngFrozenDictionary_RightJustifiedSubstring.cs | 3 +-- .../Frozen/String/OrdinalStringFrozenSet.cs | 6 ++---- .../Frozen/String/OrdinalStringFrozenSet_Full.cs | 6 +++++- ...OrdinalStringFrozenSet_FullCaseInsensitive.cs | 6 +++++- ...alStringFrozenSet_FullCaseInsensitiveAscii.cs | 6 +++++- ...LeftJustifiedCaseInsensitiveAsciiSubstring.cs | 3 +-- ...nSet_LeftJustifiedCaseInsensitiveSubstring.cs | 3 +-- ...nalStringFrozenSet_LeftJustifiedSingleChar.cs | 3 +-- ...inalStringFrozenSet_LeftJustifiedSubstring.cs | 3 +-- ...ightJustifiedCaseInsensitiveAsciiSubstring.cs | 3 +-- ...Set_RightJustifiedCaseInsensitiveSubstring.cs | 3 +-- ...alStringFrozenSet_RightJustifiedSingleChar.cs | 3 +-- ...nalStringFrozenSet_RightJustifiedSubstring.cs | 3 +-- 26 files changed, 66 insertions(+), 62 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 d1d0c4a8c27f5..dc06ca0cd9287 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 @@ -186,14 +186,14 @@ private static FrozenDictionary CreateFromDictionary if (analysis.IgnoreCase) { frozenDictionary = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, 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(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex) - : new OrdinalStringFrozenDictionary_RightJustifiedSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, 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 @@ -201,14 +201,14 @@ private static FrozenDictionary CreateFromDictionary if (analysis.IgnoreCase) { frozenDictionary = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, 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(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex) - : new OrdinalStringFrozenDictionary_LeftJustifiedSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, 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); } } } 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 10b4846e9e2e6..50bbdeb18aad6 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 @@ -134,14 +134,14 @@ private static FrozenSet CreateFromSet(HashSet source) if (analysis.IgnoreCase) { frozenSet = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount) + : new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); } else { frozenSet = analysis.HashCount == 1 - ? new OrdinalStringFrozenSet_RightJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex) - : new OrdinalStringFrozenSet_RightJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenSet_RightJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex) + : new OrdinalStringFrozenSet_RightJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); } } else @@ -149,14 +149,14 @@ private static FrozenSet CreateFromSet(HashSet source) if (analysis.IgnoreCase) { frozenSet = analysis.AllAsciiIfIgnoreCase - ? new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount) + : new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); } else { frozenSet = analysis.HashCount == 1 - ? new OrdinalStringFrozenSet_LeftJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex) - : new OrdinalStringFrozenSet_LeftJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount); + ? new OrdinalStringFrozenSet_LeftJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex) + : new OrdinalStringFrozenSet_LeftJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); } } } 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 6e27d5bb34afa..acc20a1b66ca7 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 @@ -16,7 +16,6 @@ internal abstract class OrdinalStringFrozenDictionary : FrozenDictionary private readonly TValue[] _values; private readonly int _minimumLength; private readonly int _maximumLengthDiff; - private readonly ulong _lengthFilter; internal OrdinalStringFrozenDictionary( string[] keys, @@ -24,7 +23,6 @@ internal OrdinalStringFrozenDictionary( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex = -1, int hashCount = -1) : base(comparer) @@ -38,7 +36,6 @@ internal OrdinalStringFrozenDictionary( _minimumLength = minimumLength; _maximumLengthDiff = maximumLengthDiff; - _lengthFilter = lengthFilter; HashIndex = hashIndex; HashCount = hashCount; @@ -67,6 +64,7 @@ internal OrdinalStringFrozenDictionary( private protected int HashCount { get; } private protected abstract bool Equals(string? x, string? y); private protected abstract int GetHashCode(string s); + private protected virtual bool CheckLengthQuick(string key) => true; private protected override string[] KeysCore => _keys; private protected override TValue[] ValuesCore => _values; private protected override Enumerator GetEnumeratorCore() => new Enumerator(_keys, _values); @@ -77,7 +75,7 @@ private protected override ref readonly TValue GetValueRefOrNullRefCore(string k { if ((uint)(key.Length - _minimumLength) <= (uint)_maximumLengthDiff) { - if ((_lengthFilter & (1UL << (key.Length % 64))) > 0) + if (CheckLengthQuick(key)) { int hashCode = GetHashCode(key); _hashTable.FindMatchingEntries(hashCode, out int index, out int endIndex); 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 335dfb60ed7da..03da234352f32 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 @@ -7,6 +7,8 @@ namespace System.Collections.Frozen { internal sealed class OrdinalStringFrozenDictionary_Full : OrdinalStringFrozenDictionary { + private readonly ulong _lengthFilter; + internal OrdinalStringFrozenDictionary_Full( string[] keys, TValue[] values, @@ -14,8 +16,9 @@ internal OrdinalStringFrozenDictionary_Full( int minimumLength, int maximumLengthDiff, ulong lengthFilter) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter) + : base(keys, values, comparer, minimumLength, maximumLengthDiff) { + _lengthFilter = lengthFilter; } // This override is necessary to force the jit to emit the code in such a way that it @@ -25,5 +28,6 @@ internal OrdinalStringFrozenDictionary_Full( private protected override bool Equals(string? x, string? y) => string.Equals(x, y); private protected override int GetHashCode(string s) => Hashing.GetHashCodeOrdinal(s.AsSpan()); + private protected override bool CheckLengthQuick(string key) => (_lengthFilter & (1UL << (key.Length % 64))) > 0; } } 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 46f2954855c6d..9280d82f05d77 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 @@ -7,6 +7,8 @@ namespace System.Collections.Frozen { internal sealed class OrdinalStringFrozenDictionary_FullCaseInsensitive : OrdinalStringFrozenDictionary { + private readonly ulong _lengthFilter; + internal OrdinalStringFrozenDictionary_FullCaseInsensitive( string[] keys, TValue[] values, @@ -14,8 +16,9 @@ internal OrdinalStringFrozenDictionary_FullCaseInsensitive( int minimumLength, int maximumLengthDiff, ulong lengthFilter) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter) + : base(keys, values, comparer, minimumLength, maximumLengthDiff) { + _lengthFilter = lengthFilter; } // This override is necessary to force the jit to emit the code in such a way that it @@ -25,5 +28,6 @@ internal OrdinalStringFrozenDictionary_FullCaseInsensitive( private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); private protected override int GetHashCode(string s) => Hashing.GetHashCodeOrdinalIgnoreCase(s.AsSpan()); + private protected override bool CheckLengthQuick(string key) => (_lengthFilter & (1UL << (key.Length % 64))) > 0; } } 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 1fa0434b53ffc..f32a7c64fdd8e 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 @@ -7,6 +7,8 @@ namespace System.Collections.Frozen { internal sealed class OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii : OrdinalStringFrozenDictionary { + private readonly ulong _lengthFilter; + internal OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii( string[] keys, TValue[] values, @@ -14,8 +16,9 @@ internal OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii( int minimumLength, int maximumLengthDiff, ulong lengthFilter) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter) + : base(keys, values, comparer, minimumLength, maximumLengthDiff) { + _lengthFilter = lengthFilter; } // This override is necessary to force the jit to emit the code in such a way that it @@ -25,5 +28,6 @@ internal OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii( private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); private protected override int GetHashCode(string s) => Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.AsSpan()); + private protected override bool CheckLengthQuick(string key) => (_lengthFilter & (1UL << (key.Length % 64))) > 0; } } 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 fb57a616f8fac..401b0f2dc0b12 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 @@ -13,10 +13,9 @@ internal OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstrin IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex, int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 aad28ee370d64..c533441139918 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 @@ -13,10 +13,9 @@ internal OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex, int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 724b0a9e525bc..b2bb0bb97b1a6 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 @@ -13,9 +13,8 @@ internal OrdinalStringFrozenDictionary_LeftJustifiedSingleChar( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 0a11358198457..2812dde4f1027 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 @@ -13,10 +13,9 @@ internal OrdinalStringFrozenDictionary_LeftJustifiedSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex, int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 4aa83f6230e86..22cf6b640af67 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 @@ -13,10 +13,9 @@ internal OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstri IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex, int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 99bba0ab662b7..a2fec247a2873 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 @@ -13,10 +13,9 @@ internal OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex, int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 8c1099fc5f63d..cb7ae5fda7b4d 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 @@ -13,9 +13,8 @@ internal OrdinalStringFrozenDictionary_RightJustifiedSingleChar( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, 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 da286e7228988..cd8fe0602ef7b 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 @@ -13,10 +13,9 @@ internal OrdinalStringFrozenDictionary_RightJustifiedSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex, int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) + : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } 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 b70aa92e053f7..278d1ee231b8c 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 @@ -14,14 +14,12 @@ internal abstract class OrdinalStringFrozenSet : FrozenSetInternalBase comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex = -1, int hashCount = -1) : base(comparer) @@ -29,7 +27,6 @@ internal OrdinalStringFrozenSet( _items = new string[entries.Length]; _minimumLength = minimumLength; _maximumLengthDiff = maximumLengthDiff; - _lengthFilter = lengthFilter; HashIndex = hashIndex; HashCount = hashCount; @@ -57,6 +54,7 @@ internal OrdinalStringFrozenSet( private protected int HashCount { get; } private protected abstract bool Equals(string? x, string? y); private protected abstract int GetHashCode(string s); + private protected virtual bool CheckLengthQuick(string key) => true; private protected override string[] ItemsCore => _items; private protected override Enumerator GetEnumeratorCore() => new Enumerator(_items); private protected override int CountCore => _hashTable.Count; @@ -67,7 +65,7 @@ private protected override int FindItemIndex(string item) if (item is not null && // this implementation won't be used for null values (uint)(item.Length - _minimumLength) <= (uint)_maximumLengthDiff) { - if ((_lengthFilter & (1UL << (item.Length % 64))) > 0) + if (CheckLengthQuick(item)) { int hashCode = GetHashCode(item); _hashTable.FindMatchingEntries(hashCode, out int index, out int endIndex); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_Full.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_Full.cs index 81b5de69ad469..098b0ca0d35f8 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_Full.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_Full.cs @@ -7,14 +7,17 @@ namespace System.Collections.Frozen { internal sealed class OrdinalStringFrozenSet_Full : OrdinalStringFrozenSet { + private readonly ulong _lengthFilter; + internal OrdinalStringFrozenSet_Full( string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, ulong lengthFilter) - : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter) + : base(entries, comparer, minimumLength, maximumLengthDiff) { + _lengthFilter = lengthFilter; } // This override is necessary to force the jit to emit the code in such a way that it @@ -24,5 +27,6 @@ internal OrdinalStringFrozenSet_Full( private protected override bool Equals(string? x, string? y) => string.Equals(x, y); private protected override int GetHashCode(string s) => Hashing.GetHashCodeOrdinal(s.AsSpan()); + private protected override bool CheckLengthQuick(string key) => (_lengthFilter & (1UL << (key.Length % 64))) > 0; } } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitive.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitive.cs index 9ef6609281b1a..6c9e7b0645c54 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitive.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitive.cs @@ -7,14 +7,17 @@ namespace System.Collections.Frozen { internal sealed class OrdinalStringFrozenSet_FullCaseInsensitive : OrdinalStringFrozenSet { + private readonly ulong _lengthFilter; + internal OrdinalStringFrozenSet_FullCaseInsensitive( string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, ulong lengthFilter) - : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter) + : base(entries, comparer, minimumLength, maximumLengthDiff) { + _lengthFilter = lengthFilter; } // This override is necessary to force the jit to emit the code in such a way that it @@ -24,5 +27,6 @@ internal OrdinalStringFrozenSet_FullCaseInsensitive( private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); private protected override int GetHashCode(string s) => Hashing.GetHashCodeOrdinalIgnoreCase(s.AsSpan()); + private protected override bool CheckLengthQuick(string key) => (_lengthFilter & (1UL << (key.Length % 64))) > 0; } } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitiveAscii.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitiveAscii.cs index ddf16bd69ef57..462e4a7eea75b 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitiveAscii.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_FullCaseInsensitiveAscii.cs @@ -7,14 +7,17 @@ namespace System.Collections.Frozen { internal sealed class OrdinalStringFrozenSet_FullCaseInsensitiveAscii : OrdinalStringFrozenSet { + private readonly ulong _lengthFilter; + internal OrdinalStringFrozenSet_FullCaseInsensitiveAscii( string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, ulong lengthFilter) - : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter) + : base(entries, comparer, minimumLength, maximumLengthDiff) { + _lengthFilter = lengthFilter; } // This override is necessary to force the jit to emit the code in such a way that it @@ -24,5 +27,6 @@ internal OrdinalStringFrozenSet_FullCaseInsensitiveAscii( private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); private protected override int GetHashCode(string s) => Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.AsSpan()); + private protected override bool CheckLengthQuick(string key) => (_lengthFilter & (1UL << (key.Length % 64))) > 0; } } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring.cs index eca02415ddfe9..b89d19a745b9a 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring.cs @@ -12,10 +12,9 @@ internal OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex, int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) + : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring.cs index 8f507f27717d8..548173ea43f07 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring.cs @@ -12,10 +12,9 @@ internal OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex, int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) + : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSingleChar.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSingleChar.cs index 504f391a15e97..b47deeac04da9 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSingleChar.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSingleChar.cs @@ -12,9 +12,8 @@ internal OrdinalStringFrozenSet_LeftJustifiedSingleChar( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex) - : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, 1) + : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSubstring.cs index a6555751538f5..bec754e9491b3 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSubstring.cs @@ -12,10 +12,9 @@ internal OrdinalStringFrozenSet_LeftJustifiedSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex, int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) + : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring.cs index d4d83ceeab049..3020cfd6bdc81 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring.cs @@ -12,10 +12,9 @@ internal OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex, int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) + : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring.cs index 934618cbe8b54..e1a658d6141eb 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring.cs @@ -12,10 +12,9 @@ internal OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex, int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) + : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSingleChar.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSingleChar.cs index 14caff3b27a0a..d9f510ea9a6c7 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSingleChar.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSingleChar.cs @@ -12,9 +12,8 @@ internal OrdinalStringFrozenSet_RightJustifiedSingleChar( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex) - : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, 1) + : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSubstring.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSubstring.cs index 97674902e67b2..4cb73df17c7ac 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSubstring.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSubstring.cs @@ -12,10 +12,9 @@ internal OrdinalStringFrozenSet_RightJustifiedSubstring( IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, - ulong lengthFilter, int hashIndex, int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, lengthFilter, hashIndex, hashCount) + : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { }