diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 16ba6ff21026e..29b8cda5cd196 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -329,7 +329,7 @@
-
+
@@ -2599,4 +2599,4 @@
-
+
\ No newline at end of file
diff --git a/src/libraries/System.Private.CoreLib/src/System/Convert.cs b/src/libraries/System.Private.CoreLib/src/System/Convert.cs
index 880bc2f6599ef..0967438585c4e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Convert.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Convert.cs
@@ -2099,7 +2099,7 @@ public static byte ToByte(string? value, int fromBase)
{
if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16)
{
- throw new ArgumentException(SR.Arg_InvalidBase);
+ ThrowInvalidBase();
}
if (value == null)
@@ -2122,7 +2122,7 @@ public static sbyte ToSByte(string? value, int fromBase)
{
if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16)
{
- throw new ArgumentException(SR.Arg_InvalidBase);
+ ThrowInvalidBase();
}
if (value == null)
@@ -2147,7 +2147,7 @@ public static short ToInt16(string? value, int fromBase)
{
if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16)
{
- throw new ArgumentException(SR.Arg_InvalidBase);
+ ThrowInvalidBase();
}
if (value == null)
@@ -2173,7 +2173,7 @@ public static ushort ToUInt16(string? value, int fromBase)
{
if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16)
{
- throw new ArgumentException(SR.Arg_InvalidBase);
+ ThrowInvalidBase();
}
if (value == null)
@@ -2195,7 +2195,7 @@ public static int ToInt32(string? value, int fromBase)
{
if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16)
{
- throw new ArgumentException(SR.Arg_InvalidBase);
+ ThrowInvalidBase();
}
return value != null ?
ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.IsTight) :
@@ -2211,7 +2211,7 @@ public static uint ToUInt32(string? value, int fromBase)
{
if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16)
{
- throw new ArgumentException(SR.Arg_InvalidBase);
+ ThrowInvalidBase();
}
return value != null ?
(uint)ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.TreatAsUnsigned | ParseNumbers.IsTight) :
@@ -2226,7 +2226,7 @@ public static long ToInt64(string? value, int fromBase)
{
if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16)
{
- throw new ArgumentException(SR.Arg_InvalidBase);
+ ThrowInvalidBase();
}
return value != null ?
ParseNumbers.StringToLong(value.AsSpan(), fromBase, ParseNumbers.IsTight) :
@@ -2242,7 +2242,7 @@ public static ulong ToUInt64(string? value, int fromBase)
{
if (fromBase != 2 && fromBase != 8 && fromBase != 10 && fromBase != 16)
{
- throw new ArgumentException(SR.Arg_InvalidBase);
+ ThrowInvalidBase();
}
return value != null ?
(ulong)ParseNumbers.StringToLong(value.AsSpan(), fromBase, ParseNumbers.TreatAsUnsigned | ParseNumbers.IsTight) :
@@ -2250,43 +2250,111 @@ public static ulong ToUInt64(string? value, int fromBase)
}
// Convert the byte value to a string in base fromBase
- public static string ToString(byte value, int toBase)
- {
- if (toBase != 2 && toBase != 8 && toBase != 10 && toBase != 16)
- {
- throw new ArgumentException(SR.Arg_InvalidBase);
- }
- return ParseNumbers.IntToString((int)value, toBase, -1, ' ', ParseNumbers.PrintAsI1);
- }
+ public static string ToString(byte value, int toBase) =>
+ ToString((int)value, toBase);
// Convert the Int16 value to a string in base fromBase
public static string ToString(short value, int toBase)
{
- if (toBase != 2 && toBase != 8 && toBase != 10 && toBase != 16)
+ string format = "d";
+
+ switch (toBase)
{
- throw new ArgumentException(SR.Arg_InvalidBase);
- }
- return ParseNumbers.IntToString((int)value, toBase, -1, ' ', ParseNumbers.PrintAsI2);
+ case 2:
+ format = "b";
+ break;
+
+ case 8:
+ return ToOctalString((ushort)value);
+
+ case 10:
+ break;
+
+ case 16:
+ format = "x";
+ break;
+
+ default:
+ ThrowInvalidBase();
+ break;
+ };
+
+ return value.ToString(format, CultureInfo.InvariantCulture);
}
// Convert the Int32 value to a string in base toBase
public static string ToString(int value, int toBase)
{
- if (toBase != 2 && toBase != 8 && toBase != 10 && toBase != 16)
+ string format = "d";
+
+ switch (toBase)
{
- throw new ArgumentException(SR.Arg_InvalidBase);
- }
- return ParseNumbers.IntToString(value, toBase, -1, ' ', 0);
+ case 2:
+ format = "b";
+ break;
+
+ case 8:
+ return ToOctalString((uint)value);
+
+ case 10:
+ break;
+
+ case 16:
+ format = "x";
+ break;
+
+ default:
+ ThrowInvalidBase();
+ break;
+ };
+
+ return value.ToString(format, CultureInfo.InvariantCulture);
}
// Convert the Int64 value to a string in base toBase
public static string ToString(long value, int toBase)
{
- if (toBase != 2 && toBase != 8 && toBase != 10 && toBase != 16)
+ string format = "d";
+
+ switch (toBase)
{
- throw new ArgumentException(SR.Arg_InvalidBase);
+ case 2:
+ format = "b";
+ break;
+
+ case 8:
+ return ToOctalString((ulong)value);
+
+ case 10:
+ break;
+
+ case 16:
+ format = "x";
+ break;
+
+ default:
+ ThrowInvalidBase();
+ break;
+ };
+
+ return value.ToString(format, CultureInfo.InvariantCulture);
+ }
+
+ private static void ThrowInvalidBase() => throw new ArgumentException(SR.Arg_InvalidBase);
+
+ private static string ToOctalString(ulong value)
+ {
+ Span chars = stackalloc char[22]; // max length of a ulong in octal
+
+ int i = chars.Length;
+ do
+ {
+ chars[--i] = (char)('0' + (value & 7));
+ value >>= 3;
}
- return ParseNumbers.LongToString(value, toBase, -1, ' ', 0);
+ while (value != 0);
+
+ return chars.Slice(i).ToString();
}
public static string ToBase64String(byte[] inArray)
diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs
index 41db3a79f707c..0a4d1ceaf6584 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs
@@ -102,6 +102,13 @@ namespace System
// left-padded with zeros to produce the number of digits given by the
// precision specifier.
//
+ // B b - Binary format. This format is
+ // supported for integral types only. The number is converted to a string of
+ // binary digits, '0' or '1'. The precision specifier indicates the minimum number
+ // of digits desired in the resulting string. If required, the number will be
+ // left-padded with zeros to produce the number of digits given by the
+ // precision specifier.
+ //
// Some examples of standard format strings and their results are shown in the
// table below. (The examples all assume a default NumberFormatInfo.)
//
@@ -934,6 +941,10 @@ static unsafe string FormatInt32Slow(int value, int hexMask, string? format, IFo
{
return Int32ToHexStr(value & hexMask, GetHexBase(fmt), digits);
}
+ else if (fmtUpper == 'B')
+ {
+ return UInt32ToBinaryStr((uint)(value & hexMask), digits);
+ }
else
{
NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
@@ -989,6 +1000,10 @@ static unsafe bool TryFormatInt32Slow(int value, int hexMask, ReadOnlySpan
{
return TryInt32ToHexStr(value & hexMask, GetHexBase(fmt), digits, destination, out charsWritten);
}
+ else if (fmtUpper == 'B')
+ {
+ return TryUInt32ToBinaryStr((uint)(value & hexMask), digits, destination, out charsWritten);
+ }
else
{
NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
@@ -1040,6 +1055,10 @@ static unsafe string FormatUInt32Slow(uint value, string? format, IFormatProvide
{
return Int32ToHexStr((int)value, GetHexBase(fmt), digits);
}
+ else if (fmtUpper == 'B')
+ {
+ return UInt32ToBinaryStr(value, digits);
+ }
else
{
NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
@@ -1093,6 +1112,10 @@ static unsafe bool TryFormatUInt32Slow(uint value, ReadOnlySpan format, IF
{
return TryInt32ToHexStr((int)value, GetHexBase(fmt), digits, destination, out charsWritten);
}
+ else if (fmtUpper == 'B')
+ {
+ return TryUInt32ToBinaryStr(value, digits, destination, out charsWritten);
+ }
else
{
NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
@@ -1148,6 +1171,10 @@ static unsafe string FormatInt64Slow(long value, string? format, IFormatProvider
{
return Int64ToHexStr(value, GetHexBase(fmt), digits);
}
+ else if (fmtUpper == 'B')
+ {
+ return UInt64ToBinaryStr((ulong)value, digits);
+ }
else
{
NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
@@ -1205,6 +1232,10 @@ static unsafe bool TryFormatInt64Slow(long value, ReadOnlySpan format, IFo
{
return TryInt64ToHexStr(value, GetHexBase(fmt), digits, destination, out charsWritten);
}
+ else if (fmtUpper == 'B')
+ {
+ return TryUInt64ToBinaryStr((ulong)value, digits, destination, out charsWritten);
+ }
else
{
NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
@@ -1256,6 +1287,10 @@ static unsafe string FormatUInt64Slow(ulong value, string? format, IFormatProvid
{
return Int64ToHexStr((long)value, GetHexBase(fmt), digits);
}
+ else if (fmtUpper == 'B')
+ {
+ return UInt64ToBinaryStr(value, digits);
+ }
else
{
NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
@@ -1309,6 +1344,10 @@ static unsafe bool TryFormatUInt64Slow(ulong value, ReadOnlySpan format, I
{
return TryInt64ToHexStr((long)value, GetHexBase(fmt), digits, destination, out charsWritten);
}
+ else if (fmtUpper == 'B')
+ {
+ return TryUInt64ToBinaryStr(value, digits, destination, out charsWritten);
+ }
else
{
NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
@@ -1366,6 +1405,10 @@ static unsafe string FormatInt128Slow(Int128 value, string? format, IFormatProvi
{
return Int128ToHexStr(value, GetHexBase(fmt), digits);
}
+ else if (fmtUpper == 'B')
+ {
+ return UInt128ToBinaryStr(value, digits);
+ }
else
{
NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
@@ -1423,6 +1466,10 @@ static unsafe bool TryFormatInt128Slow(Int128 value, ReadOnlySpan format,
{
return TryInt128ToHexStr(value, GetHexBase(fmt), digits, destination, out charsWritten);
}
+ else if (fmtUpper == 'B')
+ {
+ return TryUInt128ToBinaryStr(value, digits, destination, out charsWritten);
+ }
else
{
NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
@@ -1476,6 +1523,10 @@ static unsafe string FormatUInt128Slow(UInt128 value, string? format, IFormatPro
{
return Int128ToHexStr((Int128)value, GetHexBase(fmt), digits);
}
+ else if (fmtUpper == 'B')
+ {
+ return UInt128ToBinaryStr((Int128)value, digits);
+ }
else
{
NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
@@ -1529,6 +1580,10 @@ static unsafe bool TryFormatUInt128Slow(UInt128 value, ReadOnlySpan format
{
return TryInt128ToHexStr((Int128)value, GetHexBase(fmt), digits, destination, out charsWritten);
}
+ else if (fmtUpper == 'B')
+ {
+ return TryUInt128ToBinaryStr((Int128)value, digits, destination, out charsWritten);
+ }
else
{
NumberFormatInfo info = NumberFormatInfo.GetInstance(provider);
@@ -1708,6 +1763,61 @@ private static unsafe bool TryInt32ToHexStr(int value, char hexBase, int
return buffer;
}
+ private static unsafe string UInt32ToBinaryStr(uint value, int digits)
+ {
+ if (digits < 1)
+ {
+ digits = 1;
+ }
+
+ int bufferLength = Math.Max(digits, 32 - (int)uint.LeadingZeroCount(value));
+ string result = string.FastAllocateString(bufferLength);
+ fixed (char* buffer = result)
+ {
+ char* p = UInt32ToBinaryChars(buffer + bufferLength, value, digits);
+ Debug.Assert(p == buffer);
+ }
+ return result;
+ }
+
+ private static unsafe bool TryUInt32ToBinaryStr(uint value, int digits, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
+ {
+ Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
+
+ if (digits < 1)
+ {
+ digits = 1;
+ }
+
+ int bufferLength = Math.Max(digits, 32 - (int)uint.LeadingZeroCount(value));
+ if (bufferLength > destination.Length)
+ {
+ charsWritten = 0;
+ return false;
+ }
+
+ charsWritten = bufferLength;
+ fixed (TChar* buffer = &MemoryMarshal.GetReference(destination))
+ {
+ TChar* p = UInt32ToBinaryChars(buffer + bufferLength, value, digits);
+ Debug.Assert(p == buffer);
+ }
+ return true;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe TChar* UInt32ToBinaryChars(TChar* buffer, uint value, int digits) where TChar : unmanaged, IUtfChar
+ {
+ Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
+
+ while (--digits >= 0 || value != 0)
+ {
+ *(--buffer) = TChar.CastFrom('0' + (byte)(value & 0x1));
+ value >>= 1;
+ }
+ return buffer;
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void UInt32ToNumber(uint value, ref NumberBuffer number)
{
@@ -2102,6 +2212,77 @@ private static unsafe bool TryInt64ToHexStr(long value, char hexBase, int
#endif
}
+ private static unsafe string UInt64ToBinaryStr(ulong value, int digits)
+ {
+ if (digits < 1)
+ {
+ digits = 1;
+ }
+
+ int bufferLength = Math.Max(digits, 64 - (int)ulong.LeadingZeroCount(value));
+ string result = string.FastAllocateString(bufferLength);
+ fixed (char* buffer = result)
+ {
+ char* p = UInt64ToBinaryChars(buffer + bufferLength, value, digits);
+ Debug.Assert(p == buffer);
+ }
+ return result;
+ }
+
+ private static unsafe bool TryUInt64ToBinaryStr(ulong value, int digits, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
+ {
+ Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
+
+ if (digits < 1)
+ {
+ digits = 1;
+ }
+
+ int bufferLength = Math.Max(digits, 64 - (int)ulong.LeadingZeroCount(value));
+ if (bufferLength > destination.Length)
+ {
+ charsWritten = 0;
+ return false;
+ }
+
+ charsWritten = bufferLength;
+ fixed (TChar* buffer = &MemoryMarshal.GetReference(destination))
+ {
+ TChar* p = UInt64ToBinaryChars(buffer + bufferLength, value, digits);
+ Debug.Assert(p == buffer);
+ }
+ return true;
+ }
+
+#if TARGET_64BIT
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#endif
+ private static unsafe TChar* UInt64ToBinaryChars(TChar* buffer, ulong value, int digits) where TChar : unmanaged, IUtfChar
+ {
+ Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
+#if TARGET_32BIT
+ uint lower = (uint)value;
+ uint upper = (uint)(value >> 32);
+
+ if (upper != 0)
+ {
+ buffer = UInt32ToBinaryChars(buffer, lower, 32);
+ return UInt32ToBinaryChars(buffer, upper, digits - 32);
+ }
+ else
+ {
+ return UInt32ToBinaryChars(buffer, lower, Math.Max(digits, 1));
+ }
+#else
+ while (--digits >= 0 || value != 0)
+ {
+ *(--buffer) = TChar.CastFrom('0' + (byte)(value & 0x1));
+ value >>= 1;
+ }
+ return buffer;
+#endif
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void UInt64ToNumber(ulong value, ref NumberBuffer number)
{
@@ -2452,6 +2633,69 @@ private static unsafe bool TryInt128ToHexStr(Int128 value, char hexBase,
}
}
+ private static unsafe string UInt128ToBinaryStr(Int128 value, int digits)
+ {
+ if (digits < 1)
+ {
+ digits = 1;
+ }
+
+ UInt128 uValue = (UInt128)value;
+
+ int bufferLength = Math.Max(digits, 128 - (int)UInt128.LeadingZeroCount((UInt128)value));
+ string result = string.FastAllocateString(bufferLength);
+ fixed (char* buffer = result)
+ {
+ char* p = UInt128ToBinaryChars(buffer + bufferLength, uValue, digits);
+ Debug.Assert(p == buffer);
+ }
+ return result;
+ }
+
+ private static unsafe bool TryUInt128ToBinaryStr(Int128 value, int digits, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
+ {
+ Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
+
+ if (digits < 1)
+ {
+ digits = 1;
+ }
+
+ UInt128 uValue = (UInt128)value;
+
+ int bufferLength = Math.Max(digits, 128 - (int)UInt128.LeadingZeroCount((UInt128)value));
+ if (bufferLength > destination.Length)
+ {
+ charsWritten = 0;
+ return false;
+ }
+
+ charsWritten = bufferLength;
+ fixed (TChar* buffer = &MemoryMarshal.GetReference(destination))
+ {
+ TChar* p = UInt128ToBinaryChars(buffer + bufferLength, uValue, digits);
+ Debug.Assert(p == buffer);
+ }
+ return true;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe TChar* UInt128ToBinaryChars(TChar* buffer, UInt128 value, int digits) where TChar : unmanaged, IUtfChar
+ {
+ ulong lower = value.Lower;
+ ulong upper = value.Upper;
+
+ if (upper != 0)
+ {
+ buffer = UInt64ToBinaryChars(buffer, lower, 64);
+ return UInt64ToBinaryChars(buffer, upper, digits - 64);
+ }
+ else
+ {
+ return UInt64ToBinaryChars(buffer, lower, Math.Max(digits, 1));
+ }
+ }
+
private static unsafe void UInt128ToNumber(UInt128 value, ref NumberBuffer number)
{
number.DigitsCount = UInt128Precision;
diff --git a/src/libraries/System.Private.CoreLib/src/System/ParseNumbers.cs b/src/libraries/System.Private.CoreLib/src/System/ParseNumbers.cs
index 70fac44ccfe0c..76c4f52cb8719 100644
--- a/src/libraries/System.Private.CoreLib/src/System/ParseNumbers.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/ParseNumbers.cs
@@ -9,23 +9,10 @@ namespace System
/// Methods for parsing numbers and strings.
internal static class ParseNumbers
{
- internal const int LeftAlign = 0x0001;
- internal const int RightAlign = 0x0004;
- internal const int PrefixSpace = 0x0008;
- internal const int PrintSign = 0x0010;
- internal const int PrintBase = 0x0020;
- internal const int PrintAsI1 = 0x0040;
- internal const int PrintAsI2 = 0x0080;
- internal const int PrintAsI4 = 0x0100;
internal const int TreatAsUnsigned = 0x0200;
internal const int TreatAsI1 = 0x0400;
internal const int TreatAsI2 = 0x0800;
internal const int IsTight = 0x1000;
- internal const int NoSpace = 0x2000;
- internal const int PrintRadixBase = 0x4000;
-
- private const int MinRadix = 2;
- private const int MaxRadix = 36;
public static unsafe long StringToLong(ReadOnlySpan s, int radix, int flags)
{
@@ -51,7 +38,7 @@ public static long StringToLong(ReadOnlySpan s, int radix, int flags, ref
throw new ArgumentOutOfRangeException(SR.ArgumentOutOfRange_IndexMustBeLess);
// Get rid of the whitespace and then check that we've still got some digits to parse.
- if (((flags & IsTight) == 0) && ((flags & NoSpace) == 0))
+ if ((flags & IsTight) == 0)
{
EatWhiteSpace(s, ref i);
if (i == length)
@@ -139,7 +126,7 @@ public static int StringToInt(ReadOnlySpan s, int radix, int flags, ref in
throw new ArgumentOutOfRangeException(SR.ArgumentOutOfRange_IndexMustBeLess);
// Get rid of the whitespace and then check that we've still got some digits to parse.
- if (((flags & IsTight) == 0) && ((flags & NoSpace) == 0))
+ if ((flags & IsTight) == 0)
{
EatWhiteSpace(s, ref i);
if (i == length)
@@ -215,294 +202,6 @@ public static int StringToInt(ReadOnlySpan s, int radix, int flags, ref in
return result;
}
- public static string IntToString(int n, int radix, int width, char paddingChar, int flags)
- {
- Span buffer = stackalloc char[66]; // Longest possible string length for an integer in binary notation with prefix
-
- if (radix < MinRadix || radix > MaxRadix)
- throw new ArgumentException(SR.Arg_InvalidBase, nameof(radix));
-
- // If the number is negative, make it positive and remember the sign.
- // If the number is MIN_VALUE, this will still be negative, so we'll have to
- // special case this later.
- bool isNegative = false;
- uint l;
- if (n < 0)
- {
- isNegative = true;
-
- // For base 10, write out -num, but other bases write out the
- // 2's complement bit pattern
- l = (10 == radix) ? (uint)-n : (uint)n;
- }
- else
- {
- l = (uint)n;
- }
-
- // The conversion to a uint will sign extend the number. In order to ensure
- // that we only get as many bits as we expect, we chop the number.
- if ((flags & PrintAsI1) != 0)
- {
- l &= 0xFF;
- }
- else if ((flags & PrintAsI2) != 0)
- {
- l &= 0xFFFF;
- }
-
- // Special case the 0.
- int index;
- if (0 == l)
- {
- buffer[0] = '0';
- index = 1;
- }
- else
- {
- index = 0;
- for (int i = 0; i < buffer.Length; i++) // for (...;i buffer = stackalloc char[67]; // Longest possible string length for an integer in binary notation with prefix
-
- if (radix < MinRadix || radix > MaxRadix)
- throw new ArgumentException(SR.Arg_InvalidBase, nameof(radix));
-
- // If the number is negative, make it positive and remember the sign.
- ulong ul;
- bool isNegative = false;
- if (n < 0)
- {
- isNegative = true;
-
- // For base 10, write out -num, but other bases write out the
- // 2's complement bit pattern
- ul = (10 == radix) ? (ulong)(-n) : (ulong)n;
- }
- else
- {
- ul = (ulong)n;
- }
-
- if ((flags & PrintAsI1) != 0)
- {
- ul &= 0xFF;
- }
- else if ((flags & PrintAsI2) != 0)
- {
- ul &= 0xFFFF;
- }
- else if ((flags & PrintAsI4) != 0)
- {
- ul &= 0xFFFFFFFF;
- }
-
- // Special case the 0.
- int index;
- if (0 == ul)
- {
- buffer[0] = '0';
- index = 1;
- }
- else
- {
- index = 0;
- for (int i = 0; i < buffer.Length; i++) // for loop instead of do{...}while(l!=0) to help JIT eliminate span bounds checks
- {
- ulong div = ul / (ulong)radix; // TODO https://github.com/dotnet/runtime/issues/5213
- int charVal = (int)(ul - (div * (ulong)radix));
- ul = div;
-
- buffer[i] = (charVal < 10) ?
- (char)(charVal + '0') :
- (char)(charVal + 'a' - 10);
-
- if (ul == 0)
- {
- index = i + 1;
- break;
- }
- }
- Debug.Assert(ul == 0, $"Expected {ul} == 0");
- }
-
- // If they want the base, append that to the string (in reverse order)
- if (radix != 10 && ((flags & PrintBase) != 0))
- {
- if (16 == radix)
- {
- buffer[index++] = 'x';
- buffer[index++] = '0';
- }
- else if (8 == radix)
- {
- buffer[index++] = '0';
- }
- else if ((flags & PrintRadixBase) != 0)
- {
- buffer[index++] = '#';
- buffer[index++] = (char)((radix % 10) + '0');
- buffer[index++] = (char)((radix / 10) + '0');
- }
- }
-
- if (10 == radix)
- {
- // If it was negative, append the sign.
- if (isNegative)
- {
- buffer[index++] = '-';
- }
-
- // else if they requested, add the '+';
- else if ((flags & PrintSign) != 0)
- {
- buffer[index++] = '+';
- }
-
- // If they requested a leading space, put it on.
- else if ((flags & PrefixSpace) != 0)
- {
- buffer[index++] = ' ';
- }
- }
-
- // Figure out the size of and allocate the resulting string
- string result = string.FastAllocateString(Math.Max(width, index));
- unsafe
- {
- // Put the characters into the string in reverse order.
- // Fill the remaining space, if there is any, with the correct padding character.
- fixed (char* resultPtr = result)
- {
- char* p = resultPtr;
- int padding = result.Length - index;
-
- if ((flags & LeftAlign) != 0)
- {
- for (int i = 0; i < padding; i++)
- {
- *p++ = paddingChar;
- }
-
- for (int i = 0; i < index; i++)
- {
- *p++ = buffer[index - i - 1];
- }
- }
- else
- {
- for (int i = 0; i < index; i++)
- {
- *p++ = buffer[index - i - 1];
- }
-
- for (int i = 0; i < padding; i++)
- {
- *p++ = paddingChar;
- }
- }
-
- Debug.Assert((p - resultPtr) == result.Length, $"Expected {p - resultPtr} == {result.Length}");
- }
- }
- return result;
- }
-
private static void EatWhiteSpace(ReadOnlySpan s, ref int i)
{
int localIndex = i;
diff --git a/src/libraries/System.Runtime/tests/System/ByteTests.cs b/src/libraries/System.Runtime/tests/System/ByteTests.cs
index 94c41f34aa95d..6fdd9bc01646a 100644
--- a/src/libraries/System.Runtime/tests/System/ByteTests.cs
+++ b/src/libraries/System.Runtime/tests/System/ByteTests.cs
@@ -99,11 +99,15 @@ public static IEnumerable