Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

More efficient ParseNumber & MatchChars #3163

Merged
merged 2 commits into from Nov 3, 2016
Merged
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
117 changes: 51 additions & 66 deletions src/mscorlib/src/System/Number.cs
Expand Up @@ -622,16 +622,16 @@ internal unsafe struct NumberBuffer {
if (*str == '\0') {
return null;
}
for (; (*str != '\0'); p++, str++) {
if (*p != *str) { //We only hurt the failure case
if ((*str == '\u00A0') && (*p == '\u0020')) {// This fix is for French or Kazakh cultures. Since a user cannot type 0xA0 as a
// space character we use 0x20 space character instead to mean the same.
continue;
}
return null;
}
}
return p;
// We only hurt the failure case
// This fix is for French or Kazakh cultures. Since a user cannot type 0xA0 as a
// space character we use 0x20 space character instead to mean the same.
while (*p == *str || (*str == '\u00a0' && *p == '\u0020'))
{
p++;
str++;
if (*str == '\0') return p;
}
return null;
}

[System.Security.SecuritySafeCritical] // auto-generated
Expand Down Expand Up @@ -745,8 +745,6 @@ internal unsafe struct NumberBuffer {
// The alternative currency symbol used in ANSI codepage, that can not roundtrip between ANSI and Unicode.
// Currently, only ja-JP and ko-KR has non-null values (which is U+005c, backslash)
string ansicurrSymbol = null; // currency symbol from NumberFormatInfo.
string altdecSep = null; // decimal separator from NumberFormatInfo as a decimal
string altgroupSep = null; // group separator from NumberFormatInfo as a decimal

Boolean parsingCurrency = false;
if ((options & NumberStyles.AllowCurrencySymbol) != 0) {
Expand All @@ -760,8 +758,6 @@ internal unsafe struct NumberBuffer {

// The idea here is to match the currency separators and on failure match the number separators to keep the perf of VB's IsNumeric fast.
// The values of decSep are setup to use the correct relevant separator (currency in the if part and decimal in the else part).
altdecSep = numfmt.NumberDecimalSeparator;
altgroupSep = numfmt.NumberGroupSeparator;
decSep = numfmt.CurrencyDecimalSeparator;
groupSep = numfmt.CurrencyGroupSeparator;
parsingCurrency = true;
Expand All @@ -772,9 +768,7 @@ internal unsafe struct NumberBuffer {
}

Int32 state = 0;
Boolean signflag = false; // Cache the results of "options & PARSE_LEADINGSIGN && !(state & STATE_SIGN)" to avoid doing this twice
Boolean bigNumber = (sb != null); // When a StringBuilder is provided then we use it in place of the number.digits char[50]
Boolean bigNumberHex = (bigNumber && ((options & NumberStyles.AllowHexSpecifier) != 0));
Int32 maxParseDigits = bigNumber ? Int32.MaxValue : NumberMaxDigits;

char* p = str;
Expand All @@ -784,32 +778,27 @@ internal unsafe struct NumberBuffer {
while (true) {
// Eat whitespace unless we've found a sign which isn't followed by a currency symbol.
// "-Kr 1231.47" is legal but "- 1231.47" is not.
if (IsWhite(ch) && ((options & NumberStyles.AllowLeadingWhite) != 0) && (((state & StateSign) == 0) || (((state & StateSign) != 0) && (((state & StateCurrency) != 0) || numfmt.numberNegativePattern == 2)))) {
// Do nothing here. We will increase p at the end of the loop.
}
else if ((signflag = (((options & NumberStyles.AllowLeadingSign) != 0) && ((state & StateSign) == 0))) && ((next = MatchChars(p, numfmt.positiveSign)) != null)) {
state |= StateSign;
p = next - 1;
} else if (signflag && (next = MatchChars(p, numfmt.negativeSign)) != null) {
state |= StateSign;
number.sign = true;
p = next - 1;
}
else if (ch == '(' && ((options & NumberStyles.AllowParentheses) != 0) && ((state & StateSign) == 0)) {
state |= StateSign | StateParens;
number.sign = true;
}
else if ((currSymbol != null && (next = MatchChars(p, currSymbol)) != null) || (ansicurrSymbol != null && (next = MatchChars(p, ansicurrSymbol)) != null)) {
state |= StateCurrency;
currSymbol = null;
ansicurrSymbol = null;
// We already found the currency symbol. There should not be more currency symbols. Set
// currSymbol to NULL so that we won't search it again in the later code path.
p = next - 1;
}
else {
break;
}
if (!IsWhite(ch) || (options & NumberStyles.AllowLeadingWhite) == 0 || ((state & StateSign) != 0 && ((state & StateCurrency) == 0 && numfmt.NumberNegativePattern != 2))){
if ((((options & NumberStyles.AllowLeadingSign) != 0) && (state & StateSign) == 0) && ((next = MatchChars(p, numfmt.PositiveSign)) != null || ((next = MatchChars(p, numfmt.NegativeSign)) != null && (number.sign = true)))){
state |= StateSign;
p = next - 1;
}
else if (ch == '(' && ((options & NumberStyles.AllowParentheses) != 0) && ((state & StateSign) == 0)) {
state |= StateSign | StateParens;
number.sign = true;
}
else if ((currSymbol != null && (next = MatchChars(p, currSymbol)) != null) || (ansicurrSymbol != null && (next = MatchChars(p, ansicurrSymbol)) != null)) {
state |= StateCurrency;
currSymbol = null;
ansicurrSymbol = null;
// We already found the currency symbol. There should not be more currency symbols. Set
// currSymbol to NULL so that we won't search it again in the later code path.
p = next - 1;
}
else {
break;
}
}
ch = *++p;
}
Int32 digCount = 0;
Expand All @@ -818,7 +807,7 @@ internal unsafe struct NumberBuffer {
if ((ch >= '0' && ch <= '9') || (((options & NumberStyles.AllowHexSpecifier) != 0) && ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')))) {
state |= StateDigits;

if (ch != '0' || (state & StateNonZero) != 0 || bigNumberHex) {
if (ch != '0' || (state & StateNonZero) != 0 || (bigNumber && ((options & NumberStyles.AllowHexSpecifier) != 0))) {
if (digCount < maxParseDigits) {
if (bigNumber)
sb.Append(ch);
Expand All @@ -837,11 +826,11 @@ internal unsafe struct NumberBuffer {
number.scale--;
}
}
else if (((options & NumberStyles.AllowDecimalPoint) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, decSep)) != null || ((parsingCurrency) && (state & StateCurrency) == 0) && (next = MatchChars(p, altdecSep)) != null)) {
else if (((options & NumberStyles.AllowDecimalPoint) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, decSep)) != null || ((parsingCurrency) && (state & StateCurrency) == 0) && (next = MatchChars(p, numfmt.NumberDecimalSeparator)) != null)) {
state |= StateDecimal;
p = next - 1;
}
else if (((options & NumberStyles.AllowThousands) != 0) && ((state & StateDigits) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, groupSep)) != null || ((parsingCurrency) && (state & StateCurrency) == 0) && (next = MatchChars(p, altgroupSep)) != null)) {
else if (((options & NumberStyles.AllowThousands) != 0) && ((state & StateDigits) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, groupSep)) != null || ((parsingCurrency) && (state & StateCurrency) == 0) && (next = MatchChars(p, numfmt.NumberGroupSeparator)) != null)) {
p = next - 1;
}
else {
Expand Down Expand Up @@ -890,27 +879,23 @@ internal unsafe struct NumberBuffer {
}
}
while (true) {
if (IsWhite(ch) && ((options & NumberStyles.AllowTrailingWhite) != 0)) {
}
else if ((signflag = (((options & NumberStyles.AllowTrailingSign) != 0) && ((state & StateSign) == 0))) && (next = MatchChars(p, numfmt.positiveSign)) != null) {
state |= StateSign;
p = next - 1;
} else if (signflag && (next = MatchChars(p, numfmt.negativeSign)) != null) {
state |= StateSign;
number.sign = true;
p = next - 1;
}
else if (ch == ')' && ((state & StateParens) != 0)) {
state &= ~StateParens;
}
else if ((currSymbol != null && (next = MatchChars(p, currSymbol)) != null) || (ansicurrSymbol != null && (next = MatchChars(p, ansicurrSymbol)) != null)) {
currSymbol = null;
ansicurrSymbol = null;
p = next - 1;
}
else {
break;
}
if (!IsWhite(ch) || (options & NumberStyles.AllowTrailingWhite) == 0){
if (((options & NumberStyles.AllowTrailingSign) != 0 && ((state & StateSign) == 0)) && ((next = MatchChars(p, numfmt.PositiveSign)) != null || (((next = MatchChars(p, numfmt.NegativeSign)) != null) && (number.sign = true)))) {
state |= StateSign;
p = next - 1;
}
else if (ch == ')' && ((state & StateParens) != 0)) {
state &= ~StateParens;
}
else if ((currSymbol != null && (next = MatchChars(p, currSymbol)) != null) || (ansicurrSymbol != null && (next = MatchChars(p, ansicurrSymbol)) != null)) {
currSymbol = null;
ansicurrSymbol = null;
p = next - 1;
}
else {
break;
}
}
ch = *++p;
}
if ((state & StateParens) == 0) {
Expand Down