Skip to content

Commit ae70706

Browse files
authored
Use IndexOfAnyInRange in StripBidiControlCharacters (#78658)
* Use IndexOfAnyInRange in StripBidiControlCharacters * Simplify IsBidiControlCharacter
1 parent ac169e5 commit ae70706

File tree

1 file changed

+14
-20
lines changed

1 file changed

+14
-20
lines changed

src/libraries/System.Private.Uri/src/System/UriHelper.cs

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -570,51 +570,45 @@ internal static bool IsLWS(char ch)
570570
return (ch <= ' ') && (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t');
571571
}
572572

573-
//
574573
// Is this a Bidirectional control char.. These get stripped
575-
//
576-
internal static bool IsBidiControlCharacter(char ch)
577-
{
578-
return (ch == '\u200E' /*LRM*/ || ch == '\u200F' /*RLM*/ || ch == '\u202A' /*LRE*/ ||
579-
ch == '\u202B' /*RLE*/ || ch == '\u202C' /*PDF*/ || ch == '\u202D' /*LRO*/ ||
580-
ch == '\u202E' /*RLO*/);
581-
}
574+
internal static bool IsBidiControlCharacter(char ch) =>
575+
char.IsBetween(ch, '\u200E', '\u202E') && !char.IsBetween(ch, '\u2010', '\u2029');
582576

583-
//
584577
// Strip Bidirectional control characters from this string
585-
//
586578
internal static unsafe string StripBidiControlCharacters(ReadOnlySpan<char> strToClean, string? backingString = null)
587579
{
588580
Debug.Assert(backingString is null || strToClean.Length == backingString.Length);
589581

590582
int charsToRemove = 0;
591-
foreach (char c in strToClean)
583+
584+
int indexOfPossibleCharToRemove = strToClean.IndexOfAnyInRange('\u200E', '\u202E');
585+
if (indexOfPossibleCharToRemove >= 0)
592586
{
593-
if ((uint)(c - '\u200E') <= ('\u202E' - '\u200E') && IsBidiControlCharacter(c))
587+
// Slow path: Contains chars that fall in the [u200E, u202E] range (so likely Bidi)
588+
foreach (char c in strToClean.Slice(indexOfPossibleCharToRemove))
594589
{
595-
charsToRemove++;
590+
if (IsBidiControlCharacter(c))
591+
{
592+
charsToRemove++;
593+
}
596594
}
597595
}
598596

599597
if (charsToRemove == 0)
600598
{
599+
// Hot path
601600
return backingString ?? new string(strToClean);
602601
}
603602

604-
if (charsToRemove == strToClean.Length)
605-
{
606-
return string.Empty;
607-
}
608-
609603
fixed (char* pStrToClean = &MemoryMarshal.GetReference(strToClean))
610604
{
611-
return string.Create(strToClean.Length - charsToRemove, (StrToClean: (IntPtr)pStrToClean, strToClean.Length), (buffer, state) =>
605+
return string.Create(strToClean.Length - charsToRemove, (StrToClean: (IntPtr)pStrToClean, strToClean.Length), static (buffer, state) =>
612606
{
613607
var strToClean = new ReadOnlySpan<char>((char*)state.StrToClean, state.Length);
614608
int destIndex = 0;
615609
foreach (char c in strToClean)
616610
{
617-
if ((uint)(c - '\u200E') > ('\u202E' - '\u200E') || !IsBidiControlCharacter(c))
611+
if (!IsBidiControlCharacter(c))
618612
{
619613
buffer[destIndex++] = c;
620614
}

0 commit comments

Comments
 (0)