Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose IUtf8SpanParsable and implement it on the primitive numeric types #86875

Merged
merged 25 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f1d305b
Expose IUtf8SpanParsable
tannergooding May 26, 2023
9b03507
Have INumberBase implement IUtf8SpanParsable
tannergooding May 26, 2023
ca67504
Deduplicate some floating-point parsing logic
tannergooding May 28, 2023
c1f35f3
Refactoring the primitive parsing logic to support UTF-8
tannergooding May 29, 2023
fe438ca
Updating the primitive numeric types to include UTF-8 parsing support
tannergooding May 29, 2023
01066c8
Adding tests covering the new UTF-8 parsing support
tannergooding May 29, 2023
ba28bab
Ensure that tests don't try to capture a span in lambda
tannergooding May 29, 2023
0fdcd4e
Ensure that MatchChars does the right thing
tannergooding May 29, 2023
9e1fe3e
Account for the switch from string to ROSpan<TChar> for currSymbol
tannergooding May 29, 2023
6c3dfda
Ensure EqualsIgnoreCaseUtf8_Scalar handles the remaining elements cor…
tannergooding May 30, 2023
0fc41ca
Merge remote-tracking branch 'dotnet/main' into utf8-parsing
tannergooding May 30, 2023
249a2a2
Merge remote-tracking branch 'dotnet/main' into utf8-parsing
tannergooding Jun 7, 2023
5056ac8
Allow alloc-free conversion for the UTF8 parsing fallback paths
tannergooding Jun 7, 2023
cb9bef0
Remove unnecessary attributes and ensure trailing elements are correc…
tannergooding Jun 7, 2023
e5582f3
Merge remote-tracking branch 'dotnet/main' into utf8-parsing
tannergooding Jun 9, 2023
654888e
Merge remote-tracking branch 'dotnet/main' into utf8-parsing
tannergooding Jun 14, 2023
e611907
Fix the handling of UTF8 as per the feedback
tannergooding Jun 14, 2023
e944130
Merge remote-tracking branch 'dotnet/main' into utf8-parsing
tannergooding Jul 5, 2023
c7676cd
Fix a slightly broken merge
tannergooding Jul 6, 2023
5554436
Ensure the lengths are properly checked on the ASCII path
tannergooding Jul 6, 2023
c5ef2b2
Ensure that length is defined for 32-bit
tannergooding Jul 7, 2023
0ba5476
Merge remote-tracking branch 'dotnet/main' into utf8-parsing
tannergooding Jul 11, 2023
ab271db
Responding to PR feedback and allow invalid sequences to self match
tannergooding Jul 11, 2023
a78b75b
Fixing a copy/paste error
tannergooding Jul 11, 2023
b535e5c
Fixing a build failure due to not assigning the out parameter
tannergooding Jul 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,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.Utf8.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.WebAssembly.cs" Condition="'$(TargetsBrowser)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.OSX.cs" Condition="'$(IsOSXLike)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareOptions.cs" />
Expand Down Expand Up @@ -375,6 +376,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\NumberFormatInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\NumberStyles.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Ordinal.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Ordinal.Utf8.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\OrdinalCasing.Icu.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\PersianCalendar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\RegionInfo.cs" />
Expand Down Expand Up @@ -510,6 +512,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\ISpanFormattable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IUtfChar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IUtf8SpanFormattable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IUtf8SpanParsable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Lazy.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\LazyOfTTMetadata.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\LoaderOptimization.cs" />
Expand All @@ -526,7 +529,9 @@
<Compile Include="$(MSBuildThisFileDirectory)System\MemoryDebugView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MemoryExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MemoryExtensions.Globalization.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MemoryExtensions.Globalization.Utf8.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MemoryExtensions.Trim.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MemoryExtensions.Trim.Utf8.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MethodAccessException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MidpointRounding.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MissingFieldException.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public static unsafe bool TryParse(ReadOnlySpan<byte> source, out float value, o

if (TryParseNormalAsFloatingPoint(source, ref number, out bytesConsumed, standardFormat))
{
value = Number.NumberToSingle(ref number);
value = Number.NumberToFloat<float>(ref number);
return true;
}

Expand Down Expand Up @@ -66,7 +66,7 @@ public static unsafe bool TryParse(ReadOnlySpan<byte> source, out double value,

if (TryParseNormalAsFloatingPoint(source, ref number, out bytesConsumed, standardFormat))
{
value = Number.NumberToDouble(ref number);
value = Number.NumberToFloat<double>(ref number);
return true;
}

Expand Down
36 changes: 34 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Byte.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,19 @@ public static byte Parse(string s, NumberStyles style, IFormatProvider? provider
public static byte Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null)
{
NumberFormatInfo.ValidateParseStyleInteger(style);
return Number.ParseBinaryInteger<byte>(s, style, NumberFormatInfo.GetInstance(provider));
return Number.ParseBinaryInteger<char, byte>(s, style, NumberFormatInfo.GetInstance(provider));
}

public static bool TryParse([NotNullWhen(true)] string? s, out byte result) => TryParse(s, NumberStyles.Integer, provider: null, out result);

public static bool TryParse(ReadOnlySpan<char> s, out byte result) => TryParse(s, NumberStyles.Integer, provider: null, out result);

/// <summary>Tries to convert a UTF-8 character span containing the string representation of a number to its 8-bit unsigned integer equivalent.</summary>
/// <param name="utf8Text">A span containing the UTF-8 characters representing the number to convert.</param>
/// <param name="result">When this method returns, contains the 8-bit unsigned integer value equivalent to the number contained in <paramref name="utf8Text" /> if the conversion succeeded, or zero if the conversion failed. This parameter is passed uninitialized; any value originally supplied in result will be overwritten.</param>
/// <returns><c>true</c> if <paramref name="utf8Text" /> was converted successfully; otherwise, false.</returns>
public static bool TryParse(ReadOnlySpan<byte> utf8Text, out byte result) => TryParse(utf8Text, NumberStyles.Integer, provider: null, out result);

public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out byte result)
{
NumberFormatInfo.ValidateParseStyleInteger(style);
Expand All @@ -124,7 +130,7 @@ public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, I
result = 0;
return false;
}
return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK;
return Number.TryParseBinaryInteger(s.AsSpan(), style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK;
}

public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out byte result)
Expand Down Expand Up @@ -1151,6 +1157,30 @@ static bool INumberBase<byte>.TryConvertToTruncating<TOther>(byte value, [MaybeN
/// <inheritdoc cref="IUnaryPlusOperators{TSelf, TResult}.op_UnaryPlus(TSelf)" />
static byte IUnaryPlusOperators<byte, byte>.operator +(byte value) => (byte)(+value);

//
// IUtf8SpanParsable
//

/// <inheritdoc cref="INumberBase{TSelf}.Parse(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?)" />
public static byte Parse(ReadOnlySpan<byte> utf8Text, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null)
{
NumberFormatInfo.ValidateParseStyleInteger(style);
return Number.ParseBinaryInteger<byte, byte>(utf8Text, style, NumberFormatInfo.GetInstance(provider));
}

/// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?, out TSelf)" />
public static bool TryParse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out byte result)
{
NumberFormatInfo.ValidateParseStyleInteger(style);
return Number.TryParseBinaryInteger(utf8Text, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK;
}

/// <inheritdoc cref="IUtf8SpanParsable{TSelf}.Parse(ReadOnlySpan{byte}, IFormatProvider?)" />
public static byte Parse(ReadOnlySpan<byte> utf8Text, IFormatProvider? provider) => Parse(utf8Text, NumberStyles.Integer, provider);

/// <inheritdoc cref="IUtf8SpanParsable{TSelf}.TryParse(ReadOnlySpan{byte}, IFormatProvider?, out TSelf)" />
public static bool TryParse(ReadOnlySpan<byte> utf8Text, IFormatProvider? provider, out byte result) => TryParse(utf8Text, NumberStyles.Integer, provider, out result);

//
// IUtfChar
//
Expand All @@ -1161,6 +1191,8 @@ static bool INumberBase<byte>.TryConvertToTruncating<TOther>(byte value, [MaybeN
static byte IUtfChar<byte>.CastFrom(uint value) => (byte)value;
static byte IUtfChar<byte>.CastFrom(ulong value) => (byte)value;

static uint IUtfChar<byte>.CastToUInt32(byte value) => value;

//
// IBinaryIntegerParseAndFormatInfo
//
Expand Down
2 changes: 2 additions & 0 deletions src/libraries/System.Private.CoreLib/src/System/Char.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1993,6 +1993,8 @@ static bool INumberBase<char>.TryConvertToTruncating<TOther>(char value, [MaybeN
static char IUtfChar<char>.CastFrom(uint value) => (char)value;
static char IUtfChar<char>.CastFrom(ulong value) => (char)value;

static uint IUtfChar<char>.CastToUInt32(char value) => value;

//
// IBinaryIntegerParseAndFormatInfo
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ private static void UInt64x64To128(ulong a, ulong b, ref DecCalc result)
high++;

if (high > uint.MaxValue)
Number.ThrowOverflowException(TypeCode.Decimal);
Number.ThrowOverflowException(SR.Overflow_Decimal);
tannergooding marked this conversation as resolved.
Show resolved Hide resolved
result.Low64 = low;
result.High = (uint)high;
}
Expand Down Expand Up @@ -681,7 +681,7 @@ private static unsafe int ScaleResult(Buf24* bufRes, uint hiRes, int scale)
return scale;

ThrowOverflow:
Number.ThrowOverflowException(TypeCode.Decimal);
Number.ThrowOverflowException(SR.Overflow_Decimal);
return 0;
}

Expand Down Expand Up @@ -725,7 +725,7 @@ private static unsafe uint DivByConst(uint* result, uint hiRes, out uint quotien
private static int OverflowUnscale(ref Buf12 bufQuo, int scale, bool sticky)
{
if (--scale < 0)
Number.ThrowOverflowException(TypeCode.Decimal);
Number.ThrowOverflowException(SR.Overflow_Decimal);

Debug.Assert(bufQuo.U2 == 0);

Expand Down Expand Up @@ -837,7 +837,7 @@ private static int SearchScale(ref Buf12 bufQuo, int scale)
// positive if it isn't already.
//
if (curScale + scale < 0)
Number.ThrowOverflowException(TypeCode.Decimal);
Number.ThrowOverflowException(SR.Overflow_Decimal);

return curScale;
}
Expand Down Expand Up @@ -1107,7 +1107,7 @@ internal static unsafe void DecAddSub(ref DecCalc d1, ref DecCalc d2, bool sign)
// Divide the value by 10, dropping the scale factor.
//
if ((flags & ScaleMask) == 0)
Number.ThrowOverflowException(TypeCode.Decimal);
Number.ThrowOverflowException(SR.Overflow_Decimal);
flags -= 1 << ScaleShift;

const uint den = 10;
Expand Down Expand Up @@ -1534,7 +1534,7 @@ internal static void VarDecFromR4(float input, out DecCalc result)
return; // result should be zeroed out

if (exp > 96)
Number.ThrowOverflowException(TypeCode.Decimal);
Number.ThrowOverflowException(SR.Overflow_Decimal);

uint flags = 0;
if (input < 0)
Expand Down Expand Up @@ -1701,7 +1701,7 @@ internal static void VarDecFromR8(double input, out DecCalc result)
return; // result should be zeroed out

if (exp > 96)
Number.ThrowOverflowException(TypeCode.Decimal);
Number.ThrowOverflowException(SR.Overflow_Decimal);

uint flags = 0;
if (input < 0)
Expand Down Expand Up @@ -2170,7 +2170,7 @@ internal static unsafe void VarDecDiv(ref DecCalc d1, ref DecCalc d2)
}

ThrowOverflow:
Number.ThrowOverflowException(TypeCode.Decimal);
Number.ThrowOverflowException(SR.Overflow_Decimal);
}

/// <summary>
Expand Down
Loading