Skip to content

Commit

Permalink
Use IndexOfAnyInRange in StripBidiControlCharacters (#78658)
Browse files Browse the repository at this point in the history
* Use IndexOfAnyInRange in StripBidiControlCharacters

* Simplify IsBidiControlCharacter
  • Loading branch information
MihaZupan authored Nov 22, 2022
1 parent ac169e5 commit ae70706
Showing 1 changed file with 14 additions and 20 deletions.
34 changes: 14 additions & 20 deletions src/libraries/System.Private.Uri/src/System/UriHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -570,51 +570,45 @@ internal static bool IsLWS(char ch)
return (ch <= ' ') && (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t');
}

//
// Is this a Bidirectional control char.. These get stripped
//
internal static bool IsBidiControlCharacter(char ch)
{
return (ch == '\u200E' /*LRM*/ || ch == '\u200F' /*RLM*/ || ch == '\u202A' /*LRE*/ ||
ch == '\u202B' /*RLE*/ || ch == '\u202C' /*PDF*/ || ch == '\u202D' /*LRO*/ ||
ch == '\u202E' /*RLO*/);
}
internal static bool IsBidiControlCharacter(char ch) =>
char.IsBetween(ch, '\u200E', '\u202E') && !char.IsBetween(ch, '\u2010', '\u2029');

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

int charsToRemove = 0;
foreach (char c in strToClean)

int indexOfPossibleCharToRemove = strToClean.IndexOfAnyInRange('\u200E', '\u202E');
if (indexOfPossibleCharToRemove >= 0)
{
if ((uint)(c - '\u200E') <= ('\u202E' - '\u200E') && IsBidiControlCharacter(c))
// Slow path: Contains chars that fall in the [u200E, u202E] range (so likely Bidi)
foreach (char c in strToClean.Slice(indexOfPossibleCharToRemove))
{
charsToRemove++;
if (IsBidiControlCharacter(c))
{
charsToRemove++;
}
}
}

if (charsToRemove == 0)
{
// Hot path
return backingString ?? new string(strToClean);
}

if (charsToRemove == strToClean.Length)
{
return string.Empty;
}

fixed (char* pStrToClean = &MemoryMarshal.GetReference(strToClean))
{
return string.Create(strToClean.Length - charsToRemove, (StrToClean: (IntPtr)pStrToClean, strToClean.Length), (buffer, state) =>
return string.Create(strToClean.Length - charsToRemove, (StrToClean: (IntPtr)pStrToClean, strToClean.Length), static (buffer, state) =>
{
var strToClean = new ReadOnlySpan<char>((char*)state.StrToClean, state.Length);
int destIndex = 0;
foreach (char c in strToClean)
{
if ((uint)(c - '\u200E') > ('\u202E' - '\u200E') || !IsBidiControlCharacter(c))
if (!IsBidiControlCharacter(c))
{
buffer[destIndex++] = c;
}
Expand Down

0 comments on commit ae70706

Please sign in to comment.