Diff
checker
Text
Text
Images
Documents
Excel
Folders
Legal
Enterprise
Desktop
Pricing
Sign in
Download Diffchecker Desktop
Compare text
Find the difference between two text files
Tools
History
Display
Layout
Split
Unified
Real-time editor
Hide whitespace changes
Hide unchanged lines
Disable line wrap
Diff precision
Smart
Syntax
None
Change appearance
Process
Ignore
Transform text
Go to first change
Edit input
Diffchecker Desktop
The most secure way to run Diffchecker. Get the Diffchecker Desktop app: your diffs never leave your computer!
Get Desktop
TryParseNumber_char
Created
3 years ago
Diff never expires
Clear
Export
Share
Explain
7 removals
Lines
Total
Removed
Characters
Total
Removed
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
258 lines
Copy
13 additions
Lines
Total
Added
Characters
Total
Added
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
265 lines
Copy
Copy
Copied
Copy
Copied
private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, NumberStyles styles, ref NumberBuffer number, NumberFormatInfo info)
private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, NumberStyles styles, ref NumberBuffer number, NumberFormatInfo info)
{
{
Debug.Assert(str != null);
Debug.Assert(str != null);
Debug.Assert(strEnd != null);
Debug.Assert(strEnd != null);
Debug.Assert(str <= strEnd);
Debug.Assert(str <= strEnd);
Debug.Assert((styles & (NumberStyles.AllowHexSpecifier | NumberStyles.AllowBinarySpecifier)) == 0);
Debug.Assert((styles & (NumberStyles.AllowHexSpecifier | NumberStyles.AllowBinarySpecifier)) == 0);
const int StateSign = 0x0001;
const int StateSign = 0x0001;
const int StateParens = 0x0002;
const int StateParens = 0x0002;
const int StateDigits = 0x0004;
const int StateDigits = 0x0004;
const int StateNonZero = 0x0008;
const int StateNonZero = 0x0008;
const int StateDecimal = 0x0010;
const int StateDecimal = 0x0010;
const int StateCurrency = 0x0020;
const int StateCurrency = 0x0020;
Debug.Assert(number.DigitsCount == 0);
Debug.Assert(number.DigitsCount == 0);
Debug.Assert(number.Scale == 0);
Debug.Assert(number.Scale == 0);
Debug.Assert(!number.IsNegative);
Debug.Assert(!number.IsNegative);
Debug.Assert(!number.HasNonZeroTail);
Debug.Assert(!number.HasNonZeroTail);
number.CheckConsistency();
number.CheckConsistency();
string decSep; // decimal separator from NumberFormatInfo.
string decSep; // decimal separator from NumberFormatInfo.
string groupSep; // group separator from NumberFormatInfo.
string groupSep; // group separator from NumberFormatInfo.
string? currSymbol = null; // currency symbol from NumberFormatInfo.
string? currSymbol = null; // currency symbol from NumberFormatInfo.
bool parsingCurrency = false;
bool parsingCurrency = false;
if ((styles & NumberStyles.AllowCurrencySymbol) != 0)
if ((styles & NumberStyles.AllowCurrencySymbol) != 0)
{
{
currSymbol = info.CurrencySymbol;
currSymbol = info.CurrencySymbol;
// 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 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).
// The values of decSep are setup to use the correct relevant separator (currency in the if part and decimal in the else part).
decSep = info.CurrencyDecimalSeparator;
decSep = info.CurrencyDecimalSeparator;
groupSep = info.CurrencyGroupSeparator;
groupSep = info.CurrencyGroupSeparator;
parsingCurrency = true;
parsingCurrency = true;
}
}
else
else
{
{
decSep = info.NumberDecimalSeparator;
decSep = info.NumberDecimalSeparator;
groupSep = info.NumberGroupSeparator;
groupSep = info.NumberGroupSeparator;
}
}
int state = 0;
int state = 0;
char* p = str;
char* p = str;
char ch = p < strEnd ? *p : '\0';
char ch = p < strEnd ? *p : '\0';
char* next;
char* next;
while (true)
while (true)
{
{
// Eat whitespace unless we've found a sign which isn't followed by a currency symbol.
// 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.
// "-Kr 1231.47" is legal but "- 1231.47" is not.
if (!IsWhite(ch) || (styles & NumberStyles.AllowLeadingWhite) == 0 || ((state & StateSign) != 0 && ((state & StateCurrency) == 0 && info.NumberNegativePattern != 2)))
if (!IsWhite(ch) || (styles & NumberStyles.AllowLeadingWhite) == 0 || ((state & StateSign) != 0 && ((state & StateCurrency) == 0 && info.NumberNegativePattern != 2)))
{
{
if ((((styles & NumberStyles.AllowLeadingSign) != 0) && (state & StateSign) == 0) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || ((next = MatchNegativeSignChars(p, strEnd, info)) != null && (number.IsNegative = true))))
if ((((styles & NumberStyles.AllowLeadingSign) != 0) && (state & StateSign) == 0) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || ((next = MatchNegativeSignChars(p, strEnd, info)) != null && (number.IsNegative = true))))
{
{
state |= StateSign;
state |= StateSign;
p = next - 1;
p = next - 1;
}
}
else if (ch == '(' && ((styles & NumberStyles.AllowParentheses) != 0) && ((state & StateSign) == 0))
else if (ch == '(' && ((styles & NumberStyles.AllowParentheses) != 0) && ((state & StateSign) == 0))
{
{
state |= StateSign | StateParens;
state |= StateSign | StateParens;
number.IsNegative = true;
number.IsNegative = true;
}
}
else if (currSymbol != null && (next = MatchChars(p, strEnd, currSymbol)) != null)
else if (currSymbol != null && (next = MatchChars(p, strEnd, currSymbol)) != null)
{
{
state |= StateCurrency;
state |= StateCurrency;
currSymbol = null;
currSymbol = null;
// We already found the currency symbol. There should not be more currency symbols. Set
// 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.
// currSymbol to NULL so that we won't search it again in the later code path.
p = next - 1;
p = next - 1;
}
}
else
else
{
{
break;
break;
}
}
}
}
ch = ++p < strEnd ? *p : '\0';
ch = ++p < strEnd ? *p : '\0';
}
}
int digCount = 0;
int digCount = 0;
int digEnd = 0;
int digEnd = 0;
int maxDigCount = number.Digits.Length - 1;
int maxDigCount = number.Digits.Length - 1;
int numberOfTrailingZeros = 0;
int numberOfTrailingZeros = 0;
while (true)
while (true)
{
{
if (IsDigit(ch))
if (IsDigit(ch))
{
{
state |= StateDigits;
state |= StateDigits;
if (ch != '0' || (state & StateNonZero) != 0)
if (ch != '0' || (state & StateNonZero) != 0)
{
{
if (digCount < maxDigCount)
if (digCount < maxDigCount)
{
{
number.Digits[digCount] = (byte)(ch);
number.Digits[digCount] = (byte)(ch);
if ((ch != '0') || (number.Kind != NumberBufferKind.Integer))
if ((ch != '0') || (number.Kind != NumberBufferKind.Integer))
{
{
digEnd = digCount + 1;
digEnd = digCount + 1;
}
}
}
}
Saved diffs
Original text
Open file
private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, NumberStyles styles, ref NumberBuffer number, NumberFormatInfo info) { Debug.Assert(str != null); Debug.Assert(strEnd != null); Debug.Assert(str <= strEnd); Debug.Assert((styles & (NumberStyles.AllowHexSpecifier | NumberStyles.AllowBinarySpecifier)) == 0); const int StateSign = 0x0001; const int StateParens = 0x0002; const int StateDigits = 0x0004; const int StateNonZero = 0x0008; const int StateDecimal = 0x0010; const int StateCurrency = 0x0020; Debug.Assert(number.DigitsCount == 0); Debug.Assert(number.Scale == 0); Debug.Assert(!number.IsNegative); Debug.Assert(!number.HasNonZeroTail); number.CheckConsistency(); string decSep; // decimal separator from NumberFormatInfo. string groupSep; // group separator from NumberFormatInfo. string? currSymbol = null; // currency symbol from NumberFormatInfo. bool parsingCurrency = false; if ((styles & NumberStyles.AllowCurrencySymbol) != 0) { currSymbol = info.CurrencySymbol; // 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). decSep = info.CurrencyDecimalSeparator; groupSep = info.CurrencyGroupSeparator; parsingCurrency = true; } else { decSep = info.NumberDecimalSeparator; groupSep = info.NumberGroupSeparator; } int state = 0; char* p = str; char ch = p < strEnd ? *p : '\0'; char* next; 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) || (styles & NumberStyles.AllowLeadingWhite) == 0 || ((state & StateSign) != 0 && ((state & StateCurrency) == 0 && info.NumberNegativePattern != 2))) { if ((((styles & NumberStyles.AllowLeadingSign) != 0) && (state & StateSign) == 0) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || ((next = MatchNegativeSignChars(p, strEnd, info)) != null && (number.IsNegative = true)))) { state |= StateSign; p = next - 1; } else if (ch == '(' && ((styles & NumberStyles.AllowParentheses) != 0) && ((state & StateSign) == 0)) { state |= StateSign | StateParens; number.IsNegative = true; } else if (currSymbol != null && (next = MatchChars(p, strEnd, currSymbol)) != null) { state |= StateCurrency; currSymbol = 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 < strEnd ? *p : '\0'; } int digCount = 0; int digEnd = 0; int maxDigCount = number.Digits.Length - 1; int numberOfTrailingZeros = 0; while (true) { if (IsDigit(ch)) { state |= StateDigits; if (ch != '0' || (state & StateNonZero) != 0) { if (digCount < maxDigCount) { number.Digits[digCount] = (byte)(ch); if ((ch != '0') || (number.Kind != NumberBufferKind.Integer)) { digEnd = digCount + 1; } } else if (ch != '0') { // For decimal and binary floating-point numbers, we only // need to store digits up to maxDigCount. However, we still // need to keep track of whether any additional digits past // maxDigCount were non-zero, as that can impact rounding // for an input that falls evenly between two representable // results. number.HasNonZeroTail = true; } if ((state & StateDecimal) == 0) { number.Scale++; } if (digCount < maxDigCount) { // Handle a case like "53.0". We need to ignore trailing zeros in the fractional part for floating point numbers, so we keep a count of the number of trailing zeros and update digCount later if (ch == '0') { numberOfTrailingZeros++; } else { numberOfTrailingZeros = 0; } } digCount++; state |= StateNonZero; } else if ((state & StateDecimal) != 0) { number.Scale--; } } else if (((styles & NumberStyles.AllowDecimalPoint) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, strEnd, decSep)) != null || (parsingCurrency && (state & StateCurrency) == 0) && (next = MatchChars(p, strEnd, info.NumberDecimalSeparator)) != null)) { state |= StateDecimal; p = next - 1; } else if (((styles & NumberStyles.AllowThousands) != 0) && ((state & StateDigits) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, strEnd, groupSep)) != null || (parsingCurrency && (state & StateCurrency) == 0) && (next = MatchChars(p, strEnd, info.NumberGroupSeparator)) != null)) { p = next - 1; } else { break; } ch = ++p < strEnd ? *p : '\0'; } bool negExp = false; number.DigitsCount = digEnd; number.Digits[digEnd] = (byte)('\0'); if ((state & StateDigits) != 0) { if ((ch == 'E' || ch == 'e') && ((styles & NumberStyles.AllowExponent) != 0)) { char* temp = p; ch = ++p < strEnd ? *p : '\0'; if ((next = MatchChars(p, strEnd, info._positiveSign)) != null) { ch = (p = next) < strEnd ? *p : '\0'; } else if ((next = MatchNegativeSignChars(p, strEnd, info)) != null) { ch = (p = next) < strEnd ? *p : '\0'; negExp = true; } if (IsDigit(ch)) { int exp = 0; do { exp = exp * 10 + (ch - '0'); ch = ++p < strEnd ? *p : '\0'; if (exp > 1000) { exp = 9999; while (IsDigit(ch)) { ch = ++p < strEnd ? *p : '\0'; } } } while (IsDigit(ch)); if (negExp) { exp = -exp; } number.Scale += exp; } else { p = temp; ch = p < strEnd ? *p : '\0'; } } if (number.Kind == NumberBufferKind.FloatingPoint && !number.HasNonZeroTail) { // Adjust the number buffer for trailing zeros int numberOfFractionalDigits = digEnd - number.Scale; if (numberOfFractionalDigits > 0) { numberOfTrailingZeros = Math.Min(numberOfTrailingZeros, numberOfFractionalDigits); Debug.Assert(numberOfTrailingZeros >= 0); number.DigitsCount = digEnd - numberOfTrailingZeros; number.Digits[number.DigitsCount] = (byte)('\0'); } } while (true) { if (!IsWhite(ch) || (styles & NumberStyles.AllowTrailingWhite) == 0) { if ((styles & NumberStyles.AllowTrailingSign) != 0 && ((state & StateSign) == 0) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || (((next = MatchNegativeSignChars(p, strEnd, info)) != null) && (number.IsNegative = true)))) { state |= StateSign; p = next - 1; } else if (ch == ')' && ((state & StateParens) != 0)) { state &= ~StateParens; } else if (currSymbol != null && (next = MatchChars(p, strEnd, currSymbol)) != null) { currSymbol = null; p = next - 1; } else { break; } } ch = ++p < strEnd ? *p : '\0'; } if ((state & StateParens) == 0) { if ((state & StateNonZero) == 0) { if (number.Kind != NumberBufferKind.Decimal) { number.Scale = 0; } if ((number.Kind == NumberBufferKind.Integer) && (state & StateDecimal) == 0) { number.IsNegative = false; } } str = p; return true; } } str = p; return false; }
Changed text
Open file
private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, NumberStyles styles, ref NumberBuffer number, NumberFormatInfo info) { Debug.Assert(str != null); Debug.Assert(strEnd != null); Debug.Assert(str <= strEnd); Debug.Assert((styles & (NumberStyles.AllowHexSpecifier | NumberStyles.AllowBinarySpecifier)) == 0); const int StateSign = 0x0001; const int StateParens = 0x0002; const int StateDigits = 0x0004; const int StateNonZero = 0x0008; const int StateDecimal = 0x0010; const int StateCurrency = 0x0020; Debug.Assert(number.DigitsCount == 0); Debug.Assert(number.Scale == 0); Debug.Assert(!number.IsNegative); Debug.Assert(!number.HasNonZeroTail); number.CheckConsistency(); string decSep; // decimal separator from NumberFormatInfo. string groupSep; // group separator from NumberFormatInfo. string? currSymbol = null; // currency symbol from NumberFormatInfo. bool parsingCurrency = false; if ((styles & NumberStyles.AllowCurrencySymbol) != 0) { currSymbol = info.CurrencySymbol; // 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). decSep = info.CurrencyDecimalSeparator; groupSep = info.CurrencyGroupSeparator; parsingCurrency = true; } else { decSep = info.NumberDecimalSeparator; groupSep = info.NumberGroupSeparator; } int state = 0; char* p = str; char ch = p < strEnd ? *p : '\0'; char* next; 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) || (styles & NumberStyles.AllowLeadingWhite) == 0 || ((state & StateSign) != 0 && ((state & StateCurrency) == 0 && info.NumberNegativePattern != 2))) { if ((((styles & NumberStyles.AllowLeadingSign) != 0) && (state & StateSign) == 0) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || ((next = MatchNegativeSignChars(p, strEnd, info)) != null && (number.IsNegative = true)))) { state |= StateSign; p = next - 1; } else if (ch == '(' && ((styles & NumberStyles.AllowParentheses) != 0) && ((state & StateSign) == 0)) { state |= StateSign | StateParens; number.IsNegative = true; } else if (currSymbol != null && (next = MatchChars(p, strEnd, currSymbol)) != null) { state |= StateCurrency; currSymbol = 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 < strEnd ? *p : '\0'; } int digCount = 0; int digEnd = 0; int maxDigCount = number.Digits.Length - 1; int numberOfTrailingZeros = 0; while (true) { if (IsDigit(ch)) { state |= StateDigits; if (ch != '0' || (state & StateNonZero) != 0) { if (digCount < maxDigCount) { number.Digits[digCount] = (byte)(ch); if ((ch != '0') || (number.Kind != NumberBufferKind.Integer)) { digEnd = digCount + 1; } } else if (ch != '0') { // For decimal and binary floating-point numbers, we only // need to store digits up to maxDigCount. However, we still // need to keep track of whether any additional digits past // maxDigCount were non-zero, as that can impact rounding // for an input that falls evenly between two representable // results. number.HasNonZeroTail = true; } if ((state & StateDecimal) == 0) { number.Scale++; } if (digCount < maxDigCount) { // Handle a case like "53.0". We need to ignore trailing zeros in the fractional part for floating point numbers, so we keep a count of the number of trailing zeros and update digCount later if (ch == '0') { numberOfTrailingZeros++; } else { numberOfTrailingZeros = 0; } } digCount++; state |= StateNonZero; } else if ((state & StateDecimal) != 0) { number.Scale--; } } else if (((styles & NumberStyles.AllowDecimalPoint) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, strEnd, decSep)) != null || (parsingCurrency && (state & StateCurrency) == 0) && (next = MatchChars(p, strEnd, info.NumberDecimalSeparator)) != null)) { state |= StateDecimal; p = next - 1; } else if (((styles & NumberStyles.AllowThousands) != 0) && ((state & StateDigits) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, strEnd, groupSep)) != null || (parsingCurrency && (state & StateCurrency) == 0) && (next = MatchChars(p, strEnd, info.NumberGroupSeparator)) != null)) { p = next - 1; } else { break; } ch = ++p < strEnd ? *p : '\0'; } bool negExp = false; number.DigitsCount = digEnd; number.Digits[digEnd] = (byte)('\0'); if ((state & StateDigits) != 0) { if ((ch == 'E' || ch == 'e') && ((styles & NumberStyles.AllowExponent) != 0)) { char* temp = p; ch = ++p < strEnd ? *p : '\0'; if ((next = MatchChars(p, strEnd, info.PositiveSign)) != null) { ch = (p = next) < strEnd ? *p : '\0'; } else if ((next = MatchNegativeSignChars(p, strEnd, info)) != null) { ch = (p = next) < strEnd ? *p : '\0'; negExp = true; } if (IsDigit(ch)) { int exp = 0; do { // Check if we are about to overflow past our limit of 9 digits if (exp >= 100_000_000) { // Set exp to Int.MaxValue to signify the requested exponent is too large. This will lead to an OverflowException later. exp = int.MaxValue; number.Scale = 0; // Finish parsing the number, a FormatException could still occur later on. while (char.IsAsciiDigit(ch)) { ch = ++p < strEnd ? *p : '\0'; } break; } exp = exp * 10 + (ch - '0'); ch = ++p < strEnd ? *p : '\0'; } while (IsDigit(ch)); if (negExp) { exp = -exp; } number.Scale += exp; } else { p = temp; ch = p < strEnd ? *p : '\0'; } } if (number.Kind == NumberBufferKind.FloatingPoint && !number.HasNonZeroTail) { // Adjust the number buffer for trailing zeros int numberOfFractionalDigits = digEnd - number.Scale; if (numberOfFractionalDigits > 0) { numberOfTrailingZeros = Math.Min(numberOfTrailingZeros, numberOfFractionalDigits); Debug.Assert(numberOfTrailingZeros >= 0); number.DigitsCount = digEnd - numberOfTrailingZeros; number.Digits[number.DigitsCount] = (byte)('\0'); } } while (true) { if (!IsWhite(ch) || (styles & NumberStyles.AllowTrailingWhite) == 0) { if ((styles & NumberStyles.AllowTrailingSign) != 0 && ((state & StateSign) == 0) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || (((next = MatchNegativeSignChars(p, strEnd, info)) != null) && (number.IsNegative = true)))) { state |= StateSign; p = next - 1; } else if (ch == ')' && ((state & StateParens) != 0)) { state &= ~StateParens; } else if (currSymbol != null && (next = MatchChars(p, strEnd, currSymbol)) != null) { currSymbol = null; p = next - 1; } else { break; } } ch = ++p < strEnd ? *p : '\0'; } if ((state & StateParens) == 0) { if ((state & StateNonZero) == 0) { if (number.Kind != NumberBufferKind.Decimal) { number.Scale = 0; } if ((number.Kind == NumberBufferKind.Integer) && (state & StateDecimal) == 0) { number.IsNegative = false; } } str = p; return true; } } str = p; return false; }
Find difference