Fix LogsPrettifier.

Fix LogsPrettifier.

--- src/CK.Glouton.Service/LuceneSearcherService.cs
+++ src/CK.Glouton.Service/LuceneSearcherService.cs
@@ -96,22 +96,22 @@
         private (List<ILogViewModel> logs, int index) LogsPrettifier(List<ILogViewModel> logs, int index)
         {
             var indexSnapshot = index;
-            for (; index < logs.Count; index += 1)
+            for( ; index < logs.Count; index += 1 )
             {
-                if (logs[index].LogType == ELogType.OpenGroup)
+                if( logs[index].LogType == ELogType.OpenGroup )
                 {
-                    if ( !(logs[index] is OpenGroupViewModel parent) )
+                    if ( !(logs[index] is OpenGroupViewModel parent ) )
                         throw new InvalidOperationException( nameof( parent ) );
-                    var groupLogs = LogsPrettifier(logs, index + 1);
+                    var groupLogs = LogsPrettifier( logs, index + 1 );
                     parent.GroupLogs = groupLogs.logs;
-                    logs.RemoveRange(index + 1, groupLogs.index - index);
+                    logs.RemoveRange( index + 1, groupLogs.index - index );
                 }
-                else if (logs[index].LogType == ELogType.CloseGroup)
+                else if( logs[index].GroupDepth > 0 && logs[index].LogType == ELogType.CloseGroup )
                 {
-                    return (logs.GetRange(indexSnapshot, index - indexSnapshot + 1), index);
+                    return ( logs.GetRange( indexSnapshot, index - indexSnapshot + 1 ), index );
                 }
             }
-            return (logs, indexSnapshot);
+            return ( logs, indexSnapshot );
         }
     }
 }


Tweak report printer

Tweak report printer

--- src/Cake.TFBuild.Module/TFBuildReportPrinter.cs
+++ src/Cake.TFBuild.Module/TFBuildReportPrinter.cs
@@ -44,6 +44,19 @@

         private void WriteToMarkdown(CakeReport report)
         {
+            var maxTaskNameLength = 29;
+            foreach (var item in report)
+            {
+                if (item.TaskName.Length > maxTaskNameLength)
+                {
+                    maxTaskNameLength = item.TaskName.Length;
+                }
+            }
+
+            maxTaskNameLength++;
+            string lineFormat = "|{0,-" + maxTaskNameLength + "}|{1}|{2,-20}|";
+
+
             var sb = new StringBuilder();
             sb.AppendLine("");
             sb.AppendLine("|Task|Status|Duration|");
@@ -52,7 +65,7 @@
             {
                 if (ShouldWriteTask(item))
                 {
-                    sb.AppendLine(string.Format("|{0}|{1}|{2}|", item.TaskName, item.ExecutionStatus, FormatDuration(item)));
+                    sb.AppendLine(string.Format(lineFormat, item.TaskName, item.ExecutionStatus, FormatDuration(item)));
                 }
             }
             sb.AppendLine("");
@@ -63,7 +76,8 @@
             using (var writer = new StreamWriter(file.OpenWrite())) {
                 writer.Write(sb.ToString());
             }
-            b.Commands.UploadTaskSummary(absFilePath);
+            //b.Commands.UploadTaskSummary(absFilePath);
+            _console.WriteLine($"##vso[task.addattachment type=Distributedtask.Core.Summary;name=Cake Build Summary;]{absFilePath.MakeAbsolute(_context.Environment).FullPath}");
         }

         private void WriteToConsole(CakeReport report)


Updated collections extensions for lazy ToList

--- src/Collections/Collections.cs
+++ src/Collections/Collections.cs
@@ -15,13 +15,17 @@
             this ICollection<TElem> coll,
             IEnumerable<TElem> items)
         {
+            coll.CheckArgumentNull(nameof(coll));
             if (coll is List<TElem> trueList)
             {
                 trueList.AddRange(items);
                 return;
             }
-            coll.CheckArgumentNull(nameof(coll));
             items.CheckArgumentNull(nameof(items));
+            if (ReferenceEquals(coll, items))
+            {
+                items = items.ToList();
+            }
             foreach (var item in items)
             {
                 coll.Add(item);
@@ -51,7 +55,11 @@
         {
             coll.CheckArgumentNull(nameof(coll));
             items.CheckArgumentNull(nameof(items));
-            foreach (var item in items.ToList())
+            if (ReferenceEquals(coll, items))
+            {
+                items = items.ToList();
+            }
+            foreach (var item in items)
             {
                 coll.Remove(item);
             }


Improve throughput of {U}Int32/64.{Try}Parse for hex (dotnet/coreclr#18952)

* Improve throughput of {U}Int32/64.{Try}Parse for hex

- Copies/modifies the recently added TryParse32/64IntegerStyle routines for hex in order to provide more optimized parsing.
- Since AllowHexSpecifier can't be used with any other styles (other than allowing leading/trailing whitespace), deletes existing code paths for parsing hex.
- As I was copying code around, I kept getting bitten by different names used for the same thing, so I also standardized some parameter names in various helper functions.

* Clean up

- Remove a bunch of unnecessary 'unsafe' keywords
- Rephrase some while(true) loops as do/while loops for consistency and to avoid some repetition
- Remove an unnecessary wrapper function

Signed-off-by: dotnet-bot <03c4cb6107ae99956a7681f2c97ff7104809a2bd@microsoft.com>

--- src/Common/src/CoreLib/System/Number.Parsing.cs
+++ src/Common/src/CoreLib/System/Number.Parsing.cs
@@ -5,6 +5,7 @@
 using System.Diagnostics;
 using System.Globalization;
 using System.Runtime.InteropServices;
+using Internal.Runtime.CompilerServices;

 namespace System
 {
@@ -30,129 +31,26 @@
         private const int Int64Precision = 19;
         private const int UInt64Precision = 20;

-        private static bool HexNumberToInt32(ref NumberBuffer number, ref int value)
-        {
-            uint passedValue = 0;
-            bool returnValue = HexNumberToUInt32(ref number, ref passedValue);
-            value = (int)passedValue;
-            return returnValue;
-        }
-
-        private static bool HexNumberToInt64(ref NumberBuffer number, ref long value)
-        {
-            ulong passedValue = 0;
-            bool returnValue = HexNumberToUInt64(ref number, ref passedValue);
-            value = (long)passedValue;
-            return returnValue;
-        }
-
-        private static unsafe bool HexNumberToUInt32(ref NumberBuffer number, ref uint value)
-        {
-            int i = number.scale;
-            if (i > UInt32Precision || i < number.precision)
-            {
-                return false;
-            }
-            char* p = number.digits;
-            Debug.Assert(p != null);
-
-            uint n = 0;
-            while (--i >= 0)
-            {
-                if (n > ((uint)0xFFFFFFFF / 16))
-                {
-                    return false;
-                }
-                n *= 16;
-                if (*p != '\0')
-                {
-                    uint newN = n;
-                    if (*p != '\0')
-                    {
-                        if (IsDigit(*p))
-                        {
-                            newN += (uint)(*p - '0');
-                        }
-                        else
-                        {
-                            if (*p >= 'A' && *p <= 'F')
-                            {
-                                newN += (uint)((*p - 'A') + 10);
-                            }
-                            else
-                            {
-                                Debug.Assert(*p >= 'a' && *p <= 'f');
-                                newN += (uint)((*p - 'a') + 10);
-                            }
-                        }
-                        p++;
-                    }
-
-                    // Detect an overflow here...
-                    if (newN < n)
-                    {
-                        return false;
-                    }
-                    n = newN;
-                }
-            }
-            value = n;
-            return true;
-        }
-
-        private static unsafe bool HexNumberToUInt64(ref NumberBuffer number, ref ulong value)
-        {
-            int i = number.scale;
-            if (i > UInt64Precision || i < number.precision)
-            {
-                return false;
-            }
-            char* p = number.digits;
-            Debug.Assert(p != null);
-
-            ulong n = 0;
-            while (--i >= 0)
-            {
-                if (n > (0xFFFFFFFFFFFFFFFF / 16))
-                {
-                    return false;
-                }
-                n *= 16;
-                if (*p != '\0')
-                {
-                    ulong newN = n;
-                    if (*p != '\0')
-                    {
-                        if (IsDigit(*p))
-                        {
-                            newN += (ulong)(*p - '0');
-                        }
-                        else
-                        {
-                            if (*p >= 'A' && *p <= 'F')
-                            {
-                                newN += (ulong)((*p - 'A') + 10);
-                            }
-                            else
-                            {
-                                Debug.Assert(*p >= 'a' && *p <= 'f');
-                                newN += (ulong)((*p - 'a') + 10);
-                            }
-                        }
-                        p++;
-                    }
-
-                    // Detect an overflow here...
-                    if (newN < n)
-                    {
-                        return false;
-                    }
-                    n = newN;
-                }
-            }
-            value = n;
-            return true;
-        }
+        /// <summary>256-element map from an ASCII char to its hex value, e.g. arr['b'] == 11. 0xFF means it's not a hex digit.</summary>
+        private static readonly int[] s_charToHexLookup =
+        {
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 15
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 31
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 47
+            0x0,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0x7,  0x8,  0x9,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 63
+            0xFF, 0xA,  0xB,  0xC,  0xD,  0xE,  0xF,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 79
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 95
+            0xFF, 0xa,  0xb,  0xc,  0xd,  0xe,  0xf,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 111
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 127
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 143
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 159
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 175
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 191
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 207
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 223
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 239
+            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF  // 255
+        };

         private static unsafe bool NumberToInt32(ref NumberBuffer number, ref int value)
         {
@@ -173,7 +71,7 @@
                 n *= 10;
                 if (*p != '\0')
                 {
-                    n += (int)(*p++ - '0');
+                    n += (*p++ - '0');
                 }
             }
             if (number.sign)
@@ -214,7 +112,7 @@
                 n *= 10;
                 if (*p != '\0')
                 {
-                    n += (int)(*p++ - '0');
+                    n += (*p++ - '0');
                 }
             }
             if (number.sign)
@@ -300,159 +198,146 @@
             return true;
         }

-        internal static unsafe int ParseInt32(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info)
-        {
-            int i = 0;
-
-            if ((style & ~NumberStyles.Integer) == 0)
+        internal static int ParseInt32(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info)
+        {
+            if ((styles & ~NumberStyles.Integer) == 0)
             {
                 // Optimized path for the common case of anything that's allowed for integer style.
                 bool overflow = false;
-                if (!TryParseInt32IntegerStyle(s, style, info, out i, ref overflow))
-                {
-                    throw overflow ?
-                        new OverflowException(SR.Overflow_Int32) :
-                        (Exception)new FormatException(SR.Format_InvalidString);
-                }
-                return i;
+                if (!TryParseInt32IntegerStyle(value, styles, info, out int intResult, ref overflow))
+                {
+                    ThrowOverflowOrFormatException(overflow, nameof(SR.Overflow_Int32));
+                }
+                return intResult;
+            }
+
+            if ((styles & NumberStyles.AllowHexSpecifier) != 0)
+            {
+                bool overflow = false;
+                if (!TryParseUInt32HexNumberStyle(value, styles, info, out uint hexResult, ref overflow))
+                {
+                    ThrowOverflowOrFormatException(overflow, nameof(SR.Overflow_Int32));
+                }
+                return (int)hexResult;
             }

             NumberBuffer number = default;
-            StringToNumber(s, style, ref number, info, false);
-
-            if ((style & NumberStyles.AllowHexSpecifier) != 0)
-            {
-                if (!HexNumberToInt32(ref number, ref i))
-                {
-                    throw new OverflowException(SR.Overflow_Int32);
-                }
-            }
-            else
-            {
-                if (!NumberToInt32(ref number, ref i))
-                {
-                    throw new OverflowException(SR.Overflow_Int32);
-                }
-            }
-            return i;
-        }
-
-        internal static unsafe long ParseInt64(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
-        {
-            long i = 0;
-
-            if ((options & ~NumberStyles.Integer) == 0)
+            int result = 0;
+            StringToNumber(value, styles, ref number, info, false);
+            if (!NumberToInt32(ref number, ref result))
+            {
+                ThrowOverflowOrFormatException(overflow: true, nameof(SR.Overflow_Int32));
+            }
+            return result;
+        }
+
+        internal static long ParseInt64(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info)
+        {
+            if ((styles & ~NumberStyles.Integer) == 0)
             {
                 // Optimized path for the common case of anything that's allowed for integer style.
                 bool overflow = false;
-                if (!TryParseInt64IntegerStyle(value, options, numfmt, out i, ref overflow))
-                {
-                    throw overflow ?
-                        new OverflowException(SR.Overflow_Int64) :
-                        (Exception)new FormatException(SR.Format_InvalidString);
-                }
-                return i;
+                if (!TryParseInt64IntegerStyle(value, styles, info, out long intResult, ref overflow))
+                {
+                    ThrowOverflowOrFormatException(overflow, nameof(SR.Overflow_Int64));
+                }
+                return intResult;
+            }
+
+            if ((styles & NumberStyles.AllowHexSpecifier) != 0)
+            {
+                bool overflow = false;
+                if (!TryParseUInt64HexNumberStyle(value, styles, info, out ulong hexResult, ref overflow))
+                {
+                    ThrowOverflowOrFormatException(overflow, nameof(SR.Overflow_Int64));
+                }
+                return (long)hexResult;
             }

             NumberBuffer number = default;
-            StringToNumber(value, options, ref number, numfmt, false);
-
-            if ((options & NumberStyles.AllowHexSpecifier) != 0)
-            {
-                if (!HexNumberToInt64(ref number, ref i))
-                {
-                    throw new OverflowException(SR.Overflow_Int64);
-                }
-            }
-            else
-            {
-                if (!NumberToInt64(ref number, ref i))
-                {
-                    throw new OverflowException(SR.Overflow_Int64);
-                }
-            }
-            return i;
-        }
-
-        internal static unsafe uint ParseUInt32(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
-        {
-            uint i = 0;
-
-            if ((options & ~NumberStyles.Integer) == 0)
+            long result = 0;
+            StringToNumber(value, styles, ref number, info, false);
+            if (!NumberToInt64(ref number, ref result))
+            {
+                ThrowOverflowOrFormatException(overflow: true, nameof(SR.Overflow_Int64));
+            }
+            return result;
+        }
+
+        internal static uint ParseUInt32(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info)
+        {
+            uint result = 0;
+
+            if ((styles & ~NumberStyles.Integer) == 0)
             {
                 // Optimized path for the common case of anything that's allowed for integer style.
                 bool overflow = false;
-                if (!TryParseUInt32IntegerStyle(value, options, numfmt, out i, ref overflow))
-                {
-                    throw overflow ?
-                        new OverflowException(SR.Overflow_UInt32) :
-                        (Exception)new FormatException(SR.Format_InvalidString);
-                }
-                return i;
+                if (!TryParseUInt32IntegerStyle(value, styles, info, out result, ref overflow))
+                {
+                    ThrowOverflowOrFormatException(overflow, nameof(SR.Overflow_UInt32));
+                }
+                return result;
+            }
+
+            if ((styles & NumberStyles.AllowHexSpecifier) != 0)
+            {
+                bool overflow = false;
+                if (!TryParseUInt32HexNumberStyle(value, styles, info, out result, ref overflow))
+                {
+                    ThrowOverflowOrFormatException(overflow, nameof(SR.Overflow_UInt32));
+                }
+                return result;
             }

             NumberBuffer number = default;
-            StringToNumber(value, options, ref number, numfmt, false);
-
-            if ((options & NumberStyles.AllowHexSpecifier) != 0)
-            {
-                if (!HexNumberToUInt32(ref number, ref i))
-                {
-                    throw new OverflowException(SR.Overflow_UInt32);
-                }
-            }
-            else
-            {
-                if (!NumberToUInt32(ref number, ref i))
-                {
-                    throw new OverflowException(SR.Overflow_UInt32);
-                }
-            }
-
-            return i;
-        }
-
-        internal static unsafe ulong ParseUInt64(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
-        {
-            ulong i = 0;
-
-            if ((options & ~NumberStyles.Integer) == 0)
+            StringToNumber(value, styles, ref number, info, false);
+            if (!NumberToUInt32(ref number, ref result))
+            {
+                ThrowOverflowOrFormatException(overflow: true, nameof(SR.Overflow_UInt32));
+            }
+            return result;
+        }
+
+        internal static ulong ParseUInt64(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info)
+        {
+            ulong result = 0;
+
+            if ((styles & ~NumberStyles.Integer) == 0)
             {
                 // Optimized path for the common case of anything that's allowed for integer style.
                 bool overflow = false;
-                if (!TryParseUInt64IntegerStyle(value, options, numfmt, out i, ref overflow))
-                {
-                    throw overflow ?
-                        new OverflowException(SR.Overflow_UInt64) :
-                        (Exception)new FormatException(SR.Format_InvalidString);
-                }
-                return i;
+                if (!TryParseUInt64IntegerStyle(value, styles, info, out result, ref overflow))
+                {
+                    ThrowOverflowOrFormatException(overflow, nameof(SR.Overflow_UInt64));
+                }
+                return result;
+            }
+
+            if ((styles & NumberStyles.AllowHexSpecifier) != 0)
+            {
+                bool overflow = false;
+                if (!TryParseUInt64HexNumberStyle(value, styles, info, out result, ref overflow))
+                {
+                    ThrowOverflowOrFormatException(overflow, nameof(SR.Overflow_UInt64));
+                }
+                return result;
             }

             NumberBuffer number = default;
-            StringToNumber(value, options, ref number, numfmt, false);
-            if ((options & NumberStyles.AllowHexSpecifier) != 0)
-            {
-                if (!HexNumberToUInt64(ref number, ref i))
-                {
-                    throw new OverflowException(SR.Overflow_UInt64);
-                }
-            }
-            else
-            {
-                if (!NumberToUInt64(ref number, ref i))
-                {
-                    throw new OverflowException(SR.Overflow_UInt64);
-                }
-            }
-            return i;
-        }
-
-        private static unsafe bool ParseNumber(ref char* str, char* strEnd, NumberStyles options, ref NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal)
+            StringToNumber(value, styles, ref number, info, false);
+            if (!NumberToUInt64(ref number, ref result))
+            {
+                ThrowOverflowOrFormatException(overflow: true, nameof(SR.Overflow_UInt64));
+            }
+            return result;
+        }
+
+        private static unsafe bool ParseNumber(ref char* str, char* strEnd, NumberStyles styles, ref NumberBuffer number, NumberFormatInfo info, bool parseDecimal)
         {
             Debug.Assert(str != null);
             Debug.Assert(strEnd != null);
             Debug.Assert(str <= strEnd);
+            Debug.Assert((styles & NumberStyles.AllowHexSpecifier) == 0);

             const int StateSign = 0x0001;
             const int StateParens = 0x0002;
@@ -468,20 +353,20 @@
             string currSymbol = null;       // currency symbol from NumberFormatInfo.

             bool parsingCurrency = false;
-            if ((options & NumberStyles.AllowCurrencySymbol) != 0)
-            {
-                currSymbol = numfmt.CurrencySymbol;
+            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 = numfmt.CurrencyDecimalSeparator;
-                groupSep = numfmt.CurrencyGroupSeparator;
+                decSep = info.CurrencyDecimalSeparator;
+                groupSep = info.CurrencyGroupSeparator;
                 parsingCurrency = true;
             }
             else
             {
-                decSep = numfmt.NumberDecimalSeparator;
-                groupSep = numfmt.NumberGroupSeparator;
+                decSep = info.NumberDecimalSeparator;
+                groupSep = info.NumberGroupSeparator;
             }

             int state = 0;
@@ -493,14 +378,14 @@
             {
                 // 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 & StateCurrency) == 0 && numfmt.NumberNegativePattern != 2)))
-                {
-                    if ((((options & NumberStyles.AllowLeadingSign) != 0) && (state & StateSign) == 0) && ((next = MatchChars(p, strEnd, numfmt.PositiveSign)) != null || ((next = MatchChars(p, strEnd, numfmt.NegativeSign)) != null && (number.sign = true))))
+                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))))
                     {
                         state |= StateSign;
                         p = next - 1;
                     }
-                    else if (ch == '(' && ((options & NumberStyles.AllowParentheses) != 0) && ((state & StateSign) == 0))
+                    else if (ch == '(' && ((styles & NumberStyles.AllowParentheses) != 0) && ((state & StateSign) == 0))
                     {
                         state |= StateSign | StateParens;
                         number.sign = true;
@@ -524,7 +409,7 @@
             int digEnd = 0;
             while (true)
             {
-                if (IsDigit(ch) || (((options & NumberStyles.AllowHexSpecifier) != 0) && ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))))
+                if (IsDigit(ch))
                 {
                     state |= StateDigits;

@@ -549,12 +434,12 @@
                         number.scale--;
                     }
                 }
-                else if (((options & NumberStyles.AllowDecimalPoint) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, strEnd, decSep)) != null || ((parsingCurrency) && (state & StateCurrency) == 0) && (next = MatchChars(p, strEnd, numfmt.NumberDecimalSeparator)) != null))
+                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 (((options & NumberStyles.AllowThousands) != 0) && ((state & StateDigits) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, strEnd, groupSep)) != null || ((parsingCurrency) && (state & StateCurrency) == 0) && (next = MatchChars(p, strEnd, numfmt.NumberGroupSeparator)) != null))
+                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;
                 }
@@ -570,15 +455,15 @@
             number.digits[digEnd] = '\0';
             if ((state & StateDigits) != 0)
             {
-                if ((ch == 'E' || ch == 'e') && ((options & NumberStyles.AllowExponent) != 0))
+                if ((ch == 'E' || ch == 'e') && ((styles & NumberStyles.AllowExponent) != 0))
                 {
                     char* temp = p;
                     ch = ++p < strEnd ? *p : '\0';
-                    if ((next = MatchChars(p, strEnd, numfmt.positiveSign)) != null)
+                    if ((next = MatchChars(p, strEnd, info.positiveSign)) != null)
                     {
                         ch = (p = next) < strEnd ? *p : '\0';
                     }
-                    else if ((next = MatchChars(p, strEnd, numfmt.negativeSign)) != null)
+                    else if ((next = MatchChars(p, strEnd, info.negativeSign)) != null)
                     {
                         ch = (p = next) < strEnd ? *p : '\0';
                         negExp = true;
@@ -613,9 +498,9 @@
                 }
                 while (true)
                 {
-                    if (!IsWhite(ch) || (options & NumberStyles.AllowTrailingWhite) == 0)
-                    {
-                        if (((options & NumberStyles.AllowTrailingSign) != 0 && ((state & StateSign) == 0)) && ((next = MatchChars(p, strEnd, numfmt.PositiveSign)) != null || (((next = MatchChars(p, strEnd, numfmt.NegativeSign)) != null) && (number.sign = true))))
+                    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))))
                         {
                             state |= StateSign;
                             p = next - 1;
@@ -657,64 +542,52 @@
             return false;
         }

-        internal static bool TryParseInt32(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out int result)
-        {
-            NumberBuffer number = default;
-            result = 0;
-
-            if ((style & ~NumberStyles.Integer) == 0)
+        internal static bool TryParseInt32(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out int result)
+        {
+            if ((styles & ~NumberStyles.Integer) == 0)
             {
                 // Optimized path for the common case of anything that's allowed for integer style.
                 bool overflow = false;
-                return TryParseInt32IntegerStyle(s, style, info, out result, ref overflow);
-            }
-
-            if (!TryStringToNumber(s, style, ref number, info, false))
-            {
-                return false;
-            }
-
-            if ((style & NumberStyles.AllowHexSpecifier) != 0)
-            {
-                if (!HexNumberToInt32(ref number, ref result))
-                {
-                    return false;
-                }
-            }
-            else
-            {
-                if (!NumberToInt32(ref number, ref result))
-                {
-                    return false;
-                }
-            }
-            return true;
+                return TryParseInt32IntegerStyle(value, styles, info, out result, ref overflow);
+            }
+
+            result = 0;
+
+            if ((styles & NumberStyles.AllowHexSpecifier) != 0)
+            {
+                bool overflow = false;
+                return TryParseUInt32HexNumberStyle(value, styles, info, out Unsafe.As<int, uint>(ref result), ref overflow);
+            }
+
+            NumberBuffer number = default;
+            return
+                TryStringToNumber(value, styles, ref number, info, false) &&
+                NumberToInt32(ref number, ref result);
         }

         /// <summary>Parses int limited to styles that make up NumberStyles.Integer.</summary>
-        private static bool TryParseInt32IntegerStyle(ReadOnlySpan<char> source, NumberStyles styles, NumberFormatInfo info, out int result, ref bool failureIsOverflow)
+        private static bool TryParseInt32IntegerStyle(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out int result, ref bool failureIsOverflow)
         {
             Debug.Assert((styles & ~NumberStyles.Integer) == 0, "Only handles subsets of Integer format");
             Debug.Assert(!failureIsOverflow, $"failureIsOverflow should have been initialized to false");

-            if ((uint)source.Length < 1) goto FalseExit;
+            if ((uint)value.Length < 1) goto FalseExit;

             bool overflow = false;
             int sign = 1;
             int index = 0;
-            int num = source[0];
+            int num = value[0];

             // Skip past any whitespace at the beginning.
             if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num))
             {
-                index++;
-                while (true)
-                {
-                    if ((uint)index >= (uint)source.Length) goto FalseExit;
-                    num = source[index];
-                    if (!IsWhite(num)) break;
+                do
+                {
                     index++;
-                }
+                    if ((uint)index >= (uint)value.Length) goto FalseExit;
+                    num = value[index];
+                }
+                while (IsWhite(num));
             }

             // Parse leading sign.
@@ -728,32 +601,32 @@
                     {
                         sign = -1;
                         index++;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
                     }
                     else if (num == '+')
                     {
                         index++;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
                     }
                 }
                 else
                 {
-                    source = source.Slice(index);
+                    value = value.Slice(index);
                     index = 0;
-                    if (!string.IsNullOrEmpty(positiveSign) && source.StartsWith(positiveSign))
+                    if (!string.IsNullOrEmpty(positiveSign) && value.StartsWith(positiveSign))
                     {
                         index += positiveSign.Length;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
-                    }
-                    else if (!string.IsNullOrEmpty(negativeSign) && source.StartsWith(negativeSign))
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
+                    }
+                    else if (!string.IsNullOrEmpty(negativeSign) && value.StartsWith(negativeSign))
                     {
                         sign = -1;
                         index += negativeSign.Length;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
                     }
                 }
             }
@@ -768,8 +641,8 @@
                     do
                     {
                         index++;
-                        if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                        num = value[index];
                     } while (num == '0');
                     if (!IsDigit(num)) goto HasTrailingChars;
                 }
@@ -779,16 +652,16 @@
                 index++;
                 for (int i = 0; i < 8; i++) // next 8 digits can't overflow
                 {
-                    if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                    num = source[index];
+                    if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                    num = value[index];
                     if (!IsDigit(num)) goto HasTrailingChars;
                     index++;
                     answer = 10 * answer + num - '0';
                 }

                 // Potential overflow now processing the 10th digit.
-                if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                num = source[index];
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                num = value[index];
                 if (!IsDigit(num)) goto HasTrailingChars;
                 index++;
                 if (answer > int.MaxValue / 10)
@@ -800,18 +673,18 @@
                 {
                     overflow = true;
                 }
-                if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;

                 // At this point, we're either overflowing or hitting a formatting error.
                 // Format errors take precedence for compatibility.
-                num = source[index];
+                num = value[index];
                 while (IsDigit(num))
                 {
                     overflow = true;
                     index++;
-                    if ((uint)index >= (uint)source.Length)
+                    if ((uint)index >= (uint)value.Length)
                         goto DoneAtEndButPotentialOverflow;
-                    num = source[index];
+                    num = value[index];
                 }
                 goto HasTrailingChars;
             }
@@ -834,43 +707,42 @@
             if (IsWhite(num))
             {
                 if ((styles & NumberStyles.AllowTrailingWhite) == 0) goto FalseExit;
-                for (index++; index < source.Length; index++)
-                {
-                    if (!IsWhite(source[index])) break;
-                }
-                if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-            }
-
-            if (!TrailingZeros(source, index)) goto FalseExit;
+                for (index++; index < value.Length; index++)
+                {
+                    if (!IsWhite(value[index])) break;
+                }
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+            }
+
+            if (!TrailingZeros(value, index)) goto FalseExit;

             goto DoneAtEndButPotentialOverflow;
         }

         /// <summary>Parses long inputs limited to styles that make up NumberStyles.Integer.</summary>
         private static bool TryParseInt64IntegerStyle(
-            ReadOnlySpan<char> source, NumberStyles styles, NumberFormatInfo info, out long result, ref bool failureIsOverflow)
+            ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out long result, ref bool failureIsOverflow)
         {
             Debug.Assert((styles & ~NumberStyles.Integer) == 0, "Only handles subsets of Integer format");
             Debug.Assert(!failureIsOverflow, $"failureIsOverflow should have been initialized to false");

-            if ((uint)source.Length < 1) goto FalseExit;
+            if ((uint)value.Length < 1) goto FalseExit;

             bool overflow = false;
             int sign = 1;
             int index = 0;
-            int num = source[0];
+            int num = value[0];

             // Skip past any whitespace at the beginning.
             if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num))
             {
-                index++;
-                while (true)
-                {
-                    if ((uint)index >= (uint)source.Length) goto FalseExit;
-                    num = source[index];
-                    if (!IsWhite(num)) break;
+                do
+                {
                     index++;
-                }
+                    if ((uint)index >= (uint)value.Length) goto FalseExit;
+                    num = value[index];
+                }
+                while (IsWhite(num));
             }

             // Parse leading sign.
@@ -884,32 +756,32 @@
                     {
                         sign = -1;
                         index++;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
                     }
                     else if (num == '+')
                     {
                         index++;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
                     }
                 }
                 else
                 {
-                    source = source.Slice(index);
+                    value = value.Slice(index);
                     index = 0;
-                    if (!string.IsNullOrEmpty(positiveSign) && source.StartsWith(positiveSign))
+                    if (!string.IsNullOrEmpty(positiveSign) && value.StartsWith(positiveSign))
                     {
                         index += positiveSign.Length;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
-                    }
-                    else if (!string.IsNullOrEmpty(negativeSign) && source.StartsWith(negativeSign))
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
+                    }
+                    else if (!string.IsNullOrEmpty(negativeSign) && value.StartsWith(negativeSign))
                     {
                         sign = -1;
                         index += negativeSign.Length;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
                     }
                 }
             }
@@ -924,8 +796,8 @@
                     do
                     {
                         index++;
-                        if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                        num = value[index];
                     } while (num == '0');
                     if (!IsDigit(num)) goto HasTrailingChars;
                 }
@@ -935,16 +807,16 @@
                 index++;
                 for (int i = 0; i < 17; i++) // next 17 digits can't overflow
                 {
-                    if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                    num = source[index];
+                    if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                    num = value[index];
                     if (!IsDigit(num)) goto HasTrailingChars;
                     index++;
                     answer = 10 * answer + num - '0';
                 }

                 // Potential overflow now processing the 19th digit.
-                if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                num = source[index];
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                num = value[index];
                 if (!IsDigit(num)) goto HasTrailingChars;
                 index++;
                 if (answer > long.MaxValue / 10)
@@ -956,17 +828,17 @@
                 {
                     overflow = true;
                 }
-                if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;

                 // At this point, we're either overflowing or hitting a formatting error.
                 // Format errors take precedence for compatibility.
-                num = source[index];
+                num = value[index];
                 while (IsDigit(num))
                 {
                     overflow = true;
                     index++;
-                    if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                    num = source[index];
+                    if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                    num = value[index];
                 }
                 goto HasTrailingChars;
             }
@@ -989,111 +861,87 @@
             if (IsWhite(num))
             {
                 if ((styles & NumberStyles.AllowTrailingWhite) == 0) goto FalseExit;
-                for (index++; index < source.Length; index++)
-                {
-                    if (!IsWhite(source[index])) break;
-                }
-                if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-            }
-
-            if (!TrailingZeros(source, index)) goto FalseExit;
+                for (index++; index < value.Length; index++)
+                {
+                    if (!IsWhite(value[index])) break;
+                }
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+            }
+
+            if (!TrailingZeros(value, index)) goto FalseExit;

             goto DoneAtEndButPotentialOverflow;
         }

-        internal static unsafe bool TryParseInt64(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out long result)
-        {
-            result = 0;
-
-            if ((style & ~NumberStyles.Integer) == 0)
+        internal static bool TryParseInt64(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out long result)
+        {
+            if ((styles & ~NumberStyles.Integer) == 0)
             {
                 // Optimized path for the common case of anything that's allowed for integer style.
                 bool overflow = false;
-                return TryParseInt64IntegerStyle(s, style, info, out result, ref overflow);
+                return TryParseInt64IntegerStyle(value, styles, info, out result, ref overflow);
+            }
+
+            result = 0;
+
+            if ((styles & NumberStyles.AllowHexSpecifier) != 0)
+            {
+                bool overflow = false;
+                return TryParseUInt64HexNumberStyle(value, styles, info, out Unsafe.As<long, ulong>(ref result), ref overflow);
             }

             NumberBuffer number = default;
-            if (!TryStringToNumber(s, style, ref number, info, false))
-            {
-                return false;
-            }
-
-            if ((style & NumberStyles.AllowHexSpecifier) != 0)
-            {
-                if (!HexNumberToInt64(ref number, ref result))
-                {
-                    return false;
-                }
-            }
-            else
-            {
-                if (!NumberToInt64(ref number, ref result))
-                {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        internal static unsafe bool TryParseUInt32(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out uint result)
-        {
+            return
+                TryStringToNumber(value, styles, ref number, info, false) &&
+                NumberToInt64(ref number, ref result);
+        }
+
+        internal static bool TryParseUInt32(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out uint result)
+        {
+            if ((styles & ~NumberStyles.Integer) == 0)
+            {
+                // Optimized path for the common case of anything that's allowed for integer style.
+                bool overflow = false;
+                return TryParseUInt32IntegerStyle(value, styles, info, out result, ref overflow);
+            }
+
+            if ((styles & NumberStyles.AllowHexSpecifier) != 0)
+            {
+                bool overflow = false;
+                return TryParseUInt32HexNumberStyle(value, styles, info, out result, ref overflow);
+            }
+
             NumberBuffer number = default;
             result = 0;
-
-            if ((style & ~NumberStyles.Integer) == 0)
-            {
-                // Optimized path for the common case of anything that's allowed for integer style.
-                bool overflow = false;
-                return TryParseUInt32IntegerStyle(s, style, info, out result, ref overflow);
-            }
-
-            if (!TryStringToNumber(s, style, ref number, info, false))
-            {
-                return false;
-            }
-
-            if ((style & NumberStyles.AllowHexSpecifier) != 0)
-            {
-                if (!HexNumberToUInt32(ref number, ref result))
-                {
-                    return false;
-                }
-            }
-            else
-            {
-                if (!NumberToUInt32(ref number, ref result))
-                {
-                    return false;
-                }
-            }
-            return true;
+            return
+                TryStringToNumber(value, styles, ref number, info, false) &&
+                NumberToUInt32(ref number, ref result);
         }

         /// <summary>Parses uint limited to styles that make up NumberStyles.Integer.</summary>
         private static bool TryParseUInt32IntegerStyle(
-            ReadOnlySpan<char> source, NumberStyles styles, NumberFormatInfo info, out uint result, ref bool failureIsOverflow)
+            ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out uint result, ref bool failureIsOverflow)
         {
             Debug.Assert((styles & ~NumberStyles.Integer) == 0, "Only handles subsets of Integer format");
             Debug.Assert(!failureIsOverflow, $"failureIsOverflow should have been initialized to false");

-            if ((uint)source.Length < 1) goto FalseExit;
+            if ((uint)value.Length < 1) goto FalseExit;

             bool overflow = false;
             bool hasNegativeSign = false;
             int index = 0;
-            int num = source[0];
+            int num = value[0];

             // Skip past any whitespace at the beginning.
             if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num))
             {
-                index++;
-                while (true)
-                {
-                    if ((uint)index >= (uint)source.Length) goto FalseExit;
-                    num = source[index];
-                    if (!IsWhite(num)) break;
+                do
+                {
                     index++;
-                }
+                    if ((uint)index >= (uint)value.Length) goto FalseExit;
+                    num = value[index];
+                }
+                while (IsWhite(num));
             }

             // Parse leading sign.
@@ -1106,33 +954,33 @@
                     if (num == '+')
                     {
                         index++;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
                     }
                     else if (num == '-')
                     {
                         hasNegativeSign = true;
                         index++;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
                     }
                 }
                 else
                 {
-                    source = source.Slice(index);
+                    value = value.Slice(index);
                     index = 0;
-                    if (!string.IsNullOrEmpty(positiveSign) && source.StartsWith(positiveSign))
+                    if (!string.IsNullOrEmpty(positiveSign) && value.StartsWith(positiveSign))
                     {
                         index += positiveSign.Length;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
-                    }
-                    else if (!string.IsNullOrEmpty(negativeSign) && source.StartsWith(negativeSign))
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
+                    }
+                    else if (!string.IsNullOrEmpty(negativeSign) && value.StartsWith(negativeSign))
                     {
                         hasNegativeSign = true;
                         index += negativeSign.Length;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
                     }
                 }
             }
@@ -1147,8 +995,8 @@
                     do
                     {
                         index++;
-                        if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                        num = value[index];
                     } while (num == '0');
                     if (!IsDigit(num)) goto HasTrailingChars;
                 }
@@ -1158,16 +1006,16 @@
                 index++;
                 for (int i = 0; i < 8; i++) // next 8 digits can't overflow
                 {
-                    if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                    num = source[index];
+                    if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                    num = value[index];
                     if (!IsDigit(num)) goto HasTrailingChars;
                     index++;
                     answer = 10 * answer + num - '0';
                 }

                 // Potential overflow now processing the 10th digit.
-                if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                num = source[index];
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                num = value[index];
                 if (!IsDigit(num)) goto HasTrailingChars;
                 index++;
                 if ((uint)answer > uint.MaxValue / 10 || ((uint)answer == uint.MaxValue / 10 && num > '5'))
@@ -1175,17 +1023,17 @@
                     overflow = true;
                 }
                 answer = answer * 10 + num - '0';
-                if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;

                 // At this point, we're either overflowing or hitting a formatting error.
                 // Format errors take precedence for compatibility.
-                num = source[index];
+                num = value[index];
                 while (IsDigit(num))
                 {
                     overflow = true;
                     index++;
-                    if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                    num = source[index];
+                    if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                    num = value[index];
                 }
                 goto HasTrailingChars;
             }
@@ -1208,77 +1056,170 @@
             if (IsWhite(num))
             {
                 if ((styles & NumberStyles.AllowTrailingWhite) == 0) goto FalseExit;
-                for (index++; index < source.Length; index++)
-                {
-                    if (!IsWhite(source[index])) break;
-                }
-                if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-            }
-
-            if (!TrailingZeros(source, index)) goto FalseExit;
+                for (index++; index < value.Length; index++)
+                {
+                    if (!IsWhite(value[index])) break;
+                }
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+            }
+
+            if (!TrailingZeros(value, index)) goto FalseExit;

             goto DoneAtEndButPotentialOverflow;
         }

-        internal static unsafe bool TryParseUInt64(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out ulong result)
-        {
+        /// <summary>Parses uint limited to styles that make up NumberStyles.HexNumber.</summary>
+        private static bool TryParseUInt32HexNumberStyle(
+            ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out uint result, ref bool failureIsOverflow)
+        {
+            Debug.Assert((styles & ~NumberStyles.HexNumber) == 0, "Only handles subsets of HexNumber format");
+            Debug.Assert(!failureIsOverflow, $"failureIsOverflow should have been initialized to false");
+
+            if ((uint)value.Length < 1) goto FalseExit;
+
+            bool overflow = false;
+            int index = 0;
+            int num = value[0];
+            int numValue = 0;
+
+            // Skip past any whitespace at the beginning.
+            if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num))
+            {
+                do
+                {
+                    index++;
+                    if ((uint)index >= (uint)value.Length) goto FalseExit;
+                    num = value[index];
+                }
+                while (IsWhite(num));
+            }
+
+            int answer = 0;
+            int[] charToHexLookup = s_charToHexLookup;
+
+            if ((uint)num < (uint)charToHexLookup.Length && charToHexLookup[num] != 0xFF)
+            {
+                // Skip past leading zeros.
+                if (num == '0')
+                {
+                    do
+                    {
+                        index++;
+                        if ((uint)index >= (uint)value.Length) goto DoneAtEnd;
+                        num = value[index];
+                    } while (num == '0');
+                    if ((uint)num >= (uint)charToHexLookup.Length || charToHexLookup[num] == 0xFF) goto HasTrailingChars;
+                }
+
+                // Parse up through 8 digits, as no overflow is possible
+                answer = charToHexLookup[num]; // first digit
+                index++;
+                for (int i = 0; i < 7; i++) // next 7 digits can't overflow
+                {
+                    if ((uint)index >= (uint)value.Length) goto DoneAtEnd;
+                    num = value[index];
+                    if ((uint)num >= (uint)charToHexLookup.Length || (numValue = charToHexLookup[num]) == 0xFF) goto HasTrailingChars;
+                    index++;
+                    answer = 16 * answer + numValue;
+                }
+
+                // If there's another digit, it's an overflow.
+                if ((uint)index >= (uint)value.Length) goto DoneAtEnd;
+                num = value[index];
+                if ((uint)num >= (uint)charToHexLookup.Length || (numValue = charToHexLookup[num]) == 0xFF) goto HasTrailingChars;
+                index++;
+                overflow = true;
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+
+                // At this point, we're either overflowing or hitting a formatting error.
+                // Format errors take precedence for compatibility. Read through any remaining digits.
+                num = value[index];
+                while ((uint)num < (uint)charToHexLookup.Length && charToHexLookup[num] != 0xFF)
+                {
+                    index++;
+                    if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                    num = value[index];
+                }
+                goto HasTrailingChars;
+            }
+
+        FalseExit: // parsing failed
+            result = 0;
+            return false;
+
+        DoneAtEndButPotentialOverflow:
+            if (overflow)
+            {
+                failureIsOverflow = true;
+                goto FalseExit;
+            }
+        DoneAtEnd:
+            result = (uint)answer;
+            return true;
+
+        HasTrailingChars: // we've successfully parsed, but there are still remaining characters in the span
+            // Skip past trailing whitespace, then past trailing zeros, and if anything else remains, fail.
+            if (IsWhite(num))
+            {
+                if ((styles & NumberStyles.AllowTrailingWhite) == 0) goto FalseExit;
+                for (index++; index < value.Length; index++)
+                {
+                    if (!IsWhite(value[index])) break;
+                }
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+            }
+
+            if (!TrailingZeros(value, index)) goto FalseExit;
+
+            goto DoneAtEndButPotentialOverflow;
+        }
+
+        internal static bool TryParseUInt64(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out ulong result)
+        {
+            if ((styles & ~NumberStyles.Integer) == 0)
+            {
+                // Optimized path for the common case of anything that's allowed for integer style.
+                bool overflow = false;
+                return TryParseUInt64IntegerStyle(value, styles, info, out result, ref overflow);
+            }
+
+            if ((styles & NumberStyles.AllowHexSpecifier) != 0)
+            {
+                bool overflow = false;
+                return TryParseUInt64HexNumberStyle(value, styles, info, out result, ref overflow);
+            }
+
             NumberBuffer number = default;
             result = 0;
-
-            if ((style & ~NumberStyles.Integer) == 0)
-            {
-                // Optimized path for the common case of anything that's allowed for integer style.
-                bool overflow = false;
-                return TryParseUInt64IntegerStyle(s, style, info, out result, ref overflow);
-            }
-
-            if (!TryStringToNumber(s, style, ref number, info, false))
-            {
-                return false;
-            }
-
-            if ((style & NumberStyles.AllowHexSpecifier) != 0)
-            {
-                if (!HexNumberToUInt64(ref number, ref result))
-                {
-                    return false;
-                }
-            }
-            else
-            {
-                if (!NumberToUInt64(ref number, ref result))
-                {
-                    return false;
-                }
-            }
-            return true;
+            return
+                TryStringToNumber(value, styles, ref number, info, false) &&
+                NumberToUInt64(ref number, ref result);
         }

         /// <summary>Parses ulong limited to styles that make up NumberStyles.Integer.</summary>
         private static bool TryParseUInt64IntegerStyle(
-            ReadOnlySpan<char> source, NumberStyles styles, NumberFormatInfo info, out ulong result, ref bool failureIsOverflow)
+            ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out ulong result, ref bool failureIsOverflow)
         {
             Debug.Assert((styles & ~NumberStyles.Integer) == 0, "Only handles subsets of Integer format");
             Debug.Assert(!failureIsOverflow, $"failureIsOverflow should have been initialized to false");

-            if ((uint)source.Length < 1) goto FalseExit;
+            if ((uint)value.Length < 1) goto FalseExit;

             bool overflow = false;
             bool hasNegativeSign = false;
             int index = 0;
-            int num = source[0];
+            int num = value[0];

             // Skip past any whitespace at the beginning.
             if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num))
             {
-                index++;
-                while (true)
-                {
-                    if ((uint)index >= (uint)source.Length) goto FalseExit;
-                    num = source[index];
-                    if (!IsWhite(num)) break;
+                do
+                {
                     index++;
-                }
+                    if ((uint)index >= (uint)value.Length) goto FalseExit;
+                    num = value[index];
+                }
+                while (IsWhite(num));
             }

             // Parse leading sign.
@@ -1291,33 +1232,33 @@
                     if (num == '+')
                     {
                         index++;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
                     }
                     else if (num == '-')
                     {
                         hasNegativeSign = true;
                         index++;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
                     }
                 }
                 else
                 {
-                    source = source.Slice(index);
+                    value = value.Slice(index);
                     index = 0;
-                    if (!string.IsNullOrEmpty(positiveSign) && source.StartsWith(positiveSign))
+                    if (!string.IsNullOrEmpty(positiveSign) && value.StartsWith(positiveSign))
                     {
                         index += positiveSign.Length;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
-                    }
-                    else if (!string.IsNullOrEmpty(negativeSign) && source.StartsWith(negativeSign))
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
+                    }
+                    else if (!string.IsNullOrEmpty(negativeSign) && value.StartsWith(negativeSign))
                     {
                         hasNegativeSign = true;
                         index += negativeSign.Length;
-                        if ((uint)index >= (uint)source.Length) goto FalseExit;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto FalseExit;
+                        num = value[index];
                     }
                 }
             }
@@ -1332,8 +1273,8 @@
                     do
                     {
                         index++;
-                        if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                        num = source[index];
+                        if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                        num = value[index];
                     } while (num == '0');
                     if (!IsDigit(num)) goto HasTrailingChars;
                 }
@@ -1343,16 +1284,16 @@
                 index++;
                 for (int i = 0; i < 18; i++) // next 18 digits can't overflow
                 {
-                    if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                    num = source[index];
+                    if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                    num = value[index];
                     if (!IsDigit(num)) goto HasTrailingChars;
                     index++;
                     answer = 10 * answer + num - '0';
                 }

                 // Potential overflow now processing the 20th digit.
-                if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                num = source[index];
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                num = value[index];
                 if (!IsDigit(num)) goto HasTrailingChars;
                 index++;
                 if ((ulong)answer > ulong.MaxValue / 10 || ((ulong)answer == ulong.MaxValue / 10 && num > '5'))
@@ -1360,17 +1301,17 @@
                     overflow = true;
                 }
                 answer = answer * 10 + num - '0';
-                if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;

                 // At this point, we're either overflowing or hitting a formatting error.
                 // Format errors take precedence for compatibility.
-                num = source[index];
+                num = value[index];
                 while (IsDigit(num))
                 {
                     overflow = true;
                     index++;
-                    if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-                    num = source[index];
+                    if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                    num = value[index];
                 }
                 goto HasTrailingChars;
             }
@@ -1393,110 +1334,216 @@
             if (IsWhite(num))
             {
                 if ((styles & NumberStyles.AllowTrailingWhite) == 0) goto FalseExit;
-                for (index++; index < source.Length; index++)
-                {
-                    if (!IsWhite(source[index])) break;
-                }
-                if ((uint)index >= (uint)source.Length) goto DoneAtEndButPotentialOverflow;
-            }
-
-            if (!TrailingZeros(source, index)) goto FalseExit;
+                for (index++; index < value.Length; index++)
+                {
+                    if (!IsWhite(value[index])) break;
+                }
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+            }
+
+            if (!TrailingZeros(value, index)) goto FalseExit;

             goto DoneAtEndButPotentialOverflow;
         }

-        internal static unsafe decimal ParseDecimal(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
+        /// <summary>Parses ulong limited to styles that make up NumberStyles.HexNumber.</summary>
+        private static bool TryParseUInt64HexNumberStyle(
+            ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out ulong result, ref bool failureIsOverflow)
+        {
+            Debug.Assert((styles & ~NumberStyles.HexNumber) == 0, "Only handles subsets of HexNumber format");
+            Debug.Assert(!failureIsOverflow, $"failureIsOverflow should have been initialized to false");
+
+            if ((uint)value.Length < 1) goto FalseExit;
+
+            bool overflow = false;
+            int index = 0;
+            int num = value[0];
+            int numValue = 0;
+
+            // Skip past any whitespace at the beginning.
+            if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num))
+            {
+                do
+                {
+                    index++;
+                    if ((uint)index >= (uint)value.Length) goto FalseExit;
+                    num = value[index];
+                }
+                while (IsWhite(num));
+            }
+
+            long answer = 0;
+            int[] charToHexLookup = s_charToHexLookup;
+
+            if ((uint)num < (uint)charToHexLookup.Length && charToHexLookup[num] != 0xFF)
+            {
+                // Skip past leading zeros.
+                if (num == '0')
+                {
+                    do
+                    {
+                        index++;
+                        if ((uint)index >= (uint)value.Length) goto DoneAtEnd;
+                        num = value[index];
+                    } while (num == '0');
+                    if ((uint)num >= (uint)charToHexLookup.Length || charToHexLookup[num] == 0xFF) goto HasTrailingChars;
+                }
+
+                // Parse up through 16 digits, as no overflow is possible
+                answer = charToHexLookup[num]; // first digit
+                index++;
+                for (int i = 0; i < 15; i++) // next 15 digits can't overflow
+                {
+                    if ((uint)index >= (uint)value.Length) goto DoneAtEnd;
+                    num = value[index];
+                    if ((uint)num >= (uint)charToHexLookup.Length || (numValue = charToHexLookup[num]) == 0xFF) goto HasTrailingChars;
+                    index++;
+                    answer = 16 * answer + numValue;
+                }
+
+                // If there's another digit, it's an overflow.
+                if ((uint)index >= (uint)value.Length) goto DoneAtEnd;
+                num = value[index];
+                if ((uint)num >= (uint)charToHexLookup.Length || (numValue = charToHexLookup[num]) == 0xFF) goto HasTrailingChars;
+                index++;
+                overflow = true;
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+
+                // At this point, we're either overflowing or hitting a formatting error.
+                // Format errors take precedence for compatibility. Read through any remaining digits.
+                num = value[index];
+                while ((uint)num < (uint)charToHexLookup.Length && charToHexLookup[num] != 0xFF)
+                {
+                    index++;
+                    if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+                    num = value[index];
+                }
+                goto HasTrailingChars;
+            }
+
+        FalseExit: // parsing failed
+            result = 0;
+            return false;
+
+        DoneAtEndButPotentialOverflow:
+            if (overflow)
+            {
+                failureIsOverflow = true;
+                goto FalseExit;
+            }
+        DoneAtEnd:
+            result = (ulong)answer;
+            return true;
+
+        HasTrailingChars: // we've successfully parsed, but there are still remaining characters in the span
+            // Skip past trailing whitespace, then past trailing zeros, and if anything else remains, fail.
+            if (IsWhite(num))
+            {
+                if ((styles & NumberStyles.AllowTrailingWhite) == 0) goto FalseExit;
+                for (index++; index < value.Length; index++)
+                {
+                    if (!IsWhite(value[index])) break;
+                }
+                if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow;
+            }
+
+            if (!TrailingZeros(value, index)) goto FalseExit;
+
+            goto DoneAtEndButPotentialOverflow;
+        }
+
+        internal static decimal ParseDecimal(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info)
         {
             NumberBuffer number = default;
             decimal result = 0;

-            StringToNumber(value, options, ref number, numfmt, true);
+            StringToNumber(value, styles, ref number, info, true);

             if (!NumberBufferToDecimal(ref number, ref result))
             {
-                throw new OverflowException(SR.Overflow_Decimal);
+                ThrowOverflowOrFormatException(overflow: true, nameof(SR.Overflow_Decimal));
             }
             return result;
         }

-        internal static unsafe double ParseDouble(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
+        internal static double ParseDouble(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info)
         {
             NumberBuffer number = default;
             double d = 0;

-            if (!TryStringToNumber(value, options, ref number, numfmt, false))
+            if (!TryStringToNumber(value, styles, ref number, info, false))
             {
                 //If we failed TryStringToNumber, it may be from one of our special strings.
                 //Check the three with which we're concerned and rethrow if it's not one of
                 //those strings.
                 ReadOnlySpan<char> sTrim = value.Trim();
-                if (sTrim.EqualsOrdinal(numfmt.PositiveInfinitySymbol))
+                if (sTrim.EqualsOrdinal(info.PositiveInfinitySymbol))
                 {
                     return double.PositiveInfinity;
                 }
-                if (sTrim.EqualsOrdinal(numfmt.NegativeInfinitySymbol))
+                if (sTrim.EqualsOrdinal(info.NegativeInfinitySymbol))
                 {
                     return double.NegativeInfinity;
                 }
-                if (sTrim.EqualsOrdinal(numfmt.NaNSymbol))
+                if (sTrim.EqualsOrdinal(info.NaNSymbol))
                 {
                     return double.NaN;
                 }
-                throw new FormatException(SR.Format_InvalidString);
+                ThrowOverflowOrFormatException(overflow: false, null);
             }

             if (!NumberBufferToDouble(ref number, ref d))
             {
-                throw new OverflowException(SR.Overflow_Double);
+                ThrowOverflowOrFormatException(overflow: true, nameof(SR.Overflow_Double));
             }

             return d;
         }

-        internal static unsafe float ParseSingle(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
+        internal static float ParseSingle(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info)
         {
             NumberBuffer number = default;
             double d = 0;

-            if (!TryStringToNumber(value, options, ref number, numfmt, false))
+            if (!TryStringToNumber(value, styles, ref number, info, false))
             {
                 //If we failed TryStringToNumber, it may be from one of our special strings.
                 //Check the three with which we're concerned and rethrow if it's not one of
                 //those strings.
                 ReadOnlySpan<char> sTrim = value.Trim();
-                if (sTrim.EqualsOrdinal(numfmt.PositiveInfinitySymbol))
+                if (sTrim.EqualsOrdinal(info.PositiveInfinitySymbol))
                 {
                     return float.PositiveInfinity;
                 }
-                if (sTrim.EqualsOrdinal(numfmt.NegativeInfinitySymbol))
+                if (sTrim.EqualsOrdinal(info.NegativeInfinitySymbol))
                 {
                     return float.NegativeInfinity;
                 }
-                if (sTrim.EqualsOrdinal(numfmt.NaNSymbol))
+                if (sTrim.EqualsOrdinal(info.NaNSymbol))
                 {
                     return float.NaN;
                 }
-                throw new FormatException(SR.Format_InvalidString);
+                ThrowOverflowOrFormatException(overflow: false, null);
             }

             if (!NumberBufferToDouble(ref number, ref d))
             {
-                throw new OverflowException(SR.Overflow_Single);
+                ThrowOverflowOrFormatException(overflow: true, nameof(SR.Overflow_Single));
             }
             float castSingle = (float)d;
             if (float.IsInfinity(castSingle))
             {
-                throw new OverflowException(SR.Overflow_Single);
+                ThrowOverflowOrFormatException(overflow: true, nameof(SR.Overflow_Single));
             }
             return castSingle;
         }

-        internal static unsafe bool TryParseDecimal(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt, out decimal result)
+        internal static bool TryParseDecimal(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out decimal result)
         {
             NumberBuffer number = default;
             result = 0;

-            if (!TryStringToNumber(value, options, ref number, numfmt, true))
+            if (!TryStringToNumber(value, styles, ref number, info, true))
             {
                 return false;
             }
@@ -1508,13 +1555,12 @@
             return true;
         }

-        internal static unsafe bool TryParseDouble(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt, out double result)
+        internal static bool TryParseDouble(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out double result)
         {
             NumberBuffer number = default;
             result = 0;

-
-            if (!TryStringToNumber(value, options, ref number, numfmt, false))
+            if (!TryStringToNumber(value, styles, ref number, info, false))
             {
                 return false;
             }
@@ -1525,13 +1571,13 @@
             return true;
         }

-        internal static unsafe bool TryParseSingle(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt, out float result)
+        internal static bool TryParseSingle(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out float result)
         {
             NumberBuffer number = default;
             result = 0;
             double d = 0;

-            if (!TryStringToNumber(value, options, ref number, numfmt, false))
+            if (!TryStringToNumber(value, styles, ref number, info, false))
             {
                 return false;
             }
@@ -1549,28 +1595,28 @@
             return true;
         }

-        private static unsafe void StringToNumber(ReadOnlySpan<char> str, NumberStyles options, ref NumberBuffer number, NumberFormatInfo info, bool parseDecimal)
+        private static unsafe void StringToNumber(ReadOnlySpan<char> value, NumberStyles styles, ref NumberBuffer number, NumberFormatInfo info, bool parseDecimal)
         {
             Debug.Assert(info != null);
-            fixed (char* stringPointer = &MemoryMarshal.GetReference(str))
+            fixed (char* stringPointer = &MemoryMarshal.GetReference(value))
             {
                 char* p = stringPointer;
-                if (!ParseNumber(ref p, p + str.Length, options, ref number, info, parseDecimal)
-                    || (p - stringPointer < str.Length && !TrailingZeros(str, (int)(p - stringPointer))))
-                {
-                    throw new FormatException(SR.Format_InvalidString);
-                }
-            }
-        }
-
-        internal static unsafe bool TryStringToNumber(ReadOnlySpan<char> str, NumberStyles options, ref NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal)
-        {
-            Debug.Assert(numfmt != null);
-            fixed (char* stringPointer = &MemoryMarshal.GetReference(str))
+                if (!ParseNumber(ref p, p + value.Length, styles, ref number, info, parseDecimal)
+                    || (p - stringPointer < value.Length && !TrailingZeros(value, (int)(p - stringPointer))))
+                {
+                    ThrowOverflowOrFormatException(overflow: false, null);
+                }
+            }
+        }
+
+        internal static unsafe bool TryStringToNumber(ReadOnlySpan<char> value, NumberStyles styles, ref NumberBuffer number, NumberFormatInfo info, bool parseDecimal)
+        {
+            Debug.Assert(info != null);
+            fixed (char* stringPointer = &MemoryMarshal.GetReference(value))
             {
                 char* p = stringPointer;
-                if (!ParseNumber(ref p, p + str.Length, options, ref number, numfmt, parseDecimal)
-                    || (p - stringPointer < str.Length && !TrailingZeros(str, (int)(p - stringPointer))))
+                if (!ParseNumber(ref p, p + value.Length, styles, ref number, info, parseDecimal)
+                    || (p - stringPointer < value.Length && !TrailingZeros(value, (int)(p - stringPointer))))
                 {
                     return false;
                 }
@@ -1579,12 +1625,12 @@
             return true;
         }

-        private static bool TrailingZeros(ReadOnlySpan<char> s, int index)
+        private static bool TrailingZeros(ReadOnlySpan<char> value, int index)
         {
             // For compatibility, we need to allow trailing zeros at the end of a number string
-            for (int i = index; i < s.Length; i++)
-            {
-                if (s[i] != '\0')
+            for (int i = index; i < value.Length; i++)
+            {
+                if (value[i] != '\0')
                 {
                     return false;
                 }
@@ -1593,36 +1639,29 @@
             return true;
         }

-        private static unsafe char* MatchChars(char* p, char* pEnd, string str)
-        {
-            fixed (char* stringPointer = str)
-            {
-                return MatchChars(p, pEnd, stringPointer);
-            }
-        }
-
-        private static unsafe char* MatchChars(char* p, char* pEnd, char* str)
-        {
-            Debug.Assert(p != null && pEnd != null && p <= pEnd && str != null);
-
-            if (*str == '\0')
-            {
-                return null;
-            }
-
-            // 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 (true)
-            {
-                char cp = p < pEnd ? *p : '\0';
-                if (cp != *str && !(*str == '\u00a0' && cp == '\u0020'))
-                {
-                    break;
-                }
-                p++;
-                str++;
-                if (*str == '\0') return p;
+        private static unsafe char* MatchChars(char* p, char* pEnd, string value)
+        {
+            Debug.Assert(p != null && pEnd != null && p <= pEnd && value != null);
+            fixed (char* stringPointer = value)
+            {
+                char* str = stringPointer;
+                if (*str != '\0')
+                {
+                    // 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 (true)
+                    {
+                        char cp = p < pEnd ? *p : '\0';
+                        if (cp != *str && !(*str == '\u00a0' && cp == '\u0020'))
+                        {
+                            break;
+                        }
+                        p++;
+                        str++;
+                        if (*str == '\0') return p;
+                    }
+                }
             }

             return null;
@@ -1632,10 +1671,17 @@

         private static bool IsDigit(int ch) => ((uint)ch - '0') <= 9;

+        private static void ThrowOverflowOrFormatException(bool overflow, string overflowResourceKey)
+        {
+            throw overflow ?
+               new OverflowException(SR.GetResourceString(overflowResourceKey)) :
+               (Exception)new FormatException(SR.Format_InvalidString);
+        }
+
         private static bool NumberBufferToDouble(ref NumberBuffer number, ref double value)
         {
             double d = NumberToDouble(ref number);
-            if (!Double.IsFinite(d))
+            if (!double.IsFinite(d))
             {
                 value = default;
                 return false;


Fix GatewayRateLimiter not waiting long enough

--- src/Discore/WebSocket/Net/GatewayRateLimiter.cs
+++ src/Discore/WebSocket/Net/GatewayRateLimiter.cs
@@ -17,15 +17,8 @@
         public GatewayRateLimiter(int resetTimeSeconds, int maxInvokes)
         {
             this.maxInvokes = maxInvokes;
-
             resetTime = TimeSpan.FromSeconds(resetTimeSeconds);

-            Reset();
-        }
-
-        void Reset()
-        {
-            resetAt = DateTime.Now + resetTime;
             invokesLeft = maxInvokes;
         }

@@ -36,18 +29,26 @@
         /// <exception cref="OperationCanceledException"></exception>
         public async Task Invoke(CancellationToken? cancellationToken = null)
         {
+            DateTime now = DateTime.Now;
+            if (now >= resetAt)
+                invokesLeft = maxInvokes;
+
             if (invokesLeft > 0)
+            {
+                if (invokesLeft == maxInvokes)
+                    resetAt = DateTime.Now + resetTime;
+
                 invokesLeft--;
+            }
             else
             {
                 CancellationToken ct = cancellationToken ?? CancellationToken.None;

-                int waitTimeMs = (int)Math.Ceiling((resetAt - DateTime.Now).TotalMilliseconds);
+                int waitTimeMs = (int)Math.Ceiling((resetAt - now).TotalMilliseconds);
                 if (waitTimeMs > 0)
                     await Task.Delay(waitTimeMs, ct).ConfigureAwait(false);

-                Reset();
-                invokesLeft--;
+                invokesLeft = maxInvokes - 1;
             }
         }
     }


Refactor out decompilation for schedules

--- src/ContentCompiler/Program.cs
+++ src/ContentCompiler/Program.cs
@@ -55,71 +55,6 @@

             //content.Load<Dictionary<string,string>>("characters\\schedules\\leah").Dump();
         }
-    }
-    static class Extensions
-    {
-        public static int? GetInt(this string value)
-        {
-            int result;
-            if (int.TryParse(value, out result))
-                return result;
-            return null;
-        }
-    }
-    class Game1 : Microsoft.Xna.Framework.Game
-    {
-    }
-    class Schedule
-    {
-        public static Schedule Decompile(Dictionary<string,string> content, string character)
-        {
-                var schedule = new Schedule() { Character = character };
-            foreach (var keyPair in content)
-                {
-                    if (keyPair.Key.EndsWith("_Replacement"))
-                        continue;
-                    var value = keyPair.Value;
-                    schedule.ScheduledItems.Add(new Schedule.ScheduleItem()
-                    {
-                        Key = keyPair.Key
-                    });
-                    if (value.StartsWith("NOT"))
-                    {
-                        var pieces = value.Split('/')[0].Split(' ');
-                        schedule.ScheduledItems.Last().Condition = new Schedule.ScheduleItem.NotCondition()
-                        {
-                            Type = pieces[1],
-                            Name = pieces[2],
-                            Level = int.Parse(pieces[3]),
-                        };
-                        value = string.Join("/", value.Split('/').Skip(1));
-                    }
-                    if (value.StartsWith("GOTO"))
-                    {
-                        schedule.ScheduledItems.Last().GotoKey = keyPair.Value.Substring(5);
-                        continue;
-                    }
-                    var items = value.Split('/');
-                    foreach(var item in items)
-                    {
-                        var pieces = item.Split(' ');
-                        schedule.ScheduledItems.Last().TargetLocations.Add(new Schedule.ScheduleItem.TargetLocationTime()
-                        {
-                            Time = int.Parse(pieces[0]),
-                            Location = pieces[1],
-                            X = int.Parse(pieces[2]),
-                            Y = int.Parse(pieces[3]),
-                        Direction = pieces[4].GetInt() ?? 2,
-                        });
-                    }
-                    Console.WriteLine(keyPair.Key);
-                    Console.WriteLine(keyPair.Value);
-                }
-                File.WriteAllText(Path.Combine(root, "characters\\schedules", character) + ".json", JsonConvert.SerializeObject(schedule, Formatting.Indented));
-            }
-
-            //content.Load<Dictionary<string,string>>("characters\\schedules\\leah").Dump();
-        }

         static void DecompilePortraits(string root)
         {
@@ -137,20 +72,72 @@
                 }
             }
         }
-
-        static int? GetInt(string value)
+    }
+    static class Extensions
+    {
+        public static int? GetInt(this string value)
         {
             int result;
             if (int.TryParse(value, out result))
                 return result;
             return null;
         }
+    }
+    class Game1 : Microsoft.Xna.Framework.Game
+    {
+    }
+    class Schedule
+    {
+        public static Schedule Decompile(Dictionary<string, string> content, string character)
+        {
+            var schedule = new Schedule() { Character = character };
+            foreach (var keyPair in content)
+            {
+                if (keyPair.Key.EndsWith("_Replacement"))
+                    continue;
+                var value = keyPair.Value;
+                schedule.ScheduledItems.Add(new Schedule.ScheduleItem()
+                {
+                    Key = keyPair.Key
+                });
+                if (value.StartsWith("NOT"))
+                {
+                    var pieces = value.Split('/')[0].Split(' ');
+                    schedule.ScheduledItems.Last().Condition = new Schedule.ScheduleItem.NotCondition()
+                    {
+                        Type = pieces[1],
+                        Name = pieces[2],
+                        Level = int.Parse(pieces[3]),
+                    };
+                    value = string.Join("/", value.Split('/').Skip(1));
+                }
+                if (value.StartsWith("GOTO"))
+                {
+                    schedule.ScheduledItems.Last().GotoKey = keyPair.Value.Substring(5);
+                    continue;
+                }
+                var items = value.Split('/');
+                foreach (var item in items)
+                {
+                    var pieces = item.Split(' ');
+                    schedule.ScheduledItems.Last().TargetLocations.Add(new Schedule.ScheduleItem.TargetLocationTime()
+                    {
+                        Time = int.Parse(pieces[0]),
+                        Location = pieces[1],
+                        X = int.Parse(pieces[2]),
+                        Y = int.Parse(pieces[3]),
+                        Direction = pieces[4].GetInt() ?? 2,
+                    });
+                }
+                Console.WriteLine(keyPair.Key);
+                Console.WriteLine(keyPair.Value);
+            }
             return schedule;
-    }
+        }
         public Dictionary<string, string> Compile()
-    {
+        {
             throw new NotImplementedException();
-    }
+        }
         public class ScheduleItem
         {
             public class TargetLocationTime


After handling an error of a message, it is dequeued

--- src/Eventing.OfflineClient/OfflineClientBase.cs
+++ src/Eventing.OfflineClient/OfflineClientBase.cs
@@ -126,6 +126,7 @@
                 {
                     this.log.Error(ex, $"An error ocurred while trying to send pending message. The client will continue to send messages...");
                     this.onPendingError(ex);
+                    this.queue.Dequeue();
                 }
             }
         }


Reenable DTO creation

Reenable DTO creation

--- src/Bix/Mixers/CecilMixer/EncapsulateMixing/EncapsulateMixer.cs
+++ src/Bix/Mixers/CecilMixer/EncapsulateMixing/EncapsulateMixer.cs
@@ -61,7 +61,7 @@
             Contract.Requires(target != null);

             new InterfaceMixCommand<IEncapsulates, EncapsulateSource>(target).Mix();
-            //AddDataTransferObject(target);
+            AddDataTransferObject(target);
         }

         private static void AddDataTransferObject(TypeDefinition target)