Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Commit

Permalink
Use string.Create in BitConverter.ToString(byte[]) (#15218)
Browse files Browse the repository at this point in the history
Avoids unnecessary allocations and copying, and reduces the amount of unsafe code.
  • Loading branch information
justinvp authored and stephentoub committed Nov 26, 2017
1 parent a7ad29d commit dd74fca
Showing 1 changed file with 17 additions and 42 deletions.
59 changes: 17 additions & 42 deletions src/mscorlib/shared/System/BitConverter.cs
Expand Up @@ -354,17 +354,6 @@ public static double ToDouble(ReadOnlySpan<byte> value)
return Unsafe.ReadUnaligned<double>(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)
{
Expand All @@ -388,41 +377,27 @@ public static string ToString(byte[] value, int startIndex, int length)
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<byte>(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.
Expand Down

0 comments on commit dd74fca

Please sign in to comment.