From 1683760d584af4f42508995ae38091a945274b81 Mon Sep 17 00:00:00 2001 From: Andrew J Said Date: Fri, 10 Nov 2023 00:36:26 +0000 Subject: [PATCH] Only ignore case insensitivity if entire string is ASCII non-letters --- .../src/System.Collections.Immutable.csproj | 8 --- .../Collections/Frozen/FrozenDictionary.cs | 46 ++++---------- .../System/Collections/Frozen/FrozenSet.cs | 46 ++++---------- .../Collections/Frozen/String/KeyAnalyzer.cs | 28 ++++----- ..._LeftJustifiedSingleCharCaseInsensitive.cs | 29 --------- ...y_LeftJustifiedSubstringCaseInsensitive.cs | 30 --------- ...RightJustifiedSingleCharCaseInsensitive.cs | 29 --------- ..._RightJustifiedSubstringCaseInsensitive.cs | 30 --------- ..._LeftJustifiedSingleCharCaseInsensitive.cs | 28 --------- ...t_LeftJustifiedSubstringCaseInsensitive.cs | 29 --------- ...RightJustifiedSingleCharCaseInsensitive.cs | 28 --------- ..._RightJustifiedSubstringCaseInsensitive.cs | 29 --------- .../tests/Frozen/KeyAnalyzerTests.cs | 63 ++++++------------- 13 files changed, 56 insertions(+), 367 deletions(-) delete mode 100644 src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSingleCharCaseInsensitive.cs delete mode 100644 src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSubstringCaseInsensitive.cs delete mode 100644 src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSingleCharCaseInsensitive.cs delete mode 100644 src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSubstringCaseInsensitive.cs delete mode 100644 src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSingleCharCaseInsensitive.cs delete mode 100644 src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSubstringCaseInsensitive.cs delete mode 100644 src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSingleCharCaseInsensitive.cs delete mode 100644 src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSubstringCaseInsensitive.cs diff --git a/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj b/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj index 32f97b137e678a..5565f64da15f57 100644 --- a/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj +++ b/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj @@ -67,14 +67,6 @@ The System.Collections.Immutable library is built-in as part of the shared frame - - - - - - - - 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 cfde792bfc71f2..e4fbdcef00b3c6 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 @@ -181,67 +181,45 @@ private static FrozenDictionary CreateFromDictionary { if (analysis.RightJustifiedSubstring) { - if (analysis.IgnoreCaseForHash) + if (analysis.IgnoreCase) { - Debug.Assert(analysis.IgnoreCase); - frozenDictionary = analysis.AllAsciiIfIgnoreCaseForHash + 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); } else { - if (analysis.HashCount == 1) - { - frozenDictionary = analysis.IgnoreCase - ? new OrdinalStringFrozenDictionary_RightJustifiedSingleCharCaseInsensitive(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex) - : new OrdinalStringFrozenDictionary_RightJustifiedSingleChar(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex); - } - else - { - frozenDictionary = analysis.IgnoreCase - ? new OrdinalStringFrozenDictionary_RightJustifiedSubstringCaseInsensitive(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenDictionary_RightJustifiedSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); - } + 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); } } else { - if (analysis.IgnoreCaseForHash) + if (analysis.IgnoreCase) { - Debug.Assert(analysis.IgnoreCase); - frozenDictionary = analysis.AllAsciiIfIgnoreCaseForHash + 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); } else { - if (analysis.HashCount == 1) - { - frozenDictionary = analysis.IgnoreCase - ? new OrdinalStringFrozenDictionary_LeftJustifiedSingleCharCaseInsensitive(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex) - : new OrdinalStringFrozenDictionary_LeftJustifiedSingleChar(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex); - } - else - { - frozenDictionary = analysis.IgnoreCase - ? new OrdinalStringFrozenDictionary_LeftJustifiedSubstringCaseInsensitive(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenDictionary_LeftJustifiedSubstring(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); - } + 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); } } } else { - if (analysis.IgnoreCaseForHash) + if (analysis.IgnoreCase) { - Debug.Assert(analysis.IgnoreCase); - frozenDictionary = analysis.AllAsciiIfIgnoreCaseForHash + frozenDictionary = analysis.AllAsciiIfIgnoreCase ? new OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff) : new OrdinalStringFrozenDictionary_FullCaseInsensitive(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff); } else { - // if (IgnoreCase) => Can only be true if there are no letters, thus case sensitive comparison still works here. frozenDictionary = new OrdinalStringFrozenDictionary_Full(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff); } } 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 4bafeccd3882a2..8c315f214fe03c 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 @@ -129,67 +129,45 @@ private static FrozenSet CreateFromSet(HashSet source) { if (analysis.RightJustifiedSubstring) { - if (analysis.IgnoreCaseForHash) + if (analysis.IgnoreCase) { - Debug.Assert(analysis.IgnoreCase); - frozenSet = analysis.AllAsciiIfIgnoreCaseForHash + 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); } else { - if (analysis.HashCount == 1) - { - frozenSet = analysis.IgnoreCase - ? new OrdinalStringFrozenSet_RightJustifiedSingleCharCaseInsensitive(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex) - : new OrdinalStringFrozenSet_RightJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex); ; - } - else - { - frozenSet = analysis.IgnoreCase - ? new OrdinalStringFrozenSet_RightJustifiedSubstringCaseInsensitive(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenSet_RightJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); - } + 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); } } else { - if (analysis.IgnoreCaseForHash) + if (analysis.IgnoreCase) { - Debug.Assert(analysis.IgnoreCase); - frozenSet = analysis.AllAsciiIfIgnoreCaseForHash + 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); } else { - if (analysis.HashCount == 1) - { - frozenSet = analysis.IgnoreCase - ? new OrdinalStringFrozenSet_LeftJustifiedSingleCharCaseInsensitive(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex) - : new OrdinalStringFrozenSet_LeftJustifiedSingleChar(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex); - } - else - { - frozenSet = analysis.IgnoreCase - ? new OrdinalStringFrozenSet_LeftJustifiedSubstringCaseInsensitive(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount) - : new OrdinalStringFrozenSet_LeftJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount); - } + 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); } } } else { - if (analysis.IgnoreCaseForHash) + if (analysis.IgnoreCase) { - Debug.Assert(analysis.IgnoreCase); - frozenSet = analysis.AllAsciiIfIgnoreCaseForHash + frozenSet = analysis.AllAsciiIfIgnoreCase ? new OrdinalStringFrozenSet_FullCaseInsensitiveAscii(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff) : new OrdinalStringFrozenSet_FullCaseInsensitive(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff); } else { - // if (IgnoreCase) => Can only be true if there are no letters, thus case sensitive comparison still works here. frozenSet = new OrdinalStringFrozenSet_Full(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff); } } 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 41931cbc55981b..d6dcdb487c98d0 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 @@ -37,7 +37,7 @@ public static AnalysisResults Analyze( AnalysisResults results; if (minLength == 0 || !TryUseSubstring(uniqueStrings, ignoreCase, minLength, maxLength, out results)) { - results = CreateAnalysisResults(uniqueStrings, ignoreCase, minLength, maxLength, 0, 0, static (s, _, _) => s.AsSpan()); + results = CreateAnalysisResults(uniqueStrings, ignoreCase, minLength, maxLength, 0, 0, false, static (s, _, _) => s.AsSpan()); } return results; @@ -77,7 +77,7 @@ private static bool TryUseSubstring(ReadOnlySpan uniqueStrings, bool ign if (HasSufficientUniquenessFactor(set, uniqueStrings, acceptableNonUniqueCount)) { results = CreateAnalysisResults( - uniqueStrings, ignoreCase, minLength, maxLength, index, count, + uniqueStrings, ignoreCase, minLength, maxLength, index, count, true, static (string s, int index, int count) => s.AsSpan(index, count)); return true; } @@ -101,7 +101,7 @@ private static bool TryUseSubstring(ReadOnlySpan uniqueStrings, bool ign if (HasSufficientUniquenessFactor(set, uniqueStrings, acceptableNonUniqueCount)) { results = CreateAnalysisResults( - uniqueStrings, ignoreCase, minLength, maxLength, comparer.Index, count, + uniqueStrings, ignoreCase, minLength, maxLength, comparer.Index, count, true, static (string s, int index, int count) => s.AsSpan(s.Length + index, count)); return true; } @@ -115,23 +115,21 @@ private static bool TryUseSubstring(ReadOnlySpan uniqueStrings, bool ign } private static AnalysisResults CreateAnalysisResults( - ReadOnlySpan uniqueStrings, bool ignoreCase, int minLength, int maxLength, int index, int count, GetSpan getSubstringSpan) + ReadOnlySpan uniqueStrings, bool ignoreCase, int minLength, int maxLength, int index, int count, bool isSubstring, GetSpan getSubstringSpan) { // Start off by assuming all strings are ASCII bool allAsciiIfIgnoreCaseForHash = true; - bool ignoreCaseForHash = ignoreCase; - // If we're case-sensitive, it doesn't matter if the strings are ASCII or not. // But if we're case-insensitive, we can switch to a faster comparer if all the // substrings are ASCII, so we check each. - if (ignoreCaseForHash) + if (ignoreCase) { - // Further, if the ASCII substrings don't contain any letters, then we can + // Further, if the ASCII keys (in their entirety) don't contain any letters, then we can // actually perform the comparison as case-sensitive even if case-insensitive // was requested, as there's nothing that would compare equally to the substring // other than the substring itself. - bool canSwitchIgnoreCaseHashToCaseSensitive = true; + bool canSwitchIgnoreCaseHashToCaseSensitive = !isSubstring; foreach (string s in uniqueStrings) { @@ -157,12 +155,12 @@ private static AnalysisResults CreateAnalysisResults( // If we can switch to case-sensitive, do so. if (canSwitchIgnoreCaseHashToCaseSensitive) { - ignoreCaseForHash = false; + ignoreCase = false; } } // Return the analysis results. - return new AnalysisResults(ignoreCase, ignoreCaseForHash, allAsciiIfIgnoreCaseForHash, index, count, minLength, maxLength); + return new AnalysisResults(ignoreCase, allAsciiIfIgnoreCaseForHash, index, count, minLength, maxLength); } private delegate ReadOnlySpan GetSpan(string s, int index, int count); @@ -245,11 +243,10 @@ internal static bool HasSufficientUniquenessFactor(HashSet set, ReadOnly internal readonly struct AnalysisResults { - public AnalysisResults(bool ignoreCase, bool ignoreCaseForHash, bool allAsciiIfIgnoreCaseForHash, int hashIndex, int hashCount, int minLength, int maxLength) + public AnalysisResults(bool ignoreCase, bool allAsciiIfIgnoreCase, int hashIndex, int hashCount, int minLength, int maxLength) { IgnoreCase = ignoreCase; - IgnoreCaseForHash = ignoreCaseForHash; - AllAsciiIfIgnoreCaseForHash = allAsciiIfIgnoreCaseForHash; + AllAsciiIfIgnoreCase = allAsciiIfIgnoreCase; HashIndex = hashIndex; HashCount = hashCount; MinimumLength = minLength; @@ -257,8 +254,7 @@ public AnalysisResults(bool ignoreCase, bool ignoreCaseForHash, bool allAsciiIfI } public bool IgnoreCase { get; } - public bool IgnoreCaseForHash { get; } - public bool AllAsciiIfIgnoreCaseForHash { get; } + public bool AllAsciiIfIgnoreCase { get; } public int HashIndex { get; } public int HashCount { get; } public int MinimumLength { get; } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSingleCharCaseInsensitive.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSingleCharCaseInsensitive.cs deleted file mode 100644 index 2bebf7e04c18f0..00000000000000 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSingleCharCaseInsensitive.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; - -namespace System.Collections.Frozen -{ - internal sealed class OrdinalStringFrozenDictionary_LeftJustifiedSingleCharCaseInsensitive : OrdinalStringFrozenDictionary - { - internal OrdinalStringFrozenDictionary_LeftJustifiedSingleCharCaseInsensitive( - string[] keys, - TValue[] values, - IEqualityComparer comparer, - int minimumLength, - int maximumLengthDiff, - int hashIndex) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) - { - } - - // This override is necessary to force the jit to emit the code in such a way that it - // avoids virtual dispatch overhead when calling the Equals/GetHashCode methods. Don't - // remove this, or you'll tank performance. - private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) => ref base.GetValueRefOrNullRefCore(key); - - private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); - private protected override int GetHashCode(string s) => s[HashIndex]; - } -} diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSubstringCaseInsensitive.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSubstringCaseInsensitive.cs deleted file mode 100644 index 0aec2fbe80473c..00000000000000 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_LeftJustifiedSubstringCaseInsensitive.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; - -namespace System.Collections.Frozen -{ - internal sealed class OrdinalStringFrozenDictionary_LeftJustifiedSubstringCaseInsensitive : OrdinalStringFrozenDictionary - { - internal OrdinalStringFrozenDictionary_LeftJustifiedSubstringCaseInsensitive( - string[] keys, - TValue[] values, - IEqualityComparer comparer, - int minimumLength, - int maximumLengthDiff, - int hashIndex, - int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) - { - } - - // This override is necessary to force the jit to emit the code in such a way that it - // avoids virtual dispatch overhead when calling the Equals/GetHashCode methods. Don't - // remove this, or you'll tank performance. - private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) => ref base.GetValueRefOrNullRefCore(key); - - private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); - private protected override int GetHashCode(string s) => Hashing.GetHashCodeOrdinal(s.AsSpan(HashIndex, HashCount)); - } -} diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSingleCharCaseInsensitive.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSingleCharCaseInsensitive.cs deleted file mode 100644 index b60fb38ae32405..00000000000000 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSingleCharCaseInsensitive.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; - -namespace System.Collections.Frozen -{ - internal sealed class OrdinalStringFrozenDictionary_RightJustifiedSingleCharCaseInsensitive : OrdinalStringFrozenDictionary - { - internal OrdinalStringFrozenDictionary_RightJustifiedSingleCharCaseInsensitive( - string[] keys, - TValue[] values, - IEqualityComparer comparer, - int minimumLength, - int maximumLengthDiff, - int hashIndex) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) - { - } - - // This override is necessary to force the jit to emit the code in such a way that it - // avoids virtual dispatch overhead when calling the Equals/GetHashCode methods. Don't - // remove this, or you'll tank performance. - private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) => ref base.GetValueRefOrNullRefCore(key); - - private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); - private protected override int GetHashCode(string s) => s[s.Length + HashIndex]; - } -} diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSubstringCaseInsensitive.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSubstringCaseInsensitive.cs deleted file mode 100644 index 117d2f329ccf4b..00000000000000 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenDictionary_RightJustifiedSubstringCaseInsensitive.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; - -namespace System.Collections.Frozen -{ - internal sealed class OrdinalStringFrozenDictionary_RightJustifiedSubstringCaseInsensitive : OrdinalStringFrozenDictionary - { - internal OrdinalStringFrozenDictionary_RightJustifiedSubstringCaseInsensitive( - string[] keys, - TValue[] values, - IEqualityComparer comparer, - int minimumLength, - int maximumLengthDiff, - int hashIndex, - int hashCount) - : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) - { - } - - // This override is necessary to force the jit to emit the code in such a way that it - // avoids virtual dispatch overhead when calling the Equals/GetHashCode methods. Don't - // remove this, or you'll tank performance. - private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) => ref base.GetValueRefOrNullRefCore(key); - - private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); - private protected override int GetHashCode(string s) => Hashing.GetHashCodeOrdinal(s.AsSpan(s.Length + HashIndex, HashCount)); - } -} diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSingleCharCaseInsensitive.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSingleCharCaseInsensitive.cs deleted file mode 100644 index 09691e80e75ceb..00000000000000 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSingleCharCaseInsensitive.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; - -namespace System.Collections.Frozen -{ - internal sealed class OrdinalStringFrozenSet_LeftJustifiedSingleCharCaseInsensitive : OrdinalStringFrozenSet - { - internal OrdinalStringFrozenSet_LeftJustifiedSingleCharCaseInsensitive( - string[] entries, - IEqualityComparer comparer, - int minimumLength, - int maximumLengthDiff, - int hashIndex) - : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) - { - } - - // This override is necessary to force the jit to emit the code in such a way that it - // avoids virtual dispatch overhead when calling the Equals/GetHashCode methods. Don't - // remove this, or you'll tank performance. - private protected override int FindItemIndex(string item) => base.FindItemIndex(item); - - private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); - private protected override int GetHashCode(string s) => s[HashIndex]; - } -} diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSubstringCaseInsensitive.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSubstringCaseInsensitive.cs deleted file mode 100644 index ebcf89c332b9ab..00000000000000 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_LeftJustifiedSubstringCaseInsensitive.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; - -namespace System.Collections.Frozen -{ - internal sealed class OrdinalStringFrozenSet_LeftJustifiedSubstringCaseInsensitive : OrdinalStringFrozenSet - { - internal OrdinalStringFrozenSet_LeftJustifiedSubstringCaseInsensitive( - string[] entries, - IEqualityComparer comparer, - int minimumLength, - int maximumLengthDiff, - int hashIndex, - int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) - { - } - - // This override is necessary to force the jit to emit the code in such a way that it - // avoids virtual dispatch overhead when calling the Equals/GetHashCode methods. Don't - // remove this, or you'll tank performance. - private protected override int FindItemIndex(string item) => base.FindItemIndex(item); - - private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); - private protected override int GetHashCode(string s) => Hashing.GetHashCodeOrdinal(s.AsSpan(HashIndex, HashCount)); - } -} diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSingleCharCaseInsensitive.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSingleCharCaseInsensitive.cs deleted file mode 100644 index e6843b135f2401..00000000000000 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSingleCharCaseInsensitive.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; - -namespace System.Collections.Frozen -{ - internal sealed class OrdinalStringFrozenSet_RightJustifiedSingleCharCaseInsensitive : OrdinalStringFrozenSet - { - internal OrdinalStringFrozenSet_RightJustifiedSingleCharCaseInsensitive( - string[] entries, - IEqualityComparer comparer, - int minimumLength, - int maximumLengthDiff, - int hashIndex) - : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) - { - } - - // This override is necessary to force the jit to emit the code in such a way that it - // avoids virtual dispatch overhead when calling the Equals/GetHashCode methods. Don't - // remove this, or you'll tank performance. - private protected override int FindItemIndex(string item) => base.FindItemIndex(item); - - private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); - private protected override int GetHashCode(string s) => s[s.Length + HashIndex]; - } -} diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSubstringCaseInsensitive.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSubstringCaseInsensitive.cs deleted file mode 100644 index 0921da6db088ca..00000000000000 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/OrdinalStringFrozenSet_RightJustifiedSubstringCaseInsensitive.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; - -namespace System.Collections.Frozen -{ - internal sealed class OrdinalStringFrozenSet_RightJustifiedSubstringCaseInsensitive : OrdinalStringFrozenSet - { - internal OrdinalStringFrozenSet_RightJustifiedSubstringCaseInsensitive( - string[] entries, - IEqualityComparer comparer, - int minimumLength, - int maximumLengthDiff, - int hashIndex, - int hashCount) - : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) - { - } - - // This override is necessary to force the jit to emit the code in such a way that it - // avoids virtual dispatch overhead when calling the Equals/GetHashCode methods. Don't - // remove this, or you'll tank performance. - private protected override int FindItemIndex(string item) => base.FindItemIndex(item); - - private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); - private protected override int GetHashCode(string s) => Hashing.GetHashCodeOrdinal(s.AsSpan(s.Length + HashIndex, HashCount)); - } -} diff --git a/src/libraries/System.Collections.Immutable/tests/Frozen/KeyAnalyzerTests.cs b/src/libraries/System.Collections.Immutable/tests/Frozen/KeyAnalyzerTests.cs index 141e07162d572f..b7c1be20c17bd4 100644 --- a/src/libraries/System.Collections.Immutable/tests/Frozen/KeyAnalyzerTests.cs +++ b/src/libraries/System.Collections.Immutable/tests/Frozen/KeyAnalyzerTests.cs @@ -32,28 +32,24 @@ public static void LeftHand() { KeyAnalyzer.AnalysisResults r = RunAnalysis(new[] { "K0", "K20", "K300" }, false); Assert.False(r.RightJustifiedSubstring); - Assert.False(r.IgnoreCaseForHash); Assert.False(r.IgnoreCase); Assert.Equal(1, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "S1" }, false); Assert.False(r.RightJustifiedSubstring); - Assert.False(r.IgnoreCaseForHash); Assert.False(r.IgnoreCase); Assert.Equal(0, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "S1", "T1" }, false); Assert.False(r.RightJustifiedSubstring); - Assert.False(r.IgnoreCaseForHash); Assert.False(r.IgnoreCase); Assert.Equal(0, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "SA1", "TA1", "SB1" }, false); Assert.False(r.RightJustifiedSubstring); - Assert.False(r.IgnoreCaseForHash); Assert.False(r.IgnoreCase); Assert.Equal(0, r.HashIndex); Assert.Equal(2, r.HashCount); @@ -64,57 +60,50 @@ public static void LeftHandCaseInsensitive() { KeyAnalyzer.AnalysisResults r = RunAnalysis(new[] { "É1" }, true); Assert.False(r.RightJustifiedSubstring); - Assert.True(r.IgnoreCaseForHash); Assert.True(r.IgnoreCase); - Assert.False(r.AllAsciiIfIgnoreCaseForHash); + Assert.False(r.AllAsciiIfIgnoreCase); Assert.Equal(0, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "É1", "T1" }, true); Assert.False(r.RightJustifiedSubstring); - Assert.True(r.IgnoreCaseForHash); Assert.True(r.IgnoreCase); - Assert.False(r.AllAsciiIfIgnoreCaseForHash); + Assert.False(r.AllAsciiIfIgnoreCase); Assert.Equal(0, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "ÉA1", "TA1", "ÉB1" }, true); Assert.False(r.RightJustifiedSubstring); - Assert.True(r.IgnoreCaseForHash); Assert.True(r.IgnoreCase); - Assert.False(r.AllAsciiIfIgnoreCaseForHash); + Assert.False(r.AllAsciiIfIgnoreCase); Assert.Equal(0, r.HashIndex); Assert.Equal(2, r.HashCount); r = RunAnalysis(new[] { "ABCDEÉ1ABCDEF", "ABCDETA1ABCDEF", "ABCDESB1ABCDEF" }, true); Assert.False(r.RightJustifiedSubstring); - Assert.True(r.IgnoreCaseForHash); Assert.True(r.IgnoreCase); - Assert.False(r.AllAsciiIfIgnoreCaseForHash); + Assert.False(r.AllAsciiIfIgnoreCase); Assert.Equal(5, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "ABCDEFÉ1ABCDEF", "ABCDEFTA1ABCDEF", "ABCDEFSB1ABCDEF" }, true); Assert.False(r.RightJustifiedSubstring); - Assert.True(r.IgnoreCaseForHash); Assert.True(r.IgnoreCase); - Assert.False(r.AllAsciiIfIgnoreCaseForHash); + Assert.False(r.AllAsciiIfIgnoreCase); Assert.Equal(6, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "ABCÉDEFÉ1ABCDEF", "ABCÉDEFTA1ABCDEF", "ABCÉDEFSB1ABCDEF" }, true); Assert.False(r.RightJustifiedSubstring); - Assert.True(r.IgnoreCaseForHash); Assert.True(r.IgnoreCase); - Assert.False(r.AllAsciiIfIgnoreCaseForHash); + Assert.False(r.AllAsciiIfIgnoreCase); Assert.Equal(7, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "1abc", "2abc", "3abc", "4abc", "5abc", "6abc" }, true); Assert.False(r.RightJustifiedSubstring); - Assert.False(r.IgnoreCaseForHash); - Assert.True(r.IgnoreCase); - Assert.True(r.AllAsciiIfIgnoreCaseForHash); + Assert.False(r.IgnoreCase); + Assert.True(r.AllAsciiIfIgnoreCase); Assert.Equal(0, r.HashIndex); Assert.Equal(1, r.HashCount); @@ -126,24 +115,21 @@ public static void LeftHandCaseInsensitiveAscii() KeyAnalyzer.AnalysisResults r = RunAnalysis(new[] { "S1" }, true); Assert.False(r.RightJustifiedSubstring); Assert.True(r.IgnoreCase); - Assert.True(r.IgnoreCaseForHash); - Assert.True(r.AllAsciiIfIgnoreCaseForHash); + Assert.True(r.AllAsciiIfIgnoreCase); Assert.Equal(0, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "S1", "T1" }, true); Assert.False(r.RightJustifiedSubstring); Assert.True(r.IgnoreCase); - Assert.True(r.IgnoreCaseForHash); - Assert.True(r.AllAsciiIfIgnoreCaseForHash); + Assert.True(r.AllAsciiIfIgnoreCase); Assert.Equal(0, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "SA1", "TA1", "SB1" }, true); Assert.False(r.RightJustifiedSubstring); Assert.True(r.IgnoreCase); - Assert.True(r.IgnoreCaseForHash); - Assert.True(r.AllAsciiIfIgnoreCaseForHash); + Assert.True(r.AllAsciiIfIgnoreCase); Assert.Equal(0, r.HashIndex); Assert.Equal(2, r.HashCount); } @@ -154,16 +140,14 @@ public static void RightHand() KeyAnalyzer.AnalysisResults r = RunAnalysis(new[] { "1T1", "1T" }, false); Assert.True(r.RightJustifiedSubstring); Assert.False(r.IgnoreCase); - Assert.False(r.IgnoreCaseForHash); - Assert.True(r.AllAsciiIfIgnoreCaseForHash); + Assert.True(r.AllAsciiIfIgnoreCase); Assert.Equal(-1, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "1ATA", "1ATB", "1BS" }, false); Assert.True(r.RightJustifiedSubstring); Assert.False(r.IgnoreCase); - Assert.False(r.IgnoreCaseForHash); - Assert.True(r.AllAsciiIfIgnoreCaseForHash); + Assert.True(r.AllAsciiIfIgnoreCase); Assert.Equal(-1, r.HashIndex); Assert.Equal(1, r.HashCount); } @@ -174,16 +158,14 @@ public static void RightHandCaseInsensitive() KeyAnalyzer.AnalysisResults r = RunAnalysis(new[] { "1ÉÉ", "1É" }, true); Assert.True(r.RightJustifiedSubstring); Assert.True(r.IgnoreCase); - Assert.True(r.IgnoreCaseForHash); - Assert.False(r.AllAsciiIfIgnoreCaseForHash); + Assert.False(r.AllAsciiIfIgnoreCase); Assert.Equal(-2, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "ÉA", "1AT", "1AÉT" }, true); Assert.True(r.RightJustifiedSubstring); Assert.True(r.IgnoreCase); - Assert.True(r.IgnoreCaseForHash); - Assert.False(r.AllAsciiIfIgnoreCaseForHash); + Assert.False(r.AllAsciiIfIgnoreCase); Assert.Equal(-2, r.HashIndex); Assert.Equal(2, r.HashCount); } @@ -194,16 +176,14 @@ public static void RightHandCaseInsensitiveAscii() KeyAnalyzer.AnalysisResults r = RunAnalysis(new[] { "a1", "A1T" }, true); Assert.True(r.RightJustifiedSubstring); Assert.True(r.IgnoreCase); - Assert.True(r.IgnoreCaseForHash); - Assert.True(r.AllAsciiIfIgnoreCaseForHash); + Assert.True(r.AllAsciiIfIgnoreCase); Assert.Equal(-1, r.HashIndex); Assert.Equal(1, r.HashCount); r = RunAnalysis(new[] { "bÉÉ", "caT", "cAÉT" }, true); Assert.True(r.RightJustifiedSubstring); Assert.True(r.IgnoreCase); - Assert.True(r.IgnoreCaseForHash); - Assert.True(r.AllAsciiIfIgnoreCaseForHash); + Assert.True(r.AllAsciiIfIgnoreCase); Assert.Equal(-3, r.HashIndex); Assert.Equal(1, r.HashCount); } @@ -214,8 +194,7 @@ public static void Full() KeyAnalyzer.AnalysisResults r = RunAnalysis(new[] { "ABC", "DBC", "ADC", "ABD", "ABDABD" }, false); Assert.False(r.SubstringHashing); Assert.False(r.IgnoreCase); - Assert.False(r.IgnoreCaseForHash); - Assert.True(r.AllAsciiIfIgnoreCaseForHash); + Assert.True(r.AllAsciiIfIgnoreCase); } [Fact] @@ -224,8 +203,7 @@ public static void FullCaseInsensitive() KeyAnalyzer.AnalysisResults r = RunAnalysis(new[] { "æbc", "DBC", "æDC", "æbd", "æbdæbd" }, true); Assert.False(r.SubstringHashing); Assert.True(r.IgnoreCase); - Assert.True(r.IgnoreCaseForHash); - Assert.False(r.AllAsciiIfIgnoreCaseForHash); + Assert.False(r.AllAsciiIfIgnoreCase); } [Fact] @@ -234,8 +212,7 @@ public static void FullCaseInsensitiveAscii() KeyAnalyzer.AnalysisResults r = RunAnalysis(new[] { "abc", "DBC", "aDC", "abd", "abdabd" }, true); Assert.False(r.SubstringHashing); Assert.True(r.IgnoreCase); - Assert.True(r.IgnoreCaseForHash); - Assert.True(r.AllAsciiIfIgnoreCaseForHash); + Assert.True(r.AllAsciiIfIgnoreCase); } [Fact]