From 4bf1750b4c84e248ea76d67580ccc956e0e48284 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sat, 24 Jul 2021 09:40:29 -0400 Subject: [PATCH] Revert Version.TryFormat changes (#56051) * Revert Version.TryFormat changes to use interpolated strings This was already optimized to use spans directly. Using our new span-based interpolated string handler was simpler code, but a few more nanoseconds. Reverting. * Tweak original code Make error handling a bit more clear, and use uint formatting rather than int formatting for small perf boost. --- .../src/System/Version.cs | 66 +++++++++++++------ 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Version.cs b/src/libraries/System.Private.CoreLib/src/System/Version.cs index bf0ce8e2b4c53..469da80ebe7cf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Version.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Version.cs @@ -197,33 +197,61 @@ public bool TryFormat(Span destination, out int charsWritten) => public bool TryFormat(Span destination, int fieldCount, out int charsWritten) { - switch (fieldCount) + switch ((uint)fieldCount) { - case 0: - charsWritten = 0; - return true; + case > 4: + ThrowArgumentException("4"); + break; + + case >= 3 when _Build == -1: + ThrowArgumentException("2"); + break; - case 1: - return ((uint)_Major).TryFormat(destination, out charsWritten); + case 4 when _Revision == -1: + ThrowArgumentException("3"); + break; + + static void ThrowArgumentException(string failureUpperBound) => + throw new ArgumentException(SR.Format(SR.ArgumentOutOfRange_Bounds_Lower_Upper, "0", failureUpperBound), nameof(fieldCount)); + } - case 2: - return destination.TryWrite($"{(uint)_Major}.{(uint)_Minor}", out charsWritten); + int totalCharsWritten = 0; - case 3: - if (_Build == -1) throw CreateBoundException("3"); - return destination.TryWrite($"{(uint)_Major}.{(uint)_Minor}.{(uint)_Build}", out charsWritten); + for (int i = 0; i < fieldCount; i++) + { + if (i != 0) + { + if (destination.IsEmpty) + { + charsWritten = 0; + return false; + } - case 4: - if (_Build == -1) throw CreateBoundException("2"); - if (_Revision == -1) throw CreateBoundException("3"); - return destination.TryWrite($"{(uint)_Major}.{(uint)_Minor}.{(uint)_Build}.{(uint)_Revision}", out charsWritten); + destination[0] = '.'; + destination = destination.Slice(1); + totalCharsWritten++; + } + + int value = i switch + { + 0 => _Major, + 1 => _Minor, + 2 => _Build, + _ => _Revision + }; + + if (!((uint)value).TryFormat(destination, out int valueCharsWritten)) + { + charsWritten = 0; + return false; + } - default: - throw CreateBoundException("4"); + totalCharsWritten += valueCharsWritten; + destination = destination.Slice(valueCharsWritten); } - static Exception CreateBoundException(string failureUpperBound) => - new ArgumentException(SR.Format(SR.ArgumentOutOfRange_Bounds_Lower_Upper, "0", failureUpperBound), nameof(fieldCount)); + charsWritten = totalCharsWritten; + return true; } bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) =>