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 e4fbdcef00b3c6..e27789d42ec59e 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 8c315f214fe03c..1fd1ec0649a8c0 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 da050f12a83cb5..dd2d01ff6d4899 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 e510954f7c3338..6e27d5bb34afaf 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 56ce7ff720bd52..335dfb60ed7daf 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 3f09ba59dc7eee..46f2954855c6da 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 b029567243ced4..1fa0434b53ffcb 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 401b0f2dc0b121..fb57a616f8facf 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 c533441139918f..aad28ee370d64a 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 b2bb0bb97b1a6c..724b0a9e525bcc 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 2812dde4f1027c..0a11358198457c 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 22cf6b640af67b..4aa83f6230e861 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 a2fec247a28734..99bba0ab662b72 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 cb7ae5fda7b4d4..8c1099fc5f63dc 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 cd8fe0602ef7b5..da286e7228988b 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 62ce56ee3472e4..b70aa92e053f71 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 9c10bb2dd9b747..81b5de69ad4698 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 345121f202159a..9ef6609281b1a4 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 b032da0e7778c7..ddf16bd69ef570 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 b89d19a745b9ad..eca02415ddfe93 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 548173ea43f070..8f507f27717d8b 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 b47deeac04da99..504f391a15e97b 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 bec754e9491b3f..a6555751538f59 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 3020cfd6bdc811..d4d83ceeab0497 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 e1a658d6141eb9..934618cbe8b54a 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 d9f510ea9a6c79..14caff3b27a0aa 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 4cb73df17c7ac1..97674902e67b23 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 e27789d42ec59e..d1d0c4a8c27f52 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 1fd1ec0649a8c0..df643f41a8e001 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 f8024558db2cd1..f6907367d8b9a2 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 d1d0c4a8c27f52..08555b10ee403d 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 df643f41a8e001..8a173a9dddd956 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 6e27d5bb34afaf..d9e298e0eb9340 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 b70aa92e053f71..4590e51e829138 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 08555b10ee403d..d1d0c4a8c27f52 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 8a173a9dddd956..df643f41a8e001 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 d9e298e0eb9340..6e27d5bb34afaf 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 4590e51e829138..b70aa92e053f71 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 df643f41a8e001..10b4846e9e2e65 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 d1d0c4a8c27f52..dc06ca0cd9287f 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 10b4846e9e2e65..50bbdeb18aad64 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 6e27d5bb34afaf..acc20a1b66ca71 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 335dfb60ed7daf..03da234352f323 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 46f2954855c6da..9280d82f05d773 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 1fa0434b53ffcb..f32a7c64fdd8ef 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 fb57a616f8facf..401b0f2dc0b121 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 aad28ee370d64a..c533441139918f 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 724b0a9e525bcc..b2bb0bb97b1a6c 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 0a11358198457c..2812dde4f1027c 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 4aa83f6230e861..22cf6b640af67b 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 99bba0ab662b72..a2fec247a28734 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 8c1099fc5f63dc..cb7ae5fda7b4d4 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 da286e7228988b..cd8fe0602ef7b5 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 b70aa92e053f71..278d1ee231b8c1 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 81b5de69ad4698..098b0ca0d35f81 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 9ef6609281b1a4..6c9e7b0645c54b 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 ddf16bd69ef570..462e4a7eea75bf 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 eca02415ddfe93..b89d19a745b9ad 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 8f507f27717d8b..548173ea43f070 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 504f391a15e97b..b47deeac04da99 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 a6555751538f59..bec754e9491b3f 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 d4d83ceeab0497..3020cfd6bdc811 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 934618cbe8b54a..e1a658d6141eb9 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 14caff3b27a0aa..d9f510ea9a6c79 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 97674902e67b23..4cb73df17c7ac1 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) { }