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 352dc61d2c5b..1fe71ef64c89 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 @@ - + @@ -2600,4 +2600,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 880bc2f6599e..0967438585c4 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 41db3a79f707..0a4d1ceaf658 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 string Int32ToHexStr(int value, char hexBase, int digits) 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 string Int64ToHexStr(long value, char hexBase, int digits) #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 string Int128ToHexStr(Int128 value, char hexBase, int digi } } + 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 70fac44ccfe0..76c4f52cb871 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 94c41f34aa95..6fdd9bc01646 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 ToString_TestData() yield return new object[] { (byte)123, "D", emptyFormat, "123" }; yield return new object[] { (byte)123, "D99", emptyFormat, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123" }; + yield return new object[] { (byte)0, "x", emptyFormat, "0" }; yield return new object[] { (byte)0x24, "x", emptyFormat, "24" }; - yield return new object[] { (byte)24, "N", emptyFormat, string.Format("{0:N}", 24.00) }; + yield return new object[] { (byte)0, "b", emptyFormat, "0" }; + yield return new object[] { (byte)0x24, "b", emptyFormat, "100100" }; + yield return new object[] { (byte)24, "N", emptyFormat, string.Format("{0:N}", 24.00) }; } + NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; yield return new object[] { (byte)32, "C100", invariantFormat, "\u00A432.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (byte)32, "P100", invariantFormat, "3,200.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; @@ -112,6 +116,7 @@ public static IEnumerable ToString_TestData() yield return new object[] { (byte)32, "F100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (byte)32, "N100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (byte)32, "X100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020" }; + yield return new object[] { (byte)32, "B100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000" }; var customFormat = new NumberFormatInfo() { diff --git a/src/libraries/System.Runtime/tests/System/Int128Tests.cs b/src/libraries/System.Runtime/tests/System/Int128Tests.cs index 1161a6d763a7..c8e22a6be776 100644 --- a/src/libraries/System.Runtime/tests/System/Int128Tests.cs +++ b/src/libraries/System.Runtime/tests/System/Int128Tests.cs @@ -130,8 +130,14 @@ public static IEnumerable ToString_TestData() yield return new object[] { (Int128)4567, "D99\09", defaultFormat, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; yield return new object[] { (Int128)(-4567), "D99", defaultFormat, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; + yield return new object[] { (Int128)0, "x", defaultFormat, "0" }; yield return new object[] { (Int128)0x2468, "x", defaultFormat, "2468" }; yield return new object[] { (Int128)(-0x2468), "x", defaultFormat, "ffffffffffffffffffffffffffffdb98" }; + + yield return new object[] { (Int128)0, "b", defaultFormat, "0" }; + yield return new object[] { (Int128)0x2468, "b", defaultFormat, "10010001101000" }; + yield return new object[] { (Int128)(-0x2468), "b", defaultFormat, "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111101101110011000" }; + yield return new object[] { (Int128)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; } @@ -143,6 +149,7 @@ public static IEnumerable ToString_TestData() yield return new object[] { (Int128)32, "F100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (Int128)32, "N100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (Int128)32, "X100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020" }; + yield return new object[] { (Int128)32, "B100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000" }; var customFormat = new NumberFormatInfo() { diff --git a/src/libraries/System.Runtime/tests/System/Int16Tests.cs b/src/libraries/System.Runtime/tests/System/Int16Tests.cs index 60ffdcac3158..5961735ee0ee 100644 --- a/src/libraries/System.Runtime/tests/System/Int16Tests.cs +++ b/src/libraries/System.Runtime/tests/System/Int16Tests.cs @@ -115,11 +115,15 @@ public static IEnumerable ToString_TestData() yield return new object[] { (short)4567, "D99\09", defaultFormat, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; yield return new object[] { (short)-4567, "D99", defaultFormat, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; + yield return new object[] { (short)0, "x", defaultFormat, "0" }; yield return new object[] { (short)0x2468, "x", defaultFormat, "2468" }; yield return new object[] { (short)-0x2468, "x", defaultFormat, "db98" }; - yield return new object[] { (short)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; + yield return new object[] { (short)0, "b", defaultFormat, "0" }; + yield return new object[] { (short)0x2468, "b", defaultFormat, "10010001101000" }; + yield return new object[] { (short)-0x2468, "b", defaultFormat, "1101101110011000" }; + yield return new object[] { (short)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; @@ -130,6 +134,7 @@ public static IEnumerable ToString_TestData() yield return new object[] { (short)32, "F100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (short)32, "N100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (short)32, "X100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020" }; + yield return new object[] { (short)32, "B100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000" }; var customFormat = new NumberFormatInfo() { diff --git a/src/libraries/System.Runtime/tests/System/Int32Tests.cs b/src/libraries/System.Runtime/tests/System/Int32Tests.cs index e619fff5ea5d..4230c9a4194a 100644 --- a/src/libraries/System.Runtime/tests/System/Int32Tests.cs +++ b/src/libraries/System.Runtime/tests/System/Int32Tests.cs @@ -115,8 +115,14 @@ public static IEnumerable ToString_TestData() yield return new object[] { 4567, "D99\09", defaultFormat, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; yield return new object[] { -4567, "D99\09", defaultFormat, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; + yield return new object[] { 0, "x", defaultFormat, "0" }; yield return new object[] { 0x2468, "x", defaultFormat, "2468" }; yield return new object[] { -0x2468, "x", defaultFormat, "ffffdb98" }; + + yield return new object[] { 0, "b", defaultFormat, "0" }; + yield return new object[] { 0x2468, "b", defaultFormat, "10010001101000" }; + yield return new object[] { -0x2468, "b", defaultFormat, "11111111111111111101101110011000" }; + yield return new object[] { 2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; } @@ -129,6 +135,7 @@ public static IEnumerable ToString_TestData() yield return new object[] { 32, "F100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { 32, "N100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { 32, "X100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020" }; + yield return new object[] { 32, "B100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000" }; var customFormat = new NumberFormatInfo() { diff --git a/src/libraries/System.Runtime/tests/System/Int64Tests.cs b/src/libraries/System.Runtime/tests/System/Int64Tests.cs index 052ae58bdd81..da476b279cde 100644 --- a/src/libraries/System.Runtime/tests/System/Int64Tests.cs +++ b/src/libraries/System.Runtime/tests/System/Int64Tests.cs @@ -116,11 +116,15 @@ public static IEnumerable ToString_TestData() yield return new object[] { (long)4567, "D99\09", defaultFormat, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; yield return new object[] { (long)-4567, "D99", defaultFormat, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; + yield return new object[] { (long)0, "x", defaultFormat, "0" }; yield return new object[] { (long)0x2468, "x", defaultFormat, "2468" }; yield return new object[] { (long)-0x2468, "x", defaultFormat, "ffffffffffffdb98" }; - yield return new object[] { (long)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; + yield return new object[] { (long)0, "b", defaultFormat, "0" }; + yield return new object[] { (long)0x2468, "b", defaultFormat, "10010001101000" }; + yield return new object[] { (long)-0x2468, "b", defaultFormat, "1111111111111111111111111111111111111111111111111101101110011000" }; + yield return new object[] { (long)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; @@ -131,6 +135,7 @@ public static IEnumerable ToString_TestData() yield return new object[] { (long)32, "F100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (long)32, "N100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (long)32, "X100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020" }; + yield return new object[] { (long)32, "B100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000" }; var customFormat = new NumberFormatInfo() { diff --git a/src/libraries/System.Runtime/tests/System/IntPtrTests.cs b/src/libraries/System.Runtime/tests/System/IntPtrTests.cs index 24cc1d3d8585..147848f5e117 100644 --- a/src/libraries/System.Runtime/tests/System/IntPtrTests.cs +++ b/src/libraries/System.Runtime/tests/System/IntPtrTests.cs @@ -287,8 +287,14 @@ public static IEnumerable ToString_TestData() yield return new object[] { (nint)4567, "D99\09", defaultFormat, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; yield return new object[] { (nint)(-4567), "D99\09", defaultFormat, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; + yield return new object[] { (nint)0, "x", defaultFormat, "0" }; yield return new object[] { (nint)0x2468, "x", defaultFormat, "2468" }; yield return new object[] { (nint)(-0x2468), "x", defaultFormat, Is64Bit ? "ffffffffffffdb98" : "ffffdb98" }; + + yield return new object[] { (nint)0, "b", defaultFormat, "0" }; + yield return new object[] { (nint)0x2468, "b", defaultFormat, "10010001101000" }; + yield return new object[] { (nint)(-0x2468), "b", defaultFormat, Is64Bit ? "1111111111111111111111111111111111111111111111111101101110011000" : "11111111111111111101101110011000" }; + yield return new object[] { (nint)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; } diff --git a/src/libraries/System.Runtime/tests/System/SByteTests.cs b/src/libraries/System.Runtime/tests/System/SByteTests.cs index 7a2b9b946f4b..2768a5d1655c 100644 --- a/src/libraries/System.Runtime/tests/System/SByteTests.cs +++ b/src/libraries/System.Runtime/tests/System/SByteTests.cs @@ -112,11 +112,15 @@ public static IEnumerable ToString_TestData() yield return new object[] { (sbyte)123, "D99\09", defaultFormat, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123" }; yield return new object[] { (sbyte)-123, "D99", defaultFormat, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123" }; + yield return new object[] { (sbyte)0, "x", defaultFormat, "0" }; yield return new object[] { (sbyte)0x24, "x", defaultFormat, "24" }; yield return new object[] { (sbyte)-0x24, "x", defaultFormat, "dc" }; - yield return new object[] { (sbyte)24, "N", defaultFormat, string.Format("{0:N}", 24.00) }; + yield return new object[] { (sbyte)0, "b", defaultFormat, "0" }; + yield return new object[] { (sbyte)0x24, "b", defaultFormat, "100100" }; + yield return new object[] { (sbyte)-0x24, "b", defaultFormat, "11011100" }; + yield return new object[] { (sbyte)24, "N", defaultFormat, string.Format("{0:N}", 24.00) }; } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; @@ -127,6 +131,7 @@ public static IEnumerable ToString_TestData() yield return new object[] { (sbyte)32, "F100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (sbyte)32, "N100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (sbyte)32, "X100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020" }; + yield return new object[] { (sbyte)32, "B100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000" }; var customFormat = new NumberFormatInfo() { diff --git a/src/libraries/System.Runtime/tests/System/UInt128Tests.cs b/src/libraries/System.Runtime/tests/System/UInt128Tests.cs index ba67e15edb15..9482b480fb6f 100644 --- a/src/libraries/System.Runtime/tests/System/UInt128Tests.cs +++ b/src/libraries/System.Runtime/tests/System/UInt128Tests.cs @@ -115,7 +115,12 @@ public static IEnumerable ToString_TestData() yield return new object[] { (UInt128)4567, "D", defaultFormat, "4567" }; yield return new object[] { (UInt128)4567, "D18", defaultFormat, "000000000000004567" }; + yield return new object[] { (UInt128)0, "x", defaultFormat, "0" }; yield return new object[] { (UInt128)0x2468, "x", defaultFormat, "2468" }; + + yield return new object[] { (UInt128)0, "b", defaultFormat, "0" }; + yield return new object[] { (UInt128)0x2468, "b", defaultFormat, "10010001101000" }; + yield return new object[] { (UInt128)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; @@ -129,6 +134,7 @@ public static IEnumerable ToString_TestData() yield return new object[] { (UInt128)32, "F100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (UInt128)32, "N100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (UInt128)32, "X100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020" }; + yield return new object[] { (UInt128)32, "B100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000" }; var customFormat = new NumberFormatInfo() { diff --git a/src/libraries/System.Runtime/tests/System/UInt16Tests.cs b/src/libraries/System.Runtime/tests/System/UInt16Tests.cs index d43738f0e64a..b0ab9d1dac78 100644 --- a/src/libraries/System.Runtime/tests/System/UInt16Tests.cs +++ b/src/libraries/System.Runtime/tests/System/UInt16Tests.cs @@ -99,7 +99,12 @@ public static IEnumerable ToString_TestData() yield return new object[] { (ushort)123, "D", defaultFormat, "123" }; yield return new object[] { (ushort)123, "D99", defaultFormat, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123" }; + yield return new object[] { (ushort)0, "x", defaultFormat, "0" }; yield return new object[] { (ushort)0x2468, "x", defaultFormat, "2468" }; + + yield return new object[] { (ushort)0, "b", defaultFormat, "0" }; + yield return new object[] { (ushort)0x2468, "b", defaultFormat, "10010001101000" }; + yield return new object[] { (ushort)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; } @@ -111,6 +116,7 @@ public static IEnumerable ToString_TestData() yield return new object[] { (ushort)32, "F100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (ushort)32, "N100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (ushort)32, "X100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020" }; + yield return new object[] { (ushort)32, "B100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000" }; var customFormat = new NumberFormatInfo() { diff --git a/src/libraries/System.Runtime/tests/System/UInt32Tests.cs b/src/libraries/System.Runtime/tests/System/UInt32Tests.cs index d85edb2f401b..694bb7f43263 100644 --- a/src/libraries/System.Runtime/tests/System/UInt32Tests.cs +++ b/src/libraries/System.Runtime/tests/System/UInt32Tests.cs @@ -100,9 +100,13 @@ public static IEnumerable ToString_TestData() yield return new object[] { (uint)4567, "D", defaultFormat, "4567" }; yield return new object[] { (uint)4567, "D18", defaultFormat, "000000000000004567" }; + yield return new object[] { (uint)0, "x", defaultFormat, "0" }; yield return new object[] { (uint)0x2468, "x", defaultFormat, "2468" }; - yield return new object[] { (uint)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; + yield return new object[] { (uint)0, "b", defaultFormat, "0" }; + yield return new object[] { (uint)0x2468, "b", defaultFormat, "10010001101000" }; + + yield return new object[] { (uint)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; @@ -113,6 +117,7 @@ public static IEnumerable ToString_TestData() yield return new object[] { (uint)32, "F100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (uint)32, "N100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (uint)32, "X100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020" }; + yield return new object[] { (uint)32, "B100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000" }; var customFormat = new NumberFormatInfo() { diff --git a/src/libraries/System.Runtime/tests/System/UInt64Tests.cs b/src/libraries/System.Runtime/tests/System/UInt64Tests.cs index c8fae9732069..fb96368e711c 100644 --- a/src/libraries/System.Runtime/tests/System/UInt64Tests.cs +++ b/src/libraries/System.Runtime/tests/System/UInt64Tests.cs @@ -99,10 +99,13 @@ public static IEnumerable ToString_TestData() yield return new object[] { (ulong)4567, "D", defaultFormat, "4567" }; yield return new object[] { (ulong)4567, "D18", defaultFormat, "000000000000004567" }; + yield return new object[] { (ulong)0, "x", defaultFormat, "0" }; yield return new object[] { (ulong)0x2468, "x", defaultFormat, "2468" }; - yield return new object[] { (ulong)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; + yield return new object[] { (ulong)0, "b", defaultFormat, "0" }; + yield return new object[] { (ulong)0x2468, "b", defaultFormat, "10010001101000" }; + yield return new object[] { (ulong)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; @@ -113,6 +116,7 @@ public static IEnumerable ToString_TestData() yield return new object[] { (ulong)32, "F100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (ulong)32, "N100", invariantFormat, "32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (ulong)32, "X100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020" }; + yield return new object[] { (ulong)32, "B100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000" }; var customFormat = new NumberFormatInfo() { diff --git a/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs b/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs index ff8a857b9cda..4f4626f07fd4 100644 --- a/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs +++ b/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs @@ -268,7 +268,12 @@ public static IEnumerable ToString_TestData() yield return new object[] { (nuint)4567, "D", defaultFormat, "4567" }; yield return new object[] { (nuint)4567, "D18", defaultFormat, "000000000000004567" }; + yield return new object[] { (nuint)0, "x", defaultFormat, "0" }; yield return new object[] { (nuint)0x2468, "x", defaultFormat, "2468" }; + + yield return new object[] { (nuint)0, "b", defaultFormat, "0" }; + yield return new object[] { (nuint)0x2468, "b", defaultFormat, "10010001101000" }; + yield return new object[] { (nuint)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; }