From dd74fca452ccfc8666d4f88a19b79ffa3aa53d3d Mon Sep 17 00:00:00 2001 From: Justin Van Patten Date: Sat, 25 Nov 2017 18:32:15 -0800 Subject: [PATCH] Use string.Create in BitConverter.ToString(byte[]) (#15218) Avoids unnecessary allocations and copying, and reduces the amount of unsafe code. --- src/mscorlib/shared/System/BitConverter.cs | 59 +++++++--------------- 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/src/mscorlib/shared/System/BitConverter.cs b/src/mscorlib/shared/System/BitConverter.cs index 681404796b..f5e00f1833 100644 --- a/src/mscorlib/shared/System/BitConverter.cs +++ b/src/mscorlib/shared/System/BitConverter.cs @@ -354,17 +354,6 @@ namespace System return Unsafe.ReadUnaligned(ref value.DangerousGetPinnableReference()); } - private static char GetHexValue(int i) - { - Debug.Assert(i >= 0 && i < 16, "i is out of range."); - if (i < 10) - { - return (char)(i + '0'); - } - - return (char)(i - 10 + 'A'); - } - // Converts an array of bytes into a String. public static string ToString(byte[] value, int startIndex, int length) { @@ -388,41 +377,27 @@ namespace System throw new ArgumentOutOfRangeException(nameof(length), SR.Format(SR.ArgumentOutOfRange_LengthTooLarge, (int.MaxValue / 3))); } - int chArrayLength = length * 3; - const int StackLimit = 512; // arbitrary limit to switch from stack to heap allocation - unsafe + return string.Create(length * 3 - 1, (value, startIndex, length), (dst, state) => { - if (chArrayLength < StackLimit) - { - char* chArrayPtr = stackalloc char[chArrayLength]; - return ToString(value, startIndex, length, chArrayPtr, chArrayLength); - } - else - { - char[] chArray = new char[chArrayLength]; - fixed (char* chArrayPtr = &chArray[0]) - return ToString(value, startIndex, length, chArrayPtr, chArrayLength); - } - } - } + const string HexValues = "0123456789ABCDEF"; - private static unsafe string ToString(byte[] value, int startIndex, int length, char* chArray, int chArrayLength) - { - Debug.Assert(length > 0); - Debug.Assert(chArrayLength == length * 3); + var src = new ReadOnlySpan(state.value, state.startIndex, state.length); - char* p = chArray; - int endIndex = startIndex + length; - for (int i = startIndex; i < endIndex; i++) - { - byte b = value[i]; - *p++ = GetHexValue(b >> 4); - *p++ = GetHexValue(b & 0xF); - *p++ = '-'; - } + int i = 0; + int j = 0; + + byte b = src[i++]; + dst[j++] = HexValues[b >> 4]; + dst[j++] = HexValues[b & 0xF]; - // We don't need the last '-' character - return new string(chArray, 0, chArrayLength - 1); + while (i < src.Length) + { + b = src[i++]; + dst[j++] = '-'; + dst[j++] = HexValues[b >> 4]; + dst[j++] = HexValues[b & 0xF]; + } + }); } // Converts an array of bytes into a String. -- 2.34.1