Skip to content

Commit

Permalink
Expand an optimization for short values to IgnoreCase in single-value…
Browse files Browse the repository at this point in the history
… SearchValues<string>
  • Loading branch information
MihaZupan committed Oct 1, 2024
1 parent ba9b3ba commit f94a3fb
Showing 1 changed file with 10 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ internal sealed class SingleStringSearchValuesThreeChars<TValueLength, TCaseSens

private static bool IgnoreCase => typeof(TCaseSensitivity) != typeof(CaseSensitive);

// If the value is short (!TValueLength.AtLeast4Chars => 2 or 3 characters), the anchors already represent the whole value.
// With case-sensitive comparisons, we've therefore already confirmed the match.
// With case-insensitive comparisons, we've applied the CaseConversionMask to the input, so while the anchors likely matched, we can't be sure.
// An exception to that is if we know the value is composed of only ASCII letters, in which case masking the input can't produce false positives.
private static bool CanSkipAnchorMatchVerification =>
!TValueLength.AtLeast4Chars &&
(typeof(TCaseSensitivity) == typeof(CaseSensitive) || typeof(TCaseSensitivity) == typeof(CaseInsensitiveAsciiLetters));

public SingleStringSearchValuesThreeChars(HashSet<string>? uniqueValues, string value) : base(uniqueValues)
{
// We could have more than one entry in 'uniqueValues' if this value is an exact prefix of all the others.
Expand Down Expand Up @@ -327,11 +335,7 @@ private bool TryMatch(ref char searchSpaceStart, int searchSpaceLength, ref char

ValidateReadPosition(ref searchSpaceStart, searchSpaceLength, ref matchRef, _value.Length);

// If the value is short (!TValueLength.AtLeast4Chars => 2 or 3 characters), the anchors already represent the whole value.
// With case-sensitive comparisons, we've therefore already confirmed the match, so we can skip doing so here.
// With case-insensitive comparisons, we applied a mask to the input, so while the anchors likely matched, we can't be sure.
if ((typeof(TCaseSensitivity) == typeof(CaseSensitive) && !TValueLength.AtLeast4Chars) ||
TCaseSensitivity.Equals<TValueLength>(ref matchRef, _value))
if (CanSkipAnchorMatchVerification || TCaseSensitivity.Equals<TValueLength>(ref matchRef, _value))
{
offsetFromStart = (int)((nuint)Unsafe.ByteOffset(ref searchSpaceStart, ref matchRef) / 2);
return true;
Expand Down Expand Up @@ -359,11 +363,7 @@ private bool TryMatch(ref char searchSpaceStart, int searchSpaceLength, ref char

ValidateReadPosition(ref searchSpaceStart, searchSpaceLength, ref matchRef, _value.Length);

// If the value is short (!TValueLength.AtLeast4Chars => 2 or 3 characters), the anchors already represent the whole value.
// With case-sensitive comparisons, we've therefore already confirmed the match, so we can skip doing so here.
// With case-insensitive comparisons, we applied a mask to the input, so while the anchors likely matched, we can't be sure.
if ((typeof(TCaseSensitivity) == typeof(CaseSensitive) && !TValueLength.AtLeast4Chars) ||
TCaseSensitivity.Equals<TValueLength>(ref matchRef, _value))
if (CanSkipAnchorMatchVerification || TCaseSensitivity.Equals<TValueLength>(ref matchRef, _value))
{
offsetFromStart = (int)((nuint)Unsafe.ByteOffset(ref searchSpaceStart, ref matchRef) / 2);
return true;
Expand Down

0 comments on commit f94a3fb

Please sign in to comment.