diff --git a/eng/Versions.props b/eng/Versions.props
index 53f4052e9f3189..9453847bc3013b 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -49,7 +49,7 @@
- 4.3.0-2.22270.2
+ 4.3.0-2.22270.4
2.0.0-preview.4.22252.4
diff --git a/src/coreclr/tools/Common/Compiler/TypeExtensions.cs b/src/coreclr/tools/Common/Compiler/TypeExtensions.cs
index ae94eb660fdd82..287c410e16dcd9 100644
--- a/src/coreclr/tools/Common/Compiler/TypeExtensions.cs
+++ b/src/coreclr/tools/Common/Compiler/TypeExtensions.cs
@@ -562,6 +562,16 @@ public static MethodDesc TryResolveConstraintMethodApprox(this TypeDesc constrai
method = null;
}
+ // Default implementation logic, which only kicks in for default implementations when looking up on an exact interface target
+ if (isStaticVirtualMethod && method == null && !genInterfaceMethod.IsAbstract && !constrainedType.IsCanonicalSubtype(CanonicalFormKind.Any))
+ {
+ MethodDesc exactInterfaceMethod = genInterfaceMethod;
+ if (genInterfaceMethod.OwningType != interfaceType)
+ exactInterfaceMethod = context.GetMethodForInstantiatedType(
+ genInterfaceMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceType);
+ method = exactInterfaceMethod;
+ }
+
if (method == null)
{
// Fall back to VSD
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericLookupResult.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericLookupResult.cs
index 3da65b1530ed24..88f726c26d0424 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericLookupResult.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericLookupResult.cs
@@ -1438,6 +1438,10 @@ public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultCo
if (instantiatedConstrainedMethod.Signature.IsStatic)
{
implMethod = instantiatedConstraintType.GetClosestDefType().ResolveVariantInterfaceMethodToStaticVirtualMethodOnType(instantiatedConstrainedMethod);
+ if (implMethod == null && !instantiatedConstrainedMethod.IsAbstract)
+ {
+ implMethod = instantiatedConstrainedMethod;
+ }
}
else
{
@@ -1451,7 +1455,6 @@ public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultCo
// AOT use of this generic lookup is restricted to finding methods on valuetypes (runtime usage of this slot in universal generics is more flexible)
Debug.Assert(instantiatedConstraintType.IsValueType || (instantiatedConstrainedMethod.OwningType.IsInterface && instantiatedConstrainedMethod.Signature.IsStatic));
- Debug.Assert(!instantiatedConstraintType.IsValueType || implMethod.OwningType == instantiatedConstraintType);
if (implMethod.Signature.IsStatic)
{
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs
index c07d679f9be02a..c0850138a7207f 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs
@@ -424,7 +424,8 @@ private void ImportCall(ILOpcode opcode, int token)
methodAfterConstraintResolution = directMethod;
- Debug.Assert(!methodAfterConstraintResolution.OwningType.IsInterface);
+ Debug.Assert(!methodAfterConstraintResolution.OwningType.IsInterface
+ || methodAfterConstraintResolution.Signature.IsStatic);
resolvedConstraint = true;
exactType = constrained;
diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
index 1896db9fae8274..141b98bf5d93e5 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -1203,7 +1203,8 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO
methodAfterConstraintResolution = directMethod;
- Debug.Assert(!methodAfterConstraintResolution.OwningType.IsInterface);
+ Debug.Assert(!methodAfterConstraintResolution.OwningType.IsInterface
+ || methodAfterConstraintResolution.Signature.IsStatic);
resolvedConstraint = true;
pResult->thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_NO_THIS_TRANSFORM;
diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp
index 1814ff4de269c0..5aae97dd5cb67d 100644
--- a/src/coreclr/vm/methodtable.cpp
+++ b/src/coreclr/vm/methodtable.cpp
@@ -8067,7 +8067,7 @@ MethodTable::ResolveVirtualStaticMethod(MethodTable* pInterfaceType, MethodDesc*
}
}
- // Default implementation logic, which only kicks in for default implementations when lookin up on an exact interface target
+ // Default implementation logic, which only kicks in for default implementations when looking up on an exact interface target
if (!pInterfaceMD->IsAbstract() && !(this == g_pCanonMethodTableClass) && !IsSharedByGenericInstantiations())
{
return pInterfaceMD->FindOrCreateAssociatedMethodDesc(pInterfaceMD, pInterfaceType, FALSE, pInterfaceMD->GetMethodInstantiation(), FALSE);
diff --git a/src/libraries/Common/tests/System/GenericMathHelpers.cs b/src/libraries/Common/tests/System/GenericMathHelpers.cs
index b2ce6e4896fe18..c6bbb21304f2ed 100644
--- a/src/libraries/Common/tests/System/GenericMathHelpers.cs
+++ b/src/libraries/Common/tests/System/GenericMathHelpers.cs
@@ -358,9 +358,6 @@ public static TSelf CreateTruncating(TOther value)
public static TSelf Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider) => TSelf.Parse(s, style, provider);
- public static bool TryCreate(TOther value, out TSelf result)
- where TOther : INumberBase => TSelf.TryCreate(value, out result);
-
public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out TSelf result) => TSelf.TryParse(s, style, provider, out result);
public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out TSelf result) => TSelf.TryParse(s, style, provider, out result);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Byte.cs b/src/libraries/System.Private.CoreLib/src/System/Byte.cs
index 0104da49a46dac..f8bf9347ec5c16 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Byte.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Byte.cs
@@ -531,476 +531,475 @@ bool IBinaryInteger.TryWriteLittleEndian(Span destination, out int b
///
static byte INumberBase.Abs(byte value) => value;
- ///
+ ///
+ static bool INumberBase.IsCanonical(byte value) => true;
+
+ ///
+ static bool INumberBase.IsComplexNumber(byte value) => false;
+
+ ///
+ public static bool IsEvenInteger(byte value) => (value & 1) == 0;
+
+ ///
+ static bool INumberBase.IsFinite(byte value) => true;
+
+ ///
+ static bool INumberBase.IsImaginaryNumber(byte value) => false;
+
+ ///
+ static bool INumberBase.IsInfinity(byte value) => false;
+
+ ///
+ static bool INumberBase.IsInteger(byte value) => true;
+
+ ///
+ static bool INumberBase.IsNaN(byte value) => false;
+
+ ///
+ static bool INumberBase.IsNegative(byte value) => false;
+
+ ///
+ static bool INumberBase.IsNegativeInfinity(byte value) => false;
+
+ ///
+ static bool INumberBase.IsNormal(byte value) => value != 0;
+
+ ///
+ public static bool IsOddInteger(byte value) => (value & 1) != 0;
+
+ ///
+ static bool INumberBase.IsPositive(byte value) => true;
+
+ ///
+ static bool INumberBase.IsPositiveInfinity(byte value) => false;
+
+ ///
+ static bool INumberBase.IsRealNumber(byte value) => true;
+
+ ///
+ static bool INumberBase.IsSubnormal(byte value) => false;
+
+ ///
+ static bool INumberBase.IsZero(byte value) => (value == 0);
+
+ ///
+ static byte INumberBase.MaxMagnitude(byte x, byte y) => Max(x, y);
+
+ ///
+ static byte INumberBase.MaxMagnitudeNumber(byte x, byte y) => Max(x, y);
+
+ ///
+ static byte INumberBase.MinMagnitude(byte x, byte y) => Min(x, y);
+
+ ///
+ static byte INumberBase.MinMagnitudeNumber(byte x, byte y) => Min(x, y);
+
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static byte CreateChecked(TOther value)
- where TOther : INumberBase
+ static bool INumberBase.TryConvertFromChecked(TOther value, out byte result)
{
- if (typeof(TOther) == typeof(byte))
- {
- return (byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- return checked((byte)(char)(object)value);
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `byte` will handle the other unsigned types and
+ // `ConvertTo` will handle the signed types
+
+ if (typeof(TOther) == typeof(char))
+ {
+ char actualValue = (char)(object)value;
+ result = checked((byte)actualValue);
+ return true;
}
else if (typeof(TOther) == typeof(decimal))
{
- return checked((byte)(decimal)(object)value);
- }
- else if (typeof(TOther) == typeof(double))
- {
- return checked((byte)(double)(object)value);
- }
- else if (typeof(TOther) == typeof(short))
- {
- return checked((byte)(short)(object)value);
- }
- else if (typeof(TOther) == typeof(int))
- {
- return checked((byte)(int)(object)value);
- }
- else if (typeof(TOther) == typeof(long))
- {
- return checked((byte)(long)(object)value);
- }
- else if (typeof(TOther) == typeof(nint))
- {
- return checked((byte)(nint)(object)value);
- }
- else if (typeof(TOther) == typeof(sbyte))
- {
- return checked((byte)(sbyte)(object)value);
- }
- else if (typeof(TOther) == typeof(float))
- {
- return checked((byte)(float)(object)value);
+ decimal actualValue = (decimal)(object)value;
+ result = checked((byte)actualValue);
+ return true;
}
else if (typeof(TOther) == typeof(ushort))
{
- return checked((byte)(ushort)(object)value);
+ ushort actualValue = (ushort)(object)value;
+ result = checked((byte)actualValue);
+ return true;
}
else if (typeof(TOther) == typeof(uint))
{
- return checked((byte)(uint)(object)value);
+ uint actualValue = (uint)(object)value;
+ result = checked((byte)actualValue);
+ return true;
}
else if (typeof(TOther) == typeof(ulong))
{
- return checked((byte)(ulong)(object)value);
+ ulong actualValue = (ulong)(object)value;
+ result = checked((byte)actualValue);
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualValue = (UInt128)(object)value;
+ result = checked((byte)actualValue);
+ return true;
}
else if (typeof(TOther) == typeof(nuint))
{
- return checked((byte)(nuint)(object)value);
+ nuint actualValue = (nuint)(object)value;
+ result = checked((byte)actualValue);
+ return true;
}
else
{
- ThrowHelper.ThrowNotSupportedException();
- return default;
+ result = default;
+ return false;
}
}
- ///
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static byte CreateSaturating(TOther value)
- where TOther : INumberBase
+ static bool INumberBase.TryConvertFromSaturating(TOther value, out byte result)
{
- if (typeof(TOther) == typeof(byte))
- {
- return (byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- var actualValue = (char)(object)value;
- return (actualValue > MaxValue) ? MaxValue : (byte)actualValue;
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `byte` will handle the other unsigned types and
+ // `ConvertTo` will handle the signed types
+
+ if (typeof(TOther) == typeof(char))
+ {
+ char actualValue = (char)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue : (byte)actualValue;
+ return true;
}
else if (typeof(TOther) == typeof(decimal))
{
- var actualValue = (decimal)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < 0) ? MinValue : (byte)actualValue;
+ decimal actualValue = (decimal)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue :
+ (actualValue <= MinValue) ? MinValue : (byte)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(double))
+ else if (typeof(TOther) == typeof(ushort))
{
- var actualValue = (double)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < 0) ? MinValue : (byte)actualValue;
+ ushort actualValue = (ushort)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue : (byte)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(short))
+ else if (typeof(TOther) == typeof(uint))
{
- var actualValue = (short)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < 0) ? MinValue : (byte)actualValue;
+ uint actualValue = (uint)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue : (byte)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(int))
+ else if (typeof(TOther) == typeof(ulong))
{
- var actualValue = (int)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < 0) ? MinValue : (byte)actualValue;
+ ulong actualValue = (ulong)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue : (byte)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(long))
+ else if (typeof(TOther) == typeof(UInt128))
{
- var actualValue = (long)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < 0) ? MinValue : (byte)actualValue;
+ UInt128 actualValue = (UInt128)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue : (byte)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(nint))
+ else if (typeof(TOther) == typeof(nuint))
{
- var actualValue = (nint)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < 0) ? MinValue : (byte)actualValue;
+ nuint actualValue = (nuint)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue : (byte)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(sbyte))
+ else
{
- var actualValue = (sbyte)(object)value;
- return (actualValue < 0) ? MinValue : (byte)actualValue;
+ result = default;
+ return false;
}
- else if (typeof(TOther) == typeof(float))
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertFromTruncating(TOther value, out byte result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `byte` will handle the other unsigned types and
+ // `ConvertTo` will handle the signed types
+
+ if (typeof(TOther) == typeof(char))
+ {
+ char actualValue = (char)(object)value;
+ result = (byte)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(decimal))
{
- var actualValue = (float)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < 0) ? MinValue : (byte)actualValue;
+ decimal actualValue = (decimal)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue :
+ (actualValue <= MinValue) ? MinValue : (byte)actualValue;
+ return true;
}
else if (typeof(TOther) == typeof(ushort))
{
- var actualValue = (ushort)(object)value;
- return (actualValue > MaxValue) ? MaxValue : (byte)actualValue;
+ ushort actualValue = (ushort)(object)value;
+ result = (byte)actualValue;
+ return true;
}
else if (typeof(TOther) == typeof(uint))
{
- var actualValue = (uint)(object)value;
- return (actualValue > MaxValue) ? MaxValue : (byte)actualValue;
+ uint actualValue = (uint)(object)value;
+ result = (byte)actualValue;
+ return true;
}
else if (typeof(TOther) == typeof(ulong))
{
- var actualValue = (ulong)(object)value;
- return (actualValue > MaxValue) ? MaxValue : (byte)actualValue;
+ ulong actualValue = (ulong)(object)value;
+ result = (byte)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualValue = (UInt128)(object)value;
+ result = (byte)actualValue;
+ return true;
}
else if (typeof(TOther) == typeof(nuint))
{
- var actualValue = (nuint)(object)value;
- return (actualValue > MaxValue) ? MaxValue : (byte)actualValue;
+ nuint actualValue = (nuint)(object)value;
+ result = (byte)actualValue;
+ return true;
}
else
{
- ThrowHelper.ThrowNotSupportedException();
- return default;
+ result = default;
+ return false;
}
}
- ///
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static byte CreateTruncating(TOther value)
- where TOther : INumberBase
+ static bool INumberBase.TryConvertToChecked(byte value, [NotNullWhen(true)] out TOther result)
{
- if (typeof(TOther) == typeof(byte))
- {
- return (byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- return (byte)(char)(object)value;
- }
- else if (typeof(TOther) == typeof(decimal))
- {
- return (byte)(decimal)(object)value;
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `byte` will handle the other unsigned types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(double))
+ {
+ double actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
- else if (typeof(TOther) == typeof(double))
+ else if (typeof(TOther) == typeof(Half))
{
- return (byte)(double)(object)value;
+ Half actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
else if (typeof(TOther) == typeof(short))
{
- return (byte)(short)(object)value;
+ short actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
else if (typeof(TOther) == typeof(int))
{
- return (byte)(int)(object)value;
+ int actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
else if (typeof(TOther) == typeof(long))
{
- return (byte)(long)(object)value;
+ long actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(Int128))
+ {
+ Int128 actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
else if (typeof(TOther) == typeof(nint))
{
- return (byte)(nint)(object)value;
+ nint actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
else if (typeof(TOther) == typeof(sbyte))
{
- return (byte)(sbyte)(object)value;
+ sbyte actualResult = checked((sbyte)value);
+ result = (TOther)(object)actualResult;
+ return true;
}
else if (typeof(TOther) == typeof(float))
{
- return (byte)(float)(object)value;
+ float actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
- else if (typeof(TOther) == typeof(ushort))
+ else
{
- return (byte)(ushort)(object)value;
+ result = default!;
+ return false;
}
- else if (typeof(TOther) == typeof(uint))
- {
- return (byte)(uint)(object)value;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToSaturating(byte value, [NotNullWhen(true)] out TOther result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `byte` will handle the other unsigned types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(double))
+ {
+ double actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
- else if (typeof(TOther) == typeof(ulong))
+ else if (typeof(TOther) == typeof(Half))
{
- return (byte)(ulong)(object)value;
+ Half actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
- else if (typeof(TOther) == typeof(nuint))
+ else if (typeof(TOther) == typeof(short))
{
- return (byte)(nuint)(object)value;
+ short actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
- else
+ else if (typeof(TOther) == typeof(int))
{
- ThrowHelper.ThrowNotSupportedException();
- return default;
+ int actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
- }
-
- ///
- static bool INumberBase.IsCanonical(byte value) => true;
-
- ///
- static bool INumberBase.IsComplexNumber(byte value) => false;
-
- ///
- public static bool IsEvenInteger(byte value) => (value & 1) == 0;
-
- ///
- static bool INumberBase.IsFinite(byte value) => true;
-
- ///
- static bool INumberBase.IsImaginaryNumber(byte value) => false;
-
- ///
- static bool INumberBase.IsInfinity(byte value) => false;
-
- ///
- static bool INumberBase.IsInteger(byte value) => true;
-
- ///
- static bool INumberBase.IsNaN(byte value) => false;
-
- ///
- static bool INumberBase.IsNegative(byte value) => false;
-
- ///
- static bool INumberBase.IsNegativeInfinity(byte value) => false;
-
- ///
- static bool INumberBase.IsNormal(byte value) => value != 0;
-
- ///
- public static bool IsOddInteger(byte value) => (value & 1) != 0;
-
- ///
- static bool INumberBase.IsPositive(byte value) => true;
-
- ///
- static bool INumberBase.IsPositiveInfinity(byte value) => false;
-
- ///
- static bool INumberBase.IsRealNumber(byte value) => true;
-
- ///
- static bool INumberBase.IsSubnormal(byte value) => false;
-
- ///
- static bool INumberBase.IsZero(byte value) => (value == 0);
-
- ///
- static byte INumberBase.MaxMagnitude(byte x, byte y) => Max(x, y);
-
- ///
- static byte INumberBase.MaxMagnitudeNumber(byte x, byte y) => Max(x, y);
-
- ///
- static byte INumberBase.MinMagnitude(byte x, byte y) => Min(x, y);
-
- ///
- static byte INumberBase.MinMagnitudeNumber(byte x, byte y) => Min(x, y);
-
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryCreate(TOther value, out byte result)
- where TOther : INumberBase
- {
- if (typeof(TOther) == typeof(byte))
+ else if (typeof(TOther) == typeof(long))
{
- result = (byte)(object)value;
+ long actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(char))
+ else if (typeof(TOther) == typeof(Int128))
{
- var actualValue = (char)(object)value;
-
- if (actualValue > MaxValue)
- {
- result = default;
- return false;
- }
-
- result = (byte)actualValue;
+ Int128 actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(decimal))
+ else if (typeof(TOther) == typeof(nint))
{
- var actualValue = (decimal)(object)value;
-
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
-
- result = (byte)actualValue;
+ nint actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(double))
+ else if (typeof(TOther) == typeof(sbyte))
{
- var actualValue = (double)(object)value;
-
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
-
- result = (byte)actualValue;
+ sbyte actualResult = (value >= sbyte.MaxValue) ? sbyte.MaxValue : (sbyte)value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(short))
+ else if (typeof(TOther) == typeof(float))
{
- var actualValue = (short)(object)value;
-
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
-
- result = (byte)actualValue;
+ float actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(int))
+ else
{
- var actualValue = (int)(object)value;
-
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
+ result = default!;
+ return false;
+ }
+ }
- result = (byte)actualValue;
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToTruncating(byte value, [NotNullWhen(true)] out TOther result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `byte` will handle the other unsigned types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(double))
+ {
+ double actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(long))
+ else if (typeof(TOther) == typeof(Half))
{
- var actualValue = (long)(object)value;
-
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
-
- result = (byte)actualValue;
+ Half actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(nint))
+ else if (typeof(TOther) == typeof(short))
{
- var actualValue = (nint)(object)value;
-
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
-
- result = (byte)actualValue;
+ short actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(sbyte))
+ else if (typeof(TOther) == typeof(int))
{
- var actualValue = (sbyte)(object)value;
-
- if (actualValue < 0)
- {
- result = default;
- return false;
- }
-
- result = (byte)actualValue;
+ int actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(float))
+ else if (typeof(TOther) == typeof(long))
{
- var actualValue = (float)(object)value;
-
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
-
- result = (byte)actualValue;
+ long actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(ushort))
+ else if (typeof(TOther) == typeof(Int128))
{
- var actualValue = (ushort)(object)value;
-
- if (actualValue > MaxValue)
- {
- result = default;
- return false;
- }
-
- result = (byte)actualValue;
+ Int128 actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(uint))
+ else if (typeof(TOther) == typeof(nint))
{
- var actualValue = (uint)(object)value;
-
- if (actualValue > MaxValue)
- {
- result = default;
- return false;
- }
-
- result = (byte)actualValue;
+ nint actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(ulong))
+ else if (typeof(TOther) == typeof(sbyte))
{
- var actualValue = (ulong)(object)value;
-
- if (actualValue > MaxValue)
- {
- result = default;
- return false;
- }
-
- result = (byte)actualValue;
+ sbyte actualResult = (sbyte)value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(nuint))
+ else if (typeof(TOther) == typeof(float))
{
- var actualValue = (nuint)(object)value;
-
- if (actualValue > MaxValue)
- {
- result = default;
- return false;
- }
-
- result = (byte)actualValue;
+ float actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
else
{
- ThrowHelper.ThrowNotSupportedException();
- result = default;
+ result = default!;
return false;
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Char.cs b/src/libraries/System.Private.CoreLib/src/System/Char.cs
index fd3b1280859e0f..fa100bbb36e381 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Char.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Char.cs
@@ -1382,476 +1382,490 @@ bool IBinaryInteger.TryWriteLittleEndian(Span destination, out int b
///
static char INumberBase.Abs(char value) => value;
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- static char INumberBase.CreateChecked(TOther value)
+ ///
+ static bool INumberBase.IsCanonical(char value) => true;
+
+ ///
+ static bool INumberBase.IsComplexNumber(char value) => false;
+
+ ///
+ static bool INumberBase.IsEvenInteger(char value) => (value & 1) == 0;
+
+ ///
+ static bool INumberBase.IsFinite(char value) => true;
+
+ ///
+ static bool INumberBase.IsImaginaryNumber(char value) => false;
+
+ ///
+ static bool INumberBase.IsInfinity(char value) => false;
+
+ ///
+ static bool INumberBase.IsInteger(char value) => true;
+
+ ///
+ static bool INumberBase.IsNaN(char value) => false;
+
+ ///
+ static bool INumberBase.IsNegative(char value) => false;
+
+ ///
+ static bool INumberBase.IsNegativeInfinity(char value) => false;
+
+ ///
+ static bool INumberBase.IsNormal(char value) => value != 0;
+
+ ///
+ static bool INumberBase.IsOddInteger(char value) => (value & 1) != 0;
+
+ ///
+ static bool INumberBase.IsPositive(char value) => true;
+
+ ///
+ static bool INumberBase.IsPositiveInfinity(char value) => false;
+
+ ///
+ static bool INumberBase.IsRealNumber(char value) => true;
+
+ ///
+ static bool INumberBase.IsSubnormal(char value) => false;
+
+ ///
+ static bool INumberBase.IsZero(char value) => (value == 0);
+
+ ///
+ static char INumberBase.MaxMagnitude(char x, char y) => (char)Math.Max(x, y);
+
+ ///
+ static char INumberBase.MaxMagnitudeNumber(char x, char y) => (char)Math.Max(x, y);
+
+ ///
+ static char INumberBase.MinMagnitude(char x, char y) => (char)Math.Min(x, y);
+
+ ///
+ static char INumberBase.MinMagnitudeNumber(char x, char y) => (char)Math.Min(x, y);
+
+ static char INumberBase.Parse(string s, NumberStyles style, IFormatProvider? provider) => Parse(s);
+
+ static char INumberBase.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider)
{
- if (typeof(TOther) == typeof(byte))
+ if (s.Length != 1)
{
- return (char)(byte)(object)value;
+ throw new FormatException(SR.Format_NeedSingleChar);
}
- else if (typeof(TOther) == typeof(char))
+ return s[0];
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertFromChecked(TOther value, out char result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `char` will handle the other unsigned types and
+ // `ConvertTo` will handle the signed types
+
+ if (typeof(TOther) == typeof(byte))
{
- return (char)(object)value;
+ byte actualValue = (byte)(object)value;
+ result = (char)actualValue;
+ return true;
}
else if (typeof(TOther) == typeof(decimal))
{
- return checked((char)(decimal)(object)value);
- }
- else if (typeof(TOther) == typeof(double))
- {
- return checked((char)(double)(object)value);
- }
- else if (typeof(TOther) == typeof(short))
- {
- return checked((char)(short)(object)value);
- }
- else if (typeof(TOther) == typeof(int))
- {
- return checked((char)(int)(object)value);
- }
- else if (typeof(TOther) == typeof(long))
- {
- return checked((char)(long)(object)value);
- }
- else if (typeof(TOther) == typeof(nint))
- {
- return checked((char)(nint)(object)value);
- }
- else if (typeof(TOther) == typeof(sbyte))
- {
- return checked((char)(sbyte)(object)value);
- }
- else if (typeof(TOther) == typeof(float))
- {
- return checked((char)(float)(object)value);
+ decimal actualValue = (decimal)(object)value;
+ result = checked((char)actualValue);
+ return true;
}
else if (typeof(TOther) == typeof(ushort))
{
- return (char)(ushort)(object)value;
+ ushort actualValue = (ushort)(object)value;
+ result = (char)actualValue;
+ return true;
}
else if (typeof(TOther) == typeof(uint))
{
- return checked((char)(uint)(object)value);
+ uint actualValue = (uint)(object)value;
+ result = checked((char)actualValue);
+ return true;
}
else if (typeof(TOther) == typeof(ulong))
{
- return checked((char)(ulong)(object)value);
+ ulong actualValue = (ulong)(object)value;
+ result = checked((char)actualValue);
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualValue = (UInt128)(object)value;
+ result = checked((char)actualValue);
+ return true;
}
else if (typeof(TOther) == typeof(nuint))
{
- return checked((char)(nuint)(object)value);
+ nuint actualValue = (nuint)(object)value;
+ result = checked((char)actualValue);
+ return true;
}
else
{
- ThrowHelper.ThrowNotSupportedException();
- return default;
+ result = default;
+ return false;
}
}
- ///
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- static char INumberBase.CreateSaturating(TOther value)
+ static bool INumberBase.TryConvertFromSaturating(TOther value, out char result)
{
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `char` will handle the other unsigned types and
+ // `ConvertTo` will handle the signed types
+
if (typeof(TOther) == typeof(byte))
{
- return (char)(byte)(object)value;
+ byte actualValue = (byte)(object)value;
+ result = (char)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(char))
+ else if (typeof(TOther) == typeof(decimal))
{
- return (char)(object)value;
+ decimal actualValue = (decimal)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue :
+ (actualValue <= MinValue) ? MinValue : (char)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(decimal))
+ else if (typeof(TOther) == typeof(ushort))
{
- var actualValue = (decimal)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < MinValue) ? MinValue : (char)actualValue;
+ ushort actualValue = (ushort)(object)value;
+ result = (char)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(double))
+ else if (typeof(TOther) == typeof(uint))
{
- var actualValue = (double)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < MinValue) ? MinValue : (char)actualValue;
+ uint actualValue = (uint)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue : (char)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(short))
+ else if (typeof(TOther) == typeof(ulong))
{
- var actualValue = (short)(object)value;
- return (actualValue < MinValue) ? MinValue : (char)actualValue;
+ ulong actualValue = (ulong)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue : (char)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(int))
+ else if (typeof(TOther) == typeof(UInt128))
{
- var actualValue = (int)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < MinValue) ? MinValue : (char)actualValue;
+ UInt128 actualValue = (UInt128)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue : (char)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(long))
+ else if (typeof(TOther) == typeof(nuint))
{
- var actualValue = (long)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < MinValue) ? MinValue : (char)actualValue;
+ nuint actualValue = (nuint)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue : (char)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(nint))
+ else
{
- var actualValue = (nint)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < MinValue) ? MinValue : (char)actualValue;
+ result = default;
+ return false;
}
- else if (typeof(TOther) == typeof(sbyte))
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertFromTruncating(TOther value, out char result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `char` will handle the other unsigned types and
+ // `ConvertTo` will handle the signed types
+
+ if (typeof(TOther) == typeof(byte))
{
- var actualValue = (sbyte)(object)value;
- return (actualValue < MinValue) ? MinValue : (char)actualValue;
+ byte actualValue = (byte)(object)value;
+ result = (char)actualValue;
+ return true;
}
- else if (typeof(TOther) == typeof(float))
+ else if (typeof(TOther) == typeof(decimal))
{
- var actualValue = (float)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < MinValue) ? MinValue : (char)actualValue;
+ decimal actualValue = (decimal)(object)value;
+ result = (actualValue >= MaxValue) ? MaxValue :
+ (actualValue <= MinValue) ? MinValue : (char)actualValue;
+ return true;
}
else if (typeof(TOther) == typeof(ushort))
{
- return (char)(ushort)(object)value;
+ ushort actualValue = (ushort)(object)value;
+ result = (char)actualValue;
+ return true;
}
else if (typeof(TOther) == typeof(uint))
{
- var actualValue = (uint)(object)value;
- return (actualValue > MaxValue) ? MaxValue : (char)actualValue;
+ uint actualValue = (uint)(object)value;
+ result = (char)actualValue;
+ return true;
}
else if (typeof(TOther) == typeof(ulong))
{
- var actualValue = (ulong)(object)value;
- return (actualValue > MaxValue) ? MaxValue : (char)actualValue;
+ ulong actualValue = (ulong)(object)value;
+ result = (char)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualValue = (UInt128)(object)value;
+ result = (char)actualValue;
+ return true;
}
else if (typeof(TOther) == typeof(nuint))
{
- var actualValue = (nuint)(object)value;
- return (actualValue > MaxValue) ? MaxValue : (char)actualValue;
+ nuint actualValue = (nuint)(object)value;
+ result = (char)actualValue;
+ return true;
}
else
{
- ThrowHelper.ThrowNotSupportedException();
- return default;
+ result = default;
+ return false;
}
}
- ///
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- static char INumberBase.CreateTruncating(TOther value)
+ static bool INumberBase.TryConvertToChecked(char value, [NotNullWhen(true)] out TOther result)
{
- if (typeof(TOther) == typeof(byte))
- {
- return (char)(byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- return (char)(object)value;
- }
- else if (typeof(TOther) == typeof(decimal))
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `char` will handle the other unsigned types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(double))
{
- return (char)(decimal)(object)value;
+ double actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
- else if (typeof(TOther) == typeof(double))
+ else if (typeof(TOther) == typeof(Half))
{
- return (char)(double)(object)value;
+ Half actualResult = (Half)value;
+ result = (TOther)(object)actualResult;
+ return true;
}
else if (typeof(TOther) == typeof(short))
{
- return (char)(short)(object)value;
+ short actualResult = checked((short)value);
+ result = (TOther)(object)actualResult;
+ return true;
}
else if (typeof(TOther) == typeof(int))
{
- return (char)(int)(object)value;
+ int actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
else if (typeof(TOther) == typeof(long))
{
- return (char)(long)(object)value;
+ long actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(Int128))
+ {
+ Int128 actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
else if (typeof(TOther) == typeof(nint))
{
- return (char)(nint)(object)value;
+ nint actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
else if (typeof(TOther) == typeof(sbyte))
{
- return (char)(sbyte)(object)value;
+ sbyte actualResult = checked((sbyte)value);
+ result = (TOther)(object)actualResult;
+ return true;
}
else if (typeof(TOther) == typeof(float))
{
- return (char)(float)(object)value;
+ float actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
- else if (typeof(TOther) == typeof(ushort))
+ else
{
- return (char)(ushort)(object)value;
+ result = default!;
+ return false;
}
- else if (typeof(TOther) == typeof(uint))
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToSaturating(char value, [NotNullWhen(true)] out TOther result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `char` will handle the other unsigned types and
+ // `ConvertTo` will handle the signed types
+
+ if (typeof(TOther) == typeof(double))
{
- return (char)(uint)(object)value;
+ double actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
- else if (typeof(TOther) == typeof(ulong))
+ else if (typeof(TOther) == typeof(Half))
{
- return (char)(ulong)(object)value;
+ Half actualResult = (Half)value;
+ result = (TOther)(object)actualResult;
+ return true;
}
- else if (typeof(TOther) == typeof(nuint))
+ else if (typeof(TOther) == typeof(short))
{
- return (char)(nuint)(object)value;
+ short actualResult = (value >= short.MaxValue) ? short.MaxValue : (short)value;
+ result = (TOther)(object)actualResult;
+ return true;
}
- else
+ else if (typeof(TOther) == typeof(int))
{
- ThrowHelper.ThrowNotSupportedException();
- return default;
+ int actualResult = value;
+ result = (TOther)(object)actualResult;
+ return true;
}
- }
-
- ///
- static bool INumberBase.IsCanonical(char value) => true;
-
- ///
- static bool INumberBase.IsComplexNumber(char value) => false;
-
- ///
- static bool INumberBase.IsEvenInteger(char value) => (value & 1) == 0;
-
- ///
- static bool INumberBase.IsFinite(char value) => true;
-
- ///
- static bool INumberBase.IsImaginaryNumber(char value) => false;
-
- ///
- static bool INumberBase.IsInfinity(char value) => false;
-
- ///
- static bool INumberBase.IsInteger(char value) => true;
-
- ///
- static bool INumberBase.IsNaN(char value) => false;
-
- ///
- static bool INumberBase.IsNegative(char value) => false;
-
- ///
- static bool INumberBase.IsNegativeInfinity(char value) => false;
-
- ///
- static bool INumberBase.IsNormal(char value) => value != 0;
-
- ///
- static bool INumberBase.IsOddInteger(char value) => (value & 1) != 0;
-
- ///
- static bool INumberBase.IsPositive(char value) => true;
-
- ///
- static bool INumberBase.IsPositiveInfinity(char value) => false;
-
- ///
- static bool INumberBase.IsRealNumber(char value) => true;
-
- ///
- static bool INumberBase.IsSubnormal(char value) => false;
-
- ///
- static bool INumberBase.IsZero(char value) => (value == 0);
-
- ///
- static char INumberBase.MaxMagnitude(char x, char y) => (char)Math.Max(x, y);
-
- ///
- static char INumberBase.MaxMagnitudeNumber(char x, char y) => (char)Math.Max(x, y);
-
- ///
- static char INumberBase.MinMagnitude(char x, char y) => (char)Math.Min(x, y);
-
- ///
- static char INumberBase.MinMagnitudeNumber(char x, char y) => (char)Math.Min(x, y);
-
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- static bool INumberBase.TryCreate(TOther value, out char result)
- {
- if (typeof(TOther) == typeof(byte))
+ else if (typeof(TOther) == typeof(long))
{
- result = (char)(byte)(object)value;
+ long actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(char))
+ else if (typeof(TOther) == typeof(Int128))
{
- result = (char)(object)value;
+ Int128 actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(decimal))
+ else if (typeof(TOther) == typeof(nint))
{
- var actualValue = (decimal)(object)value;
-
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
-
- result = (char)actualValue;
+ nint actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(double))
+ else if (typeof(TOther) == typeof(sbyte))
{
- var actualValue = (double)(object)value;
-
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
-
- result = (char)actualValue;
+ sbyte actualResult = (value >= sbyte.MaxValue) ? sbyte.MaxValue : (sbyte)value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(short))
+ else if (typeof(TOther) == typeof(float))
{
- var actualValue = (short)(object)value;
-
- if (actualValue < 0)
- {
- result = default;
- return false;
- }
-
- result = (char)actualValue;
+ float actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(int))
+ else
{
- var actualValue = (int)(object)value;
+ result = default!;
+ return false;
+ }
+ }
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToTruncating(char value, [NotNullWhen(true)] out TOther result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `char` will handle the other unsigned types and
+ // `ConvertTo` will handle the unsigned types
- result = (char)actualValue;
+ if (typeof(TOther) == typeof(double))
+ {
+ double actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(long))
+ else if (typeof(TOther) == typeof(Half))
{
- var actualValue = (long)(object)value;
-
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
-
- result = (char)actualValue;
+ Half actualResult = (Half)value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(nint))
+ else if (typeof(TOther) == typeof(short))
{
- var actualValue = (nint)(object)value;
-
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
-
- result = (char)actualValue;
+ short actualResult = (short)value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(sbyte))
+ else if (typeof(TOther) == typeof(int))
{
- var actualValue = (sbyte)(object)value;
-
- if (actualValue < 0)
- {
- result = default;
- return false;
- }
-
- result = (char)actualValue;
+ int actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(float))
+ else if (typeof(TOther) == typeof(long))
{
- var actualValue = (float)(object)value;
-
- if ((actualValue < 0) || (actualValue > MaxValue))
- {
- result = default;
- return false;
- }
-
- result = (char)actualValue;
+ long actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(ushort))
+ else if (typeof(TOther) == typeof(Int128))
{
- var actualValue = (ushort)(object)value;
-
- if (actualValue > MaxValue)
- {
- result = default;
- return false;
- }
-
- result = (char)actualValue;
+ Int128 actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(uint))
+ else if (typeof(TOther) == typeof(nint))
{
- var actualValue = (uint)(object)value;
-
- if (actualValue > MaxValue)
- {
- result = default;
- return false;
- }
-
- result = (char)actualValue;
+ nint actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(ulong))
+ else if (typeof(TOther) == typeof(sbyte))
{
- var actualValue = (ulong)(object)value;
-
- if (actualValue > MaxValue)
- {
- result = default;
- return false;
- }
-
- result = (char)actualValue;
+ sbyte actualResult = (sbyte)value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(nuint))
+ else if (typeof(TOther) == typeof(float))
{
- var actualValue = (nuint)(object)value;
-
- if (actualValue > MaxValue)
- {
- result = default;
- return false;
- }
-
- result = (char)actualValue;
+ float actualResult = value;
+ result = (TOther)(object)actualResult;
return true;
}
else
{
- ThrowHelper.ThrowNotSupportedException();
- result = default;
+ result = default!;
return false;
}
}
- static char INumberBase.Parse(string s, NumberStyles style, IFormatProvider? provider) => Parse(s);
-
- static char INumberBase.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider)
- {
- if (s.Length != 1)
- {
- throw new FormatException(SR.Format_NeedSingleChar);
- }
- return s[0];
- }
-
static bool INumberBase.TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out char result) => TryParse(s, out result);
static bool INumberBase.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out char result)
diff --git a/src/libraries/System.Private.CoreLib/src/System/Decimal.cs b/src/libraries/System.Private.CoreLib/src/System/Decimal.cs
index 1fea9eba514a5c..fdad839460d8fb 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Decimal.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Decimal.cs
@@ -1344,250 +1344,6 @@ public static decimal Abs(decimal value)
return new decimal(in value, value._flags & ~SignMask);
}
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static decimal CreateChecked(TOther value)
- where TOther : INumberBase
- {
- if (typeof(TOther) == typeof(byte))
- {
- return (byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- return (char)(object)value;
- }
- else if (typeof(TOther) == typeof(decimal))
- {
- return (decimal)(object)value;
- }
- else if (typeof(TOther) == typeof(double))
- {
- return (decimal)(double)(object)value;
- }
- else if (typeof(TOther) == typeof(short))
- {
- return (short)(object)value;
- }
- else if (typeof(TOther) == typeof(int))
- {
- return (int)(object)value;
- }
- else if (typeof(TOther) == typeof(long))
- {
- return (long)(object)value;
- }
- else if (typeof(TOther) == typeof(Int128))
- {
- return (decimal)(Int128)(object)value;
- }
- else if (typeof(TOther) == typeof(nint))
- {
- return (nint)(object)value;
- }
- else if (typeof(TOther) == typeof(sbyte))
- {
- return (sbyte)(object)value;
- }
- else if (typeof(TOther) == typeof(float))
- {
- return (decimal)(float)(object)value;
- }
- else if (typeof(TOther) == typeof(ushort))
- {
- return (ushort)(object)value;
- }
- else if (typeof(TOther) == typeof(uint))
- {
- return (uint)(object)value;
- }
- else if (typeof(TOther) == typeof(ulong))
- {
- return (ulong)(object)value;
- }
- else if (typeof(TOther) == typeof(UInt128))
- {
- return (decimal)(UInt128)(object)value;
- }
- else if (typeof(TOther) == typeof(nuint))
- {
- return (nuint)(object)value;
- }
- else
- {
- ThrowHelper.ThrowNotSupportedException();
- return default;
- }
- }
-
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static decimal CreateSaturating(TOther value)
- where TOther : INumberBase
- {
- if (typeof(TOther) == typeof(byte))
- {
- return (byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- return (char)(object)value;
- }
- else if (typeof(TOther) == typeof(decimal))
- {
- return (decimal)(object)value;
- }
- else if (typeof(TOther) == typeof(double))
- {
- return (decimal)(double)(object)value;
- }
- else if (typeof(TOther) == typeof(short))
- {
- return (short)(object)value;
- }
- else if (typeof(TOther) == typeof(int))
- {
- return (int)(object)value;
- }
- else if (typeof(TOther) == typeof(long))
- {
- return (long)(object)value;
- }
- else if (typeof(TOther) == typeof(Int128))
- {
- var actualValue = (Int128)(object)value;
- return (actualValue > new Int128(0x0000_0000_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF)) ? MaxValue :
- (actualValue < new Int128(0xFFFF_FFFF_0000_0000, 0x0000_0000_0000_0001)) ? MinValue : (decimal)actualValue;
- }
- else if (typeof(TOther) == typeof(nint))
- {
- return (nint)(object)value;
- }
- else if (typeof(TOther) == typeof(sbyte))
- {
- return (sbyte)(object)value;
- }
- else if (typeof(TOther) == typeof(float))
- {
- return (decimal)(float)(object)value;
- }
- else if (typeof(TOther) == typeof(ushort))
- {
- return (ushort)(object)value;
- }
- else if (typeof(TOther) == typeof(uint))
- {
- return (uint)(object)value;
- }
- else if (typeof(TOther) == typeof(ulong))
- {
- return (ulong)(object)value;
- }
- else if (typeof(TOther) == typeof(UInt128))
- {
- var actualValue = (UInt128)(object)value;
- return (actualValue > new UInt128(0x0000_0000_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF)) ? MaxValue : (decimal)actualValue;
- }
- else if (typeof(TOther) == typeof(nuint))
- {
- return (nuint)(object)value;
- }
- else
- {
- ThrowHelper.ThrowNotSupportedException();
- return default;
- }
- }
-
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static decimal CreateTruncating(TOther value)
- where TOther : INumberBase
- {
- if (typeof(TOther) == typeof(byte))
- {
- return (byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- return (char)(object)value;
- }
- else if (typeof(TOther) == typeof(decimal))
- {
- return (decimal)(object)value;
- }
- else if (typeof(TOther) == typeof(double))
- {
- return (decimal)(double)(object)value;
- }
- else if (typeof(TOther) == typeof(short))
- {
- return (short)(object)value;
- }
- else if (typeof(TOther) == typeof(int))
- {
- return (int)(object)value;
- }
- else if (typeof(TOther) == typeof(long))
- {
- return (long)(object)value;
- }
- else if (typeof(TOther) == typeof(Int128))
- {
- var actualValue = (Int128)(object)value;
-
- if (Int128.IsNegative(actualValue))
- {
- actualValue = (-actualValue) & new Int128(0x0000_0000_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF);
- return -(decimal)actualValue;
- }
- else
- {
- actualValue &= new Int128(0x0000_0000_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF);
- return (decimal)actualValue;
- }
- }
- else if (typeof(TOther) == typeof(nint))
- {
- return (nint)(object)value;
- }
- else if (typeof(TOther) == typeof(sbyte))
- {
- return (sbyte)(object)value;
- }
- else if (typeof(TOther) == typeof(float))
- {
- return (decimal)(float)(object)value;
- }
- else if (typeof(TOther) == typeof(ushort))
- {
- return (ushort)(object)value;
- }
- else if (typeof(TOther) == typeof(uint))
- {
- return (uint)(object)value;
- }
- else if (typeof(TOther) == typeof(ulong))
- {
- return (ulong)(object)value;
- }
- else if (typeof(TOther) == typeof(UInt128))
- {
- var actualValue = (UInt128)(object)value;
- actualValue &= new UInt128(0x0000_0000_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF);
- return (decimal)actualValue;
- }
- else if (typeof(TOther) == typeof(nuint))
- {
- return (nuint)(object)value;
- }
- else
- {
- ThrowHelper.ThrowNotSupportedException();
- return default;
- }
- }
-
///
public static bool IsCanonical(decimal value)
{
@@ -1711,111 +1467,305 @@ public static decimal MinMagnitude(decimal x, decimal y)
///
static decimal INumberBase.MinMagnitudeNumber(decimal x, decimal y) => MinMagnitude(x, y);
- ///
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertFromChecked(TOther value, out decimal result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `decimal` will handle the other unsigned types and
+ // `ConvertTo` will handle the signed types
+
+ if (typeof(TOther) == typeof(byte))
+ {
+ byte actualValue = (byte)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(char))
+ {
+ char actualValue = (char)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ushort))
+ {
+ ushort actualValue = (ushort)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(uint))
+ {
+ uint actualValue = (uint)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ulong))
+ {
+ ulong actualValue = (ulong)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualValue = (UInt128)(object)value;
+ result = checked((decimal)actualValue);
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nuint))
+ {
+ nuint actualValue = (nuint)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
+
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryCreate(TOther value, out decimal result)
+ static bool INumberBase.TryConvertFromSaturating(TOther value, out decimal result)
+ {
+ return TryConvertFrom(value, out result);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertFromTruncating(TOther value, out decimal result)
+ {
+ return TryConvertFrom(value, out result);
+ }
+
+ private static bool TryConvertFrom(TOther value, out decimal result)
where TOther : INumberBase
{
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `decimal` will handle the other unsigned types and
+ // `ConvertTo` will handle the signed types
+
if (typeof(TOther) == typeof(byte))
{
- result = (byte)(object)value;
+ byte actualValue = (byte)(object)value;
+ result = actualValue;
return true;
}
else if (typeof(TOther) == typeof(char))
{
- result = (char)(object)value;
+ char actualValue = (char)(object)value;
+ result = actualValue;
return true;
}
- else if (typeof(TOther) == typeof(decimal))
+ else if (typeof(TOther) == typeof(ushort))
{
- result = (decimal)(object)value;
+ ushort actualValue = (ushort)(object)value;
+ result = actualValue;
return true;
}
- else if (typeof(TOther) == typeof(double))
+ else if (typeof(TOther) == typeof(uint))
{
- result = (decimal)(double)(object)value;
+ uint actualValue = (uint)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ulong))
+ {
+ ulong actualValue = (ulong)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualValue = (UInt128)(object)value;
+ result = (actualValue >= new UInt128(0x0000_0000_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF)) ? MaxValue : (decimal)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nuint))
+ {
+ nuint actualValue = (nuint)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToChecked(decimal value, [NotNullWhen(true)] out TOther result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `decimal` will handle the other unsigned types and
+ // `ConvertTo` will handle the signed types
+
+ if (typeof(TOther) == typeof(double))
+ {
+ double actualResult = checked((double)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(Half))
+ {
+ Half actualResult = checked((Half)value);
+ result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(short))
{
- result = (short)(object)value;
+ short actualResult = checked((short)value);
+ result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(int))
{
- result = (int)(object)value;
+ int actualResult = checked((int)value);
+ result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(long))
{
- result = (long)(object)value;
+ long actualResult = checked((long)value);
+ result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(Int128))
{
- var actualValue = (Int128)(object)value;
-
- if ((actualValue > new Int128(0x0000_0000_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF)) || (actualValue < new Int128(0xFFFF_FFFF_0000_0000, 0x0000_0000_0000_0001)))
- {
- result = default;
- return false;
- }
-
- result = (decimal)actualValue;
+ Int128 actualResult = checked((Int128)value);
+ result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(nint))
{
- result = (nint)(object)value;
+ nint actualResult = checked((nint)value);
+ result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(sbyte))
{
- result = (sbyte)(object)value;
+ sbyte actualResult = checked((sbyte)value);
+ result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(float))
{
- result = (decimal)(float)(object)value;
+ float actualResult = checked((float)value);
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(ushort))
+ else
{
- result = (ushort)(object)value;
+ result = default!;
+ return false;
+ }
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToSaturating(decimal value, [NotNullWhen(true)] out TOther result)
+ {
+ return TryConvertTo(value, out result);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToTruncating(decimal value, [NotNullWhen(true)] out TOther result)
+ {
+ return TryConvertTo(value, out result);
+ }
+
+ private static bool TryConvertTo(decimal value, [NotNullWhen(true)] out TOther result)
+ where TOther : INumberBase
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `decimal` will handle the other unsigned types and
+ // `ConvertTo` will handle the signed types
+
+ if (typeof(TOther) == typeof(double))
+ {
+ double actualResult = (double)value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(uint))
+ else if (typeof(TOther) == typeof(Half))
{
- result = (uint)(object)value;
+ Half actualResult = (Half)value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(ulong))
+ else if (typeof(TOther) == typeof(short))
{
- result = (ulong)(object)value;
+ short actualResult = (value >= short.MaxValue) ? short.MaxValue :
+ (value <= short.MinValue) ? short.MinValue : (short)value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(UInt128))
+ else if (typeof(TOther) == typeof(int))
{
- var actualValue = (UInt128)(object)value;
-
- if (actualValue > new UInt128(0x0000_0000_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF))
- {
- result = default;
- return false;
- }
-
- result = (decimal)actualValue;
+ int actualResult = (value >= int.MaxValue) ? int.MaxValue :
+ (value <= int.MinValue) ? int.MinValue : (int)value;
+ result = (TOther)(object)actualResult;
return true;
}
- else if (typeof(TOther) == typeof(nuint))
+ else if (typeof(TOther) == typeof(long))
+ {
+ long actualResult = (value >= long.MaxValue) ? long.MaxValue :
+ (value <= long.MinValue) ? long.MinValue : (long)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(Int128))
+ {
+ Int128 actualResult = (Int128)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nint))
{
- result = (nuint)(object)value;
+ nint actualResult = (value >= nint.MaxValue) ? nint.MaxValue :
+ (value <= nint.MinValue) ? nint.MinValue : (nint)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(sbyte))
+ {
+ sbyte actualResult = (value >= sbyte.MaxValue) ? sbyte.MaxValue :
+ (value <= sbyte.MinValue) ? sbyte.MinValue : (sbyte)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(float))
+ {
+ float actualResult = (float)value;
+ result = (TOther)(object)actualResult;
return true;
}
else
{
- ThrowHelper.ThrowNotSupportedException();
- result = default;
+ result = default!;
return false;
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs
index a84a966f9c53f9..1655435fbeae4f 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Double.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs
@@ -1003,98 +1003,6 @@ public static double MinNumber(double x, double y)
///
public static double Abs(double value) => Math.Abs(value);
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double CreateChecked(TOther value)
- where TOther : INumberBase
- {
- return CreateSaturating(value);
- }
-
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double CreateSaturating(TOther value)
- where TOther : INumberBase
- {
- if (typeof(TOther) == typeof(byte))
- {
- return (byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- return (char)(object)value;
- }
- else if (typeof(TOther) == typeof(decimal))
- {
- return (double)(decimal)(object)value;
- }
- else if (typeof(TOther) == typeof(double))
- {
- return (double)(object)value;
- }
- else if (typeof(TOther) == typeof(short))
- {
- return (short)(object)value;
- }
- else if (typeof(TOther) == typeof(int))
- {
- return (int)(object)value;
- }
- else if (typeof(TOther) == typeof(long))
- {
- return (long)(object)value;
- }
- else if (typeof(TOther) == typeof(Int128))
- {
- return (double)(Int128)(object)value;
- }
- else if (typeof(TOther) == typeof(nint))
- {
- return (nint)(object)value;
- }
- else if (typeof(TOther) == typeof(sbyte))
- {
- return (sbyte)(object)value;
- }
- else if (typeof(TOther) == typeof(float))
- {
- return (float)(object)value;
- }
- else if (typeof(TOther) == typeof(ushort))
- {
- return (ushort)(object)value;
- }
- else if (typeof(TOther) == typeof(uint))
- {
- return (uint)(object)value;
- }
- else if (typeof(TOther) == typeof(ulong))
- {
- return (ulong)(object)value;
- }
- else if (typeof(TOther) == typeof(UInt128))
- {
- return (double)(UInt128)(object)value;
- }
- else if (typeof(TOther) == typeof(nuint))
- {
- return (nuint)(object)value;
- }
- else
- {
- ThrowHelper.ThrowNotSupportedException();
- return default;
- }
- }
-
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double CreateTruncating(TOther value)
- where TOther : INumberBase
- {
- return CreateSaturating(value);
- }
-
///
static bool INumberBase.IsCanonical(double value) => true;
@@ -1186,13 +1094,258 @@ public static double MinMagnitudeNumber(double x, double y)
return y;
}
- ///
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertFromChecked(TOther value, out double result)
+ {
+ return TryConvertFrom(value, out result);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertFromSaturating(TOther value, out double result)
+ {
+ return TryConvertFrom(value, out result);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertFromTruncating(TOther value, out double result)
+ {
+ return TryConvertFrom(value, out result);
+ }
+
+ private static bool TryConvertFrom(TOther value, out double result)
+ where TOther : INumberBase
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `double` will handle the other signed types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(Half))
+ {
+ Half actualValue = (Half)(object)value;
+ result = (double)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(short))
+ {
+ short actualValue = (short)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(int))
+ {
+ int actualValue = (int)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(long))
+ {
+ long actualValue = (long)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(Int128))
+ {
+ Int128 actualValue = (Int128)(object)value;
+ result = (double)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nint))
+ {
+ nint actualValue = (nint)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(sbyte))
+ {
+ sbyte actualValue = (sbyte)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(float))
+ {
+ float actualValue = (float)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
+
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryCreate(TOther value, out double result)
+ static bool INumberBase.TryConvertToChecked(double value, [NotNullWhen(true)] out TOther result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `double` will handle the other signed types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(byte))
+ {
+ byte actualResult = checked((byte)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(char))
+ {
+ char actualResult = checked((char)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(decimal))
+ {
+ decimal actualResult = checked((decimal)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ushort))
+ {
+ ushort actualResult = checked((ushort)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(uint))
+ {
+ uint actualResult = checked((uint)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ulong))
+ {
+ ulong actualResult = checked((ulong)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualResult = checked((UInt128)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nuint))
+ {
+ nuint actualResult = checked((nuint)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else
+ {
+ result = default!;
+ return false;
+ }
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToSaturating(double value, [NotNullWhen(true)] out TOther result)
+ {
+ return TryConvertTo(value, out result);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToTruncating(double value, [NotNullWhen(true)] out TOther result)
+ {
+ return TryConvertTo(value, out result);
+ }
+
+ private static bool TryConvertTo(double value, [NotNullWhen(true)] out TOther result)
where TOther : INumberBase
{
- result = CreateSaturating(value);
- return true;
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `double` will handle the other signed types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(byte))
+ {
+ byte actualResult = (value >= byte.MaxValue) ? byte.MaxValue :
+ (value <= byte.MinValue) ? byte.MinValue : (byte)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(char))
+ {
+ char actualResult = (value >= char.MaxValue) ? char.MaxValue :
+ (value <= char.MinValue) ? char.MinValue : (char)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(decimal))
+ {
+ decimal actualResult = (value >= +79228162514264337593543950336.0) ? decimal.MaxValue :
+ (value <= -79228162514264337593543950336.0) ? decimal.MinValue :
+ IsNaN(value) ? 0.0m : (decimal)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ushort))
+ {
+ ushort actualResult = (value >= ushort.MaxValue) ? ushort.MaxValue :
+ (value <= ushort.MinValue) ? ushort.MinValue : (ushort)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(uint))
+ {
+ uint actualResult = (value >= uint.MaxValue) ? uint.MaxValue :
+ (value <= uint.MinValue) ? uint.MinValue : (uint)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ulong))
+ {
+ ulong actualResult = (value >= ulong.MaxValue) ? ulong.MaxValue :
+ (value <= ulong.MinValue) ? ulong.MinValue :
+ IsNaN(value) ? 0 : (ulong)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualResult = (value >= 340282366920938463463374607431768211455.0) ? UInt128.MaxValue :
+ (value <= 0.0) ? UInt128.MinValue : (UInt128)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nuint))
+ {
+#if TARGET_64BIT
+ nuint actualResult = (value >= ulong.MaxValue) ? unchecked((nuint)ulong.MaxValue) :
+ (value <= ulong.MinValue) ? unchecked((nuint)ulong.MinValue) : (nuint)value;
+ result = (TOther)(object)actualResult;
+ return true;
+#else
+ nuint actualResult = (value >= uint.MaxValue) ? uint.MaxValue :
+ (value <= uint.MinValue) ? uint.MinValue : (nuint)value;
+ result = (TOther)(object)actualResult;
+ return true;
+#endif
+ }
+ else
+ {
+ result = default!;
+ return false;
+ }
}
//
diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs
index 782abe963f7a37..059299f5effb5e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Half.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs
@@ -539,64 +539,311 @@ public bool TryFormat(Span destination, out int charsWritten, [StringSynta
return Number.TryFormatHalf(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
}
- // -----------------------Start of to-half conversions-------------------------
+ //
+ // Explicit Convert To Half
+ //
- public static explicit operator Half(float value)
+ /// Explicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ public static explicit operator Half(char value) => (Half)(float)value;
+
+ /// Explicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ public static explicit operator Half(decimal value) => (Half)(float)value;
+
+ /// Explicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ public static explicit operator Half(double value)
{
- const int SingleMaxExponent = 0xFF;
+ const int DoubleMaxExponent = 0x7FF;
- uint floatInt = BitConverter.SingleToUInt32Bits(value);
- bool sign = (floatInt & float.SignMask) >> float.SignShift != 0;
- int exp = (int)(floatInt & float.BiasedExponentMask) >> float.BiasedExponentShift;
- uint sig = floatInt & float.TrailingSignificandMask;
+ ulong doubleInt = BitConverter.DoubleToUInt64Bits(value);
+ bool sign = (doubleInt & double.SignMask) >> double.SignShift != 0;
+ int exp = (int)((doubleInt & double.BiasedExponentMask) >> double.BiasedExponentShift);
+ ulong sig = doubleInt & double.TrailingSignificandMask;
- if (exp == SingleMaxExponent)
+ if (exp == DoubleMaxExponent)
{
if (sig != 0) // NaN
{
- return CreateHalfNaN(sign, (ulong)sig << 41); // Shift the significand bits to the left end
+ return CreateHalfNaN(sign, sig << 12); // Shift the significand bits to the left end
}
return sign ? NegativeInfinity : PositiveInfinity;
}
- uint sigHalf = sig >> 9 | ((sig & 0x1FFU) != 0 ? 1U : 0U); // RightShiftJam
-
+ uint sigHalf = (uint)ShiftRightJam(sig, 38);
if ((exp | (int)sigHalf) == 0)
{
return new Half(sign, 0, 0);
}
-
- return new Half(RoundPackToHalf(sign, (short)(exp - 0x71), (ushort)(sigHalf | 0x4000)));
+ return new Half(RoundPackToHalf(sign, (short)(exp - 0x3F1), (ushort)(sigHalf | 0x4000)));
}
- public static explicit operator Half(double value)
+ /// Explicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ public static explicit operator Half(short value) => (Half)(float)value;
+
+ /// Explicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ public static explicit operator Half(int value) => (Half)(float)value;
+
+ /// Explicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ public static explicit operator Half(long value) => (Half)(float)value;
+
+ /// Explicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ public static explicit operator Half(nint value) => (Half)(float)value;
+
+ /// Explicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ public static explicit operator Half(float value)
{
- const int DoubleMaxExponent = 0x7FF;
+ const int SingleMaxExponent = 0xFF;
- ulong doubleInt = BitConverter.DoubleToUInt64Bits(value);
- bool sign = (doubleInt & double.SignMask) >> double.SignShift != 0;
- int exp = (int)((doubleInt & double.BiasedExponentMask) >> double.BiasedExponentShift);
- ulong sig = doubleInt & double.TrailingSignificandMask;
+ uint floatInt = BitConverter.SingleToUInt32Bits(value);
+ bool sign = (floatInt & float.SignMask) >> float.SignShift != 0;
+ int exp = (int)(floatInt & float.BiasedExponentMask) >> float.BiasedExponentShift;
+ uint sig = floatInt & float.TrailingSignificandMask;
- if (exp == DoubleMaxExponent)
+ if (exp == SingleMaxExponent)
{
if (sig != 0) // NaN
{
- return CreateHalfNaN(sign, sig << 12); // Shift the significand bits to the left end
+ return CreateHalfNaN(sign, (ulong)sig << 41); // Shift the significand bits to the left end
}
return sign ? NegativeInfinity : PositiveInfinity;
}
- uint sigHalf = (uint)ShiftRightJam(sig, 38);
+ uint sigHalf = sig >> 9 | ((sig & 0x1FFU) != 0 ? 1U : 0U); // RightShiftJam
+
if ((exp | (int)sigHalf) == 0)
{
return new Half(sign, 0, 0);
}
- return new Half(RoundPackToHalf(sign, (short)(exp - 0x3F1), (ushort)(sigHalf | 0x4000)));
+
+ return new Half(RoundPackToHalf(sign, (short)(exp - 0x71), (ushort)(sigHalf | 0x4000)));
}
- // -----------------------Start of from-half conversions-------------------------
- public static explicit operator float(Half value)
+ /// Explicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ [CLSCompliant(false)]
+ public static explicit operator Half(ushort value) => (Half)(float)value;
+
+ /// Explicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ [CLSCompliant(false)]
+ public static explicit operator Half(uint value) => (Half)(float)value;
+
+ /// Explicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ [CLSCompliant(false)]
+ public static explicit operator Half(ulong value) => (Half)(float)value;
+
+ /// Explicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ [CLSCompliant(false)]
+ public static explicit operator Half(nuint value) => (Half)(float)value;
+
+ //
+ // Explicit Convert From Half
+ //
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ public static explicit operator byte(Half value) => (byte)(float)value;
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ /// is not representable by .
+ public static explicit operator checked byte(Half value) => checked((byte)(float)value);
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ public static explicit operator char(Half value) => (char)(float)value;
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ /// is not representable by .
+ public static explicit operator checked char(Half value) => checked((char)(float)value);
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ public static explicit operator decimal(Half value) => (decimal)(float)value;
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ public static explicit operator short(Half value) => (short)(float)value;
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ /// is not representable by .
+ public static explicit operator checked short(Half value) => checked((short)(float)value);
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ public static explicit operator int(Half value) => (int)(float)value;
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ /// is not representable by .
+ public static explicit operator checked int(Half value) => checked((int)(float)value);
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ public static explicit operator long(Half value) => (long)(float)value;
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ /// is not representable by .
+ public static explicit operator checked long(Half value) => checked((long)(float)value);
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable .
+ /// The value to convert.
+ /// converted to a 128-bit signed integer.
+ public static explicit operator Int128(Half value) => (Int128)(double)(value);
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable , throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to a 128-bit signed integer.
+ /// is not representable by .
+ public static explicit operator checked Int128(Half value) => checked((Int128)(double)(value));
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ public static explicit operator nint(Half value) => (nint)(float)value;
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ /// is not representable by .
+ public static explicit operator checked nint(Half value) => checked((nint)(float)value);
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ [CLSCompliant(false)]
+ public static explicit operator sbyte(Half value) => (sbyte)(float)value;
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ /// is not representable by .
+ [CLSCompliant(false)]
+ public static explicit operator checked sbyte(Half value) => checked((sbyte)(float)value);
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ [CLSCompliant(false)]
+ public static explicit operator ushort(Half value) => (ushort)(float)value;
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ /// is not representable by .
+ [CLSCompliant(false)]
+ public static explicit operator checked ushort(Half value) => checked((ushort)(float)value);
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ [CLSCompliant(false)]
+ public static explicit operator uint(Half value) => (uint)(float)value;
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ /// is not representable by .
+ [CLSCompliant(false)]
+ public static explicit operator checked uint(Half value) => checked((uint)(float)value);
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ [CLSCompliant(false)]
+ public static explicit operator ulong(Half value) => (ulong)(float)value;
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ /// is not representable by .
+ [CLSCompliant(false)]
+ public static explicit operator checked ulong(Half value) => checked((ulong)(float)value);
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable .
+ /// The value to convert.
+ /// converted to a 128-bit unsigned integer.
+ [CLSCompliant(false)]
+ public static explicit operator UInt128(Half value) => (UInt128)(double)(value);
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable , throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to a 128-bit unsigned integer.
+ /// is not representable by .
+ [CLSCompliant(false)]
+ public static explicit operator checked UInt128(Half value) => checked((UInt128)(double)(value));
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ [CLSCompliant(false)]
+ public static explicit operator nuint(Half value) => (nuint)(float)value;
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ /// is not representable by .
+ [CLSCompliant(false)]
+ public static explicit operator checked nuint(Half value) => checked((nuint)(float)value);
+
+ //
+ // Implicit Convert To Half
+ //
+
+ /// Implicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ public static implicit operator Half(byte value) => (Half)(float)value;
+
+ /// Implicitly converts a value to its nearest representable half-precision floating-point value.
+ /// The value to convert.
+ /// converted to its nearest representable half-precision floating-point value.
+ [CLSCompliant(false)]
+ public static implicit operator Half(sbyte value) => (Half)(float)value;
+
+ //
+ // Implicit Convert From Half (actually explicit due to back-compat)
+ //
+
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ public static explicit operator double(Half value)
{
bool sign = IsNegative(value);
int exp = value.BiasedExponent;
@@ -606,25 +853,28 @@ public static explicit operator float(Half value)
{
if (sig != 0)
{
- return CreateSingleNaN(sign, (ulong)sig << 54);
+ return CreateDoubleNaN(sign, (ulong)sig << 54);
}
- return sign ? float.NegativeInfinity : float.PositiveInfinity;
+ return sign ? double.NegativeInfinity : double.PositiveInfinity;
}
if (exp == 0)
{
if (sig == 0)
{
- return BitConverter.UInt32BitsToSingle(sign ? float.SignMask : 0); // Positive / Negative zero
+ return BitConverter.UInt64BitsToDouble(sign ? double.SignMask : 0); // Positive / Negative zero
}
(exp, sig) = NormSubnormalF16Sig(sig);
exp -= 1;
}
- return CreateSingle(sign, (byte)(exp + 0x70), sig << 13);
+ return CreateDouble(sign, (ushort)(exp + 0x3F0), (ulong)sig << 42);
}
- public static explicit operator double(Half value)
+ /// Explicitly converts a half-precision floating-point value to its nearest representable value.
+ /// The value to convert.
+ /// converted to its nearest representable value.
+ public static explicit operator float(Half value)
{
bool sign = IsNegative(value);
int exp = value.BiasedExponent;
@@ -634,22 +884,22 @@ public static explicit operator double(Half value)
{
if (sig != 0)
{
- return CreateDoubleNaN(sign, (ulong)sig << 54);
+ return CreateSingleNaN(sign, (ulong)sig << 54);
}
- return sign ? double.NegativeInfinity : double.PositiveInfinity;
+ return sign ? float.NegativeInfinity : float.PositiveInfinity;
}
if (exp == 0)
{
if (sig == 0)
{
- return BitConverter.UInt64BitsToDouble(sign ? double.SignMask : 0); // Positive / Negative zero
+ return BitConverter.UInt32BitsToSingle(sign ? float.SignMask : 0); // Positive / Negative zero
}
(exp, sig) = NormSubnormalF16Sig(sig);
exp -= 1;
}
- return CreateDouble(sign, (ushort)(exp + 0x3F0), (ulong)sig << 42);
+ return CreateSingle(sign, (byte)(exp + 0x70), sig << 13);
}
// IEEE 754 specifies NaNs to be propagated
@@ -770,7 +1020,7 @@ public static bool IsPow2(Half value)
byte biasedExponent = ExtractBiasedExponentFromBits(bits);
ushort trailingSignificand = ExtractTrailingSignificandFromBits(bits);
- return (value > default(Half))
+ return (value > Zero)
&& (biasedExponent != MinBiasedExponent) && (biasedExponent != MaxBiasedExponent)
&& (trailingSignificand == MinTrailingSignificand);
}
@@ -1195,98 +1445,6 @@ public static Half MinNumber(Half x, Half y)
///
public static Half Abs(Half value) => (Half)MathF.Abs((float)value);
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Half CreateChecked(TOther value)
- where TOther : INumberBase
- {
- return CreateSaturating(value);
- }
-
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Half CreateSaturating(TOther value)
- where TOther : INumberBase
- {
- if (typeof(TOther) == typeof(byte))
- {
- return (Half)(byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- return (Half)(char)(object)value;
- }
- else if (typeof(TOther) == typeof(decimal))
- {
- return (Half)(float)(decimal)(object)value;
- }
- else if (typeof(TOther) == typeof(double))
- {
- return (Half)(double)(object)value;
- }
- else if (typeof(TOther) == typeof(short))
- {
- return (Half)(short)(object)value;
- }
- else if (typeof(TOther) == typeof(int))
- {
- return (Half)(int)(object)value;
- }
- else if (typeof(TOther) == typeof(long))
- {
- return (Half)(long)(object)value;
- }
- else if (typeof(TOther) == typeof(Int128))
- {
- return (Half)(Int128)(object)value;
- }
- else if (typeof(TOther) == typeof(nint))
- {
- return (Half)(long)(nint)(object)value;
- }
- else if (typeof(TOther) == typeof(sbyte))
- {
- return (Half)(sbyte)(object)value;
- }
- else if (typeof(TOther) == typeof(float))
- {
- return (Half)(float)(object)value;
- }
- else if (typeof(TOther) == typeof(ushort))
- {
- return (Half)(ushort)(object)value;
- }
- else if (typeof(TOther) == typeof(uint))
- {
- return (Half)(uint)(object)value;
- }
- else if (typeof(TOther) == typeof(ulong))
- {
- return (Half)(ulong)(object)value;
- }
- else if (typeof(TOther) == typeof(UInt128))
- {
- return (Half)(UInt128)(object)value;
- }
- else if (typeof(TOther) == typeof(nuint))
- {
- return (Half)(ulong)(nuint)(object)value;
- }
- else
- {
- ThrowHelper.ThrowNotSupportedException();
- return default;
- }
- }
-
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Half CreateTruncating(TOther value)
- where TOther : INumberBase
- {
- return CreateSaturating(value);
- }
-
///
static bool INumberBase.IsCanonical(Half value) => true;
@@ -1378,13 +1536,251 @@ public static Half MinMagnitudeNumber(Half x, Half y)
return y;
}
- ///
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertFromChecked(TOther value, out Half result)
+ {
+ return TryConvertFrom(value, out result);
+ }
+
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryCreate(TOther value, out Half result)
+ static bool INumberBase.TryConvertFromSaturating(TOther value, out Half result)
+ {
+ return TryConvertFrom(value, out result);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertFromTruncating(TOther value, out Half result)
+ {
+ return TryConvertFrom(value, out result);
+ }
+
+ private static bool TryConvertFrom(TOther value, out Half result)
where TOther : INumberBase
{
- result = CreateSaturating(value);
- return true;
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `Half` will handle the other signed types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(double))
+ {
+ double actualValue = (double)(object)value;
+ result = (Half)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(short))
+ {
+ short actualValue = (short)(object)value;
+ result = (Half)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(int))
+ {
+ int actualValue = (int)(object)value;
+ result = (Half)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(long))
+ {
+ long actualValue = (long)(object)value;
+ result = (Half)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(Int128))
+ {
+ Int128 actualValue = (Int128)(object)value;
+ result = (Half)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nint))
+ {
+ nint actualValue = (nint)(object)value;
+ result = (Half)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(sbyte))
+ {
+ sbyte actualValue = (sbyte)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(float))
+ {
+ float actualValue = (float)(object)value;
+ result = (Half)actualValue;
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToChecked(Half value, [NotNullWhen(true)] out TOther result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `Half` will handle the other signed types and
+ // `ConvertTo` will handle the unsigned types.
+
+ if (typeof(TOther) == typeof(byte))
+ {
+ byte actualResult = checked((byte)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(char))
+ {
+ char actualResult = checked((char)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(decimal))
+ {
+ decimal actualResult = checked((decimal)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ushort))
+ {
+ ushort actualResult = checked((ushort)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(uint))
+ {
+ uint actualResult = checked((uint)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ulong))
+ {
+ ulong actualResult = checked((ulong)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualResult = checked((UInt128)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nuint))
+ {
+ nuint actualResult = checked((nuint)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else
+ {
+ result = default!;
+ return false;
+ }
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToSaturating(Half value, [NotNullWhen(true)] out TOther result)
+ {
+ return TryConvertTo(value, out result);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToTruncating(Half value, [NotNullWhen(true)] out TOther result)
+ {
+ return TryConvertTo(value, out result);
+ }
+
+ private static bool TryConvertTo(Half value, [NotNullWhen(true)] out TOther result)
+ where TOther : INumberBase
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `Half` will handle the other signed types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(byte))
+ {
+ var actualResult = (value >= byte.MaxValue) ? byte.MaxValue :
+ (value <= byte.MinValue) ? byte.MinValue : (byte)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(char))
+ {
+ char actualResult = (value == PositiveInfinity) ? char.MaxValue :
+ (value <= Zero) ? char.MinValue : (char)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(decimal))
+ {
+ decimal actualResult = (value == PositiveInfinity) ? decimal.MaxValue :
+ (value == NegativeInfinity) ? decimal.MinValue :
+ IsNaN(value) ? 0.0m : (decimal)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ushort))
+ {
+ ushort actualResult = (value == PositiveInfinity) ? ushort.MaxValue :
+ (value <= Zero) ? ushort.MinValue : (ushort)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(uint))
+ {
+ uint actualResult = (value == PositiveInfinity) ? uint.MaxValue :
+ (value <= Zero) ? uint.MinValue : (uint)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ulong))
+ {
+ ulong actualResult = (value == PositiveInfinity) ? ulong.MaxValue :
+ (value <= Zero) ? ulong.MinValue :
+ IsNaN(value) ? 0 : (ulong)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualResult = (value == PositiveInfinity) ? UInt128.MaxValue :
+ (value <= Zero) ? UInt128.MinValue : (UInt128)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nuint))
+ {
+ nuint actualResult = (value == PositiveInfinity) ? nuint.MaxValue :
+ (value <= Zero) ? nuint.MinValue : (nuint)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else
+ {
+ result = default!;
+ return false;
+ }
}
//
diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs
index 56919478ccca7d..31fdfd22ebf813 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs
@@ -604,17 +604,6 @@ internal static Int128 ToInt128(double value)
}
}
- /// Explicitly converts a value to a 128-bit signed integer.
- /// The value to convert.
- /// converted to a 128-bit signed integer.
- public static explicit operator Int128(Half value) => (Int128)(double)(value);
-
- /// Explicitly converts a value to a 128-bit signed integer, throwing an overflow exception for any values that fall outside the representable range.
- /// The value to convert.
- /// converted to a 128-bit signed integer.
- /// is not representable by .
- public static explicit operator checked Int128(Half value) => checked((Int128)(double)(value));
-
/// Explicitly converts a value to a 128-bit signed integer.
/// The value to convert.
/// converted to a 128-bit signed integer.
@@ -1286,222 +1275,6 @@ public static Int128 Abs(Int128 value)
return value;
}
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Int128 CreateChecked(TOther value)
- where TOther : INumberBase
- {
- if (typeof(TOther) == typeof(byte))
- {
- return (byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- return (char)(object)value;
- }
- else if (typeof(TOther) == typeof(decimal))
- {
- return checked((Int128)(decimal)(object)value);
- }
- else if (typeof(TOther) == typeof(double))
- {
- return checked((Int128)(double)(object)value);
- }
- else if (typeof(TOther) == typeof(Half))
- {
- return checked((Int128)(Half)(object)value);
- }
- else if (typeof(TOther) == typeof(short))
- {
- return (short)(object)value;
- }
- else if (typeof(TOther) == typeof(int))
- {
- return (int)(object)value;
- }
- else if (typeof(TOther) == typeof(long))
- {
- return (long)(object)value;
- }
- else if (typeof(TOther) == typeof(nint))
- {
- return (nint)(object)value;
- }
- else if (typeof(TOther) == typeof(sbyte))
- {
- return (sbyte)(object)value;
- }
- else if (typeof(TOther) == typeof(float))
- {
- return checked((Int128)(float)(object)value);
- }
- else if (typeof(TOther) == typeof(ushort))
- {
- return (ushort)(object)value;
- }
- else if (typeof(TOther) == typeof(uint))
- {
- return (uint)(object)value;
- }
- else if (typeof(TOther) == typeof(ulong))
- {
- return (ulong)(object)value;
- }
- else if (typeof(TOther) == typeof(nuint))
- {
- return (nuint)(object)value;
- }
- else
- {
- ThrowHelper.ThrowNotSupportedException();
- return default;
- }
- }
-
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Int128 CreateSaturating(TOther value)
- where TOther : INumberBase
- {
- if (typeof(TOther) == typeof(byte))
- {
- return (byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- return (char)(object)value;
- }
- else if (typeof(TOther) == typeof(decimal))
- {
- return (Int128)(decimal)(object)value;
- }
- else if (typeof(TOther) == typeof(double))
- {
- return (Int128)(double)(object)value;
- }
- else if (typeof(TOther) == typeof(Half))
- {
- return (Int128)(Half)(object)value;
- }
- else if (typeof(TOther) == typeof(short))
- {
- return (short)(object)value;
- }
- else if (typeof(TOther) == typeof(int))
- {
- return (int)(object)value;
- }
- else if (typeof(TOther) == typeof(long))
- {
- return (long)(object)value;
- }
- else if (typeof(TOther) == typeof(nint))
- {
- return (nint)(object)value;
- }
- else if (typeof(TOther) == typeof(sbyte))
- {
- return (sbyte)(object)value;
- }
- else if (typeof(TOther) == typeof(float))
- {
- return (Int128)(float)(object)value;
- }
- else if (typeof(TOther) == typeof(ushort))
- {
- return (ushort)(object)value;
- }
- else if (typeof(TOther) == typeof(uint))
- {
- return (uint)(object)value;
- }
- else if (typeof(TOther) == typeof(ulong))
- {
- return (ulong)(object)value;
- }
- else if (typeof(TOther) == typeof(nuint))
- {
- return (nuint)(object)value;
- }
- else
- {
- ThrowHelper.ThrowNotSupportedException();
- return default;
- }
- }
-
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Int128 CreateTruncating(TOther value)
- where TOther : INumberBase
- {
- if (typeof(TOther) == typeof(byte))
- {
- return (byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- return (char)(object)value;
- }
- else if (typeof(TOther) == typeof(decimal))
- {
- return (Int128)(decimal)(object)value;
- }
- else if (typeof(TOther) == typeof(double))
- {
- return (Int128)(double)(object)value;
- }
- else if (typeof(TOther) == typeof(Half))
- {
- return (Int128)(Half)(object)value;
- }
- else if (typeof(TOther) == typeof(short))
- {
- return (short)(object)value;
- }
- else if (typeof(TOther) == typeof(int))
- {
- return (int)(object)value;
- }
- else if (typeof(TOther) == typeof(long))
- {
- return (long)(object)value;
- }
- else if (typeof(TOther) == typeof(nint))
- {
- return (nint)(object)value;
- }
- else if (typeof(TOther) == typeof(sbyte))
- {
- return (sbyte)(object)value;
- }
- else if (typeof(TOther) == typeof(float))
- {
- return (Int128)(float)(object)value;
- }
- else if (typeof(TOther) == typeof(ushort))
- {
- return (ushort)(object)value;
- }
- else if (typeof(TOther) == typeof(uint))
- {
- return (uint)(object)value;
- }
- else if (typeof(TOther) == typeof(ulong))
- {
- return (ulong)(object)value;
- }
- else if (typeof(TOther) == typeof(nuint))
- {
- return (nuint)(object)value;
- }
- else
- {
- ThrowHelper.ThrowNotSupportedException();
- return default;
- }
- }
-
///
static bool INumberBase.IsCanonical(Int128 value) => true;
@@ -1639,114 +1412,423 @@ public static Int128 MinMagnitude(Int128 x, Int128 y)
///
static Int128 INumberBase.MinMagnitudeNumber(Int128 x, Int128 y) => MinMagnitude(x, y);
- ///
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryCreate(TOther value, out Int128 result)
- where TOther : INumberBase
+ static bool INumberBase.TryConvertFromChecked(TOther value, out Int128 result)
{
- if (typeof(TOther) == typeof(byte))
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `Int128` will handle the other signed types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(double))
{
- result = (byte)(object)value;
+ double actualValue = (double)(object)value;
+ result = checked((Int128)actualValue);
return true;
}
- else if (typeof(TOther) == typeof(char))
+ else if (typeof(TOther) == typeof(Half))
{
- result = (char)(object)value;
+ Half actualValue = (Half)(object)value;
+ result = checked((Int128)actualValue);
return true;
}
- else if (typeof(TOther) == typeof(decimal))
+ else if (typeof(TOther) == typeof(short))
+ {
+ short actualValue = (short)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(int))
{
- result = (Int128)(decimal)(object)value;
+ int actualValue = (int)(object)value;
+ result = actualValue;
return true;
}
- else if (typeof(TOther) == typeof(double))
+ else if (typeof(TOther) == typeof(long))
{
- var actualValue = (double)(object)value;
+ long actualValue = (long)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nint))
+ {
+ nint actualValue = (nint)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(sbyte))
+ {
+ sbyte actualValue = (sbyte)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(float))
+ {
+ float actualValue = (float)(object)value;
+ result = checked((Int128)actualValue);
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
- if ((actualValue < -170141183460469231731687303715884105728.0) || (actualValue >= +170141183460469231731687303715884105728.0) || double.IsNaN(actualValue))
- {
- result = default;
- return false;
- }
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertFromSaturating(TOther value, out Int128 result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `Int128` will handle the other signed types and
+ // `ConvertTo` will handle the unsigned types
- result = (Int128)actualValue;
+ if (typeof(TOther) == typeof(double))
+ {
+ double actualValue = (double)(object)value;
+ result = (actualValue >= +170141183460469231731687303715884105727.0) ? MaxValue :
+ (actualValue <= -170141183460469231731687303715884105728.0) ? MinValue : (Int128)actualValue;
return true;
}
else if (typeof(TOther) == typeof(Half))
{
- var actualValue = (Half)(object)value;
+ Half actualValue = (Half)(object)value;
+ result = (actualValue == Half.PositiveInfinity) ? MaxValue :
+ (actualValue == Half.NegativeInfinity) ? MinValue : (Int128)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(short))
+ {
+ short actualValue = (short)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(int))
+ {
+ int actualValue = (int)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(long))
+ {
+ long actualValue = (long)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nint))
+ {
+ nint actualValue = (nint)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(sbyte))
+ {
+ sbyte actualValue = (sbyte)(object)value;
+ result = actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(float))
+ {
+ float actualValue = (float)(object)value;
+ result = (actualValue >= +170141183460469231731687303715884105727.0f) ? MaxValue :
+ (actualValue <= -170141183460469231731687303715884105728.0f) ? MinValue : (Int128)actualValue;
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
- if ((actualValue < Half.MinValue) || (actualValue > Half.MaxValue) || Half.IsNaN(actualValue))
- {
- result = default;
- return false;
- }
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertFromTruncating(TOther value, out Int128 result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `Int128` will handle the other signed types and
+ // `ConvertTo` will handle the unsigned types
- result = (Int128)actualValue;
+ if (typeof(TOther) == typeof(double))
+ {
+ double actualValue = (double)(object)value;
+ result = (actualValue >= +170141183460469231731687303715884105727.0) ? MaxValue :
+ (actualValue <= -170141183460469231731687303715884105728.0) ? MinValue : (Int128)actualValue;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(Half))
+ {
+ Half actualValue = (Half)(object)value;
+ result = (actualValue == Half.PositiveInfinity) ? MaxValue :
+ (actualValue == Half.NegativeInfinity) ? MinValue : (Int128)actualValue;
return true;
}
else if (typeof(TOther) == typeof(short))
{
- result = (short)(object)value;
+ short actualValue = (short)(object)value;
+ result = actualValue;
return true;
}
else if (typeof(TOther) == typeof(int))
{
- result = (int)(object)value;
+ int actualValue = (int)(object)value;
+ result = actualValue;
return true;
}
else if (typeof(TOther) == typeof(long))
{
- result = (long)(object)value;
+ long actualValue = (long)(object)value;
+ result = actualValue;
return true;
}
else if (typeof(TOther) == typeof(nint))
{
- result = (nint)(object)value;
+ nint actualValue = (nint)(object)value;
+ result = actualValue;
return true;
}
else if (typeof(TOther) == typeof(sbyte))
{
- result = (sbyte)(object)value;
+ sbyte actualValue = (sbyte)(object)value;
+ result = actualValue;
return true;
}
else if (typeof(TOther) == typeof(float))
{
- var actualValue = (float)(object)value;
+ float actualValue = (float)(object)value;
+ result = (actualValue >= +170141183460469231731687303715884105727.0f) ? MaxValue :
+ (actualValue <= -170141183460469231731687303715884105728.0f) ? MinValue : (Int128)actualValue;
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
- if ((actualValue < -170141183460469231731687303715884105728.0f) || (actualValue >= +170141183460469231731687303715884105728.0f) || float.IsNaN(actualValue))
- {
- result = default;
- return false;
- }
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToChecked(Int128 value, [NotNullWhen(true)] out TOther result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `Int128` will handle the other signed types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(byte))
+ {
+ byte actualResult = checked((byte)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(char))
+ {
+ char actualResult = checked((char)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(decimal))
+ {
+ decimal actualResult = checked((decimal)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ushort))
+ {
+ ushort actualResult = checked((ushort)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(uint))
+ {
+ uint actualResult = checked((uint)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ulong))
+ {
+ ulong actualResult = checked((ulong)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualResult = checked((UInt128)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nuint))
+ {
+ nuint actualResult = checked((nuint)value);
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else
+ {
+ result = default!;
+ return false;
+ }
+ }
- result = (Int128)actualValue;
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToSaturating(Int128 value, [NotNullWhen(true)] out TOther result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `Int128` will handle the other signed types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(byte))
+ {
+ byte actualResult = (value >= byte.MaxValue) ? byte.MaxValue :
+ (value <= byte.MinValue) ? byte.MinValue : (byte)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(char))
+ {
+ char actualResult = (value >= char.MaxValue) ? char.MaxValue :
+ (value <= char.MinValue) ? char.MinValue : (char)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(decimal))
+ {
+ decimal actualResult = (value >= new Int128(0x0000_0000_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF)) ? decimal.MaxValue :
+ (value <= new Int128(0xFFFF_FFFF_0000_0000, 0x0000_0000_0000_0001)) ? decimal.MinValue : (decimal)value;
+ result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(ushort))
{
- result = (ushort)(object)value;
+ ushort actualResult = (value >= ushort.MaxValue) ? ushort.MaxValue :
+ (value <= ushort.MinValue) ? ushort.MinValue : (ushort)value;
+ result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(uint))
{
- result = (uint)(object)value;
+ uint actualResult = (value >= uint.MaxValue) ? uint.MaxValue :
+ (value <= uint.MinValue) ? uint.MinValue : (uint)value;
+ result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(ulong))
{
- result = (ulong)(object)value;
+ ulong actualResult = (value <= 0) ? ulong.MinValue : (ulong)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualResult = (value <= 0) ? UInt128.MinValue : (UInt128)value;
+ result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(nuint))
{
- result = (nuint)(object)value;
+ nuint actualResult = (value >= nuint.MaxValue) ? nuint.MaxValue :
+ (value <= nuint.MinValue) ? nuint.MinValue : (nuint)value;
+ result = (TOther)(object)actualResult;
return true;
}
else
{
- ThrowHelper.ThrowNotSupportedException();
- result = default;
+ result = default!;
+ return false;
+ }
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool INumberBase.TryConvertToTruncating(Int128 value, [NotNullWhen(true)] out TOther result)
+ {
+ // In order to reduce overall code duplication and improve the inlinabilty of these
+ // methods for the corelib types we have `ConvertFrom` handle the same sign and
+ // `ConvertTo` handle the opposite sign. However, since there is an uneven split
+ // between signed and unsigned types, the one that handles unsigned will also
+ // handle `Decimal`.
+ //
+ // That is, `ConvertFrom` for `Int128` will handle the other signed types and
+ // `ConvertTo` will handle the unsigned types
+
+ if (typeof(TOther) == typeof(byte))
+ {
+ byte actualResult = (byte)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(char))
+ {
+ char actualResult = (char)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(decimal))
+ {
+ decimal actualResult = (value >= new Int128(0x0000_0000_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF)) ? decimal.MaxValue :
+ (value <= new Int128(0xFFFF_FFFF_0000_0000, 0x0000_0000_0000_0001)) ? decimal.MinValue : (decimal)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ushort))
+ {
+ ushort actualResult = (ushort)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(uint))
+ {
+ uint actualResult = (uint)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(ulong))
+ {
+ ulong actualResult = (ulong)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(UInt128))
+ {
+ UInt128 actualResult = (UInt128)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else if (typeof(TOther) == typeof(nuint))
+ {
+ nuint actualResult = (nuint)value;
+ result = (TOther)(object)actualResult;
+ return true;
+ }
+ else
+ {
+ result = default!;
return false;
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Int16.cs b/src/libraries/System.Private.CoreLib/src/System/Int16.cs
index 0456102d42d950..75025b7a59732e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Int16.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Int16.cs
@@ -577,227 +577,6 @@ public static short CopySign(short value, short sign)
///
public static short Abs(short value) => Math.Abs(value);
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static short CreateChecked(TOther value)
- where TOther : INumberBase
- {
- if (typeof(TOther) == typeof(byte))
- {
- return (byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- return checked((short)(char)(object)value);
- }
- else if (typeof(TOther) == typeof(decimal))
- {
- return checked((short)(decimal)(object)value);
- }
- else if (typeof(TOther) == typeof(double))
- {
- return checked((short)(double)(object)value);
- }
- else if (typeof(TOther) == typeof(short))
- {
- return (short)(object)value;
- }
- else if (typeof(TOther) == typeof(int))
- {
- return checked((short)(int)(object)value);
- }
- else if (typeof(TOther) == typeof(long))
- {
- return checked((short)(long)(object)value);
- }
- else if (typeof(TOther) == typeof(nint))
- {
- return checked((short)(nint)(object)value);
- }
- else if (typeof(TOther) == typeof(sbyte))
- {
- return (sbyte)(object)value;
- }
- else if (typeof(TOther) == typeof(float))
- {
- return checked((short)(float)(object)value);
- }
- else if (typeof(TOther) == typeof(ushort))
- {
- return checked((short)(ushort)(object)value);
- }
- else if (typeof(TOther) == typeof(uint))
- {
- return checked((short)(uint)(object)value);
- }
- else if (typeof(TOther) == typeof(ulong))
- {
- return checked((short)(ulong)(object)value);
- }
- else if (typeof(TOther) == typeof(nuint))
- {
- return checked((short)(nuint)(object)value);
- }
- else
- {
- ThrowHelper.ThrowNotSupportedException();
- return default;
- }
- }
-
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static short CreateSaturating(TOther value)
- where TOther : INumberBase
- {
- if (typeof(TOther) == typeof(byte))
- {
- return (byte)(object)value;
- }
- else if (typeof(TOther) == typeof(char))
- {
- var actualValue = (char)(object)value;
- return (actualValue > MaxValue) ? MaxValue : (short)actualValue;
- }
- else if (typeof(TOther) == typeof(decimal))
- {
- var actualValue = (decimal)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < MinValue) ? MinValue : (short)actualValue;
- }
- else if (typeof(TOther) == typeof(double))
- {
- var actualValue = (double)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < MinValue) ? MinValue : (short)actualValue;
- }
- else if (typeof(TOther) == typeof(short))
- {
- return (short)(object)value;
- }
- else if (typeof(TOther) == typeof(int))
- {
- var actualValue = (int)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < MinValue) ? MinValue : (short)actualValue;
- }
- else if (typeof(TOther) == typeof(long))
- {
- var actualValue = (long)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < MinValue) ? MinValue : (short)actualValue;
- }
- else if (typeof(TOther) == typeof(nint))
- {
- var actualValue = (nint)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < MinValue) ? MinValue : (short)actualValue;
- }
- else if (typeof(TOther) == typeof(sbyte))
- {
- return (sbyte)(object)value;
- }
- else if (typeof(TOther) == typeof(float))
- {
- var actualValue = (float)(object)value;
- return (actualValue > MaxValue) ? MaxValue :
- (actualValue < MinValue) ? MinValue : (short)actualValue;
- }
- else if (typeof(TOther) == typeof(ushort))
- {
- var actualValue = (ushort)(object)value;
- return (actualValue > MaxValue) ? MaxValue : (short)actualValue;
- }
- else if (typeof(TOther) == typeof(uint))
- {
- var actualValue = (uint)(object)value;
- return (actualValue > MaxValue) ? MaxValue : (short)actualValue;
- }
- else if (typeof(TOther) == typeof(ulong))
- {
- var actualValue = (ulong)(object)value;
- return (actualValue > (uint)MaxValue) ? MaxValue : (short)actualValue;
- }
- else if (typeof(TOther) == typeof(nuint))
- {
- var actualValue = (nuint)(object)value;
- return (actualValue > (uint)MaxValue) ? MaxValue : (short)actualValue;
- }
- else
- {
- ThrowHelper.ThrowNotSupportedException();
- return default;
- }
- }
-
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static short CreateTruncating(TOther value)
- where TOther : INumberBase