From 70086cf416fcb7b7442c64b7431cf00592903221 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Tue, 24 Dec 2024 00:48:16 +0100 Subject: [PATCH 1/4] Guid cleanup: hex format --- .../System.Private.CoreLib/src/System/Guid.cs | 148 ++++++++---------- 1 file changed, 62 insertions(+), 86 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Guid.cs b/src/libraries/System.Private.CoreLib/src/System/Guid.cs index e4bea80bf69bf..d1576731ace81 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Guid.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Guid.cs @@ -423,40 +423,18 @@ public static bool TryParseExact(ReadOnlySpan input, [StringSyntax(StringS input = input.Trim(); var parseResult = new GuidResult(GuidParseThrowStyle.None); - bool success = false; - switch ((char)(format[0] | 0x20)) - { - case 'd': - success = TryParseExactD(input, ref parseResult); - break; - - case 'n': - success = TryParseExactN(input, ref parseResult); - break; - - case 'b': - success = TryParseExactB(input, ref parseResult); - break; - - case 'p': - success = TryParseExactP(input, ref parseResult); - break; - - case 'x': - success = TryParseExactX(input, ref parseResult); - break; - } + bool success = (char)(format[0] | 0x20) switch + { + 'd' => TryParseExactD(input, ref parseResult), + 'n' => TryParseExactN(input, ref parseResult), + 'b' => TryParseExactB(input, ref parseResult), + 'p' => TryParseExactP(input, ref parseResult), + 'x' => TryParseExactX(input, ref parseResult), + _ => false + }; - if (success) - { - result = parseResult.ToGuid(); - return true; - } - else - { - result = default; - return false; - } + result = success ? parseResult.ToGuid() : default; + return success; } private static bool TryParseGuid(ReadOnlySpan guidString, ref GuidResult result) @@ -469,7 +447,7 @@ private static bool TryParseGuid(ReadOnlySpan guidString, ref GuidResult r return false; } - return (guidString[0]) switch + return guidString[0] switch { '(' => TryParseExactP(guidString, ref result), '{' => guidString[9] == '-' ? @@ -1108,24 +1086,6 @@ private static unsafe int HexsToChars(TChar* guidChars, int a, int b) whe return 4; } - private static unsafe int HexsToCharsHexOutput(TChar* guidChars, int a, int b) where TChar : unmanaged, IUtfChar - { - guidChars[0] = TChar.CastFrom('0'); - guidChars[1] = TChar.CastFrom('x'); - - guidChars[2] = TChar.CastFrom(HexConverter.ToCharLower(a >> 4)); - guidChars[3] = TChar.CastFrom(HexConverter.ToCharLower(a)); - - guidChars[4] = TChar.CastFrom(','); - guidChars[5] = TChar.CastFrom('0'); - guidChars[6] = TChar.CastFrom('x'); - - guidChars[7] = TChar.CastFrom(HexConverter.ToCharLower(b >> 4)); - guidChars[8] = TChar.CastFrom(HexConverter.ToCharLower(b)); - - return 9; - } - // Returns the guid in "registry" format. public override string ToString() => ToString("d", null); @@ -1379,48 +1339,64 @@ internal unsafe bool TryFormatCore(Span destination, out int chars return true; } - private unsafe bool TryFormatX(Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar + private bool TryFormatX(Span dest, out int charsWritten) where TChar : unmanaged, IUtfChar { - if (destination.Length < 68) + if (dest.Length < 68) { charsWritten = 0; return false; } - charsWritten = 68; - - fixed (TChar* guidChars = &MemoryMarshal.GetReference(destination)) - { - TChar* p = guidChars; - // {0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}} - *p++ = TChar.CastFrom('{'); - *p++ = TChar.CastFrom('0'); - *p++ = TChar.CastFrom('x'); - p += HexsToChars(p, _a >> 24, _a >> 16); - p += HexsToChars(p, _a >> 8, _a); - *p++ = TChar.CastFrom(','); - *p++ = TChar.CastFrom('0'); - *p++ = TChar.CastFrom('x'); - p += HexsToChars(p, _b >> 8, _b); - *p++ = TChar.CastFrom(','); - *p++ = TChar.CastFrom('0'); - *p++ = TChar.CastFrom('x'); - p += HexsToChars(p, _c >> 8, _c); - *p++ = TChar.CastFrom(','); - *p++ = TChar.CastFrom('{'); - p += HexsToCharsHexOutput(p, _d, _e); - *p++ = TChar.CastFrom(','); - p += HexsToCharsHexOutput(p, _f, _g); - *p++ = TChar.CastFrom(','); - p += HexsToCharsHexOutput(p, _h, _i); - *p++ = TChar.CastFrom(','); - p += HexsToCharsHexOutput(p, _j, _k); - *p++ = TChar.CastFrom('}'); - *p = TChar.CastFrom('}'); - - Debug.Assert(p == guidChars + charsWritten - 1); + // {0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}} + dest[0] = TChar.CastFrom('{'); + dest[1] = TChar.CastFrom('0'); + dest[2] = TChar.CastFrom('x'); + dest[3] = TChar.CastFrom(HexConverter.ToCharLower(_a >> 28)); + dest[4] = TChar.CastFrom(HexConverter.ToCharLower(_a >> 24)); + dest[5] = TChar.CastFrom(HexConverter.ToCharLower(_a >> 20)); + dest[6] = TChar.CastFrom(HexConverter.ToCharLower(_a >> 16)); + dest[7] = TChar.CastFrom(HexConverter.ToCharLower(_a >> 12)); + dest[8] = TChar.CastFrom(HexConverter.ToCharLower(_a >> 8)); + dest[9] = TChar.CastFrom(HexConverter.ToCharLower(_a >> 4)); + dest[10] = TChar.CastFrom(HexConverter.ToCharLower(_a)); + dest[11] = TChar.CastFrom(','); + dest[12] = TChar.CastFrom('0'); + dest[13] = TChar.CastFrom('x'); + dest[14] = TChar.CastFrom(HexConverter.ToCharLower(_b >> 12)); + dest[15] = TChar.CastFrom(HexConverter.ToCharLower(_b >> 8)); + dest[16] = TChar.CastFrom(HexConverter.ToCharLower(_b >> 4)); + dest[17] = TChar.CastFrom(HexConverter.ToCharLower(_b)); + dest[18] = TChar.CastFrom(','); + dest[19] = TChar.CastFrom('0'); + dest[20] = TChar.CastFrom('x'); + dest[21] = TChar.CastFrom(HexConverter.ToCharLower(_c >> 12)); + dest[22] = TChar.CastFrom(HexConverter.ToCharLower(_c >> 8)); + dest[23] = TChar.CastFrom(HexConverter.ToCharLower(_c >> 4)); + dest[24] = TChar.CastFrom(HexConverter.ToCharLower(_c)); + dest[25] = TChar.CastFrom(','); + dest[26] = TChar.CastFrom('{'); + + // Write trailing "}}" here: + dest[66] = TChar.CastFrom('}'); + dest[67] = TChar.CastFrom('}'); + + // Write _d to _k bytes: + dest = dest[27..]; + var dkBytes = new Span(ref Unsafe.AsRef(in _d), 8); + for (int i = 0; i < dkBytes.Length; i++) + { + dest[0] = TChar.CastFrom('0'); + dest[1] = TChar.CastFrom('x'); + dest[2] = TChar.CastFrom(HexConverter.ToCharLower(dkBytes[i] >> 4)); + dest[3] = TChar.CastFrom(HexConverter.ToCharLower(dkBytes[i])); + if (i != dkBytes.Length - 1) + { + dest[4] = TChar.CastFrom(','); + dest = dest[5..]; + } } + charsWritten = 68; return true; } From cf36bce1511c2f92c0cd4ec3068baec8c05995aa Mon Sep 17 00:00:00 2001 From: EgorBo Date: Tue, 24 Dec 2024 01:40:29 +0100 Subject: [PATCH 2/4] Optimize TryFormatX --- .../System.Private.CoreLib/src/System/Guid.cs | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Guid.cs b/src/libraries/System.Private.CoreLib/src/System/Guid.cs index d1576731ace81..be51f9928c686 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Guid.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Guid.cs @@ -1375,29 +1375,31 @@ private bool TryFormatX(Span dest, out int charsWritten) where TCh dest[24] = TChar.CastFrom(HexConverter.ToCharLower(_c)); dest[25] = TChar.CastFrom(','); dest[26] = TChar.CastFrom('{'); - - // Write trailing "}}" here: + WriteHex(dest, 27, _d); + WriteHex(dest, 32, _e); + WriteHex(dest, 37, _f); + WriteHex(dest, 42, _g); + WriteHex(dest, 47, _h); + WriteHex(dest, 52, _i); + WriteHex(dest, 57, _j); + WriteHex(dest, 62, _k, appendComma: false); dest[66] = TChar.CastFrom('}'); dest[67] = TChar.CastFrom('}'); + charsWritten = 68; + return true; - // Write _d to _k bytes: - dest = dest[27..]; - var dkBytes = new Span(ref Unsafe.AsRef(in _d), 8); - for (int i = 0; i < dkBytes.Length; i++) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static void WriteHex(Span dest, int offset, int val, bool appendComma = true) { - dest[0] = TChar.CastFrom('0'); - dest[1] = TChar.CastFrom('x'); - dest[2] = TChar.CastFrom(HexConverter.ToCharLower(dkBytes[i] >> 4)); - dest[3] = TChar.CastFrom(HexConverter.ToCharLower(dkBytes[i])); - if (i != dkBytes.Length - 1) + dest[offset + 0] = TChar.CastFrom('0'); + dest[offset + 1] = TChar.CastFrom('x'); + dest[offset + 2] = TChar.CastFrom(HexConverter.ToCharLower(val >> 4)); + dest[offset + 3] = TChar.CastFrom(HexConverter.ToCharLower(val)); + if (appendComma) { - dest[4] = TChar.CastFrom(','); - dest = dest[5..]; + dest[offset + 4] = TChar.CastFrom(','); } } - - charsWritten = 68; - return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] From 94cd16aa287b6d84d24030bb437aeb20da794651 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Tue, 24 Dec 2024 04:52:59 +0100 Subject: [PATCH 3/4] revert unrelated changes --- .../System.Private.CoreLib/src/System/Guid.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Guid.cs b/src/libraries/System.Private.CoreLib/src/System/Guid.cs index be51f9928c686..4e4a6e21fd14e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Guid.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Guid.cs @@ -433,8 +433,16 @@ public static bool TryParseExact(ReadOnlySpan input, [StringSyntax(StringS _ => false }; - result = success ? parseResult.ToGuid() : default; - return success; + if (success) + { + result = parseResult.ToGuid(); + return true; + } + else + { + result = default; + return false; + } } private static bool TryParseGuid(ReadOnlySpan guidString, ref GuidResult result) @@ -447,7 +455,7 @@ private static bool TryParseGuid(ReadOnlySpan guidString, ref GuidResult r return false; } - return guidString[0] switch + return (guidString[0]) switch { '(' => TryParseExactP(guidString, ref result), '{' => guidString[9] == '-' ? From 61f5fe79f2e914ff279e6c5aa180ea44e3002b53 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 26 Dec 2024 20:33:17 +0100 Subject: [PATCH 4/4] Refactor switch statement in Guid parsing --- src/libraries/System.Private.CoreLib/src/System/Guid.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Guid.cs b/src/libraries/System.Private.CoreLib/src/System/Guid.cs index 4e4a6e21fd14e..999e82e81377e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Guid.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Guid.cs @@ -423,7 +423,7 @@ public static bool TryParseExact(ReadOnlySpan input, [StringSyntax(StringS input = input.Trim(); var parseResult = new GuidResult(GuidParseThrowStyle.None); - bool success = (char)(format[0] | 0x20) switch + bool success = (format[0] | 0x20) switch { 'd' => TryParseExactD(input, ref parseResult), 'n' => TryParseExactN(input, ref parseResult),