Decompiled source of ZString v2.6.1
BepInEx/core/ZString/netstandard2.1/ZString.dll
Decompiled 5 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Buffers; using System.Buffers.Text; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("ConsoleApp, PublicKey=00240000048000009400000006020000002400005253413100040000010001000144ec28f1e9ef7b17dacc47425a7a153aea0a7baa590743a2d1a86f4b3e10a8a12712c6e647966bfd8bd6e830048b23bd42bbc56f179585c15b8c19cf86c0eed1b73c993dd7a93a30051dd50fdda0e4d6b65e6874e30f1c37cf8bcbc7fe02c7f2e6a0a3327c0ccc1631bf645f40732521fa0b41a30c178d08f7dd779d42a1ee")] [assembly: InternalsVisibleTo("ConsoleAppNet472, PublicKey=00240000048000009400000006020000002400005253413100040000010001000144ec28f1e9ef7b17dacc47425a7a153aea0a7baa590743a2d1a86f4b3e10a8a12712c6e647966bfd8bd6e830048b23bd42bbc56f179585c15b8c19cf86c0eed1b73c993dd7a93a30051dd50fdda0e4d6b65e6874e30f1c37cf8bcbc7fe02c7f2e6a0a3327c0ccc1631bf645f40732521fa0b41a30c178d08f7dd779d42a1ee")] [assembly: InternalsVisibleTo("ZString.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001000144ec28f1e9ef7b17dacc47425a7a153aea0a7baa590743a2d1a86f4b3e10a8a12712c6e647966bfd8bd6e830048b23bd42bbc56f179585c15b8c19cf86c0eed1b73c993dd7a93a30051dd50fdda0e4d6b65e6874e30f1c37cf8bcbc7fe02c7f2e6a0a3327c0ccc1631bf645f40732521fa0b41a30c178d08f7dd779d42a1ee")] [assembly: InternalsVisibleTo("ZString.NetCore2Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001000144ec28f1e9ef7b17dacc47425a7a153aea0a7baa590743a2d1a86f4b3e10a8a12712c6e647966bfd8bd6e830048b23bd42bbc56f179585c15b8c19cf86c0eed1b73c993dd7a93a30051dd50fdda0e4d6b65e6874e30f1c37cf8bcbc7fe02c7f2e6a0a3327c0ccc1631bf645f40732521fa0b41a30c178d08f7dd779d42a1ee")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Cysharp")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("© Cysharp, Inc.")] [assembly: AssemblyDescription("Zero allocation StringBuilder for .NET Core and Unity.")] [assembly: AssemblyFileVersion("2.6.0.0")] [assembly: AssemblyInformationalVersion("2.6.0+3156134075b89a162fe95350a2e92a4c85ccca59")] [assembly: AssemblyProduct("ZString")] [assembly: AssemblyTitle("ZString")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Cysharp/ZString")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.6.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace System { internal static class BufferEx { internal unsafe static void ZeroMemory(byte* dest, uint len) { if (len != 0) { for (int i = 0; i < len; i++) { dest[i] = 0; } } } internal unsafe static void Memcpy(byte* dest, byte* src, int len) { if (len != 0) { for (int i = 0; i < len; i++) { dest[i] = src[i]; } } } } internal static class DecimalEx { [StructLayout(LayoutKind.Explicit)] private struct DecimalBits { [FieldOffset(0)] public int flags; [FieldOffset(4)] public int hi; [FieldOffset(8)] public int lo; [FieldOffset(12)] public int mid; } [StructLayout(LayoutKind.Explicit)] private struct DecCalc { private const uint TenToPowerNine = 1000000000u; [FieldOffset(0)] public uint uflags; [FieldOffset(4)] public uint uhi; [FieldOffset(8)] public uint ulo; [FieldOffset(12)] public uint umid; [FieldOffset(8)] private ulong ulomidLE; internal static uint DecDivMod1E9(ref DecCalc value) { ulong num = ((ulong)value.uhi << 32) + value.umid; ulong num2 = num / 1000000000; value.uhi = (uint)(num2 >> 32); value.umid = (uint)num2; ulong num3 = (num - (uint)((int)num2 * 1000000000) << 32) + value.ulo; return (uint)(int)num3 - (value.ulo = (uint)(num3 / 1000000000)) * 1000000000; } } private const int ScaleShift = 16; private static ref DecCalc AsMutable(ref decimal d) { return ref Unsafe.As<decimal, DecCalc>(ref d); } internal static uint High(this decimal value) { return Unsafe.As<decimal, DecCalc>(ref value).uhi; } internal static uint Low(this decimal value) { return Unsafe.As<decimal, DecCalc>(ref value).ulo; } internal static uint Mid(this decimal value) { return Unsafe.As<decimal, DecCalc>(ref value).umid; } internal static bool IsNegative(this decimal value) { return Unsafe.As<decimal, DecimalBits>(ref value).flags < 0; } internal static int Scale(this decimal value) { return (byte)(Unsafe.As<decimal, DecimalBits>(ref value).flags >> 16); } internal static uint DecDivMod1E9(ref decimal value) { return DecCalc.DecDivMod1E9(ref AsMutable(ref value)); } } internal static class FloatEx { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(double d) { return (BitConverter.DoubleToInt64Bits(d) & 0x7FFFFFFFFFFFFFFFL) < 9218868437227405312L; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegative(double d) { return BitConverter.DoubleToInt64Bits(d) < 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(float f) { return (SingleToInt32Bits(f) & 0x7FFFFFFF) < 2139095040; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegative(float f) { return SingleToInt32Bits(f) < 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static int SingleToInt32Bits(float value) { return *(int*)(&value); } } internal struct GuidEx { private int _a; private short _b; private short _c; private byte _d; private byte _e; private byte _f; private byte _g; private byte _h; private byte _i; private byte _j; private byte _k; private unsafe static int HexsToChars(char* guidChars, int a, int b) { *guidChars = System.HexConverter.ToCharLower(a >> 4); guidChars[1] = System.HexConverter.ToCharLower(a); guidChars[2] = System.HexConverter.ToCharLower(b >> 4); guidChars[3] = System.HexConverter.ToCharLower(b); return 4; } private unsafe static int HexsToCharsHexOutput(char* guidChars, int a, int b) { *guidChars = '0'; guidChars[1] = 'x'; guidChars[2] = System.HexConverter.ToCharLower(a >> 4); guidChars[3] = System.HexConverter.ToCharLower(a); guidChars[4] = ','; guidChars[5] = '0'; guidChars[6] = 'x'; guidChars[7] = System.HexConverter.ToCharLower(b >> 4); guidChars[8] = System.HexConverter.ToCharLower(b); return 9; } public unsafe bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default(ReadOnlySpan<char>)) { if (format.Length == 0) { format = "D".AsSpan(); } if (format.Length != 1) { throw new FormatException("InvalidGuidFormatSpecification"); } bool flag = true; bool flag2 = false; int num = 0; int num2; switch (format[0]) { case 'D': case 'd': num2 = 36; break; case 'N': case 'n': flag = false; num2 = 32; break; case 'B': case 'b': num = 8192123; num2 = 38; break; case 'P': case 'p': num = 2687016; num2 = 38; break; case 'X': case 'x': num = 8192123; flag = false; flag2 = true; num2 = 68; break; default: throw new FormatException("InvalidGuidFormatSpecification"); } if (destination.Length < num2) { charsWritten = 0; return false; } fixed (char* ptr = &MemoryMarshal.GetReference(destination)) { char* ptr2 = ptr; if (num != 0) { *(ptr2++) = (char)num; } if (flag2) { *(ptr2++) = '0'; *(ptr2++) = 'x'; ptr2 += HexsToChars(ptr2, _a >> 24, _a >> 16); ptr2 += HexsToChars(ptr2, _a >> 8, _a); *(ptr2++) = ','; *(ptr2++) = '0'; *(ptr2++) = 'x'; ptr2 += HexsToChars(ptr2, _b >> 8, _b); *(ptr2++) = ','; *(ptr2++) = '0'; *(ptr2++) = 'x'; ptr2 += HexsToChars(ptr2, _c >> 8, _c); *(ptr2++) = ','; *(ptr2++) = '{'; ptr2 += HexsToCharsHexOutput(ptr2, _d, _e); *(ptr2++) = ','; ptr2 += HexsToCharsHexOutput(ptr2, _f, _g); *(ptr2++) = ','; ptr2 += HexsToCharsHexOutput(ptr2, _h, _i); *(ptr2++) = ','; ptr2 += HexsToCharsHexOutput(ptr2, _j, _k); *(ptr2++) = '}'; } else { ptr2 += HexsToChars(ptr2, _a >> 24, _a >> 16); ptr2 += HexsToChars(ptr2, _a >> 8, _a); if (flag) { *(ptr2++) = '-'; } ptr2 += HexsToChars(ptr2, _b >> 8, _b); if (flag) { *(ptr2++) = '-'; } ptr2 += HexsToChars(ptr2, _c >> 8, _c); if (flag) { *(ptr2++) = '-'; } ptr2 += HexsToChars(ptr2, _d, _e); if (flag) { *(ptr2++) = '-'; } ptr2 += HexsToChars(ptr2, _f, _g); ptr2 += HexsToChars(ptr2, _h, _i); ptr2 += HexsToChars(ptr2, _j, _k); } if (num != 0) { *(ptr2++) = (char)(num >> 16); } } charsWritten = num2; return true; } } internal static class HexConverter { public enum Casing : uint { Upper = 0u, Lower = 8224u } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToBytesBuffer(byte value, Span<byte> buffer, int startingIndex = 0, Casing casing = Casing.Upper) { uint num = (uint)(((value & 0xF0) << 4) + (value & 0xF) - 35209); uint num2 = ((((0 - num) & 0x7070) >> 4) + num + 47545) | (uint)casing; buffer[startingIndex + 1] = (byte)num2; buffer[startingIndex] = (byte)(num2 >> 8); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToCharsBuffer(byte value, Span<char> buffer, int startingIndex = 0, Casing casing = Casing.Upper) { uint num = (uint)(((value & 0xF0) << 4) + (value & 0xF) - 35209); uint num2 = ((((0 - num) & 0x7070) >> 4) + num + 47545) | (uint)casing; buffer[startingIndex + 1] = (char)(num2 & 0xFFu); buffer[startingIndex] = (char)(num2 >> 8); } public static string ToString(ReadOnlySpan<byte> bytes, Casing casing = Casing.Upper) { Span<char> span = default(Span<char>); span = ((bytes.Length <= 16) ? stackalloc char[bytes.Length * 2] : new char[bytes.Length * 2].AsSpan()); int num = 0; ReadOnlySpan<byte> readOnlySpan = bytes; for (int i = 0; i < readOnlySpan.Length; i++) { ToCharsBuffer(readOnlySpan[i], span, num, casing); num += 2; } return span.ToString(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static char ToCharUpper(int value) { value &= 0xF; value += 48; if (value > 57) { value += 7; } return (char)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static char ToCharLower(int value) { value &= 0xF; value += 48; if (value > 57) { value += 39; } return (char)value; } } internal static class InternalSpanEx { [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool EqualsOrdinalIgnoreCase(this ReadOnlySpan<char> span, ReadOnlySpan<char> value) { if (span.Length != value.Length) { return false; } if (value.Length == 0) { return true; } return EqualsOrdinalIgnoreCase(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), span.Length); } private static bool EqualsOrdinalIgnoreCase(ref char charA, ref char charB, int length) { IntPtr zero = IntPtr.Zero; if (IntPtr.Size == 8) { while ((uint)length >= 4u) { ulong num = Unsafe.ReadUnaligned<ulong>(ref Unsafe.As<char, byte>(ref Unsafe.AddByteOffset(ref charA, zero))); ulong num2 = Unsafe.ReadUnaligned<ulong>(ref Unsafe.As<char, byte>(ref Unsafe.AddByteOffset(ref charB, zero))); ulong num3 = num | num2; if (AllCharsInUInt32AreAscii((uint)((int)num3 | (int)(num3 >> 32)))) { if (!UInt64OrdinalIgnoreCaseAscii(num, num2)) { return false; } zero += 8; length -= 4; continue; } goto IL_0101; } } while (true) { switch (length) { default: { uint num6 = Unsafe.ReadUnaligned<uint>(ref Unsafe.As<char, byte>(ref Unsafe.AddByteOffset(ref charA, zero))); uint num7 = Unsafe.ReadUnaligned<uint>(ref Unsafe.As<char, byte>(ref Unsafe.AddByteOffset(ref charB, zero))); if (AllCharsInUInt32AreAscii(num6 | num7)) { if (UInt32OrdinalIgnoreCaseAscii(num6, num7)) { goto IL_00aa; } return false; } break; } case 1: { uint num4 = Unsafe.AddByteOffset(ref charA, zero); uint num5 = Unsafe.AddByteOffset(ref charB, zero); if ((num4 | num5) <= 127) { if (num4 == num5) { return true; } num4 |= 0x20u; if (num4 - 97 > 25) { return false; } return num4 == (num5 | 0x20); } break; } case 0: return true; } break; IL_00aa: zero += 4; length -= 2; } goto IL_0101; IL_0101: return EqualsOrdinalIgnoreCaseNonAscii(ref Unsafe.AddByteOffset(ref charA, zero), ref Unsafe.AddByteOffset(ref charB, zero), length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool AllCharsInUInt32AreAscii(uint value) { return (value & 0xFF80FF80u) == 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool AllCharsInUInt64AreAscii(ulong value) { return (value & 0xFF80FF80FF80FF80uL) == 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool UInt32OrdinalIgnoreCaseAscii(uint valueA, uint valueB) { uint num = valueA ^ valueB; uint num2 = valueA + 16777472 - 4259905; uint num3 = (valueA | 0x200020) + 8388736 - 8061051; return ((((num2 | num3) >> 2) | 0xFFDFFFDFu) & num) == 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool UInt64OrdinalIgnoreCaseAscii(ulong valueA, ulong valueB) { ulong num = valueA + 36029346783166592L - 18296152663326785L; ulong num2 = (valueA | 0x20002000200020L) + 72058693566333184L - 34621950424449147L; ulong num3 = (0x80008000800080L & num & num2) >> 2; return (valueA | num3) == (valueB | num3); } private static bool EqualsOrdinalIgnoreCaseNonAscii(ref char charA, ref char charB, int length) { IntPtr zero = IntPtr.Zero; while (length != 0) { uint num = Unsafe.AddByteOffset(ref charA, zero); uint num2 = Unsafe.AddByteOffset(ref charB, zero); if (num == num2 || ((num | 0x20) == (num2 | 0x20) && (num | 0x20) - 97 <= 25)) { zero += 2; length--; continue; } return false; } return true; } } internal static class MathEx { public static uint DivRem(uint a, uint b, out uint result) { uint num = a / b; result = a - num * b; return num; } public static ulong DivRem(ulong a, ulong b, out ulong result) { ulong num = a / b; result = a - num * b; return num; } public static int DivRem(int a, int b, out int result) { int num = a / b; result = a - num * b; return num; } public static long DivRem(long a, long b, out long result) { long num = a / b; result = a - num * b; return num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Clamp(byte value, byte min, byte max) { if (min > max) { ThrowMinMaxException(min, max); } if (value < min) { return min; } if (value > max) { return max; } return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Clamp(decimal value, decimal min, decimal max) { if (min > max) { ThrowMinMaxException(min, max); } if (value < min) { return min; } if (value > max) { return max; } return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Clamp(double value, double min, double max) { if (min > max) { ThrowMinMaxException(min, max); } if (value < min) { return min; } if (value > max) { return max; } return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Clamp(short value, short min, short max) { if (min > max) { ThrowMinMaxException(min, max); } if (value < min) { return min; } if (value > max) { return max; } return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Clamp(int value, int min, int max) { if (min > max) { ThrowMinMaxException(min, max); } if (value < min) { return min; } if (value > max) { return max; } return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Clamp(long value, long min, long max) { if (min > max) { ThrowMinMaxException(min, max); } if (value < min) { return min; } if (value > max) { return max; } return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Clamp(sbyte value, sbyte min, sbyte max) { if (min > max) { ThrowMinMaxException(min, max); } if (value < min) { return min; } if (value > max) { return max; } return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Clamp(float value, float min, float max) { if (min > max) { ThrowMinMaxException(min, max); } if (value < min) { return min; } if (value > max) { return max; } return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Clamp(ushort value, ushort min, ushort max) { if (min > max) { ThrowMinMaxException(min, max); } if (value < min) { return min; } if (value > max) { return max; } return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Clamp(uint value, uint min, uint max) { if (min > max) { ThrowMinMaxException(min, max); } if (value < min) { return min; } if (value > max) { return max; } return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Clamp(ulong value, ulong min, ulong max) { if (min > max) { ThrowMinMaxException(min, max); } if (value < min) { return min; } if (value > max) { return max; } return value; } private static void ThrowMinMaxException<T>(T min, T max) { throw new ArgumentException($"Argument_MinMaxValue, min:{min} max:{max}"); } } internal static class Number { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal ref struct BigInteger { private const int BitsForLongestBinaryMantissa = 1074; private const int BitsForLongestDigitSequence = 2552; private const int MaxBits = 3658; private const int BitsPerBlock = 32; private const int MaxBlockCount = 115; private static readonly uint[] s_Pow10UInt32Table = new uint[8] { 1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u, 10000000u }; private static readonly int[] s_Pow10BigNumTableIndices = new int[8] { 0, 2, 5, 10, 18, 33, 61, 116 }; private static readonly uint[] s_Pow10BigNumTable = new uint[233] { 1u, 100000000u, 2u, 1874919424u, 2328306u, 4u, 0u, 2242703233u, 762134875u, 1262u, 7u, 0u, 0u, 3211403009u, 1849224548u, 3668416493u, 3913284084u, 1593091u, 14u, 0u, 0u, 0u, 0u, 781532673u, 64985353u, 253049085u, 594863151u, 3553621484u, 3288652808u, 3167596762u, 2788392729u, 3911132675u, 590u, 27u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 2553183233u, 3201533787u, 3638140786u, 303378311u, 1809731782u, 3477761648u, 3583367183u, 649228654u, 2915460784u, 487929380u, 1011012442u, 1677677582u, 3428152256u, 1710878487u, 1438394610u, 2161952759u, 4100910556u, 1608314830u, 349175u, 54u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 4234999809u, 2012377703u, 2408924892u, 1570150255u, 3090844311u, 3273530073u, 1187251475u, 2498123591u, 3364452033u, 1148564857u, 687371067u, 2854068671u, 1883165473u, 505794538u, 2988060450u, 3159489326u, 2531348317u, 3215191468u, 849106862u, 3892080979u, 3288073877u, 2242451748u, 4183778142u, 2995818208u, 2477501924u, 325481258u, 2487842652u, 1774082830u, 1933815724u, 2962865281u, 1168579910u, 2724829000u, 2360374019u, 2315984659u, 2360052375u, 3251779801u, 1664357844u, 28u, 107u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 689565697u, 4116392818u, 1853628763u, 516071302u, 2568769159u, 365238920u, 336250165u, 1283268122u, 3425490969u, 248595470u, 2305176814u, 2111925499u, 507770399u, 2681111421u, 589114268u, 591287751u, 1708941527u, 4098957707u, 475844916u, 3378731398u, 2452339615u, 2817037361u, 2678008327u, 1656645978u, 2383430340u, 73103988u, 448667107u, 2329420453u, 3124020241u, 3625235717u, 3208634035u, 2412059158u, 2981664444u, 4117622508u, 838560765u, 3069470027u, 270153238u, 1802868219u, 3692709886u, 2161737865u, 2159912357u, 2585798786u, 837488486u, 4237238160u, 2540319504u, 3798629246u, 3748148874u, 1021550776u, 2386715342u, 1973637538u, 1823520457u, 1146713475u, 833971519u, 3277251466u, 905620390u, 26278816u, 2680483154u, 2294040859u, 373297482u, 5996609u, 4109575006u, 512575049u, 917036550u, 1942311753u, 2816916778u, 3248920332u, 1192784020u, 3537586671u, 2456567643u, 2925660628u, 759380297u, 888447942u, 3559939476u, 3654687237u, 805u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u }; private int _length; private unsafe fixed uint _blocks[115]; public unsafe static void Add(ref BigInteger lhs, ref BigInteger rhs, out BigInteger result) { ref BigInteger reference = ref lhs._length < rhs._length ? ref rhs : ref lhs; ref BigInteger reference2 = ref lhs._length < rhs._length ? ref lhs : ref rhs; int length = reference._length; int length2 = reference2._length; result._length = length; ulong num = 0uL; int num2 = 0; int num3 = 0; int num4 = 0; while (num3 < length2) { ulong num5 = num + reference._blocks[num2] + reference2._blocks[num3]; num = num5 >> 32; result._blocks[num4] = (uint)num5; num2++; num3++; num4++; } while (num2 < length) { ulong num6 = num + reference._blocks[num2]; num = num6 >> 32; result._blocks[num4] = (uint)num6; num2++; num4++; } if (num != 0L) { result._blocks[num4] = 1u; result._length++; } } public unsafe static int Compare(ref BigInteger lhs, ref BigInteger rhs) { int length = lhs._length; int length2 = rhs._length; int num = length - length2; if (num != 0) { return num; } if (length == 0) { return 0; } for (int num2 = length - 1; num2 >= 0; num2--) { long num3 = (long)lhs._blocks[num2] - (long)rhs._blocks[num2]; if (num3 != 0L) { if (num3 <= 0) { return -1; } return 1; } } return 0; } public static uint CountSignificantBits(uint value) { return (uint)(32 - BitOperations.LeadingZeroCount(value)); } public static uint CountSignificantBits(ulong value) { return (uint)(64 - BitOperations.LeadingZeroCount(value)); } public unsafe static uint CountSignificantBits(ref BigInteger value) { if (value.IsZero()) { return 0u; } uint num = (uint)(value._length - 1); return num * 32 + CountSignificantBits(value._blocks[num]); } public unsafe static void DivRem(ref BigInteger lhs, ref BigInteger rhs, out BigInteger quo, out BigInteger rem) { if (lhs.IsZero()) { SetZero(out quo); SetZero(out rem); return; } int length = lhs._length; int length2 = rhs._length; if (length == 1 && length2 == 1) { uint result; uint value = MathEx.DivRem(lhs._blocks[0], rhs._blocks[0], out result); SetUInt32(out quo, value); SetUInt32(out rem, result); return; } if (length2 == 1) { int num = length; ulong b = rhs._blocks[0]; ulong result2 = 0uL; for (int num2 = num - 1; num2 >= 0; num2--) { ulong num3 = MathEx.DivRem((result2 << 32) | lhs._blocks[num2], b, out result2); if (num3 == 0L && num2 == num - 1) { num--; } else { quo._blocks[num2] = (uint)num3; } } quo._length = num; SetUInt32(out rem, (uint)result2); return; } if (length2 > length) { SetZero(out quo); SetValue(out rem, ref lhs); return; } int num4 = length - length2 + 1; SetValue(out rem, ref lhs); int num5 = length; uint num6 = rhs._blocks[length2 - 1]; uint num7 = rhs._blocks[length2 - 2]; int num8 = BitOperations.LeadingZeroCount(num6); int num9 = 32 - num8; if (num8 > 0) { num6 = (num6 << num8) | (num7 >> num9); num7 <<= num8; if (length2 > 2) { num7 |= rhs._blocks[length2 - 3] >> num9; } } for (int num10 = length; num10 >= length2; num10--) { int num11 = num10 - length2; uint num12 = ((num10 < length) ? rem._blocks[num10] : 0u); ulong num13 = ((ulong)num12 << 32) | rem._blocks[num10 - 1]; uint num14 = ((num10 > 1) ? rem._blocks[num10 - 2] : 0u); if (num8 > 0) { num13 = (num13 << num8) | (num14 >> num9); num14 <<= num8; if (num10 > 2) { num14 |= rem._blocks[num10 - 3] >> num9; } } ulong num15 = num13 / num6; if (num15 > uint.MaxValue) { num15 = 4294967295uL; } while (DivideGuessTooBig(num15, num13, num14, num6, num7)) { num15--; } if (num15 != 0 && SubtractDivisor(ref rem, num11, ref rhs, num15) != num12) { AddDivisor(ref rem, num11, ref rhs); num15--; } if (num4 != 0) { if (num15 == 0L && num11 == num4 - 1) { num4--; } else { quo._blocks[num11] = (uint)num15; } } if (num10 < num5) { num5--; } } quo._length = num4; for (int num16 = num5 - 1; num16 >= 0; num16--) { if (rem._blocks[num16] == 0) { num5--; } } rem._length = num5; } public unsafe static uint HeuristicDivide(ref BigInteger dividend, ref BigInteger divisor) { int num = divisor._length; if (dividend._length < num) { return 0u; } int num2 = num - 1; uint num3 = dividend._blocks[num2] / (divisor._blocks[num2] + 1); if (num3 != 0) { int num4 = 0; ulong num5 = 0uL; ulong num6 = 0uL; do { ulong num7 = (ulong)((long)divisor._blocks[num4] * (long)num3) + num6; num6 = num7 >> 32; ulong num8 = (ulong)((long)dividend._blocks[num4] - (long)(uint)num7) - num5; num5 = (num8 >> 32) & 1; dividend._blocks[num4] = (uint)num8; num4++; } while (num4 < num); while (num > 0 && dividend._blocks[num - 1] == 0) { num--; } dividend._length = num; } if (Compare(ref dividend, ref divisor) >= 0) { num3++; int num9 = 0; ulong num10 = 0uL; do { ulong num11 = (ulong)((long)dividend._blocks[num9] - (long)divisor._blocks[num9]) - num10; num10 = (num11 >> 32) & 1; dividend._blocks[num9] = (uint)num11; num9++; } while (num9 < num); while (num > 0 && dividend._blocks[num - 1] == 0) { num--; } dividend._length = num; } return num3; } public unsafe static void Multiply(ref BigInteger lhs, uint value, out BigInteger result) { if (!lhs.IsZero()) { switch (value) { case 1u: break; case 0u: SetZero(out result); return; default: { int length = lhs._length; int i = 0; uint num = 0u; for (; i < length; i++) { ulong num2 = (ulong)((long)lhs._blocks[i] * (long)value + num); result._blocks[i] = (uint)num2; num = (uint)(num2 >> 32); } if (num != 0) { result._blocks[i] = num; result._length = length + 1; } else { result._length = length; } return; } } } SetValue(out result, ref lhs); } public unsafe static void Multiply(ref BigInteger lhs, ref BigInteger rhs, out BigInteger result) { if (lhs.IsZero() || rhs.IsOne()) { SetValue(out result, ref lhs); return; } if (rhs.IsZero()) { SetZero(out result); return; } ref BigInteger reference = ref lhs; int length = lhs._length; ref BigInteger reference2 = ref rhs; int length2 = rhs._length; if (length < length2) { reference = ref rhs; length = rhs._length; reference2 = ref lhs; length2 = lhs._length; } int num = (result._length = length2 + length); BufferEx.ZeroMemory((byte*)result.GetBlocksPointer(), (uint)(num * 4)); int num2 = 0; int num3 = 0; while (num2 < length2) { if (reference2._blocks[num2] != 0) { int num4 = 0; int num5 = num3; ulong num6 = 0uL; do { ulong num7 = (ulong)(result._blocks[num5] + (long)reference2._blocks[num2] * (long)reference._blocks[num4]) + num6; num6 = num7 >> 32; result._blocks[num5] = (uint)num7; num5++; num4++; } while (num4 < length); result._blocks[num5] = (uint)num6; } num2++; num3++; } if (num > 0 && result._blocks[num - 1] == 0) { result._length--; } } public unsafe static void Pow2(uint exponent, out BigInteger result) { uint remainder; uint num = DivRem32(exponent, out remainder); result._length = (int)(num + 1); if (num != 0) { BufferEx.ZeroMemory((byte*)result.GetBlocksPointer(), num * 4); } result._blocks[num] = (uint)(1 << (int)remainder); } public unsafe static void Pow10(uint exponent, out BigInteger result) { SetUInt32(out var result2, s_Pow10UInt32Table[exponent & 7]); ref BigInteger reference = ref result2; SetZero(out var result3); ref BigInteger reference2 = ref result3; exponent >>= 3; uint num = 0u; while (exponent != 0) { if ((exponent & (true ? 1u : 0u)) != 0) { fixed (uint* ptr = &s_Pow10BigNumTable[s_Pow10BigNumTableIndices[num]]) { Multiply(ref reference, ref *(BigInteger*)ptr, out reference2); } ref BigInteger reference3 = ref reference2; reference2 = ref reference; reference = ref reference3; } num++; exponent >>= 1; } SetValue(out result, ref reference); } private unsafe static uint AddDivisor(ref BigInteger lhs, int lhsStartIndex, ref BigInteger rhs) { int length = rhs._length; ulong num = 0uL; for (int i = 0; i < length; i++) { ref uint reference = ref lhs._blocks[lhsStartIndex + i]; ulong num2 = reference + num + rhs._blocks[i]; reference = (uint)num2; num = num2 >> 32; } return (uint)num; } private static bool DivideGuessTooBig(ulong q, ulong valHi, uint valLo, uint divHi, uint divLo) { ulong num = divHi * q; ulong num2 = divLo * q; num += num2 >> 32; num2 &= 0xFFFFFFFFu; if (num < valHi) { return false; } if (num > valHi) { return true; } if (num2 < valLo) { return false; } if (num2 > valLo) { return true; } return false; } private unsafe static uint SubtractDivisor(ref BigInteger lhs, int lhsStartIndex, ref BigInteger rhs, ulong q) { int length = rhs._length; ulong num = 0uL; for (int i = 0; i < length; i++) { num += rhs._blocks[i] * q; uint num2 = (uint)num; num >>= 32; ref uint reference = ref lhs._blocks[lhsStartIndex + i]; if (reference < num2) { num++; } reference -= num2; } return (uint)num; } public unsafe void Add(uint value) { int length = _length; if (length == 0) { SetUInt32(out this, value); return; } _blocks[0] += value; if (_blocks[0] >= value) { return; } for (int i = 1; i < length; i++) { ref uint reference = ref _blocks[i]; reference++; if (_blocks[i] != 0) { return; } } _blocks[length] = 1u; _length = length + 1; } public unsafe uint GetBlock(uint index) { return _blocks[index]; } public int GetLength() { return _length; } public unsafe bool IsOne() { if (_length == 1) { return _blocks[0] == 1; } return false; } public bool IsZero() { return _length == 0; } public void Multiply(uint value) { Multiply(ref this, value, out this); } public void Multiply(ref BigInteger value) { SetValue(out var result, ref this); Multiply(ref result, ref value, out this); } public unsafe void Multiply10() { if (!IsZero()) { int i = 0; int length = _length; ulong num = 0uL; for (; i < length; i++) { ulong num2 = _blocks[i]; ulong num3 = (num2 << 3) + (num2 << 1) + num; num = num3 >> 32; _blocks[i] = (uint)num3; } if (num != 0L) { _blocks[i] = (uint)num; _length++; } } } public unsafe void MultiplyPow10(uint exponent) { if (!IsZero()) { Pow10(exponent, out var result); if (result._length == 1) { Multiply(result._blocks[0]); } else { Multiply(ref result); } } } public unsafe static void SetUInt32(out BigInteger result, uint value) { if (value == 0) { SetZero(out result); return; } result._blocks[0] = value; result._length = 1; } public unsafe static void SetUInt64(out BigInteger result, ulong value) { if (value <= uint.MaxValue) { SetUInt32(out result, (uint)value); return; } result._blocks[0] = (uint)value; result._blocks[1] = (uint)(value >> 32); result._length = 2; } public unsafe static void SetValue(out BigInteger result, ref BigInteger value) { BufferEx.Memcpy(len: (result._length = value._length) * 4, dest: (byte*)result.GetBlocksPointer(), src: (byte*)value.GetBlocksPointer()); } public static void SetZero(out BigInteger result) { result._length = 0; } public unsafe void ShiftLeft(uint shift) { int length = _length; if (length == 0 || shift == 0) { return; } uint remainder; uint num = DivRem32(shift, out remainder); int num2 = length - 1; int num3 = num2 + (int)num; if (remainder == 0) { while (num2 >= 0) { _blocks[num3] = _blocks[num2]; num2--; num3--; } _length += (int)num; BufferEx.ZeroMemory((byte*)GetBlocksPointer(), num * 4); return; } num3++; _length = num3 + 1; uint num4 = 32 - remainder; uint num5 = 0u; uint num6 = _blocks[num2]; uint num7 = num6 >> (int)num4; while (num2 > 0) { _blocks[num3] = num5 | num7; num5 = num6 << (int)remainder; num2--; num3--; num6 = _blocks[num2]; num7 = num6 >> (int)num4; } _blocks[num3] = num5 | num7; _blocks[num3 - 1] = num6 << (int)remainder; BufferEx.ZeroMemory((byte*)GetBlocksPointer(), num * 4); if (_blocks[_length - 1] == 0) { _length--; } } public unsafe ulong ToUInt64() { if (_length > 1) { return ((ulong)_blocks[1] << 32) + _blocks[0]; } if (_length > 0) { return _blocks[0]; } return 0uL; } private unsafe uint* GetBlocksPointer() { return (uint*)Unsafe.AsPointer(ref _blocks[0]); } private static uint DivRem32(uint value, out uint remainder) { remainder = value & 0x1Fu; return value >> 5; } } internal readonly ref struct DiyFp { public const int DoubleImplicitBitIndex = 52; public const int SingleImplicitBitIndex = 23; public const int SignificandSize = 64; public readonly ulong f; public readonly int e; public static DiyFp CreateAndGetBoundaries(double value, out DiyFp mMinus, out DiyFp mPlus) { DiyFp result = new DiyFp(value); result.GetBoundaries(52, out mMinus, out mPlus); return result; } public static DiyFp CreateAndGetBoundaries(float value, out DiyFp mMinus, out DiyFp mPlus) { DiyFp result = new DiyFp(value); result.GetBoundaries(23, out mMinus, out mPlus); return result; } public DiyFp(double value) { f = ExtractFractionAndBiasedExponent(value, out e); } public DiyFp(float value) { f = ExtractFractionAndBiasedExponent(value, out e); } public DiyFp(ulong f, int e) { this.f = f; this.e = e; } public DiyFp Multiply(in DiyFp other) { int num = (int)(f >> 32); uint num2 = (uint)f; uint num3 = (uint)(other.f >> 32); uint num4 = (uint)other.f; ulong num5 = (ulong)(uint)num * (ulong)num3; ulong num6 = (ulong)num2 * (ulong)num3; ulong num7 = (ulong)(uint)num * (ulong)num4; ulong num8 = (ulong)(((long)num2 * (long)num4 >>> 32) + (uint)num7 + (uint)num6); num8 += 2147483648u; return new DiyFp(num5 + (num7 >> 32) + (num6 >> 32) + (num8 >> 32), e + other.e + 64); } public DiyFp Normalize() { int num = BitOperations.LeadingZeroCount(f); return new DiyFp(f << num, e - num); } public DiyFp Subtract(in DiyFp other) { return new DiyFp(f - other.f, e); } private void GetBoundaries(int implicitBitIndex, out DiyFp mMinus, out DiyFp mPlus) { mPlus = new DiyFp((f << 1) + 1, e - 1).Normalize(); if (f == (ulong)(1L << implicitBitIndex)) { mMinus = new DiyFp((f << 2) - 1, e - 2); } else { mMinus = new DiyFp((f << 1) - 1, e - 1); } mMinus = new DiyFp(mMinus.f << mMinus.e - mPlus.e, mPlus.e); } } internal static class Grisu3 { private const int CachedPowersDecimalExponentDistance = 8; private const int CachedPowersMinDecimalExponent = -348; private const int CachedPowersPowerMaxDecimalExponent = 340; private const int CachedPowersOffset = 348; private const double D1Log210 = 0.3010299956639812; private const int MaximalTargetExponent = -32; private const int MinimalTargetExponent = -60; private static readonly short[] s_CachedPowersBinaryExponent = new short[87] { -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 }; private static readonly short[] s_CachedPowersDecimalExponent = new short[87] { -348, -340, -332, -324, -316, -308, -300, -292, -284, -276, -268, -260, -252, -244, -236, -228, -220, -212, -204, -196, -188, -180, -172, -164, -156, -148, -140, -132, -124, -116, -108, -100, -92, -84, -76, -68, -60, -52, -44, -36, -28, -20, -12, -4, 4, 12, 20, 28, 36, 44, 52, 60, 68, 76, 84, 92, 100, 108, 116, 124, 132, 140, 148, 156, 164, 172, 180, 188, 196, 204, 212, 220, 228, 236, 244, 252, 260, 268, 276, 284, 292, 300, 308, 316, 324, 332, 340 }; private static readonly ulong[] s_CachedPowersSignificand = new ulong[87] { 18054884314459144840uL, 13451937075301367670uL, 10022474136428063862uL, 14934650266808366570uL, 11127181549972568877uL, 16580792590934885855uL, 12353653155963782858uL, 18408377700990114895uL, 13715310171984221708uL, 10218702384817765436uL, 15227053142812498563uL, 11345038669416679861uL, 16905424996341287883uL, 12595523146049147757uL, 9384396036005875287uL, 13983839803942852151uL, 10418772551374772303uL, 15525180923007089351uL, 11567161174868858868uL, 17236413322193710309uL, 12842128665889583758uL, 9568131466127621947uL, 14257626930069360058uL, 10622759856335341974uL, 15829145694278690180uL, 11793632577567316726uL, 17573882009934360870uL, 13093562431584567480uL, 9755464219737475723uL, 14536774485912137811uL, 10830740992659433045uL, 16139061738043178685uL, 12024538023802026127uL, 17917957937422433684uL, 13349918974505688015uL, 9946464728195732843uL, 14821387422376473014uL, 11042794154864902060uL, 16455045573212060422uL, 12259964326927110867uL, 18268770466636286478uL, 13611294676837538539uL, 10141204801825835212uL, 15111572745182864684uL, 11258999068426240000uL, 16777216000000000000uL, 12500000000000000000uL, 9313225746154785156uL, 13877787807814456755uL, 10339757656912845936uL, 15407439555097886824uL, 11479437019748901445uL, 17105694144590052135uL, 12744735289059618216uL, 9495567745759798747uL, 14149498560666738074uL, 10542197943230523224uL, 15709099088952724970uL, 11704190886730495818uL, 17440603504673385349uL, 12994262207056124023uL, 9681479787123295682uL, 14426529090290212157uL, 10748601772107342003uL, 16016664761464807395uL, 11933345169920330789uL, 17782069995880619868uL, 13248674568444952270uL, 9871031767461413346uL, 14708983551653345445uL, 10959046745042015199uL, 16330252207878254650uL, 12166986024289022870uL, 18130221999122236476uL, 13508068024458167312uL, 10064294952495520794uL, 14996968138956309548uL, 11173611982879273257uL, 16649979327439178909uL, 12405201291620119593uL, 9242595204427927429uL, 13772540099066387757uL, 10261342003245940623uL, 15290591125556738113uL, 11392378155556871081uL, 16975966327722178521uL, 12648080533535911531uL }; private static readonly uint[] s_SmallPowersOfTen = new uint[10] { 1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u, 10000000u, 100000000u, 1000000000u }; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsNegative(double d) { return BitConverter.DoubleToInt64Bits(d) < 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsNegativeInfinity(float f) { return f == float.NegativeInfinity; } public static bool TryRunDouble(double value, int requestedDigits, ref NumberBuffer number) { double value2 = (IsNegative(value) ? (0.0 - value) : value); DiyFp diyFp; bool flag; int length; int decimalExponent; if (requestedDigits == -1) { diyFp = DiyFp.CreateAndGetBoundaries(value2, out var mMinus, out var mPlus); DiyFp w = diyFp.Normalize(); flag = TryRunShortest(in mMinus, in w, in mPlus, number.Digits, out length, out decimalExponent); } else { diyFp = new DiyFp(value2); DiyFp w2 = diyFp.Normalize(); flag = TryRunCounted(in w2, requestedDigits, number.Digits, out length, out decimalExponent); } if (flag) { number.Scale = length + decimalExponent; number.Digits[length] = 0; number.DigitsCount = length; } return flag; } public static bool TryRunSingle(float value, int requestedDigits, ref NumberBuffer number) { float value2 = (IsNegative(value) ? (0f - value) : value); DiyFp diyFp; bool flag; int length; int decimalExponent; if (requestedDigits == -1) { diyFp = DiyFp.CreateAndGetBoundaries(value2, out var mMinus, out var mPlus); DiyFp w = diyFp.Normalize(); flag = TryRunShortest(in mMinus, in w, in mPlus, number.Digits, out length, out decimalExponent); } else { diyFp = new DiyFp(value2); DiyFp w2 = diyFp.Normalize(); flag = TryRunCounted(in w2, requestedDigits, number.Digits, out length, out decimalExponent); } if (flag) { number.Scale = length + decimalExponent; number.Digits[length] = 0; number.DigitsCount = length; } return flag; } private static bool TryRunCounted(in DiyFp w, int requestedDigits, Span<byte> buffer, out int length, out int decimalExponent) { int minExponent = -60 - (w.e + 64); int maxExponent = -32 - (w.e + 64); int decimalExponent2; DiyFp other = GetCachedPowerForBinaryExponentRange(minExponent, maxExponent, out decimalExponent2); DiyFp w2 = w.Multiply(in other); int kappa; bool result = TryDigitGenCounted(in w2, requestedDigits, buffer, out length, out kappa); decimalExponent = -decimalExponent2 + kappa; return result; } private static bool TryRunShortest(in DiyFp boundaryMinus, in DiyFp w, in DiyFp boundaryPlus, Span<byte> buffer, out int length, out int decimalExponent) { int minExponent = -60 - (w.e + 64); int maxExponent = -32 - (w.e + 64); int decimalExponent2; DiyFp other = GetCachedPowerForBinaryExponentRange(minExponent, maxExponent, out decimalExponent2); DiyFp w2 = w.Multiply(in other); DiyFp low = boundaryMinus.Multiply(in other); DiyFp high = boundaryPlus.Multiply(in other); int kappa; bool result = TryDigitGenShortest(in low, in w2, in high, buffer, out length, out kappa); decimalExponent = -decimalExponent2 + kappa; return result; } private static uint BiggestPowerTen(uint number, int numberBits, out int exponentPlusOne) { int num = (numberBits + 1) * 1233 >> 12; uint num2 = s_SmallPowersOfTen[num]; if (number < num2) { num--; num2 = s_SmallPowersOfTen[num]; } exponentPlusOne = num + 1; return num2; } private static bool TryDigitGenCounted(in DiyFp w, int requestedDigits, Span<byte> buffer, out int length, out int kappa) { ulong num = 1uL; DiyFp diyFp = new DiyFp((ulong)(1L << -w.e), w.e); uint result = (uint)(w.f >> -diyFp.e); ulong num2 = w.f & (diyFp.f - 1); if (num2 == 0L && (requestedDigits >= 11 || result < s_SmallPowersOfTen[requestedDigits - 1])) { length = 0; kappa = 0; return false; } uint num3 = BiggestPowerTen(result, 64 - -diyFp.e, out kappa); length = 0; while (kappa > 0) { uint num4 = MathEx.DivRem(result, num3, out result); buffer[length] = (byte)(48 + num4); length++; requestedDigits--; kappa--; if (requestedDigits == 0) { break; } num3 /= 10; } if (requestedDigits == 0) { ulong rest = ((ulong)result << -diyFp.e) + num2; return TryRoundWeedCounted(buffer, length, rest, (ulong)num3 << -diyFp.e, num, ref kappa); } while (requestedDigits > 0 && num2 > num) { num2 *= 10; num *= 10; uint num5 = (uint)(num2 >> -diyFp.e); buffer[length] = (byte)(48 + num5); length++; requestedDigits--; kappa--; num2 &= diyFp.f - 1; } if (requestedDigits != 0) { buffer[0] = 0; length = 0; kappa = 0; return false; } return TryRoundWeedCounted(buffer, length, num2, diyFp.f, num, ref kappa); } private static bool TryDigitGenShortest(in DiyFp low, in DiyFp w, in DiyFp high, Span<byte> buffer, out int length, out int kappa) { ulong num = 1uL; DiyFp other = new DiyFp(low.f - num, low.e); DiyFp diyFp = new DiyFp(high.f + num, high.e); DiyFp diyFp2 = diyFp.Subtract(in other); DiyFp diyFp3 = new DiyFp((ulong)(1L << -w.e), w.e); uint result = (uint)(diyFp.f >> -diyFp3.e); ulong num2 = diyFp.f & (diyFp3.f - 1); uint num3 = BiggestPowerTen(result, 64 - -diyFp3.e, out kappa); length = 0; while (kappa > 0) { uint num4 = MathEx.DivRem(result, num3, out result); buffer[length] = (byte)(48 + num4); length++; kappa--; ulong num5 = ((ulong)result << -diyFp3.e) + num2; if (num5 < diyFp2.f) { return TryRoundWeedShortest(buffer, length, diyFp.Subtract(in w).f, diyFp2.f, num5, (ulong)num3 << -diyFp3.e, num); } num3 /= 10; } do { num2 *= 10; num *= 10; diyFp2 = new DiyFp(diyFp2.f * 10, diyFp2.e); uint num6 = (uint)(num2 >> -diyFp3.e); buffer[length] = (byte)(48 + num6); length++; kappa--; num2 &= diyFp3.f - 1; } while (num2 >= diyFp2.f); return TryRoundWeedShortest(buffer, length, diyFp.Subtract(in w).f * num, diyFp2.f, num2, diyFp3.f, num); } private static DiyFp GetCachedPowerForBinaryExponentRange(int minExponent, int maxExponent, out int decimalExponent) { double num = Math.Ceiling((double)(minExponent + 64 - 1) * 0.3010299956639812); int num2 = (348 + (int)num - 1) / 8 + 1; decimalExponent = s_CachedPowersDecimalExponent[num2]; return new DiyFp(s_CachedPowersSignificand[num2], s_CachedPowersBinaryExponent[num2]); } private static bool TryRoundWeedCounted(Span<byte> buffer, int length, ulong rest, ulong tenKappa, ulong unit, ref int kappa) { if (unit >= tenKappa || tenKappa - unit <= unit) { return false; } if (tenKappa - rest > rest && tenKappa - 2 * rest >= 2 * unit) { return true; } if (rest > unit && (tenKappa <= rest - unit || tenKappa - (rest - unit) <= rest - unit)) { buffer[length - 1]++; int num = length - 1; while (num > 0 && buffer[num] == 58) { buffer[num] = 48; buffer[num - 1]++; num--; } if (buffer[0] == 58) { buffer[0] = 49; kappa++; } return true; } return false; } private static bool TryRoundWeedShortest(Span<byte> buffer, int length, ulong distanceTooHighW, ulong unsafeInterval, ulong rest, ulong tenKappa, ulong unit) { ulong num = distanceTooHighW - unit; ulong num2 = distanceTooHighW + unit; while (rest < num && unsafeInterval - rest >= tenKappa && (rest + tenKappa < num || num - rest >= rest + tenKappa - num)) { buffer[length - 1]--; rest += tenKappa; } if (rest < num2 && unsafeInterval - rest >= tenKappa && (rest + tenKappa < num2 || num2 - rest > rest + tenKappa - num2)) { return false; } if (2 * unit <= rest) { return rest <= unsafeInterval - 4 * unit; } return false; } } internal ref struct NumberBuffer { public int DigitsCount; public int Scale; public bool IsNegative; public bool HasNonZeroTail; public NumberBufferKind Kind; public Span<byte> Digits; public unsafe NumberBuffer(NumberBufferKind kind, byte* digits, int digitsLength) { DigitsCount = 0; Scale = 0; IsNegative = false; HasNonZeroTail = false; Kind = kind; Digits = new Span<byte>(digits, digitsLength); Digits[0] = 0; } [Conditional("DEBUG")] public void CheckConsistency() { } public unsafe byte* GetDigitsPointer() { return (byte*)Unsafe.AsPointer(ref Digits[0]); } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append('['); stringBuilder.Append('"'); for (int i = 0; i < Digits.Length; i++) { byte b = Digits[i]; if (b == 0) { break; } stringBuilder.Append((char)b); } stringBuilder.Append('"'); stringBuilder.Append(", Length = ").Append(DigitsCount); stringBuilder.Append(", Scale = ").Append(Scale); stringBuilder.Append(", IsNegative = ").Append(IsNegative); stringBuilder.Append(", HasNonZeroTail = ").Append(HasNonZeroTail); stringBuilder.Append(", Kind = ").Append(Kind); stringBuilder.Append(']'); return stringBuilder.ToString(); } } internal enum NumberBufferKind : byte { Unknown, Integer, Decimal, FloatingPoint } public readonly struct FloatingPointInfo { public static readonly FloatingPointInfo Double = new FloatingPointInfo(52, 11, 1023, 1023, 9218868437227405312uL); public static readonly FloatingPointInfo Single = new FloatingPointInfo(23, 8, 127, 127, 2139095040uL); public ulong ZeroBits { get; } public ulong InfinityBits { get; } public ulong NormalMantissaMask { get; } public ulong DenormalMantissaMask { get; } public int MinBinaryExponent { get; } public int MaxBinaryExponent { get; } public int ExponentBias { get; } public int OverflowDecimalExponent { get; } public ushort NormalMantissaBits { get; } public ushort DenormalMantissaBits { get; } public ushort ExponentBits { get; } public FloatingPointInfo(ushort denormalMantissaBits, ushort exponentBits, int maxBinaryExponent, int exponentBias, ulong infinityBits) { ExponentBits = exponentBits; DenormalMantissaBits = denormalMantissaBits; NormalMantissaBits = (ushort)(denormalMantissaBits + 1); OverflowDecimalExponent = (maxBinaryExponent + 2 * NormalMantissaBits) / 3; ExponentBias = exponentBias; MaxBinaryExponent = maxBinaryExponent; MinBinaryExponent = 1 - maxBinaryExponent; DenormalMantissaMask = (ulong)((1L << (int)denormalMantissaBits) - 1); NormalMantissaMask = (ulong)((1L << (int)NormalMantissaBits) - 1); InfinityBits = infinityBits; ZeroBits = 0uL; } } internal enum ParsingStatus { OK, Failed, Overflow } internal const int DecimalPrecision = 29; private const int SinglePrecision = 9; private const int DoublePrecision = 17; private const int SinglePrecisionCustomFormat = 7; private const int DoublePrecisionCustomFormat = 15; private const int DefaultPrecisionExponentialFormat = 6; private const int MaxUInt32DecDigits = 10; private const int CharStackBufferSize = 32; private const string PosNumberFormat = "#"; private static readonly string[] s_singleDigitStringCache = new string[10] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; private static readonly string[] s_posCurrencyFormats = new string[4] { "$#", "#$", "$ #", "# $" }; private static readonly string[] s_negCurrencyFormats = new string[16] { "($#)", "-$#", "$-#", "$#-", "(#$)", "-#$", "#-$", "#$-", "-# $", "-$ #", "# $-", "$ #-", "$ -#", "#- $", "($ #)", "(# $)" }; private static readonly string[] s_posPercentFormats = new string[4] { "# %", "#%", "%#", "% #" }; private static readonly string[] s_negPercentFormats = new string[12] { "-# %", "-#%", "-%#", "%-#", "%#-", "#-%", "#%-", "-% #", "# %-", "% #-", "% -#", "#- %" }; private static readonly string[] s_negNumberFormats = new string[5] { "(#)", "-#", "- #", "#-", "# -" }; internal const int DecimalNumberBufferLength = 31; internal const int DoubleNumberBufferLength = 769; internal const int Int32NumberBufferLength = 11; internal const int Int64NumberBufferLength = 20; internal const int SingleNumberBufferLength = 114; internal const int UInt32NumberBufferLength = 11; internal const int UInt64NumberBufferLength = 21; private static readonly float[] s_Pow10SingleTable = new float[11] { 1f, 10f, 100f, 1000f, 10000f, 100000f, 1000000f, 10000000f, 100000000f, 1E+09f, 1E+10f }; private static readonly double[] s_Pow10DoubleTable = new double[23] { 1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 100000000000000.0, 1000000000000000.0, 10000000000000000.0, 1E+17, 1E+18, 1E+19, 1E+20, 1E+21, 1E+22 }; private const int Int32Precision = 10; private const int UInt32Precision = 10; private const int Int64Precision = 19; private const int UInt64Precision = 20; private const int DoubleMaxExponent = 309; private const int DoubleMinExponent = -324; private const int FloatingPointMaxExponent = 309; private const int FloatingPointMinExponent = -324; private const int SingleMaxExponent = 39; private const int SingleMinExponent = -45; internal static ReadOnlySpan<byte> CharToHexLookup => new byte[103] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15 }; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsNegative(double d) { return BitConverter.DoubleToInt64Bits(d) < 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(float f) { return f == float.NegativeInfinity; } public static void Dragon4Double(double value, int cutoffNumber, bool isSignificantDigits, ref NumberBuffer number) { IsNegative(value); int exponent; ulong num = ExtractFractionAndBiasedExponent(value, out exponent); bool hasUnequalMargins = false; uint mantissaHighBitIdx; if (num >> 52 != 0L) { mantissaHighBitIdx = 52u; hasUnequalMargins = num == 4503599627370496L; } else { mantissaHighBitIdx = (uint)BitOperations.Log2(num); } int decimalExponent; int num2 = (int)Dragon4(num, exponent, mantissaHighBitIdx, hasUnequalMargins, cutoffNumber, isSignificantDigits, number.Digits, out decimalExponent); number.Scale = decimalExponent + 1; number.Digits[num2] = 0; number.DigitsCount = num2; } public static void Dragon4Single(float value, int cutoffNumber, bool isSignificantDigits, ref NumberBuffer number) { IsNegative(value); int exponent; uint num = ExtractFractionAndBiasedExponent(value, out exponent); bool hasUnequalMargins = false; uint mantissaHighBitIdx; if (num >> 23 != 0) { mantissaHighBitIdx = 23u; hasUnequalMargins = num == 8388608; } else { mantissaHighBitIdx = (uint)BitOperations.Log2(num); } int decimalExponent; int num2 = (int)Dragon4(num, exponent, mantissaHighBitIdx, hasUnequalMargins, cutoffNumber, isSignificantDigits, number.Digits, out decimalExponent); number.Scale = decimalExponent + 1; number.Digits[num2] = 0; number.DigitsCount = num2; } private unsafe static uint Dragon4(ulong mantissa, int exponent, uint mantissaHighBitIdx, bool hasUnequalMargins, int cutoffNumber, bool isSignificantDigits, Span<byte> buffer, out int decimalExponent) { int num = 0; BigInteger result; BigInteger result2; BigInteger result3; BigInteger* ptr; if (hasUnequalMargins) { BigInteger result4; if (exponent > 0) { BigInteger.SetUInt64(out result, 4 * mantissa); result.ShiftLeft((uint)exponent); BigInteger.SetUInt32(out result2, 4u); BigInteger.Pow2((uint)exponent, out result3); BigInteger.Pow2((uint)(exponent + 1), out result4); } else { BigInteger.SetUInt64(out result, 4 * mantissa); BigInteger.Pow2((uint)(-exponent + 2), out result2); BigInteger.SetUInt32(out result3, 1u); BigInteger.SetUInt32(out result4, 2u); } ptr = &result4; } else { if (exponent > 0) { BigInteger.SetUInt64(out result, 2 * mantissa); result.ShiftLeft((uint)exponent); BigInteger.SetUInt32(out result2, 2u); BigInteger.Pow2((uint)exponent, out result3); } else { BigInteger.SetUInt64(out result, 2 * mantissa); BigInteger.Pow2((uint)(-exponent + 1), out result2); BigInteger.SetUInt32(out result3, 1u); } ptr = &result3; } int num2 = (int)Math.Ceiling((double)((int)mantissaHighBitIdx + exponent) * 0.3010299956639812 - 0.69); if (num2 > 0) { result2.MultiplyPow10((uint)num2); } else if (num2 < 0) { BigInteger.Pow10((uint)(-num2), out var result5); result.Multiply(ref result5); result3.Multiply(ref result5); if (ptr != &result3) { BigInteger.Multiply(ref result3, 2u, out *ptr); } } bool flag = mantissa % 2 == 0; bool flag2 = false; if (cutoffNumber == -1) { BigInteger.Add(ref result, ref *ptr, out var result6); int num3 = BigInteger.Compare(ref result6, ref result2); flag2 = (flag ? (num3 >= 0) : (num3 > 0)); } else { flag2 = BigInteger.Compare(ref result, ref result2) >= 0; } if (flag2) { num2++; } else { result.Multiply10(); result3.Multiply10(); if (ptr != &result3) { BigInteger.Multiply(ref result3, 2u, out *ptr); } } int num4 = num2 - buffer.Length; if (cutoffNumber != -1) { int num5 = 0; num5 = ((!isSignificantDigits) ? (-cutoffNumber) : (num2 - cutoffNumber)); if (num5 > num4) { num4 = num5; } } num2 = (decimalExponent = num2 - 1); uint block = result2.GetBlock((uint)(result2.GetLength() - 1)); if (block < 8 || block > 429496729) { uint num6 = (uint)BitOperations.Log2(block); uint shift = (59 - num6) % 32; result2.ShiftLeft(shift); result.ShiftLeft(shift); result3.ShiftLeft(shift); if (ptr != &result3) { BigInteger.Multiply(ref result3, 2u, out *ptr); } } bool flag3; bool flag4; uint num7; if (cutoffNumber == -1) { while (true) { num7 = BigInteger.HeuristicDivide(ref result, ref result2); BigInteger.Add(ref result, ref *ptr, out var result7); int num8 = BigInteger.Compare(ref result, ref result3); int num9 = BigInteger.Compare(ref result7, ref result2); if (flag) { flag3 = num8 <= 0; flag4 = num9 >= 0; } else { flag3 = num8 < 0; flag4 = num9 > 0; } if (flag3 || flag4 || num2 == num4) { break; } buffer[num] = (byte)(48 + num7); num++; result.Multiply10(); result3.Multiply10(); if (ptr != &result3) { BigInteger.Multiply(ref result3, 2u, out *ptr); } num2--; } } else { if (num2 < num4) { num7 = BigInteger.HeuristicDivide(ref result, ref result2); if (num7 > 5 || (num7 == 5 && !result.IsZero())) { decimalExponent++; num7 = 1u; } buffer[num] = (byte)(48 + num7); return (uint)(num + 1); } flag3 = false; flag4 = false; while (true) { num7 = BigInteger.HeuristicDivide(ref result, ref result2); if (result.IsZero() || num2 <= num4) { break; } buffer[num] = (byte)(48 + num7); num++; result.Multiply10(); num2--; } } bool flag5 = flag3; if (flag3 == flag4) { result.ShiftLeft(1u); int num10 = BigInteger.Compare(ref result, ref result2); flag5 = num10 < 0; if (num10 == 0) { flag5 = (num7 & 1) == 0; } } if (flag5) { buffer[num] = (byte)(48 + num7); num++; } else if (num7 == 9) { while (true) { if (num == 0) { buffer[num] = 49; num++; decimalExponent++; break; } num--; if (buffer[num] != 57) { buffer[num]++; num++; break; } } } else { buffer[num] = (byte)(48 + num7 + 1); num++; } return (uint)num; } public unsafe static string FormatDecimal(decimal value, ReadOnlySpan<char> format, NumberFormatInfo info) { int digits; char c = ParseFormatSpecifier(format, out digits); byte* digits2 = stackalloc byte[31]; NumberBuffer number = new NumberBuffer(NumberBufferKind.Decimal, digits2, 31); DecimalToNumber(ref value, ref number); char* pointer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(new Span<char>(pointer, 32)); if (c != 0) { NumberToString(ref sb, ref number, c, digits, info); } else { NumberToStringFormat(ref sb, ref number, format, info); } return sb.ToString(); } public unsafe static bool TryFormatDecimal(decimal value, ReadOnlySpan<char> format, NumberFormatInfo info, Span<char> destination, out int charsWritten) { int digits; char c = ParseFormatSpecifier(format, out digits); byte* digits2 = stackalloc byte[31]; NumberBuffer number = new NumberBuffer(NumberBufferKind.Decimal, digits2, 31); DecimalToNumber(ref value, ref number); char* pointer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(new Span<char>(pointer, 32)); if (c != 0) { NumberToString(ref sb, ref number, c, digits, info); } else { NumberToStringFormat(ref sb, ref number, format, info); } return sb.TryCopyTo(destination, out charsWritten); } internal unsafe static void DecimalToNumber(ref decimal d, ref NumberBuffer number) { byte* digitsPointer = number.GetDigitsPointer(); number.DigitsCount = 29; number.IsNegative = d.IsNegative(); byte* bufferEnd = digitsPointer + 29; while ((d.Mid() | d.High()) != 0) { bufferEnd = UInt32ToDecChars(bufferEnd, DecimalEx.DecDivMod1E9(ref d), 9); } bufferEnd = UInt32ToDecChars(bufferEnd, d.Low(), 0); int num = (number.DigitsCount = (int)(digitsPointer + 29 - bufferEnd)); number.Scale = num - d.Scale(); byte* digitsPointer2 = number.GetDigitsPointer(); while (--num >= 0) { *(digitsPointer2++) = *(bufferEnd++); } *digitsPointer2 = 0; } public static string FormatDouble(double value, string format, NumberFormatInfo info) { Span<char> initialBuffer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(initialBuffer); return FormatDouble(ref sb, value, format.AsSpan(), info) ?? sb.ToString(); } public static bool TryFormatDouble(double value, ReadOnlySpan<char> format, NumberFormatInfo info, Span<char> destination, out int charsWritten) { Span<char> initialBuffer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(initialBuffer); string text = FormatDouble(ref sb, value, format, info); if (text == null) { return sb.TryCopyTo(destination, out charsWritten); } return TryCopyTo(text, destination, out charsWritten); } private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int precision, NumberFormatInfo info, out bool isSignificantDigits) { if (fmt == '\0') { isSignificantDigits = true; return precision; } int result = precision; switch (fmt) { case 'C': case 'c': if (precision == -1) { precision = info.CurrencyDecimalDigits; } isSignificantDigits = false; break; case 'E': case 'e': if (precision == -1) { precision = 6; } precision++; isSignificantDigits = true; break; case 'F': case 'N': case 'f': case 'n': if (precision == -1) { precision = info.NumberDecimalDigits; } isSignificantDigits = false; break; case 'G': case 'g': if (precision == 0) { precision = -1; } isSignificantDigits = true; break; case 'P': case 'p': if (precision == -1) { precision = info.PercentDecimalDigits; } precision += 2; isSignificantDigits = false; break; case 'R': case 'r': precision = -1; isSignificantDigits = true; break; default: throw new FormatException("SR.Argument_BadFormatSpecifier"); } return result; } private unsafe static string FormatDouble(ref System.Text.ValueStringBuilder sb, double value, ReadOnlySpan<char> format, NumberFormatInfo info) { if (!FloatEx.IsFinite(value)) { if (double.IsNaN(value)) { return info.NaNSymbol; } if (!FloatEx.IsNegative(value)) { return info.PositiveInfinitySymbol; } return info.NegativeInfinitySymbol; } int digits; char c = ParseFormatSpecifier(format, out digits); byte* digits2 = stackalloc byte[769]; if (c == '\0') { digits = 15; } NumberBuffer number = new NumberBuffer(NumberBufferKind.FloatingPoint, digits2, 769); number.IsNegative = FloatEx.IsNegative(value); bool isSignificantDigits; int nMaxDigits = GetFloatingPointMaxDigitsAndPrecision(c, ref digits, info, out isSignificantDigits); if (value != 0.0 && (!isSignificantDigits || !Grisu3.TryRunDouble(value, digits, ref number))) { Dragon4Double(value, digits, isSignificantDigits, ref number); } if (c != 0) { if (digits == -1) { nMaxDigits = Math.Max(number.DigitsCount, 17); } NumberToString(ref sb, ref number, c, nMaxDigits, info); } else { NumberToStringFormat(ref sb, ref number, format, info); } return null; } public static string FormatSingle(float value, string format, NumberFormatInfo info) { Span<char> initialBuffer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(initialBuffer); return FormatSingle(ref sb, value, format.AsSpan(), info) ?? sb.ToString(); } public static bool TryFormatSingle(float value, ReadOnlySpan<char> format, NumberFormatInfo info, Span<char> destination, out int charsWritten) { Span<char> initialBuffer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(initialBuffer); string text = FormatSingle(ref sb, value, format, info); if (text == null) { return sb.TryCopyTo(destination, out charsWritten); } return TryCopyTo(text, destination, out charsWritten); } private unsafe static string FormatSingle(ref System.Text.ValueStringBuilder sb, float value, ReadOnlySpan<char> format, NumberFormatInfo info) { if (!FloatEx.IsFinite(value)) { if (float.IsNaN(value)) { return info.NaNSymbol; } if (!FloatEx.IsNegative(value)) { return info.PositiveInfinitySymbol; } return info.NegativeInfinitySymbol; } int digits; char c = ParseFormatSpecifier(format, out digits); byte* digits2 = stackalloc byte[114]; if (c == '\0') { digits = 7; } NumberBuffer number = new NumberBuffer(NumberBufferKind.FloatingPoint, digits2, 114); number.IsNegative = FloatEx.IsNegative(value); bool isSignificantDigits; int nMaxDigits = GetFloatingPointMaxDigitsAndPrecision(c, ref digits, info, out isSignificantDigits); if (value != 0f && (!isSignificantDigits || !Grisu3.TryRunSingle(value, digits, ref number))) { Dragon4Single(value, digits, isSignificantDigits, ref number); } if (c != 0) { if (digits == -1) { nMaxDigits = Math.Max(number.DigitsCount, 9); } NumberToString(ref sb, ref number, c, nMaxDigits, info); } else { NumberToStringFormat(ref sb, ref number, format, info); } return null; } private static bool TryCopyTo(string source, Span<char> destination, out int charsWritten) { if (source.AsSpan().TryCopyTo(destination)) { charsWritten = source.Length; return true; } charsWritten = 0; return false; } public unsafe static string FormatInt32(int value, ReadOnlySpan<char> format, IFormatProvider provider) { if (value >= 0 && format.Length == 0) { return UInt32ToDecStr((uint)value, -1); } int digits; char c = ParseFormatSpecifier(format, out digits); char c2 = (char)(c & 0xFFDFu); if (c2 != 'G' || digits >= 1) { switch (c2) { case 'D': break; case 'X': return Int32ToHexStr(value, (char)(c - 33), digits); default: { NumberFormatInfo instance = NumberFormatInfo.GetInstance(provider); byte* digits2 = stackalloc byte[11]; NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, digits2, 11); Int32ToNumber(value, ref number); char* pointer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(new Span<char>(pointer, 32)); if (c != 0) { NumberToString(ref sb, ref number, c, digits, instance); } else { NumberToStringFormat(ref sb, ref number, format, instance); } return sb.ToString(); } } } if (value < 0) { return NegativeInt32ToDecStr(value, digits, NumberFormatInfo.GetInstance(provider).NegativeSign); } return UInt32ToDecStr((uint)value, digits); } public unsafe static bool TryFormatInt32(int value, ReadOnlySpan<char> format, IFormatProvider provider, Span<char> destination, out int charsWritten) { if (value >= 0 && format.Length == 0) { return TryUInt32ToDecStr((uint)value, -1, destination, out charsWritten); } int digits; char c = ParseFormatSpecifier(format, out digits); char c2 = (char)(c & 0xFFDFu); if (c2 != 'G' || digits >= 1) { switch (c2) { case 'D': break; case 'X': return TryInt32ToHexStr(value, (char)(c - 33), digits, destination, out charsWritten); default: { NumberFormatInfo instance = NumberFormatInfo.GetInstance(provider); byte* digits2 = stackalloc byte[11]; NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, digits2, 11); Int32ToNumber(value, ref number); char* pointer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(new Span<char>(pointer, 32)); if (c != 0) { NumberToString(ref sb, ref number, c, digits, instance); } else { NumberToStringFormat(ref sb, ref number, format, instance); } return sb.TryCopyTo(destination, out charsWritten); } } } if (value < 0) { return TryNegativeInt32ToDecStr(value, digits, NumberFormatInfo.GetInstance(provider).NegativeSign, destination, out charsWritten); } return TryUInt32ToDecStr((uint)value, digits, destination, out charsWritten); } public unsafe static string FormatUInt32(uint value, ReadOnlySpan<char> format, IFormatProvider provider) { if (format.Length == 0) { return UInt32ToDecStr(value, -1); } int digits; char c = ParseFormatSpecifier(format, out digits); char c2 = (char)(c & 0xFFDFu); if (c2 != 'G' || digits >= 1) { switch (c2) { case 'D': break; case 'X': return Int32ToHexStr((int)value, (char)(c - 33), digits); default: { NumberFormatInfo instance = NumberFormatInfo.GetInstance(provider); byte* digits2 = stackalloc byte[11]; NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, digits2, 11); UInt32ToNumber(value, ref number); char* pointer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(new Span<char>(pointer, 32)); if (c != 0) { NumberToString(ref sb, ref number, c, digits, instance); } else { NumberToStringFormat(ref sb, ref number, format, instance); } return sb.ToString(); } } } return UInt32ToDecStr(value, digits); } public unsafe static bool TryFormatUInt32(uint value, ReadOnlySpan<char> format, IFormatProvider provider, Span<char> destination, out int charsWritten) { if (format.Length == 0) { return TryUInt32ToDecStr(value, -1, destination, out charsWritten); } int digits; char c = ParseFormatSpecifier(format, out digits); char c2 = (char)(c & 0xFFDFu); if (c2 != 'G' || digits >= 1) { switch (c2) { case 'D': break; case 'X': return TryInt32ToHexStr((int)value, (char)(c - 33), digits, destination, out charsWritten); default: { NumberFormatInfo instance = NumberFormatInfo.GetInstance(provider); byte* digits2 = stackalloc byte[11]; NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, digits2, 11); UInt32ToNumber(value, ref number); char* pointer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(new Span<char>(pointer, 32)); if (c != 0) { NumberToString(ref sb, ref number, c, digits, instance); } else { NumberToStringFormat(ref sb, ref number, format, instance); } return sb.TryCopyTo(destination, out charsWritten); } } } return TryUInt32ToDecStr(value, digits, destination, out charsWritten); } public unsafe static string FormatInt64(long value, ReadOnlySpan<char> format, IFormatProvider provider) { if (value >= 0 && format.Length == 0) { return UInt64ToDecStr((ulong)value, -1); } int digits; char c = ParseFormatSpecifier(format, out digits); char c2 = (char)(c & 0xFFDFu); if (c2 != 'G' || digits >= 1) { switch (c2) { case 'D': break; case 'X': return Int64ToHexStr(value, (char)(c - 33), digits); default: { NumberFormatInfo instance = NumberFormatInfo.GetInstance(provider); byte* digits2 = stackalloc byte[20]; NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, digits2, 20); Int64ToNumber(value, ref number); char* pointer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(new Span<char>(pointer, 32)); if (c != 0) { NumberToString(ref sb, ref number, c, digits, instance); } else { NumberToStringFormat(ref sb, ref number, format, instance); } return sb.ToString(); } } } if (value < 0) { return NegativeInt64ToDecStr(value, digits, NumberFormatInfo.GetInstance(provider).NegativeSign); } return UInt64ToDecStr((ulong)value, digits); } public unsafe static bool TryFormatInt64(long value, ReadOnlySpan<char> format, IFormatProvider provider, Span<char> destination, out int charsWritten) { if (value >= 0 && format.Length == 0) { return TryUInt64ToDecStr((ulong)value, -1, destination, out charsWritten); } int digits; char c = ParseFormatSpecifier(format, out digits); char c2 = (char)(c & 0xFFDFu); if (c2 != 'G' || digits >= 1) { switch (c2) { case 'D': break; case 'X': return TryInt64ToHexStr(value, (char)(c - 33), digits, destination, out charsWritten); default: { NumberFormatInfo instance = NumberFormatInfo.GetInstance(provider); byte* digits2 = stackalloc byte[20]; NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, digits2, 20); Int64ToNumber(value, ref number); char* pointer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(new Span<char>(pointer, 32)); if (c != 0) { NumberToString(ref sb, ref number, c, digits, instance); } else { NumberToStringFormat(ref sb, ref number, format, instance); } return sb.TryCopyTo(destination, out charsWritten); } } } if (value < 0) { return TryNegativeInt64ToDecStr(value, digits, NumberFormatInfo.GetInstance(provider).NegativeSign, destination, out charsWritten); } return TryUInt64ToDecStr((ulong)value, digits, destination, out charsWritten); } public unsafe static string FormatUInt64(ulong value, ReadOnlySpan<char> format, IFormatProvider provider) { if (format.Length == 0) { return UInt64ToDecStr(value, -1); } int digits; char c = ParseFormatSpecifier(format, out digits); char c2 = (char)(c & 0xFFDFu); if (c2 != 'G' || digits >= 1) { switch (c2) { case 'D': break; case 'X': return Int64ToHexStr((long)value, (char)(c - 33), digits); default: { NumberFormatInfo instance = NumberFormatInfo.GetInstance(provider); byte* digits2 = stackalloc byte[21]; NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, digits2, 21); UInt64ToNumber(value, ref number); char* pointer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(new Span<char>(pointer, 32)); if (c != 0) { NumberToString(ref sb, ref number, c, digits, instance); } else { NumberToStringFormat(ref sb, ref number, format, instance); } return sb.ToString(); } } } return UInt64ToDecStr(value, digits); } public unsafe static bool TryFormatUInt64(ulong value, ReadOnlySpan<char> format, IFormatProvider provider, Span<char> destination, out int charsWritten) { if (format.Length == 0) { return TryUInt64ToDecStr(value, -1, destination, out charsWritten); } int digits; char c = ParseFormatSpecifier(format, out digits); char c2 = (char)(c & 0xFFDFu); if (c2 != 'G' || digits >= 1) { switch (c2) { case 'D': break; case 'X': return TryInt64ToHexStr((long)value, (char)(c - 33), digits, destination, out charsWritten); default: { NumberFormatInfo instance = NumberFormatInfo.GetInstance(provider); byte* digits2 = stackalloc byte[21]; NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, digits2, 21); UInt64ToNumber(value, ref number); char* pointer = stackalloc char[32]; System.Text.ValueStringBuilder sb = new System.Text.ValueStringBuilder(new Span<char>(pointer, 32)); if (c != 0) { NumberToString(ref sb, ref number, c, digits, instance); } else { NumberToStringFormat(ref sb, ref number, format, instance); } return sb.TryCopyTo(destination, out charsWritten); } } } return TryUInt64ToDecStr(value, digits, destination, out charsWritten); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private unsafe static void Int32ToNumber(int value, ref NumberBuffer number) { number.DigitsCount = 10; if (value >= 0) { number.IsNegative = false; } else { number.IsNegative = true; value = -value; } byte* digitsPointer = number.GetDigitsPointer(); byte* ptr = UInt32ToDecChars(digitsPointer + 10, (uint)value, 0); int num = (number.Scale = (number.DigitsCount = (int)(digitsPointer + 10 - ptr))); byte* digitsPointer2 = number.GetDigitsPointer(); while (--num >= 0) { *(digitsPointer2++) = *(ptr++); } *digitsPointer2 = 0; } private unsafe static string NegativeInt32ToDecStr(int value, int digits, string sNegative) { if (digits < 1) { digits = 1; } int num = Math.Max(digits, System.Buffers.Text.FormattingHelpers.CountDigits((uint)(-value))) + sNegative.Length; string text = FastAllocateString(num); fixed (char* ptr = text) { char* ptr2 = UInt32ToDecChars(ptr + num, (uint)(-value), digits); for (int num2 = sNegative.Length - 1; num2 >= 0; num2--) { *(--ptr2) = sNegative[num2]; } } return text; } private unsafe static bool TryNegativeInt32ToDecStr(int value, int digits, string sNegative, Span<char> destination, out int charsWritten) { if (digits < 1) { digits = 1; } int num = Math.Max(digits, System.Buffers.Text.FormattingHelpers.CountDigits((uint)(-value))) + sNegative.Length; if (num > destination.Length) { charsWritten = 0; return false; } charsWritten = num; fixed (char* ptr = &MemoryMarshal.GetReference(destination)) { char* ptr2 = UInt32ToDecChars(ptr + num, (uint)(-value), digits); for (int num2 = sNegative.Length - 1; num2 >= 0; num2--) { *(--ptr2) = sNegative[num2]; } } return true; } private unsafe static string Int32ToHexStr(int value, char hexBase, int digits) { if (digits < 1) { digits = 1; } int num = Math.Max(digits, System.Buffers.Text.FormattingHelpers.CountHexDigits((uint)value)); string text = FastAllocateString(num); fixed (char* ptr = text) { Int32ToHexChars(ptr + num, (uint)value, hexBase, digits); } return text; } private unsafe static bool TryInt32ToHexStr(int value, char hexBase, int digits, Span<char> destination, out int charsWritten) { if (digits < 1) { digits = 1; } int num = Math.Max(digits, System.Buffers.Text.FormattingHelpers.CountHexDigits((uint)value)); if (num > destination.Length) { charsWritten = 0; return false; } charsWritten = num; fixed (char* ptr = &MemoryMarshal.GetReference(destination)) { Int32ToHexChars(ptr + num, (uint)value, hexBase, digits); } return true; } private unsafe static char* Int32ToHexChars(char* buffer, uint value, int hexBase, int digits) { while (--digits >= 0 || value != 0) { byte b = (byte)(value & 0xFu); *(--buffer) = (char)(b + ((b < 10) ? 48 : hexBase)); value >>= 4; } return buffer; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private unsafe static void UInt32ToNumber(uint value, ref NumberBuffer number) { number.DigitsCount = 10; number.IsNegative = false; byte* digitsPointer = number.GetDigitsPointer(); byte* ptr = UInt32ToDecChars(digitsPointer + 10, value, 0); int num = (number.Scale = (number.DigitsCount = (int)(digitsPointer + 10 - ptr))); byte* digitsPointer2 = number.GetDigitsPointer(); while (--num >= 0) { *(digitsPointer2++) = *(ptr++); } *digitsPointer2 = 0; } internal unsafe static byte* UInt32ToDecChars(byte* bufferEnd, uint value, int digits) { while (--digits >= 0 || value != 0) { value = MathEx.DivRem(value, 10u, out var result); *(--bufferEnd) = (byte)(result + 48); } return bufferEnd; } internal unsafe static char* UInt32ToDecChars(char* bufferEnd, uint value, int digits) { while (--digits >= 0 || value != 0) { value = MathEx.DivRem(value, 10u, out var result); *(--bufferEnd) = (char)(result + 48); } return bufferEnd; } internal unsafe static string UInt32ToDecStr(uint value, int digits) { int num = Math.Max(digits, System.Buffers.Text.FormattingHelpers.CountDigits(value)); if (num == 1) { return s_singleDigitStringCache[value]; } string text = FastAllocateString(num); fixed (char* ptr = text) { char* ptr2 = ptr + num; if (digits <= 1) { do { value = MathEx.DivRem(value, 10u, out var result); *(--ptr2) = (char)(result + 48); } while (value != 0); } else { ptr2 = UInt32ToDecChars(ptr2, value, digits); } } return text; } private unsafe static bool TryUInt32ToDecStr(uint value, int digits, Span<char> destination, out int charsWritten) { int num = Math.Max(digits, System.Buffers.Text.FormattingHelpers.CountDigits(value)); if (num > destination.Length) { charsWritten = 0; return false; } charsWritten = num; fixed (char* ptr = &MemoryMarshal.GetReference(destination)) { char* ptr2 = ptr + num; if (digits <= 1) { do { value = MathEx.DivRem(value, 10u, out var result); *(--ptr2) = (char)(result + 48); } while (value != 0); } else { ptr2 = UInt32ToDecChars(ptr2, value, digits); } } return true; } private unsafe static void Int64ToNumber(long input, ref NumberBuffer number) { ulong value = (ulong)input; number.IsNegative = input < 0; number.DigitsCount = 19; if (number.IsNegative) { value = (ulong)(-input); } byte* digitsPointer = number.GetDigitsPointer(); byte* bufferEnd = digitsPointer + 19; while (High32(value) != 0) { bufferEnd = UInt32ToDecChars(bufferEnd, Int64DivMod1E9(ref value), 9); } bufferEnd = UInt32ToDecChars(bufferEnd, Low32(value), 0); int num = (number.Scale = (number.DigitsCount = (int)(digitsPointer + 19 - bufferEnd))); byte* digitsPointer2 = number.GetDigitsPointer(); while (--num >= 0) { *(digitsPointer2++) = *(bufferEnd++); } *digitsPointer2 = 0; } private unsafe static string NegativeInt64ToDecStr(long input, int digits, string sNegative) { if (digits < 1) { digits = 1; } ulong value = (ulong)(-input); int num = Math.Max(digits, System.Buffers.Text.FormattingHelpers.CountDigits(value)) + sNegative.Length; string text = FastAllocateString(num); fixed (char* ptr = text) { char* bufferEnd = ptr + num; while (High32(value) != 0) { bufferEnd = UInt32ToDecChars(bufferEnd, Int64DivMod1E9(ref value), 9); digits -= 9; } bufferEnd = UInt32ToDecChars(bufferEnd, Low32(value), digits); for (int num2 = sNegative.Length - 1; num2 >= 0; num2--) { *(--bufferEnd) = sNegative[num2]; } } return text; } private unsafe static bool TryNegativeInt64ToDecStr(long input, int digits, string sNegative, Span<char> destination, out int charsWritten) { if (digits < 1) { digits = 1; } ulong value = (ulong)(-input); int num = Math.Max(digits, System.Buffers.Text.FormattingHelpers.CountDigits((ulong)(-input))) + sNegative.Length; if (num > destination.Length) { charsWritten = 0; return false; } charsWritten = num; fixed (char* ptr = &MemoryMarshal.GetReference(destination)) { char* bufferEnd = ptr + num; while (High32(value) != 0) { bufferEnd = UInt32ToDecChars(bufferEnd, Int64DivMod1E9(ref value), 9); digits -= 9; } bufferEnd = UInt32ToDecChars(bufferEnd, Low32(value), digits); for (int num2 = sNegative.Length - 1; num2 >= 0; num2--) { *(--bufferEnd) = sNegative[num2]; } } return true; } private unsafe static string Int64ToHexStr(long value, char hexBase, int digits) { int num = Math.Max(digits, System.Buffers.Text.FormattingHelpers.CountHexDigits((ulong)value)); string text = FastAllocateString(num); fixed (char* ptr = text) { char* buffer = ptr + num; if (High32((ulong)value) != 0) { buffer = Int32ToHexChars(buffer, Low32((ulong)value), hexBase, 8); buffer = Int32ToHexChars(buffer, High32((ulong)value), hexBase, digits - 8); } else { buffer = Int32ToHexChars(buffer, Low32((ulong)value), hexBase, Math.Max(digits, 1)); } } return text; } private unsafe static bool TryInt64ToHexStr(long value, char hexBase, int digits, Span<char> destination, out int charsWritten) { int num = Math.Max(digits, System.Buffers.Text.FormattingHelpers.CountHexDigits((ulong)value)); if (num > destination.Length) { charsWritten = 0; return false; } charsWritten = num; fixed (char* ptr = &MemoryMarshal.GetReference(destination)) { char* buffer = ptr + num; if (High32((ulong)value) != 0) { buffer = Int32ToHexChars(buffer, Low32((ulong)value), hexBase, 8); buffer = Int32ToHexChars(buffer, High32((ulong)value), hexBase, digits - 8); } else { buffer = Int32ToHexChars(buffer, Low32((ulong)value), hexBase, Math.Max(digits, 1)); } } return true; } private unsafe static void UInt64ToNumber(ulong value, ref NumberBuffer number) { number.DigitsCount = 20; number.IsNegative = false; byte* digitsPointer = number.GetDigitsPointer(); byte* bufferEnd = digitsPointer + 20; while (High32(value) != 0) { bufferEnd = UInt32ToDecChars(bufferEnd, Int64DivMod1E9(ref value), 9); } bufferEnd = UInt32ToDecChars(bufferEnd, Low32(value), 0); int num = (number.Scale = (number.DigitsCount = (int)(digitsPointer + 20 - bufferEnd))); byte* digitsPointer2 = number.GetDigitsPointer(); while (--num >= 0) { *(digitsPointer2++) = *(bufferEnd++); } *digitsPointer2 = 0; } internal unsafe static string UInt64ToDecStr(ulong value, int digits) { if (digits < 1) { digits = 1; } int num = Math.Max(digits, System.Buffers.Text.FormattingHelpers.CountDigits(value)); if (num == 1) { return s_singleDigitStringCache[value]; } string text = FastAllocateString(num); fixed (char* ptr = text) { char* bufferEnd = ptr + num; while (High32(value) != 0) { bufferEnd = UInt32ToDecChars(bufferEnd, Int64DivMod1E9(ref value), 9); digits -= 9; } bufferEnd = UInt32ToDecChars(bufferEnd, Low32(value), digits); } return text; } private unsafe static bool TryUInt64ToDecStr(ulong value, int digits, Span<char> destination, out int charsWritten) { if (digits < 1) { digits = 1; } int num = Math.Max(digits, System.Buffers.Text.FormattingHelpers.CountDigits(value)); if (num > destination.Length) { charsWritten = 0; return false; } charsWritten = num; fixed (char* ptr = &MemoryMarshal.GetReference(destination)) { char* bufferEnd = ptr + num; while (High32(value) != 0) { bufferEnd = UInt32ToDecChars(bufferEnd, Int64DivMod1E9(ref value), 9); digits -= 9; } bufferEnd = UInt32ToDecChars(bufferEnd, Low32(value), digits); } return true; } internal static char ParseFormatSpecifier(ReadOnlySpan<char> format, out int digits) { char c = '\0'; if (format.Length > 0) { c = format[0]; if ((uint)(c - 65) <= 25u || (uint)(c - 97) <= 25u) { if (format.Length == 1) { digits = -1; return c; } if (format.Length == 2) { int num = format[1] - 48; if ((uint)num < 10u) { digits = num; return c; } } else if (format.Length == 3) { int num2 = format[1] - 48; int num3 = format[2] - 48; if ((uint)num2 < 10u && (uint)num3 < 10u) { digits = num2 * 10 + num3; return c; } } int num4 = 0; int num5 = 1; while (num5 < format.Length && (uint)(format[num5] - 48) < 10u && num4 < 10) { num4 = num4 * 10 + format[num5++] - 48; } if (num5 == format.Length || format[num5] == '\0') { digits = num4; return c; } } } digits = -1; if (format.Length != 0 && c != 0) { return '\0'; } return 'G'; } internal static void NumberToString(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, char format, int nMaxDigits, NumberFormatInfo info) { bool isCorrectlyRounded = number.Kind == NumberBufferKind.FloatingPoint; bool bSuppressScientific; switch (format) { case 'C': case 'c': if (nMaxDigits < 0) { nMaxDigits = info.CurrencyDecimalDigits; } RoundNumber(ref number, number.Scale + nMaxDigits, isCorrectlyRounded); FormatCurrency(ref sb, ref number, nMaxDigits, info); return; case 'F': case 'f': if (nMaxDigits < 0) { nMaxDigits = info.NumberDecimalDigits; } RoundNumber(ref number, number.Scale + nMaxDigits, isCorrectlyRounded); if (number.IsNegative) { sb.Append(info.NegativeSign); } FormatFixed(ref sb, ref number, nMaxDigits, null, info.NumberDecimalSeparator, null); return; case 'N': case 'n': if (nMaxDigits < 0) { nMaxDigits = info.NumberDecimalDigits; } RoundNumber(ref number, number.Scale + nMaxDigits, isCorrectlyRounded); FormatNumber(ref sb, ref number, nMaxDigits, info); return; case 'E': case 'e': if (nMaxDigits < 0) { nMaxDigits = 6; } nMaxDigits++; RoundNumber(ref number, nMaxDigits, isCorrectlyRounded); if (number.IsNegative) { sb.Append(info.NegativeSign); } FormatScientific(ref sb, ref number, nMaxDigits, info, format); return; case 'G': case 'g': bSuppressScientific = false; if (nMaxDigits < 1) { if (number.Kind == NumberBufferKind.Decimal && nMaxDigits == -1) { bSuppressScientific = true; if (number.Digits[0] != 0) { goto IL_0189; } goto IL_019e; } nMaxDigits = number.DigitsCount; } RoundNumber(ref number, nMaxDigits, isCorrectlyRounded); goto IL_0189; case 'P': case 'p': if (nMaxDigits < 0) { nMaxDigits = info.PercentDecimalDigits; } number.Scale += 2; RoundNumber(ref number, number.Scale + nMaxDigits, isCorrectlyRounded); FormatPercent(ref sb, ref number, nMaxDigits, info); return; case 'R': case 'r': { if (number.Kind != NumberBufferKind.FloatingPoint) { break; } format = (char)(format - 11); goto case 'G'; } IL_0189: if (number.IsNegative) { sb.Append(info.NegativeSign); } goto IL_019e; IL_019e: FormatGeneral(ref sb, ref number, nMaxDigits, info, (char)(format - 2), bSuppressScientific); return; } throw new FormatException("SR.Argument_BadFormatSpecifier"); } internal unsafe static void NumberToStringFormat(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, ReadOnlySpan<char> format, NumberFormatInfo info) { int num = 0; byte* digitsPointer = number.GetDigitsPointer(); int num2 = FindSection(format, (*digitsPointer == 0) ? 2 : (number.IsNegative ? 1 : 0)); int num3; int num4; bool flag; bool flag2; int num5; int num6; int num9; while (true) { num3 = 0; num4 = -1; num5 = int.MaxValue; num6 = 0; flag = false; int num7 = -1; flag2 = false; int num8 = 0; num9 = num2; fixed (char* ptr = &MemoryMarshal.GetReference(format)) { char c; while (num9 < format.Length && (c = ptr[num9++]) != 0) { switch (c) { case ';': break; case '#': num3++; continue; case '0': if (num5 == int.MaxValue) { num5 = num3; } num3++; num6 = num3; continue; case '.': if (num4 < 0) { num4 = num3; } continue; case ',': if (num3 <= 0 || num4 >= 0) { continue; } if (num7 >= 0) { if (num7 == num3) { num++; continue; } flag2 = true; } num7 = num3; num = 1; continue; case '%': num8 += 2; continue; case '‰': num8 += 3; continue; case '"': case '\'': while (num9 < format.Length && ptr[num9] != 0 && ptr[num9++] != c) { } continue; case '\\': if (num9 < format.Length && ptr[num9] != 0) { num9++; } continue; case 'E': case 'e': if ((num9 < format.Length && ptr[num9] == '0') || (num9 + 1 < format.Length && (ptr[num9] == '+' || ptr[num9] == '-') && ptr[num9 + 1] == '0')) { while (++num9 < format.Length && ptr[num9] == '0') { } flag = true; } continue; default: continue; } break; } } if (num4 < 0) { num4 = num3; } if (num7 >= 0) { if (num7 == num4) { num8 -= num * 3; } else { flag2 = true; } } if (*digitsPointer != 0) { number.Scale += num8; int pos = (flag ? num3 : (number.Scale + num3 - num4)); RoundNumber(ref number, pos, isCorrectlyRounded: false); if (*digitsPointer != 0) { break; } num9 = FindSection(format, 2); if (num9 == num2) { break; } num2 = num9; continue; } if (number.Kind != NumberBufferKind.FloatingPoint) { number.IsNegative = false; } number.Scale = 0; break; } num5 = ((num5 < num4) ? (num4 - num5) : 0); num6 = ((num6 > num4) ? (num4 - num6) : 0); int num10; int num11; if (flag) { num10 = num4; num11 = 0; } else { num10 = ((number.Scale > num4) ? number.Scale : num4); num11 = number.Scale - num4; } num9 = num2; Span<int> span = stackalloc int[4]; int num12 = -1; if (flag2 && info.NumberGroupSeparator.Length > 0) { int[] numberGroupSizes = info.NumberGroupSizes; int num13 = 0; int i = 0; int num14 = numberGroupSizes.Length; if (num14 != 0) { i = numberGroupSizes[num13]; } int num15 = i; int num16 = num10 + ((num11 < 0) ? num11 : 0); for (int num17 = ((num5 > num16) ? num5 : num16); num17 > i; i += num15) { if (num15 == 0) { break; } num12++; if (num12 >= span.Length) { int[] array = new int[span.Length * 2]; span.CopyTo(array); span = array; } span[num12] = i; if (num13 < num14 - 1) { num13++; num15 = numberGroupSizes[num13]; } } } if (number.IsNegative && num2 == 0 && number.Scale != 0) { sb.Append(info.NegativeSign); } bool flag3 = false;