Changing Number.NumberBuffer to carry a `Span<byte>` rather than a `Span<char>` ...
authorTanner Gooding <tagoo@outlook.com>
Fri, 9 Nov 2018 03:47:35 +0000 (19:47 -0800)
committerGitHub <noreply@github.com>
Fri, 9 Nov 2018 03:47:35 +0000 (19:47 -0800)
* Changing Number.NumberBuffer to carry a `Span<byte>` rather than a `Span<char>`

* Renaming NumberBuffer.Sign to NumberBuffer.IsNegative

* Renaming NumberBuffer.Precision to NumberBuffer.DigitsCount

* Adding a ToString and CheckConsistency method to NumberBuffer

* Adding some number.CheckConsistency() calls for debug validation

* Fixing the UTF16Formatter to meet the consistency checks

Commit migrated from https://github.com/dotnet/coreclr/commit/3e6f7cb772febd83eaf3fecc3baf169ddd6a920f

src/libraries/System.Private.CoreLib/src/System/Number.Dragon4.cs
src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs
src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs
src/libraries/System.Private.CoreLib/src/System/Number.NumberBuffer.cs
src/libraries/System.Private.CoreLib/src/System/Number.NumberToFloatingPointBits.cs
src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs

index ec51104..67c9082 100644 (file)
@@ -168,7 +168,7 @@ namespace System
                     break;
                 }
 
-                number.Digits[digitsNum] = (char)('0' + currentDigit);
+                number.Digits[digitsNum] = (byte)('0' + currentDigit);
                 digitsNum++;
 
                 r.Multiply10();
@@ -196,12 +196,12 @@ namespace System
 
             if (isRoundDown)
             {
-                number.Digits[digitsNum] = (char)('0' + currentDigit);
+                number.Digits[digitsNum] = (byte)('0' + currentDigit);
                 digitsNum++;
             }
             else
             {
-                char* pCurrentDigit = (number.GetDigitsPointer() + digitsNum);
+                byte* pCurrentDigit = (number.GetDigitsPointer() + digitsNum);
 
                 // Rounding up for 9 is special.
                 if (currentDigit == 9)
@@ -213,7 +213,7 @@ namespace System
                         if (pCurrentDigit == number.GetDigitsPointer())
                         {
                             // Output 1 at the next highest exponent
-                            *pCurrentDigit = '1';
+                            *pCurrentDigit = (byte)('1');
                             digitsNum++;
                             number.Scale += 1;
                             break;
@@ -225,7 +225,7 @@ namespace System
                         if (*pCurrentDigit != '9')
                         {
                             // increment the digit
-                            *pCurrentDigit += (char)(1);
+                            *pCurrentDigit += 1;
                             digitsNum++;
                             break;
                         }
@@ -234,21 +234,21 @@ namespace System
                 else
                 {
                     // It's simple if the digit is not 9.
-                    *pCurrentDigit = (char)('0' + currentDigit + 1);
+                    *pCurrentDigit = (byte)('0' + currentDigit + 1);
                     digitsNum++;
                 }
             }
 
             while (digitsNum < precision)
             {
-                number.Digits[digitsNum] = '0';
+                number.Digits[digitsNum] = (byte)('0');
                 digitsNum++;
             }
 
-            number.Digits[precision] = '\0';
+            number.Digits[precision] = (byte)('\0');
 
             number.Scale++;
-            number.Sign = double.IsNegative(value);
+            number.IsNegative = double.IsNegative(value);
         }
     }
 }
index 1c56546..a8c2df9 100644 (file)
@@ -289,17 +289,13 @@ namespace System
         {
             char fmt = ParseFormatSpecifier(format, out int digits);
 
-            char* pDigits = stackalloc char[DecimalNumberBufferLength];
+            byte* pDigits = stackalloc byte[DecimalNumberBufferLength];
             NumberBuffer number = new NumberBuffer(NumberBufferKind.Decimal, pDigits, DecimalNumberBufferLength);
 
             DecimalToNumber(ref value, ref number);
 
-            ValueStringBuilder sb;
-            unsafe
-            {
-                char* stackPtr = stackalloc char[CharStackBufferSize];
-                sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
-            }
+            char* stackPtr = stackalloc char[CharStackBufferSize];
+            ValueStringBuilder sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
 
             if (fmt != 0)
             {
@@ -317,17 +313,13 @@ namespace System
         {
             char fmt = ParseFormatSpecifier(format, out int digits);
 
-            char* pDigits = stackalloc char[DecimalNumberBufferLength];
+            byte* pDigits = stackalloc byte[DecimalNumberBufferLength];
             NumberBuffer number = new NumberBuffer(NumberBufferKind.Decimal, pDigits, DecimalNumberBufferLength);
 
             DecimalToNumber(ref value, ref number);
 
-            ValueStringBuilder sb;
-            unsafe
-            {
-                char* stackPtr = stackalloc char[CharStackBufferSize];
-                sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
-            }
+            char* stackPtr = stackalloc char[CharStackBufferSize];
+            ValueStringBuilder sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
 
             if (fmt != 0)
             {
@@ -343,26 +335,30 @@ namespace System
 
         private static unsafe void DecimalToNumber(ref decimal d, ref NumberBuffer number)
         {
-            char* buffer = number.GetDigitsPointer();
-            number.Precision = DecimalPrecision;
-            number.Sign = d.IsNegative;
+            byte* buffer = number.GetDigitsPointer();
+            number.DigitsCount = DecimalPrecision;
+            number.IsNegative = d.IsNegative;
 
-            char* p = buffer + DecimalPrecision;
+            byte* p = buffer + DecimalPrecision;
             while ((d.Mid | d.High) != 0)
             {
                 p = UInt32ToDecChars(p, decimal.DecDivMod1E9(ref d), 9);
             }
             p = UInt32ToDecChars(p, d.Low, 0);
 
-            int i = (int)((byte*)(buffer + DecimalPrecision) - (byte*)p) >> 1;
+            int i = (int)((buffer + DecimalPrecision) - p);
+
+            number.DigitsCount = i;
             number.Scale = i - d.Scale;
 
-            char* dst = number.GetDigitsPointer();
+            byte* dst = number.GetDigitsPointer();
             while (--i >= 0)
             {
                 *dst++ = *p++;
             }
-            *dst = '\0';
+            *dst = (byte)('\0');
+
+            number.CheckConsistency();
         }
 
         public static string FormatDouble(double value, string format, NumberFormatInfo info)
@@ -392,7 +388,7 @@ namespace System
             char fmt = ParseFormatSpecifier(format, out int digits);
             int precision = DoublePrecision;
 
-            char* pDigits = stackalloc char[DoubleNumberBufferLength];
+            byte* pDigits = stackalloc byte[DoubleNumberBufferLength];
             NumberBuffer number = new NumberBuffer(NumberBufferKind.FloatingPoint, pDigits, DoubleNumberBufferLength);
 
             switch (fmt)
@@ -404,13 +400,14 @@ namespace System
                     // number using 15 digits and then determine if it round trips to the same value. If it does, we
                     // convert that NUMBER to a string, otherwise we reparse using 17 digits and display that.
                     DoubleToNumber(value, DoublePrecision, ref number);
+
                     if (number.Scale == ScaleNAN)
                     {
                         return info.NaNSymbol;
                     }
                     else if (number.Scale == ScaleINF)
                     {
-                        return number.Sign ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol;
+                        return number.IsNegative ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol;
                     }
 
                     double roundTrip = NumberToDouble(ref number);
@@ -448,13 +445,14 @@ namespace System
             }
 
             DoubleToNumber(value, precision, ref number);
+
             if (number.Scale == ScaleNAN)
             {
                 return info.NaNSymbol;
             }
             else if (number.Scale == ScaleINF)
             {
-                return number.Sign ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol;
+                return number.IsNegative ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol;
             }
 
             if (fmt != 0)
@@ -496,7 +494,7 @@ namespace System
             char fmt = ParseFormatSpecifier(format, out int digits);
             int precision = SinglePrecision;
 
-            char* pDigits = stackalloc char[SingleNumberBufferLength];
+            byte* pDigits = stackalloc byte[SingleNumberBufferLength];
             NumberBuffer number = new NumberBuffer(NumberBufferKind.FloatingPoint, pDigits, SingleNumberBufferLength);
 
             switch (fmt)
@@ -508,13 +506,14 @@ namespace System
                     // number using 7 digits and then determine if it round trips to the same value. If it does, we
                     // convert that NUMBER to a string, otherwise we reparse using 9 digits and display that.
                     DoubleToNumber(value, SinglePrecision, ref number);
+
                     if (number.Scale == ScaleNAN)
                     {
                         return info.NaNSymbol;
                     }
                     else if (number.Scale == ScaleINF)
                     {
-                        return number.Sign ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol;
+                        return number.IsNegative ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol;
                     }
 
                     float roundTrip = NumberToSingle(ref number);
@@ -551,13 +550,14 @@ namespace System
             }
 
             DoubleToNumber(value, precision, ref number);
+
             if (number.Scale == ScaleNAN)
             {
                 return info.NaNSymbol;
             }
             else if (number.Scale == ScaleINF)
             {
-                return number.Sign ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol;
+                return number.IsNegative ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol;
             }
 
             if (fmt != 0)
@@ -611,16 +611,14 @@ namespace System
             {
                 NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
 
-                char* pDigits = stackalloc char[Int32NumberBufferLength];
+                byte* pDigits = stackalloc byte[Int32NumberBufferLength];
                 NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, Int32NumberBufferLength);
 
                 Int32ToNumber(value, ref number);
-                ValueStringBuilder sb;
-                unsafe
-                {
-                    char* stackPtr = stackalloc char[CharStackBufferSize];
-                    sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
-                }
+
+                char* stackPtr = stackalloc char[CharStackBufferSize];
+                ValueStringBuilder sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
+
                 if (fmt != 0)
                 {
                     NumberToString(ref sb, ref number, fmt, digits, info);
@@ -659,16 +657,14 @@ namespace System
             {
                 NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
 
-                char* pDigits = stackalloc char[Int32NumberBufferLength];
+                byte* pDigits = stackalloc byte[Int32NumberBufferLength];
                 NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, Int32NumberBufferLength);
 
                 Int32ToNumber(value, ref number);
-                ValueStringBuilder sb;
-                unsafe
-                {
-                    char* stackPtr = stackalloc char[CharStackBufferSize];
-                    sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
-                }
+
+                char* stackPtr = stackalloc char[CharStackBufferSize];
+                ValueStringBuilder sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
+
                 if (fmt != 0)
                 {
                     NumberToString(ref sb, ref number, fmt, digits, info);
@@ -705,16 +701,14 @@ namespace System
             {
                 NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
 
-                char* pDigits = stackalloc char[UInt32NumberBufferLength];
+                byte* pDigits = stackalloc byte[UInt32NumberBufferLength];
                 NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, UInt32NumberBufferLength);
 
                 UInt32ToNumber(value, ref number);
-                ValueStringBuilder sb;
-                unsafe
-                {
-                    char* stackPtr = stackalloc char[CharStackBufferSize];
-                    sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
-                }
+
+                char* stackPtr = stackalloc char[CharStackBufferSize];
+                ValueStringBuilder sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
+
                 if (fmt != 0)
                 {
                     NumberToString(ref sb, ref number, fmt, digits, info);
@@ -751,16 +745,14 @@ namespace System
             {
                 NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
 
-                char* pDigits = stackalloc char[UInt32NumberBufferLength];
+                byte* pDigits = stackalloc byte[UInt32NumberBufferLength];
                 NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, UInt32NumberBufferLength);
 
                 UInt32ToNumber(value, ref number);
-                ValueStringBuilder sb;
-                unsafe
-                {
-                    char* stackPtr = stackalloc char[CharStackBufferSize];
-                    sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
-                }
+
+                char* stackPtr = stackalloc char[CharStackBufferSize];
+                ValueStringBuilder sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
+
                 if (fmt != 0)
                 {
                     NumberToString(ref sb, ref number, fmt, digits, info);
@@ -800,16 +792,14 @@ namespace System
             {
                 NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
 
-                char* pDigits = stackalloc char[Int64NumberBufferLength];
+                byte* pDigits = stackalloc byte[Int64NumberBufferLength];
                 NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, Int64NumberBufferLength);
 
                 Int64ToNumber(value, ref number);
-                ValueStringBuilder sb;
-                unsafe
-                {
-                    char* stackPtr = stackalloc char[CharStackBufferSize];
-                    sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
-                }
+
+                char* stackPtr = stackalloc char[CharStackBufferSize];
+                ValueStringBuilder sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
+
                 if (fmt != 0)
                 {
                     NumberToString(ref sb, ref number, fmt, digits, info);
@@ -849,16 +839,14 @@ namespace System
             {
                 NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
 
-                char* pDigits = stackalloc char[Int64NumberBufferLength];
+                byte* pDigits = stackalloc byte[Int64NumberBufferLength];
                 NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, Int64NumberBufferLength);
 
                 Int64ToNumber(value, ref number);
-                ValueStringBuilder sb;
-                unsafe
-                {
-                    char* stackPtr = stackalloc char[CharStackBufferSize];
-                    sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
-                }
+
+                char* stackPtr = stackalloc char[CharStackBufferSize];
+                ValueStringBuilder sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
+
                 if (fmt != 0)
                 {
                     NumberToString(ref sb, ref number, fmt, digits, info);
@@ -896,16 +884,14 @@ namespace System
             {
                 NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
 
-                char* pDigits = stackalloc char[UInt64NumberBufferLength];
+                byte* pDigits = stackalloc byte[UInt64NumberBufferLength];
                 NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, UInt64NumberBufferLength);
 
                 UInt64ToNumber(value, ref number);
-                ValueStringBuilder sb;
-                unsafe
-                {
-                    char* stackPtr = stackalloc char[CharStackBufferSize];
-                    sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
-                }
+
+                char* stackPtr = stackalloc char[CharStackBufferSize];
+                ValueStringBuilder sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
+
                 if (fmt != 0)
                 {
                     NumberToString(ref sb, ref number, fmt, digits, info);
@@ -943,16 +929,14 @@ namespace System
             {
                 NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
 
-                char* pDigits = stackalloc char[UInt64NumberBufferLength];
+                byte* pDigits = stackalloc byte[UInt64NumberBufferLength];
                 NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, UInt64NumberBufferLength);
 
                 UInt64ToNumber(value, ref number);
-                ValueStringBuilder sb;
-                unsafe
-                {
-                    char* stackPtr = stackalloc char[CharStackBufferSize];
-                    sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
-                }
+
+                char* stackPtr = stackalloc char[CharStackBufferSize];
+                ValueStringBuilder sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
+
                 if (fmt != 0)
                 {
                     NumberToString(ref sb, ref number, fmt, digits, info);
@@ -968,28 +952,32 @@ namespace System
         [MethodImpl(MethodImplOptions.AggressiveInlining)] // called from only one location
         private static unsafe void Int32ToNumber(int value, ref NumberBuffer number)
         {
-            number.Precision = Int32Precision;
+            number.DigitsCount = Int32Precision;
 
             if (value >= 0)
             {
-                number.Sign = false;
+                number.IsNegative = false;
             }
             else
             {
-                number.Sign = true;
+                number.IsNegative = true;
                 value = -value;
             }
 
-            char* buffer = number.GetDigitsPointer();
-            char* p = UInt32ToDecChars(buffer + Int32Precision, (uint)value, 0);
+            byte* buffer = number.GetDigitsPointer();
+            byte* p = UInt32ToDecChars(buffer + Int32Precision, (uint)value, 0);
+
             int i = (int)(buffer + Int32Precision - p);
 
+            number.DigitsCount = i;
             number.Scale = i;
 
-            char* dst = number.GetDigitsPointer();
+            byte* dst = number.GetDigitsPointer();
             while (--i >= 0)
                 *dst++ = *p++;
-            *dst = '\0';
+            *dst = (byte)('\0');
+
+            number.CheckConsistency();
         }
 
         private static unsafe string NegativeInt32ToDecStr(int value, int digits, string sNegative)
@@ -1094,18 +1082,35 @@ namespace System
         [MethodImpl(MethodImplOptions.AggressiveInlining)] // called from only one location
         private static unsafe void UInt32ToNumber(uint value, ref NumberBuffer number)
         {
-            number.Precision = UInt32Precision;
-            number.Sign = false;
+            number.DigitsCount = UInt32Precision;
+            number.IsNegative = false;
+
+            byte* buffer = number.GetDigitsPointer();
+            byte* p = UInt32ToDecChars(buffer + UInt32Precision, value, 0);
 
-            char* buffer = number.GetDigitsPointer();
-            char* p = UInt32ToDecChars(buffer + UInt32Precision, value, 0);
             int i = (int)(buffer + UInt32Precision - p);
+
+            number.DigitsCount = i;
             number.Scale = i;
 
-            char* dst = number.GetDigitsPointer();
+            byte* dst = number.GetDigitsPointer();
             while (--i >= 0)
                 *dst++ = *p++;
-            *dst = '\0';
+            *dst = (byte)('\0');
+
+            number.CheckConsistency();
+        }
+
+        internal static unsafe byte* UInt32ToDecChars(byte* bufferEnd, uint value, int digits)
+        {
+            while (--digits >= 0 || value != 0)
+            {
+                // TODO https://github.com/dotnet/coreclr/issues/3439
+                uint newValue = value / 10;
+                *(--bufferEnd) = (byte)(value - (newValue * 10) + '0');
+                value = newValue;
+            }
+            return bufferEnd;
         }
 
         internal static unsafe char* UInt32ToDecChars(char* bufferEnd, uint value, int digits)
@@ -1205,26 +1210,30 @@ namespace System
         private static unsafe void Int64ToNumber(long input, ref NumberBuffer number)
         {
             ulong value = (ulong)input;
-            number.Sign = input < 0;
-            number.Precision = Int64Precision;
-            if (number.Sign)
+            number.IsNegative = input < 0;
+            number.DigitsCount = Int64Precision;
+            if (number.IsNegative)
             {
                 value = (ulong)(-input);
             }
 
-            char* buffer = number.GetDigitsPointer();
-            char* p = buffer + Int64Precision;
+            byte* buffer = number.GetDigitsPointer();
+            byte* p = buffer + Int64Precision;
             while (High32(value) != 0)
                 p = UInt32ToDecChars(p, Int64DivMod1E9(ref value), 9);
             p = UInt32ToDecChars(p, Low32(value), 0);
+
             int i = (int)(buffer + Int64Precision - p);
 
+            number.DigitsCount = i;
             number.Scale = i;
 
-            char* dst = number.GetDigitsPointer();
+            byte* dst = number.GetDigitsPointer();
             while (--i >= 0)
                 *dst++ = *p++;
-            *dst = '\0';
+            *dst = (byte)('\0');
+
+            number.CheckConsistency();
         }
 
         private static unsafe string NegativeInt64ToDecStr(long input, int digits, string sNegative)
@@ -1349,23 +1358,27 @@ namespace System
 
         private static unsafe void UInt64ToNumber(ulong value, ref NumberBuffer number)
         {
-            number.Precision = UInt64Precision;
-            number.Sign = false;
+            number.DigitsCount = UInt64Precision;
+            number.IsNegative = false;
 
-            char* buffer = number.GetDigitsPointer();
-            char* p = buffer + UInt64Precision;
+            byte* buffer = number.GetDigitsPointer();
+            byte* p = buffer + UInt64Precision;
 
             while (High32(value) != 0)
                 p = UInt32ToDecChars(p, Int64DivMod1E9(ref value), 9);
             p = UInt32ToDecChars(p, Low32(value), 0);
+
             int i = (int)(buffer + UInt64Precision - p);
 
+            number.DigitsCount = i;
             number.Scale = i;
 
-            char* dst = number.GetDigitsPointer();
+            byte* dst = number.GetDigitsPointer();
             while (--i >= 0)
                 *dst++ = *p++;
-            *dst = '\0';
+            *dst = (byte)('\0');
+
+            number.CheckConsistency();
         }
 
         private static unsafe string UInt64ToDecStr(ulong value, int digits)
@@ -1491,7 +1504,7 @@ namespace System
 
         internal static unsafe void NumberToString(ref ValueStringBuilder sb, ref NumberBuffer number, char format, int nMaxDigits, NumberFormatInfo info)
         {
-            Debug.Assert(number.Kind != NumberBufferKind.Unknown);
+            number.CheckConsistency();
 
             switch (format)
             {
@@ -1516,7 +1529,7 @@ namespace System
 
                     RoundNumber(ref number, number.Scale + nMaxDigits);
 
-                    if (number.Sign)
+                    if (number.IsNegative)
                         sb.Append(info.NegativeSign);
 
                     FormatFixed(ref sb, ref number, nMaxDigits, info, null, info.NumberDecimalSeparator, null);
@@ -1546,7 +1559,7 @@ namespace System
 
                     RoundNumber(ref number, nMaxDigits);
 
-                    if (number.Sign)
+                    if (number.IsNegative)
                         sb.Append(info.NegativeSign);
 
                     FormatScientific(ref sb, ref number, nMaxDigits, info, format);
@@ -1568,14 +1581,14 @@ namespace System
                         else
                         {
                             // This ensures that the PAL code pads out to the correct place even when we use the default precision
-                            nMaxDigits = number.Precision;
+                            nMaxDigits = number.DigitsCount;
                         }
                     }
 
                     RoundNumber(ref number, nMaxDigits);
 
                 SkipRounding:
-                    if (number.Sign)
+                    if (number.IsNegative)
                         sb.Append(info.NegativeSign);
 
                     FormatGeneral(ref sb, ref number, nMaxDigits, info, (char)(format - ('G' - 'E')), noRounding);
@@ -1604,7 +1617,7 @@ namespace System
 
         internal static unsafe void NumberToStringFormat(ref ValueStringBuilder sb, ref NumberBuffer number, ReadOnlySpan<char> format, NumberFormatInfo info)
         {
-            Debug.Assert(number.Kind != NumberBufferKind.Unknown);
+            number.CheckConsistency();
 
             int digitCount;
             int decimalPos;
@@ -1620,10 +1633,10 @@ namespace System
 
             int section;
             int src;
-            char* dig = number.GetDigitsPointer();
+            byte* dig = number.GetDigitsPointer();
             char ch;
 
-            section = FindSection(format, dig[0] == 0 ? 2 : number.Sign ? 1 : 0);
+            section = FindSection(format, dig[0] == 0 ? 2 : number.IsNegative ? 1 : 0);
 
             while (true)
             {
@@ -1801,14 +1814,14 @@ namespace System
                 }
             }
 
-            if (number.Sign && (section == 0) && (number.Scale != 0))
+            if (number.IsNegative && (section == 0) && (number.Scale != 0))
                 sb.Append(info.NegativeSign);
 
             bool decimalWritten = false;
 
             fixed (char* pFormat = &MemoryMarshal.GetReference(format))
             {
-                char* cur = dig;
+                byte* cur = dig;
 
                 while (src < format.Length && (ch = pFormat[src++]) != 0 && ch != ';')
                 {
@@ -1823,7 +1836,7 @@ namespace System
                                 {
                                     // digPos will be one greater than thousandsSepPos[thousandsSepCtr] since we are at
                                     // the character after which the groupSeparator needs to be appended.
-                                    sb.Append(*cur != 0 ? *cur++ : '0');
+                                    sb.Append(*cur != 0 ? (char)(*cur++) : '0');
                                     if (thousandSeps && digPos > 1 && thousandsSepCtr >= 0)
                                     {
                                         if (digPos == thousandsSepPos[thousandsSepCtr] + 1)
@@ -1851,7 +1864,7 @@ namespace System
                             }
                             else
                             {
-                                ch = *cur != 0 ? *cur++ : digPos > lastDigit ? '0' : '\0';
+                                ch = *cur != 0 ? (char)(*cur++) : digPos > lastDigit ? '0' : '\0';
                             }
                             if (ch != 0)
                             {
@@ -1960,13 +1973,13 @@ namespace System
                 }
             }
 
-            if (number.Sign && (section == 0) && (number.Scale == 0) && (sb.Length > 0))
+            if (number.IsNegative && (section == 0) && (number.Scale == 0) && (sb.Length > 0))
                 sb.Insert(0, info.NegativeSign);
         }
 
         private static void FormatCurrency(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info)
         {
-            string fmt = number.Sign ?
+            string fmt = number.IsNegative ?
                 s_negCurrencyFormats[info.CurrencyNegativePattern] :
                 s_posCurrencyFormats[info.CurrencyPositivePattern];
 
@@ -1993,7 +2006,7 @@ namespace System
         private static unsafe void FormatFixed(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info, int[] groupDigits, string sDecimal, string sGroup)
         {
             int digPos = number.Scale;
-            char* dig = number.GetDigitsPointer();
+            byte* dig = number.GetDigitsPointer();
 
             if (digPos > 0)
             {
@@ -2028,14 +2041,14 @@ namespace System
 
                     groupSizeIndex = 0;
                     int digitCount = 0;
-                    int digLength = string.wcslen(dig);
+                    int digLength = number.DigitsCount;
                     int digStart = (digPos < digLength) ? digPos : digLength;
                     fixed (char* spanPtr = &MemoryMarshal.GetReference(sb.AppendSpan(bufferSize)))
                     {
                         char* p = spanPtr + bufferSize - 1;
                         for (int i = digPos - 1; i >= 0; i--)
                         {
-                            *(p--) = (i < digStart) ? dig[i] : '0';
+                            *(p--) = (i < digStart) ? (char)(dig[i]) : '0';
 
                             if (groupSize > 0)
                             {
@@ -2063,7 +2076,7 @@ namespace System
                 {
                     do
                     {
-                        sb.Append(*dig != 0 ? *dig++ : '0');
+                        sb.Append(*dig != 0 ? (char)(*dig++) : '0');
                     }
                     while (--digPos > 0);
                 }
@@ -2086,7 +2099,7 @@ namespace System
 
                 while (nMaxDigits > 0)
                 {
-                    sb.Append((*dig != 0) ? *dig++ : '0');
+                    sb.Append((*dig != 0) ? (char)(*dig++) : '0');
                     nMaxDigits--;
                 }
             }
@@ -2094,7 +2107,7 @@ namespace System
 
         private static void FormatNumber(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info)
         {
-            string fmt = number.Sign ?
+            string fmt = number.IsNegative ?
                 s_negNumberFormats[info.NumberNegativePattern] :
                 PosNumberFormat;
 
@@ -2117,15 +2130,15 @@ namespace System
 
         private static unsafe void FormatScientific(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info, char expChar)
         {
-            char* dig = number.GetDigitsPointer();
+            byte* dig = number.GetDigitsPointer();
 
-            sb.Append((*dig != 0) ? *dig++ : '0');
+            sb.Append((*dig != 0) ? (char)(*dig++) : '0');
 
             if (nMaxDigits != 1) // For E0 we would like to suppress the decimal point
                 sb.Append(info.NumberDecimalSeparator);
 
             while (--nMaxDigits > 0)
-                sb.Append((*dig != 0) ? *dig++ : '0');
+                sb.Append((*dig != 0) ? (char)(*dig++) : '0');
 
             int e = number.Digits[0] == 0 ? 0 : number.Scale - 1;
             FormatExponent(ref sb, info, e, expChar, 3, true);
@@ -2167,13 +2180,13 @@ namespace System
                 }
             }
 
-            char* dig = number.GetDigitsPointer();
+            byte* dig = number.GetDigitsPointer();
 
             if (digPos > 0)
             {
                 do
                 {
-                    sb.Append((*dig != 0) ? *dig++ : '0');
+                    sb.Append((*dig != 0) ? (char)(*dig++) : '0');
                 } while (--digPos > 0);
             }
             else
@@ -2192,7 +2205,7 @@ namespace System
                 }
 
                 while (*dig != 0)
-                    sb.Append(*dig++);
+                    sb.Append((char)(*dig++));
             }
 
             if (scientific)
@@ -2201,7 +2214,7 @@ namespace System
 
         private static void FormatPercent(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info)
         {
-            string fmt = number.Sign ?
+            string fmt = number.IsNegative ?
                 s_negPercentFormats[info.PercentNegativePattern] :
                 s_posPercentFormats[info.PercentPositivePattern];
 
@@ -2227,7 +2240,7 @@ namespace System
 
         private static unsafe void RoundNumber(ref NumberBuffer number, int pos)
         {
-            char* dig = number.GetDigitsPointer();
+            byte* dig = number.GetDigitsPointer();
 
             int i = 0;
             while (i < pos && dig[i] != 0)
@@ -2245,7 +2258,7 @@ namespace System
                 else
                 {
                     number.Scale++;
-                    dig[0] = '1';
+                    dig[0] = (byte)('1');
                     i = 1;
                 }
             }
@@ -2260,10 +2273,13 @@ namespace System
 
                 if (number.Kind == NumberBufferKind.Integer)
                 {
-                    number.Sign = false;
+                    number.IsNegative = false;
                 }
             }
-            dig[i] = '\0';
+
+            dig[i] = (byte)('\0');
+            number.DigitsCount = i;
+            number.CheckConsistency();
         }
 
         private static unsafe int FindSection(ReadOnlySpan<char> format, int section)
@@ -2321,24 +2337,29 @@ namespace System
 
         private static unsafe void DoubleToNumber(double value, int precision, ref NumberBuffer number)
         {
-            number.Precision = precision;
-
             if (!double.IsFinite(value))
             {
                 number.Scale = double.IsNaN(value) ? ScaleNAN : ScaleINF;
-                number.Sign = double.IsNegative(value);
-                number.Digits[0] = '\0';
+                number.IsNegative = double.IsNegative(value);
+                number.Digits[0] = (byte)('\0');
             }
             else if (value == 0.0)
             {
                 number.Scale = 0;
-                number.Sign = double.IsNegative(value);
-                number.Digits[0] = '\0';
+                number.IsNegative = double.IsNegative(value);
+                number.Digits[0] = (byte)('\0');
             }
-            else if (!Grisu3.Run(value, precision, ref number))
+            else
             {
-                Dragon4(value, precision, ref number);
+                number.DigitsCount = precision;
+
+                if (!Grisu3.Run(value, precision, ref number))
+                {
+                    Dragon4(value, precision, ref number);
+                }
             }
+
+            number.CheckConsistency();
         }
 
         private static long ExtractFractionAndBiasedExponent(double value, out int exponent)
index 0cbf258..1f0072e 100644 (file)
@@ -341,11 +341,11 @@ namespace System
                 if (double.IsNegative(value))
                 {
                     value = -value;
-                    number.Sign = true;
+                    number.IsNegative = true;
                 }
                 else
                 {
-                    number.Sign = false;
+                    number.IsNegative = false;
                 }
 
                 // Step 1: Determine the normalized DiyFp w.
@@ -370,7 +370,7 @@ namespace System
 
                 if (isSuccess)
                 {
-                    number.Digits[precision] = '\0';
+                    number.Digits[precision] = (byte)('\0');
                     number.Scale = (length - decimalExponent + kappa);
                 }
 
@@ -549,7 +549,7 @@ namespace System
                 decimalExponent = s_CachedPowerDecimalExponents[index];
             }
 
-            private static bool DigitGen(ref DiyFp mp, int precision, char* digits, out int length, out int k)
+            private static bool DigitGen(ref DiyFp mp, int precision, byte* digits, out int length, out int k)
             {
                 // Split the input mp to two parts. Part 1 is integral. Part 2 can be used to calculate
                 // fractional.
@@ -604,7 +604,7 @@ namespace System
                 while (kappa > 0)
                 {
                     int d = (int)(Math.DivRem(p1, div, out p1));
-                    digits[index] = (char)('0' + d);
+                    digits[index] = (byte)('0' + d);
 
                     index++;
                     precision--;
@@ -643,7 +643,7 @@ namespace System
                     p2 *= 10;
 
                     int d = (int)(p2 >> oneNegE);
-                    digits[index] = (char)('0' + d);
+                    digits[index] = (byte)('0' + d);
 
                     index++;
                     precision--;
@@ -673,7 +673,7 @@ namespace System
                 return (int)(Math.Ceiling((Alpha - e + DiyFp.SignificandLength - 1) * D1Log210));
             }
 
-            private static bool RoundWeed(char* buffer, int len, ulong rest, ulong tenKappa, ulong ulp, ref int kappa)
+            private static bool RoundWeed(byte* buffer, int len, ulong rest, ulong tenKappa, ulong ulp, ref int kappa)
             {
                 Debug.Assert(rest < tenKappa);
 
@@ -700,14 +700,14 @@ namespace System
                     buffer[len - 1]++;
                     for (int i = len - 1; i > 0; i--)
                     {
-                        if (buffer[i] != (char)('0' + 10))
+                        if (buffer[i] != (byte)('0' + 10))
                         {
                             // We end up a number less than 9.
                             break;
                         }
 
                         // Current number becomes 0 and add the promotion to the next number.
-                        buffer[i] = '0';
+                        buffer[i] = (byte)('0');
                         buffer[i - 1]++;
                     }
 
@@ -715,7 +715,7 @@ namespace System
                     {
                         // First number is '0' + 10 means all numbers are 9.
                         // We simply make the first number to 1 and increase the kappa.
-                        buffer[0] = '1';
+                        buffer[0] = (byte)('1');
                         kappa++;
                     }
 
index 82bfbba..9d053c6 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Diagnostics;
+using System.Text;
 using Internal.Runtime.CompilerServices;
 
 namespace System
@@ -20,33 +21,95 @@ namespace System
 
         internal unsafe ref struct NumberBuffer
         {
-            public int Precision;
+            public int DigitsCount;
             public int Scale;
-            public bool Sign;
+            public bool IsNegative;
             public bool HasNonZeroTail;
             public NumberBufferKind Kind;
-            public Span<char> Digits;
+            public Span<byte> Digits;
 
-            public NumberBuffer(NumberBufferKind kind, char* digits, int digitsLength)
+            public NumberBuffer(NumberBufferKind kind, byte* digits, int digitsLength)
             {
-                Debug.Assert(kind == NumberBufferKind.Integer
-                    || kind == NumberBufferKind.Decimal
-                    || kind == NumberBufferKind.FloatingPoint);
                 Debug.Assert(digits != null);
                 Debug.Assert(digitsLength > 0);
 
-                Precision = 0;
+                DigitsCount = 0;
                 Scale = 0;
-                Sign = false;
+                IsNegative = false;
                 HasNonZeroTail = false;
                 Kind = kind;
-                Digits = new Span<char>(digits, digitsLength);
+                Digits = new Span<byte>(digits, digitsLength);
+
+#if DEBUG
+                Digits.Fill(0xCC);
+#endif
+
+                Digits[0] = (byte)('\0');
+                CheckConsistency();
+            }
+
+            [Conditional("DEBUG")]
+            public void CheckConsistency()
+            {
+#if DEBUG
+                Debug.Assert((Kind == NumberBufferKind.Integer) || (Kind == NumberBufferKind.Decimal) || (Kind == NumberBufferKind.FloatingPoint));
+                Debug.Assert(Digits[0] != '0', "Leading zeros should never be stored in a Number");
+
+                int numDigits;
+                for (numDigits = 0; numDigits < Digits.Length; numDigits++)
+                {
+                    byte digit = Digits[numDigits];
+
+                    if (digit == 0)
+                    {
+                        break;
+                    }
+
+                    Debug.Assert((digit >= '0') && (digit <= '9'), "Unexpected character found in Number");
+                }
+
+                Debug.Assert(numDigits == DigitsCount, "Null terminator found in unexpected location in Number");
+                Debug.Assert(numDigits < Digits.Length, "Null terminator not found in Number");
+#endif // DEBUG
             }
 
-            public char* GetDigitsPointer()
+            public byte* GetDigitsPointer()
             {
                 // This is safe to do since we are a ref struct
-                return (char*)(Unsafe.AsPointer(ref Digits[0]));
+                return (byte*)(Unsafe.AsPointer(ref Digits[0]));
+            }
+
+            //
+            // Code coverage note: This only exists so that Number displays nicely in the VS watch window. So yes, I know it works.
+            //
+            public override string ToString()
+            {
+                StringBuilder sb = new StringBuilder();
+
+                sb.Append('[');
+                sb.Append('"');
+
+                for (int i = 0; i < Digits.Length; i++)
+                {
+                    byte digit = Digits[i];
+
+                    if (digit == 0)
+                    {
+                        break;
+                    }
+
+                    sb.Append((char)(digit));
+                }
+
+                sb.Append('"');
+                sb.Append(", Length = " + DigitsCount);
+                sb.Append(", Scale = " + Scale);
+                sb.Append(", IsNegative = " + IsNegative);
+                sb.Append(", HasNonZeroTail = " + HasNonZeroTail);
+                sb.Append(", Kind = " + Kind);
+                sb.Append(']');
+
+                return sb.ToString();
             }
         }
 
index 16626bb..5474a60 100644 (file)
@@ -110,7 +110,7 @@ namespace System
         {
             result = new BigInteger(0);
 
-            char* src = number.GetDigitsPointer() + firstIndex;
+            byte* src = number.GetDigitsPointer() + firstIndex;
             uint remaining = lastIndex - firstIndex;
 
             while (remaining != 0)
@@ -298,11 +298,11 @@ namespace System
         }
 
         // get 32-bit integer from at most 9 digits
-        private static uint DigitsToUInt32(char* p, int count)
+        private static uint DigitsToUInt32(byte* p, int count)
         {
             Debug.Assert((1 <= count) && (count <= 9));
 
-            char* end = (p + count);
+            byte* end = (p + count);
             uint res = (uint)(p[0] - '0');
 
             for (p++; p < end; p++)
@@ -314,11 +314,11 @@ namespace System
         }
 
         // get 64-bit integer from at most 19 digits
-        private static ulong DigitsToUInt64(char* p, int count)
+        private static ulong DigitsToUInt64(byte* p, int count)
         {
             Debug.Assert((1 <= count) && (count <= 19));
 
-            char* end = (p + count);
+            byte* end = (p + count);
             ulong res = (ulong)(p[0] - '0');
 
             for (p++; p < end; p++)
@@ -341,7 +341,7 @@ namespace System
             // If the exponent is zero or negative, then the integer part is empty.  In
             // either case, the remaining digits form the fractional part of the mantissa.
 
-            uint totalDigits = (uint)(number.Precision);
+            uint totalDigits = (uint)(number.DigitsCount);
             uint positiveExponent = (uint)(Math.Max(0, number.Scale));
 
             uint integerDigitsPresent = Math.Min(positiveExponent, totalDigits);
@@ -358,7 +358,7 @@ namespace System
             // computed to the infinitely precise result and then rounded, which means that
             // we can rely on it to produce the correct result when both inputs are exact.
 
-            char* src = number.GetDigitsPointer();
+            byte* src = number.GetDigitsPointer();
 
             if (totalDigits == 0)
             {
@@ -422,7 +422,7 @@ namespace System
             // have and we don't need to round).
             uint requiredBitsOfPrecision = (uint)(info.NormalMantissaBits + 1);
 
-            uint totalDigits = (uint)(number.Precision);
+            uint totalDigits = (uint)(number.DigitsCount);
             uint integerDigitsMissing = positiveExponent - integerDigitsPresent;
 
             uint integerFirstIndex = 0;
index 60185b4..b814ba8 100644 (file)
@@ -54,12 +54,14 @@ namespace System
 
         private static unsafe bool TryNumberToInt32(ref NumberBuffer number, ref int value)
         {
+            number.CheckConsistency();
+
             int i = number.Scale;
-            if (i > Int32Precision || i < number.Precision)
+            if (i > Int32Precision || i < number.DigitsCount)
             {
                 return false;
             }
-            char* p = number.GetDigitsPointer();
+            byte* p = number.GetDigitsPointer();
             Debug.Assert(p != null);
             int n = 0;
             while (--i >= 0)
@@ -74,7 +76,7 @@ namespace System
                     n += (*p++ - '0');
                 }
             }
-            if (number.Sign)
+            if (number.IsNegative)
             {
                 n = -n;
                 if (n > 0)
@@ -95,12 +97,14 @@ namespace System
 
         private static unsafe bool TryNumberToInt64(ref NumberBuffer number, ref long value)
         {
+            number.CheckConsistency();
+
             int i = number.Scale;
-            if (i > Int64Precision || i < number.Precision)
+            if (i > Int64Precision || i < number.DigitsCount)
             {
                 return false;
             }
-            char* p = number.GetDigitsPointer();
+            byte* p = number.GetDigitsPointer();
             Debug.Assert(p != null);
             long n = 0;
             while (--i >= 0)
@@ -115,7 +119,7 @@ namespace System
                     n += (*p++ - '0');
                 }
             }
-            if (number.Sign)
+            if (number.IsNegative)
             {
                 n = -n;
                 if (n > 0)
@@ -136,12 +140,14 @@ namespace System
 
         private static unsafe bool TryNumberToUInt32(ref NumberBuffer number, ref uint value)
         {
+            number.CheckConsistency();
+
             int i = number.Scale;
-            if (i > UInt32Precision || i < number.Precision || number.Sign)
+            if (i > UInt32Precision || i < number.DigitsCount || number.IsNegative)
             {
                 return false;
             }
-            char* p = number.GetDigitsPointer();
+            byte* p = number.GetDigitsPointer();
             Debug.Assert(p != null);
             uint n = 0;
             while (--i >= 0)
@@ -168,12 +174,14 @@ namespace System
 
         private static unsafe bool TryNumberToUInt64(ref NumberBuffer number, ref ulong value)
         {
+            number.CheckConsistency();
+
             int i = number.Scale;
-            if (i > UInt64Precision || i < number.Precision || number.Sign)
+            if (i > UInt64Precision || i < number.DigitsCount || number.IsNegative)
             {
                 return false;
             }
-            char* p = number.GetDigitsPointer();
+            byte* p = number.GetDigitsPointer();
             Debug.Assert(p != null);
             ulong n = 0;
             while (--i >= 0)
@@ -252,11 +260,12 @@ namespace System
             const int StateDecimal = 0x0010;
             const int StateCurrency = 0x0020;
 
-            Debug.Assert(number.Precision == 0);
+            Debug.Assert(number.DigitsCount == 0);
             Debug.Assert(number.Scale == 0);
-            Debug.Assert(number.Sign == false);
+            Debug.Assert(number.IsNegative == false);
             Debug.Assert(number.HasNonZeroTail == false);
-            Debug.Assert(number.Kind != NumberBufferKind.Unknown);
+
+            number.CheckConsistency();
 
             string decSep;                  // decimal separator from NumberFormatInfo.
             string groupSep;                // group separator from NumberFormatInfo.
@@ -290,7 +299,7 @@ namespace System
                 // "-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 = MatchChars(p, strEnd, info.NegativeSign)) != null && (number.Sign = true))))
+                    if ((((styles & NumberStyles.AllowLeadingSign) != 0) && (state & StateSign) == 0) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || ((next = MatchChars(p, strEnd, info.NegativeSign)) != null && (number.IsNegative = true))))
                     {
                         state |= StateSign;
                         p = next - 1;
@@ -298,7 +307,7 @@ namespace System
                     else if (ch == '(' && ((styles & NumberStyles.AllowParentheses) != 0) && ((state & StateSign) == 0))
                     {
                         state |= StateSign | StateParens;
-                        number.Sign = true;
+                        number.IsNegative = true;
                     }
                     else if (currSymbol != null && (next = MatchChars(p, strEnd, currSymbol)) != null)
                     {
@@ -330,7 +339,7 @@ namespace System
                     {
                         if (digCount < maxDigCount)
                         {
-                            number.Digits[digCount++] = ch;
+                            number.Digits[digCount++] = (byte)(ch);
                             if ((ch != '0') || (number.Kind != NumberBufferKind.Integer))
                             {
                                 digEnd = digCount;
@@ -376,8 +385,8 @@ namespace System
             }
 
             bool negExp = false;
-            number.Precision = digEnd;
-            number.Digits[digEnd] = '\0';
+            number.DigitsCount = digEnd;
+            number.Digits[digEnd] = (byte)('\0');
             if ((state & StateDigits) != 0)
             {
                 if ((ch == 'E' || ch == 'e') && ((styles & NumberStyles.AllowExponent) != 0))
@@ -425,7 +434,7 @@ namespace System
                 {
                     if (!IsWhite(ch) || (styles & NumberStyles.AllowTrailingWhite) == 0)
                     {
-                        if (((styles & NumberStyles.AllowTrailingSign) != 0 && ((state & StateSign) == 0)) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || (((next = MatchChars(p, strEnd, info.NegativeSign)) != null) && (number.Sign = true))))
+                        if (((styles & NumberStyles.AllowTrailingSign) != 0 && ((state & StateSign) == 0)) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || (((next = MatchChars(p, strEnd, info.NegativeSign)) != null) && (number.IsNegative = true))))
                         {
                             state |= StateSign;
                             p = next - 1;
@@ -456,7 +465,7 @@ namespace System
                         }
                         if ((state & StateDecimal) == 0)
                         {
-                            number.Sign = false;
+                            number.IsNegative = false;
                         }
                     }
                     str = p;
@@ -483,7 +492,7 @@ namespace System
                 return TryParseUInt32HexNumberStyle(value, styles, out Unsafe.As<int, uint>(ref result), ref failureIsOverflow);
             }
 
-            char* pDigits = stackalloc char[Int32NumberBufferLength];
+            byte* pDigits = stackalloc byte[Int32NumberBufferLength];
             NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, Int32NumberBufferLength);
 
             if (!TryStringToNumber(value, styles, ref number, info))
@@ -859,7 +868,7 @@ namespace System
                 return TryParseUInt64HexNumberStyle(value, styles, out Unsafe.As<long, ulong>(ref result), ref failureIsOverflow);
             }
 
-            char* pDigits = stackalloc char[Int64NumberBufferLength];
+            byte* pDigits = stackalloc byte[Int64NumberBufferLength];
             NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, Int64NumberBufferLength);
 
             if (!TryStringToNumber(value, styles, ref number, info))
@@ -892,7 +901,7 @@ namespace System
                 return TryParseUInt32HexNumberStyle(value, styles, out result, ref failureIsOverflow);
             }
 
-            char* pDigits = stackalloc char[UInt32NumberBufferLength];
+            byte* pDigits = stackalloc byte[UInt32NumberBufferLength];
             NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, UInt32NumberBufferLength);
 
             if (!TryStringToNumber(value, styles, ref number, info))
@@ -900,7 +909,6 @@ namespace System
                 return false;
             }
 
-
             if (!TryNumberToUInt32(ref number, ref result))
             {
                 failureIsOverflow = true;
@@ -1214,7 +1222,7 @@ namespace System
                 return TryParseUInt64HexNumberStyle(value, styles, out result, ref failureIsOverflow);
             }
 
-            char* pDigits = stackalloc char[UInt64NumberBufferLength];
+            byte* pDigits = stackalloc byte[UInt64NumberBufferLength];
             NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, UInt64NumberBufferLength);
 
             if (!TryStringToNumber(value, styles, ref number, info))
@@ -1222,7 +1230,6 @@ namespace System
                 return false;
             }
 
-
             if (!TryNumberToUInt64(ref number, ref result))
             {
                 failureIsOverflow = true;
@@ -1532,9 +1539,11 @@ namespace System
 
         private static unsafe bool TryNumberToDecimal(ref NumberBuffer number, ref decimal value)
         {
-            char* p = number.GetDigitsPointer();
+            number.CheckConsistency();
+
+            byte* p = number.GetDigitsPointer();
             int e = number.Scale;
-            bool sign = number.Sign;
+            bool sign = number.IsNegative;
             uint c = *p;
             if (c == 0)
             {
@@ -1655,7 +1664,7 @@ namespace System
 
         internal static unsafe bool TryParseDecimal(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out decimal result, out bool failureIsOverflow)
         {
-            char* pDigits = stackalloc char[DecimalNumberBufferLength];
+            byte* pDigits = stackalloc byte[DecimalNumberBufferLength];
             NumberBuffer number = new NumberBuffer(NumberBufferKind.Decimal, pDigits, DecimalNumberBufferLength);
 
             result = 0;
@@ -1677,7 +1686,7 @@ namespace System
 
         internal static unsafe bool TryParseDouble(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out double result)
         {
-            char* pDigits = stackalloc char[DoubleNumberBufferLength];
+            byte* pDigits = stackalloc byte[DoubleNumberBufferLength];
             NumberBuffer number = new NumberBuffer(NumberBufferKind.FloatingPoint, pDigits, DoubleNumberBufferLength);
 
             if (!TryStringToNumber(value, styles, ref number, info))
@@ -1712,7 +1721,7 @@ namespace System
 
         internal static unsafe bool TryParseSingle(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out float result)
         {
-            char* pDigits = stackalloc char[SingleNumberBufferLength];
+            byte* pDigits = stackalloc byte[SingleNumberBufferLength];
             NumberBuffer number = new NumberBuffer(NumberBufferKind.FloatingPoint, pDigits, SingleNumberBufferLength);
 
             if (!TryStringToNumber(value, styles, ref number, info))
@@ -1762,10 +1771,12 @@ namespace System
                 if (!TryParseNumber(ref p, p + value.Length, styles, ref number, info)
                     || (p - stringPointer < value.Length && !TrailingZeros(value, (int)(p - stringPointer))))
                 {
+                    number.CheckConsistency();
                     return false;
                 }
             }
 
+            number.CheckConsistency();
             return true;
         }
 
@@ -1825,16 +1836,20 @@ namespace System
 
         private static double NumberToDouble(ref NumberBuffer number)
         {
+            number.CheckConsistency();
+
             ulong bits = NumberToFloatingPointBits(ref number, in FloatingPointInfo.Double);
             double result = BitConverter.Int64BitsToDouble((long)(bits));
-            return number.Sign ? -result : result;
+            return number.IsNegative ? -result : result;
         }
 
         private static float NumberToSingle(ref NumberBuffer number)
         {
+            number.CheckConsistency();
+
             uint bits = (uint)(NumberToFloatingPointBits(ref number, in FloatingPointInfo.Single));
             float result = BitConverter.Int32BitsToSingle((int)(bits));
-            return number.Sign ? -result : result;
+            return number.IsNegative ? -result : result;
         }
     }
 }