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 more char.Is* helpers for common ASCII sets #69318

Merged
merged 2 commits into from May 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -87,7 +87,7 @@ public override bool IsAssignableFrom([NotNullWhen(true)] TypeInfo? typeInfo)
curIndex++;
}
// consume, one dimension at a time
if ((format[curIndex] >= '0' && format[curIndex] <= '9') || format[curIndex] == '-')
if (char.IsAsciiDigit(format[curIndex]) || format[curIndex] == '-')
{
bool isNegative = false;
if (format[curIndex] == '-')
Expand All @@ -97,7 +97,7 @@ public override bool IsAssignableFrom([NotNullWhen(true)] TypeInfo? typeInfo)
}

// lower bound is specified. Consume the low bound
while (format[curIndex] >= '0' && format[curIndex] <= '9')
while (char.IsAsciiDigit(format[curIndex]))
{
iLowerBound *= 10;
iLowerBound += format[curIndex] - '0';
Expand Down Expand Up @@ -126,7 +126,7 @@ public override bool IsAssignableFrom([NotNullWhen(true)] TypeInfo? typeInfo)

curIndex++;
// consume the upper bound
if ((format[curIndex] >= '0' && format[curIndex] <= '9') || format[curIndex] == '-')
if (char.IsAsciiDigit(format[curIndex]) || format[curIndex] == '-')
{
bool isNegative = false;
iUpperBound = 0;
Expand All @@ -137,7 +137,7 @@ public override bool IsAssignableFrom([NotNullWhen(true)] TypeInfo? typeInfo)
}

// lower bound is specified. Consume the low bound
while (format[curIndex] >= '0' && format[curIndex] <= '9')
while (char.IsAsciiDigit(format[curIndex]))
{
iUpperBound *= 10;
iUpperBound += format[curIndex] - '0';
Expand Down
Expand Up @@ -440,7 +440,7 @@ private static unsafe bool ParseNumber(ref char* str, char* strEnd, NumberStyles
int digEnd = 0;
while (true)
{
if ((ch >= '0' && ch <= '9') || (((options & NumberStyles.AllowHexSpecifier) != 0) && ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))))
if (char.IsAsciiDigit(ch) || (((options & NumberStyles.AllowHexSpecifier) != 0) && char.IsBetween((char)(ch | 0x20), 'a', 'f')))
{
state |= StateDigits;

Expand Down Expand Up @@ -510,7 +510,7 @@ private static unsafe bool ParseNumber(ref char* str, char* strEnd, NumberStyles
ch = (p = next) < strEnd ? *p : '\0';
negExp = true;
}
if (ch >= '0' && ch <= '9')
if (char.IsAsciiDigit(ch))
{
int exp = 0;
do
Expand All @@ -520,12 +520,12 @@ private static unsafe bool ParseNumber(ref char* str, char* strEnd, NumberStyles
if (exp > 1000)
{
exp = 9999;
while (ch >= '0' && ch <= '9')
while (char.IsAsciiDigit(ch))
{
ch = ++p < strEnd ? *p : '\0';
}
}
} while (ch >= '0' && ch <= '9');
} while (char.IsAsciiDigit(ch));
if (negExp)
{
exp = -exp;
Expand Down Expand Up @@ -678,8 +678,7 @@ internal static char ParseFormatSpecifier(ReadOnlySpan<char> format, out int dig
// If the format begins with a symbol, see if it's a standard format
// with or without a specified number of digits.
c = format[0];
if ((uint)(c - 'A') <= 'Z' - 'A' ||
(uint)(c - 'a') <= 'z' - 'a')
if (char.IsAsciiLetter(c))
{
// Fast path for sole symbol, e.g. "D"
if (format.Length == 1)
Expand Down Expand Up @@ -714,7 +713,7 @@ internal static char ParseFormatSpecifier(ReadOnlySpan<char> format, out int dig
// digits. Further, for compat, we need to stop when we hit a null char.
int n = 0;
int i = 1;
while (i < format.Length && (((uint)format[i] - '0') < 10))
while ((uint)i < (uint)format.Length && char.IsAsciiDigit(format[i]))
{
int temp = (n * 10) + format[i++] - '0';
if (temp < n)
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/Common/src/System/IO/PathInternal.Windows.cs
Expand Up @@ -69,7 +69,7 @@ internal static partial class PathInternal
/// </summary>
internal static bool IsValidDriveChar(char value)
{
return (value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z');
return (uint)((value | 0x20) - 'a') <= (uint)('z' - 'a');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this use the new API, or is it too low level to be dependent on it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately this file is compiled into a library that has a pre-.NET 7 target. It wasn't worth ifdef'ing it to use the new API in some builds and the open-coded version in others.

}

internal static bool EndsWithPeriodOrSpace(string? path)
Expand Down
Expand Up @@ -126,7 +126,7 @@ internal static unsafe bool IsValidCanonical(char* name, int start, ref int end,
break;
}

if (ch <= '9' && ch >= '0')
if (char.IsAsciiDigit(ch))
{
if (!haveNumber && (ch == '0'))
{
Expand Down Expand Up @@ -217,7 +217,7 @@ internal static unsafe long ParseNonCanonical(char* name, int start, ref int end
ch = name[current];
int digitValue;

if ((numberBase == Decimal || numberBase == Hex) && '0' <= ch && ch <= '9')
if ((numberBase == Decimal || numberBase == Hex) && char.IsAsciiDigit(ch))
{
digitValue = ch - '0';
}
Expand Down
Expand Up @@ -123,7 +123,7 @@ internal static unsafe bool IsValidStrict(char* name, int start, ref int end)
int i;
for (i = start; i < end; ++i)
{
if (Uri.IsHexDigit(name[i]))
if (char.IsAsciiHexDigit(name[i]))
{
++sequenceLength;
expectingNumber = false;
Expand Down Expand Up @@ -176,7 +176,7 @@ internal static unsafe bool IsValidStrict(char* name, int start, ref int end)
i += 4;
for (; i < end; i++)
{
if (!Uri.IsHexDigit(name[i]))
if (!char.IsAsciiHexDigit(name[i]))
{
return false;
}
Expand All @@ -187,7 +187,7 @@ internal static unsafe bool IsValidStrict(char* name, int start, ref int end)
i += 2;
for (; i < end; i++)
{
if (name[i] < '0' || name[i] > '9')
if (!char.IsAsciiDigit(name[i]))
{
return false;
}
Expand Down
Expand Up @@ -35,8 +35,8 @@ public override bool IsValid(object? value)
// Note: string.Reverse() does not exist for WinPhone
for (var i = ccValue.Length - 1; i >= 0; i--)
{
var digit = ccValue[i];
if (digit < '0' || digit > '9')
char digit = ccValue[i];
if (!char.IsAsciiDigit(digit))
{
return false;
}
Expand Down
Expand Up @@ -1395,14 +1395,6 @@ private static bool IsAscii(char c)
return (c >= '!' && c <= '~');
}

/// <summary>
/// Helper function for alphanumeric char in ascii mode.
/// </summary>
private static bool IsAciiAlphanumeric(char c)
{
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}

/// <summary>
/// Helper function for testing mask language alphanumeric identifiers.
/// </summary>
Expand All @@ -1411,14 +1403,6 @@ private static bool IsAlphanumeric(char c)
return char.IsLetter(c) || char.IsDigit(c);
}

/// <summary>
/// Helper function for testing letter char in ascii mode.
/// </summary>
private static bool IsAsciiLetter(char c)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}

/// <summary>
/// Checks whether the specified position is available for assignment. Returns false if it is assigned
/// or it is not editable, true otherwise.
Expand Down Expand Up @@ -2302,7 +2286,7 @@ private bool TestChar(char input, int position, out MaskedTextResultHint resultH
resultHint = MaskedTextResultHint.LetterExpected;
return false;
}
if (!IsAsciiLetter(input) && AsciiOnly)
if (!char.IsAsciiLetter(input) && AsciiOnly)
{
resultHint = MaskedTextResultHint.AsciiCharacterExpected;
return false;
Expand All @@ -2315,7 +2299,7 @@ private bool TestChar(char input, int position, out MaskedTextResultHint resultH
resultHint = MaskedTextResultHint.LetterExpected;
return false;
}
if (!IsAsciiLetter(input) && AsciiOnly)
if (!char.IsAsciiLetter(input) && AsciiOnly)
{
resultHint = MaskedTextResultHint.AsciiCharacterExpected;
return false;
Expand Down Expand Up @@ -2344,7 +2328,7 @@ private bool TestChar(char input, int position, out MaskedTextResultHint resultH
resultHint = MaskedTextResultHint.AlphanumericCharacterExpected;
return false;
}
if (!IsAciiAlphanumeric(input) && AsciiOnly)
if (!char.IsAsciiLetterOrDigit(input) && AsciiOnly)
{
resultHint = MaskedTextResultHint.AsciiCharacterExpected;
return false;
Expand All @@ -2357,7 +2341,7 @@ private bool TestChar(char input, int position, out MaskedTextResultHint resultH
resultHint = MaskedTextResultHint.AlphanumericCharacterExpected;
return false;
}
if (!IsAciiAlphanumeric(input) && AsciiOnly)
if (!char.IsAsciiLetterOrDigit(input) && AsciiOnly)
{
resultHint = MaskedTextResultHint.AsciiCharacterExpected;
return false;
Expand Down
5 changes: 1 addition & 4 deletions src/libraries/System.Console/src/System/ConsolePal.Unix.cs
Expand Up @@ -629,7 +629,7 @@ static void ReadRowOrCol(int startExclusive, int endExclusive, StdInReader reade
for (int i = startExclusive + 1; i < endExclusive; i++)
{
byte b = source[i];
if (IsDigit(b))
if (char.IsAsciiDigit((char)b))
{
try
{
Expand Down Expand Up @@ -675,9 +675,6 @@ public static void MoveBufferArea(int sourceLeft, int sourceTop, int sourceWidth
throw new PlatformNotSupportedException();
}

/// <summary>Gets whether the specified character is a digit 0-9.</summary>
private static bool IsDigit(byte c) => c >= '0' && c <= '9';

/// <summary>
/// Gets whether the specified file descriptor was redirected.
/// It's considered redirected if it doesn't refer to a terminal.
Expand Down
8 changes: 4 additions & 4 deletions src/libraries/System.Console/src/System/IO/StdInReader.cs
Expand Up @@ -344,27 +344,27 @@ internal static ConsoleKey GetKeyFromCharValue(char x, out bool isShift, out boo

default:
// 1. Ctrl A to Ctrl Z.
if (x >= 1 && x <= 26)
if (char.IsBetween(x, (char)1, (char)26))
{
isCtrl = true;
return ConsoleKey.A + x - 1;
}

// 2. Numbers from 0 to 9.
if (x >= '0' && x <= '9')
if (char.IsAsciiDigit(x))
{
return ConsoleKey.D0 + x - '0';
}

//3. A to Z
if (x >= 'A' && x <= 'Z')
if (char.IsAsciiLetterUpper(x))
{
isShift = true;
return ConsoleKey.A + (x - 'A');
}

// 4. a to z.
if (x >= 'a' && x <= 'z')
if (char.IsAsciiLetterLower(x))
{
return ConsoleKey.A + (x - 'a');
}
Expand Down
8 changes: 4 additions & 4 deletions src/libraries/System.Console/src/System/TermInfo.cs
Expand Up @@ -687,7 +687,7 @@ public static string Evaluate(string format, params FormatParam[] args)
// Stack pushing operations
case 'p': // Push the specified parameter (1-based) onto the stack
pos++;
Debug.Assert(format[pos] >= '0' && format[pos] <= '9');
Debug.Assert(char.IsAsciiDigit(format[pos]));
stack.Push(args[format[pos] - '1']);
break;
case 'l': // Pop a string and push its length
Expand All @@ -698,7 +698,7 @@ public static string Evaluate(string format, params FormatParam[] args)
int intLit = 0;
while (format[pos] != '}')
{
Debug.Assert(format[pos] >= '0' && format[pos] <= '9');
Debug.Assert(char.IsAsciiDigit(format[pos]));
intLit = (intLit * 10) + (format[pos] - '0');
pos++;
}
Expand Down Expand Up @@ -900,12 +900,12 @@ private static unsafe string FormatPrintF(string format, object arg)
private static FormatParam[] GetDynamicOrStaticVariables(
char c, ref FormatParam[]? dynamicVars, ref FormatParam[]? staticVars, out int index)
{
if (c >= 'A' && c <= 'Z')
if (char.IsAsciiLetterUpper(c))
{
index = c - 'A';
return staticVars ?? (staticVars = new FormatParam[26]); // one slot for each letter of alphabet
}
else if (c >= 'a' && c <= 'z')
else if (char.IsAsciiLetterLower(c))
{
index = c - 'a';
return dynamicVars ?? (dynamicVars = new FormatParam[26]); // one slot for each letter of alphabet
Expand Down
Expand Up @@ -1073,15 +1073,19 @@ public static SqlDecimal Parse(string s)
usChar = rgwchStr[iCurChar];
iCurChar++;

if (usChar >= '0' && usChar <= '9')
if (char.IsAsciiDigit(usChar))
{
usChar -= '0';
}
else if (usChar == '.' && lDecPnt < 0)
{
lDecPnt = iData;
continue;
}
else
{
throw new FormatException(SQLResource.FormatMessage);
}

snResult.MultByULong(s_ulBase10);
snResult.AddULong(usChar);
Expand Down
Expand Up @@ -234,7 +234,7 @@ private static ushort ParseUInt16UntilNonDigit(string s, out bool endedEarly)
for (int index = 0; index < s.Length; index++)
{
char c = s[index];
if (c < '0' || c > '9')
if (!char.IsAsciiDigit(c))
{
endedEarly = true;
break;
Expand Down
Expand Up @@ -442,7 +442,7 @@ private static bool TryReadQuotedInt32Value(ReadOnlySpan<char> value, out int re
// The port shouldn't ever need a quoted-pair, but they're still valid... skip if found.
if (ch == '\\') continue;

if ((uint)(ch - '0') > '9' - '0') // ch < '0' || ch > '9'
if (!char.IsAsciiDigit(ch))
{
result = 0;
return false;
Expand Down
Expand Up @@ -126,7 +126,7 @@ internal static int GetRetryConditionLength(string? input, int startIndex, out o
// If it is a number, we have a timespan, otherwise we assume we have a date.
char firstChar = input[current];

if ((firstChar >= '0') && (firstChar <= '9'))
if (char.IsAsciiDigit(firstChar))
{
int deltaStartIndex = current;
int deltaLength = HttpRuleParser.GetNumberLength(input, current, false);
Expand Down
Expand Up @@ -177,7 +177,7 @@ internal static int GetNumberLength(string input, int startIndex, bool allowDeci
while (current < input.Length)
{
c = input[current];
if ((c >= '0') && (c <= '9'))
if (char.IsAsciiDigit(c))
{
current++;
}
Expand Down
Expand Up @@ -89,14 +89,8 @@ private static void ValidateBoundary(string boundary)

foreach (char ch in boundary)
{
if (('0' <= ch && ch <= '9') || // Digit.
('a' <= ch && ch <= 'z') || // alpha.
('A' <= ch && ch <= 'Z') || // ALPHA.
(AllowedMarks.Contains(ch))) // Marks.
{
// Valid.
}
else
if (!char.IsAsciiLetterOrDigit(ch) &&
!AllowedMarks.Contains(ch)) // Marks.
{
throw new ArgumentException(SR.Format(System.Globalization.CultureInfo.InvariantCulture, SR.net_http_headers_invalid_value, boundary), nameof(boundary));
}
Expand Down
Expand Up @@ -87,10 +87,8 @@ internal void SetRequestLine(string req)
_method = parts[0];
foreach (char c in _method)
{
int ic = (int)c;

if ((ic >= 'A' && ic <= 'Z') ||
(ic > 32 && c < 127 && c != '(' && c != ')' && c != '<' &&
if (char.IsAsciiLetterUpper(c) ||
(c > 32 && c < 127 && c != '(' && c != ')' && c != '<' &&
bartonjs marked this conversation as resolved.
Show resolved Hide resolved
c != '<' && c != '>' && c != '@' && c != ',' && c != ';' &&
c != ':' && c != '\\' && c != '"' && c != '/' && c != '[' &&
c != ']' && c != '?' && c != '=' && c != '{' && c != '}'))
Expand Down