Skip to content

Commit

Permalink
Add binary support to number formatting (#84889)
Browse files Browse the repository at this point in the history
* Add binary support to number formatting

* Fix inlining of Convert.ToString

It's now typically inlined by the JIT if toBase is a const.
  • Loading branch information
stephentoub committed Apr 18, 2023
1 parent 327c536 commit 0f91a6c
Show file tree
Hide file tree
Showing 16 changed files with 415 additions and 338 deletions.
Expand Up @@ -329,7 +329,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Icu.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Invariant.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Nls.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.WebAssembly.cs" Condition="'$(TargetsBrowser)' == 'true'"/>
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.WebAssembly.cs" Condition="'$(TargetsBrowser)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareOptions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Icu.cs" />
Expand Down Expand Up @@ -2600,4 +2600,4 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\IUnaryPlusOperators.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\IUnsignedNumber.cs" />
</ItemGroup>
</Project>
</Project>
122 changes: 95 additions & 27 deletions src/libraries/System.Private.CoreLib/src/System/Convert.cs
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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) :
Expand All @@ -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) :
Expand All @@ -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) :
Expand All @@ -2242,51 +2242,119 @@ 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) :
0;
}

// 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<char> 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)
Expand Down

0 comments on commit 0f91a6c

Please sign in to comment.