diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/StandardFormat.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/StandardFormat.cs
index 91dca61b2415a3..9a738100d8b7b9 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Buffers/StandardFormat.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/StandardFormat.cs
@@ -40,6 +40,9 @@ namespace System.Buffers
///
public bool HasPrecision => _precision != NoPrecision;
+ /// Gets the precision if one was specified; otherwise, 0.
+ internal byte PrecisionOrZero => _precision != NoPrecision ? _precision : (byte)0;
+
///
/// true if the StandardFormat == default(StandardFormat)
///
diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.cs
index 303383a097e33b..0a55ad664ab270 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.cs
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Runtime.CompilerServices;
+
namespace System.Buffers.Text
{
///
@@ -30,7 +32,7 @@ public static partial class Utf8Formatter
/// System.FormatException if the format is not valid for this data type.
///
public static bool TryFormat(byte value, Span destination, out int bytesWritten, StandardFormat format = default) =>
- FormattingHelpers.TryFormat(value, destination, out bytesWritten, format);
+ TryFormat((uint)value, destination, out bytesWritten, format);
///
/// Formats an SByte as a UTF8 string.
@@ -55,7 +57,7 @@ public static bool TryFormat(byte value, Span destination, out int bytesWr
///
[CLSCompliant(false)]
public static bool TryFormat(sbyte value, Span destination, out int bytesWritten, StandardFormat format = default) =>
- FormattingHelpers.TryFormat(value, destination, out bytesWritten, format);
+ TryFormat(value, 0xFF, destination, out bytesWritten, format);
///
/// Formats a Unt16 as a UTF8 string.
@@ -80,7 +82,7 @@ public static bool TryFormat(sbyte value, Span destination, out int bytesW
///
[CLSCompliant(false)]
public static bool TryFormat(ushort value, Span destination, out int bytesWritten, StandardFormat format = default) =>
- FormattingHelpers.TryFormat(value, destination, out bytesWritten, format);
+ TryFormat((uint)value, destination, out bytesWritten, format);
///
/// Formats an Int16 as a UTF8 string.
@@ -104,7 +106,7 @@ public static bool TryFormat(ushort value, Span destination, out int bytes
/// System.FormatException if the format is not valid for this data type.
///
public static bool TryFormat(short value, Span destination, out int bytesWritten, StandardFormat format = default) =>
- FormattingHelpers.TryFormat(value, destination, out bytesWritten, format);
+ TryFormat(value, 0xFFFF, destination, out bytesWritten, format);
///
/// Formats a UInt32 as a UTF8 string.
@@ -127,9 +129,38 @@ public static bool TryFormat(short value, Span destination, out int bytesW
///
/// System.FormatException if the format is not valid for this data type.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
[CLSCompliant(false)]
- public static bool TryFormat(uint value, Span destination, out int bytesWritten, StandardFormat format = default) =>
- FormattingHelpers.TryFormat(value, destination, out bytesWritten, format);
+ public static bool TryFormat(uint value, Span destination, out int bytesWritten, StandardFormat format = default)
+ {
+ if (format.IsDefault)
+ {
+ return Number.TryUInt32ToDecStr(value, destination, out bytesWritten);
+ }
+
+ switch (format.Symbol | 0x20)
+ {
+ case 'd':
+ return Number.TryUInt32ToDecStr(value, format.PrecisionOrZero, destination, out bytesWritten);
+
+ case 'x':
+ return Number.TryInt32ToHexStr((int)value, Number.GetHexBase(format.Symbol), format.PrecisionOrZero, destination, out bytesWritten);
+
+ case 'n':
+ return FormattingHelpers.TryFormat(value, destination, out bytesWritten, format);
+
+ case 'g' or 'r':
+ if (format.HasPrecision)
+ {
+ ThrowGWithPrecisionNotSupported();
+ }
+ goto case 'd';
+
+ default:
+ ThrowHelper.ThrowFormatException_BadFormatSpecifier();
+ goto case 'd';
+ }
+ }
///
/// Formats an Int32 as a UTF8 string.
@@ -153,7 +184,43 @@ public static bool TryFormat(uint value, Span destination, out int bytesWr
/// System.FormatException if the format is not valid for this data type.
///
public static bool TryFormat(int value, Span destination, out int bytesWritten, StandardFormat format = default) =>
- FormattingHelpers.TryFormat(value, destination, out bytesWritten, format);
+ TryFormat(value, ~0, destination, out bytesWritten, format);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool TryFormat(int value, int hexMask, Span destination, out int bytesWritten, StandardFormat format = default)
+ {
+ if (format.IsDefault)
+ {
+ return value >= 0 ?
+ Number.TryUInt32ToDecStr((uint)value, destination, out bytesWritten) :
+ Number.TryNegativeInt32ToDecStr(value, format.PrecisionOrZero, "-"u8, destination, out bytesWritten);
+ }
+
+ switch (format.Symbol | 0x20)
+ {
+ case 'd':
+ return value >= 0 ?
+ Number.TryUInt32ToDecStr((uint)value, format.PrecisionOrZero, destination, out bytesWritten) :
+ Number.TryNegativeInt32ToDecStr(value, format.PrecisionOrZero, "-"u8, destination, out bytesWritten);
+
+ case 'x':
+ return Number.TryInt32ToHexStr(value & hexMask, Number.GetHexBase(format.Symbol), format.PrecisionOrZero, destination, out bytesWritten);
+
+ case 'n':
+ return FormattingHelpers.TryFormat(value, destination, out bytesWritten, format);
+
+ case 'g' or 'r':
+ if (format.HasPrecision)
+ {
+ ThrowGWithPrecisionNotSupported();
+ }
+ goto case 'd';
+
+ default:
+ ThrowHelper.ThrowFormatException_BadFormatSpecifier();
+ goto case 'd';
+ }
+ }
///
/// Formats a UInt64 as a UTF8 string.
@@ -176,9 +243,38 @@ public static bool TryFormat(int value, Span destination, out int bytesWri
///
/// System.FormatException if the format is not valid for this data type.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
[CLSCompliant(false)]
- public static bool TryFormat(ulong value, Span destination, out int bytesWritten, StandardFormat format = default) =>
- FormattingHelpers.TryFormat(value, destination, out bytesWritten, format);
+ public static bool TryFormat(ulong value, Span destination, out int bytesWritten, StandardFormat format = default)
+ {
+ if (format.IsDefault)
+ {
+ return Number.TryUInt64ToDecStr(value, destination, out bytesWritten);
+ }
+
+ switch (format.Symbol | 0x20)
+ {
+ case 'd':
+ return Number.TryUInt64ToDecStr(value, format.PrecisionOrZero, destination, out bytesWritten);
+
+ case 'x':
+ return Number.TryInt64ToHexStr((long)value, Number.GetHexBase(format.Symbol), format.PrecisionOrZero, destination, out bytesWritten);
+
+ case 'n':
+ return FormattingHelpers.TryFormat(value, destination, out bytesWritten, format);
+
+ case 'g' or 'r':
+ if (format.HasPrecision)
+ {
+ ThrowGWithPrecisionNotSupported();
+ }
+ goto case 'd';
+
+ default:
+ ThrowHelper.ThrowFormatException_BadFormatSpecifier();
+ goto case 'd';
+ }
+ }
///
/// Formats an Int64 as a UTF8 string.
@@ -201,7 +297,44 @@ public static bool TryFormat(ulong value, Span destination, out int bytesW
///
/// System.FormatException if the format is not valid for this data type.
///
- public static bool TryFormat(long value, Span destination, out int bytesWritten, StandardFormat format = default) =>
- FormattingHelpers.TryFormat(value, destination, out bytesWritten, format);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool TryFormat(long value, Span destination, out int bytesWritten, StandardFormat format = default)
+ {
+ if (format.IsDefault)
+ {
+ return value >= 0 ?
+ Number.TryUInt64ToDecStr((ulong)value, destination, out bytesWritten) :
+ Number.TryNegativeInt64ToDecStr(value, format.PrecisionOrZero, "-"u8, destination, out bytesWritten);
+ }
+
+ switch (format.Symbol | 0x20)
+ {
+ case 'd':
+ return value >= 0 ?
+ Number.TryUInt64ToDecStr((ulong)value, format.PrecisionOrZero, destination, out bytesWritten) :
+ Number.TryNegativeInt64ToDecStr(value, format.PrecisionOrZero, "-"u8, destination, out bytesWritten);
+
+ case 'x':
+ return Number.TryInt64ToHexStr(value, Number.GetHexBase(format.Symbol), format.PrecisionOrZero, destination, out bytesWritten);
+
+ case 'n':
+ return FormattingHelpers.TryFormat(value, destination, out bytesWritten, format);
+
+ case 'g' or 'r':
+ if (format.HasPrecision)
+ {
+ ThrowGWithPrecisionNotSupported();
+ }
+ goto case 'd';
+
+ default:
+ ThrowHelper.ThrowFormatException_BadFormatSpecifier();
+ goto case 'd';
+ }
+ }
+
+ private static void ThrowGWithPrecisionNotSupported() =>
+ // With a precision, 'G' can produce exponential format, even for integers.
+ throw new NotSupportedException(SR.Argument_GWithPrecisionNotSupported);
}
}
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 0a4d1ceaf65845..ed689b5d9ec774 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs
@@ -907,7 +907,7 @@ private static bool TryCopyTo(string source, Span destination, out
}
}
- private static char GetHexBase(char fmt)
+ internal static char GetHexBase(char fmt)
{
// The fmt-(X-A+10) hack has the effect of dictating whether we produce uppercase or lowercase
// hex numbers for a-f. 'X' as the fmt code produces uppercase. 'x' as the format code produces lowercase.
@@ -1675,7 +1675,7 @@ private static unsafe string NegativeInt32ToDecStr(int value, int digits, string
return result;
}
- private static unsafe bool TryNegativeInt32ToDecStr(int value, int digits, ReadOnlySpan sNegative, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
+ internal static unsafe bool TryNegativeInt32ToDecStr(int value, int digits, ReadOnlySpan sNegative, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
Debug.Assert(value < 0);
@@ -1724,7 +1724,7 @@ private static unsafe string Int32ToHexStr(int value, char hexBase, int digits)
return result;
}
- private static unsafe bool TryInt32ToHexStr(int value, char hexBase, int digits, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
+ internal static unsafe bool TryInt32ToHexStr(int value, char hexBase, int digits, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
@@ -1999,7 +1999,7 @@ private static unsafe string UInt32ToDecStr(uint value, int digits)
return result;
}
- private static unsafe bool TryUInt32ToDecStr(uint value, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
+ internal static unsafe bool TryUInt32ToDecStr(uint value, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
@@ -2019,7 +2019,7 @@ private static unsafe bool TryUInt32ToDecStr(uint value, Span dest
return false;
}
- private static unsafe bool TryUInt32ToDecStr(uint value, int digits, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
+ internal static unsafe bool TryUInt32ToDecStr(uint value, int digits, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
@@ -2108,7 +2108,7 @@ private static unsafe string NegativeInt64ToDecStr(long value, int digits, strin
return result;
}
- private static unsafe bool TryNegativeInt64ToDecStr(long value, int digits, ReadOnlySpan sNegative, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
+ internal static unsafe bool TryNegativeInt64ToDecStr(long value, int digits, ReadOnlySpan sNegative, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
Debug.Assert(value < 0);
@@ -2157,7 +2157,7 @@ private static unsafe string Int64ToHexStr(long value, char hexBase, int digits)
return result;
}
- private static unsafe bool TryInt64ToHexStr(long value, char hexBase, int digits, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
+ internal static unsafe bool TryInt64ToHexStr(long value, char hexBase, int digits, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
@@ -2427,7 +2427,7 @@ internal static unsafe string UInt64ToDecStr(ulong value, int digits)
return result;
}
- private static unsafe bool TryUInt64ToDecStr(ulong value, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
+ internal static unsafe bool TryUInt64ToDecStr(ulong value, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
@@ -2448,7 +2448,7 @@ private static unsafe bool TryUInt64ToDecStr(ulong value, Span des
return false;
}
- private static unsafe bool TryUInt64ToDecStr(ulong value, int digits, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
+ internal static unsafe bool TryUInt64ToDecStr(ulong value, int digits, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar
{
int countedDigits = FormattingHelpers.CountDigits(value);
int bufferLength = Math.Max(digits, countedDigits);