Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an additional length check to FrozenDictionary and FrozenSet #92546

Merged
merged 9 commits into from
Dec 11, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,12 @@ private static FrozenDictionary<TKey, TValue> CreateFromDictionary<TKey, TValue>

// 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);

Expand All @@ -184,29 +186,29 @@ private static FrozenDictionary<TKey, TValue> CreateFromDictionary<TKey, TValue>
if (analysis.IgnoreCase)
{
frozenDictionary = analysis.AllAsciiIfIgnoreCase
? new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount)
: new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount);
? new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount)
: new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount);
}
else
{
frozenDictionary = analysis.HashCount == 1
? new OrdinalStringFrozenDictionary_RightJustifiedSingleChar<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex)
: new OrdinalStringFrozenDictionary_RightJustifiedSubstring<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount);
? new OrdinalStringFrozenDictionary_RightJustifiedSingleChar<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex)
: new OrdinalStringFrozenDictionary_RightJustifiedSubstring<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount);
}
}
else
{
if (analysis.IgnoreCase)
{
frozenDictionary = analysis.AllAsciiIfIgnoreCase
? new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount)
: new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount);
? new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount)
: new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount);
}
else
{
frozenDictionary = analysis.HashCount == 1
? new OrdinalStringFrozenDictionary_LeftJustifiedSingleChar<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex)
: new OrdinalStringFrozenDictionary_LeftJustifiedSubstring<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, analysis.HashIndex, analysis.HashCount);
? new OrdinalStringFrozenDictionary_LeftJustifiedSingleChar<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex)
: new OrdinalStringFrozenDictionary_LeftJustifiedSubstring<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter, analysis.HashIndex, analysis.HashCount);
}
}
}
Expand All @@ -215,12 +217,12 @@ private static FrozenDictionary<TKey, TValue> CreateFromDictionary<TKey, TValue>
if (analysis.IgnoreCase)
{
frozenDictionary = analysis.AllAsciiIfIgnoreCase
? new OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff)
: new OrdinalStringFrozenDictionary_FullCaseInsensitive<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff);
? new OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter)
: new OrdinalStringFrozenDictionary_FullCaseInsensitive<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter);
}
else
{
frozenDictionary = new OrdinalStringFrozenDictionary_Full<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff);
frozenDictionary = new OrdinalStringFrozenDictionary_Full<TValue>(keys, values, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,12 @@ private static FrozenSet<T> CreateFromSet<T>(HashSet<T> 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 s in entries)
{
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);

Expand All @@ -132,29 +134,29 @@ private static FrozenSet<T> CreateFromSet<T>(HashSet<T> 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, 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.HashIndex)
: new OrdinalStringFrozenSet_RightJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, 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
{
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, 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.HashIndex)
: new OrdinalStringFrozenSet_LeftJustifiedSubstring(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, 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);
}
}
}
Expand All @@ -163,12 +165,12 @@ private static FrozenSet<T> CreateFromSet<T>(HashSet<T> 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, lengthFilter)
: new OrdinalStringFrozenSet_FullCaseInsensitive(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter);
}
else
{
frozenSet = new OrdinalStringFrozenSet_Full(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff);
frozenSet = new OrdinalStringFrozenSet_Full(entries, stringComparer, analysis.MinimumLength, analysis.MaximumLengthDiff, lengthFilter);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ internal abstract class OrdinalStringFrozenDictionary<TValue> : FrozenDictionary
private readonly TValue[] _values;
private readonly int _minimumLength;
private readonly int _maximumLengthDiff;
private readonly ulong _lengthFilter;

internal OrdinalStringFrozenDictionary(
string[] keys,
TValue[] values,
IEqualityComparer<string> comparer,
int minimumLength,
int maximumLengthDiff,
ulong lengthFilter,
int hashIndex = -1,
int hashCount = -1) :
base(comparer)
Expand All @@ -36,6 +38,7 @@ internal OrdinalStringFrozenDictionary(

_minimumLength = minimumLength;
_maximumLengthDiff = maximumLengthDiff;
_lengthFilter = lengthFilter;

HashIndex = hashIndex;
HashCount = hashCount;
Expand Down Expand Up @@ -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++;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ internal OrdinalStringFrozenDictionary_Full(
TValue[] values,
IEqualityComparer<string> comparer,
int minimumLength,
int maximumLengthDiff)
: base(keys, values, comparer, minimumLength, maximumLengthDiff)
int maximumLengthDiff,
ulong lengthFilter)
: base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ internal OrdinalStringFrozenDictionary_FullCaseInsensitive(
TValue[] values,
IEqualityComparer<string> comparer,
int minimumLength,
int maximumLengthDiff)
: base(keys, values, comparer, minimumLength, maximumLengthDiff)
int maximumLengthDiff,
ulong lengthFilter)
: base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ internal OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii(
TValue[] values,
IEqualityComparer<string> comparer,
int minimumLength,
int maximumLengthDiff)
: base(keys, values, comparer, minimumLength, maximumLengthDiff)
int maximumLengthDiff,
ulong lengthFilter)
: base(keys, values, comparer, minimumLength, maximumLengthDiff, lengthFilter)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ internal OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstrin
IEqualityComparer<string> 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)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ internal OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring(
IEqualityComparer<string> 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)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ internal OrdinalStringFrozenDictionary_LeftJustifiedSingleChar(
IEqualityComparer<string> 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)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ internal OrdinalStringFrozenDictionary_LeftJustifiedSubstring(
IEqualityComparer<string> 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)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ internal OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstri
IEqualityComparer<string> 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)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ internal OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring(
IEqualityComparer<string> 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)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ internal OrdinalStringFrozenDictionary_RightJustifiedSingleChar(
IEqualityComparer<string> 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)
{
}

Expand Down
Loading