|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Buffers.Binary;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
#if TARGET_64BIT
using nuint_t = System.UInt64;
#else
using nuint_t = System.UInt32;
#endif
namespace System
{
[Serializable]
[CLSCompliant(false)]
[StructLayout(LayoutKind.Sequential)]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public readonly struct UIntPtr
: IEquatable<nuint>,
IComparable,
IComparable<nuint>,
ISpanFormattable,
ISerializable,
IBinaryInteger<nuint>,
IMinMaxValue<nuint>,
IUnsignedNumber<nuint>,
IUtf8SpanFormattable
{
private readonly nuint _value;
[Intrinsic]
public static readonly nuint Zero;
[NonVersionable]
public UIntPtr(uint value)
{
_value = value;
}
[NonVersionable]
public UIntPtr(ulong value)
{
#if TARGET_64BIT
_value = (nuint)value;
#else
_value = checked((nuint)value);
#endif
}
[NonVersionable]
public unsafe UIntPtr(void* value)
{
_value = (nuint)value;
}
private UIntPtr(SerializationInfo info, StreamingContext context)
{
ulong value = info.GetUInt64("value");
#if TARGET_32BIT
if (value > uint.MaxValue)
{
throw new ArgumentException(SR.Serialization_InvalidPtrValue);
}
#endif
_value = (nuint)value;
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
ArgumentNullException.ThrowIfNull(info);
ulong value = _value;
info.AddValue("value", value);
}
public override bool Equals([NotNullWhen(true)] object? obj) => (obj is nuint other) && Equals(other);
public override int GetHashCode()
{
#if TARGET_64BIT
ulong value = _value;
return value.GetHashCode();
#else
return (int)_value;
#endif
}
[NonVersionable]
public uint ToUInt32()
{
#if TARGET_64BIT
return checked((uint)_value);
#else
return (uint)_value;
#endif
}
[NonVersionable]
public ulong ToUInt64() => _value;
[NonVersionable]
public static explicit operator nuint(uint value) => value;
[NonVersionable]
public static explicit operator nuint(ulong value) => checked((nuint)value);
[NonVersionable]
public static unsafe explicit operator nuint(void* value) => (nuint)value;
[NonVersionable]
public static unsafe explicit operator void*(nuint value) => (void*)value;
[NonVersionable]
public static explicit operator uint(nuint value)
{
#if TARGET_64BIT
return checked((uint)value);
#else
return (uint)value;
#endif
}
[NonVersionable]
public static explicit operator ulong(nuint value) => value;
[NonVersionable]
public static bool operator ==(nuint value1, nuint value2) => value1 == value2;
[NonVersionable]
public static bool operator !=(nuint value1, nuint value2) => value1 != value2;
[NonVersionable]
public static nuint Add(nuint pointer, int offset) => pointer + (nuint)offset;
[NonVersionable]
public static nuint operator +(nuint pointer, int offset) => pointer + (nuint)offset;
[NonVersionable]
public static nuint Subtract(nuint pointer, int offset) => pointer - (nuint)offset;
[NonVersionable]
public static nuint operator -(nuint pointer, int offset) => pointer - (nuint)offset;
public static int Size
{
[NonVersionable]
get => sizeof(nuint_t);
}
[NonVersionable]
public unsafe void* ToPointer() => (void*)_value;
/// <inheritdoc cref="IMinMaxValue{TSelf}.MaxValue" />
public static nuint MaxValue
{
[NonVersionable]
get => unchecked((nuint)nuint_t.MaxValue);
}
/// <inheritdoc cref="IMinMaxValue{TSelf}.MinValue" />
public static nuint MinValue
{
[NonVersionable]
get => unchecked((nuint)nuint_t.MinValue);
}
public int CompareTo(object? value)
{
if (value is nuint other)
{
return CompareTo(other);
}
else if (value is null)
{
return 1;
}
throw new ArgumentException(SR.Arg_MustBeUIntPtr);
}
public int CompareTo(nuint value)
{
if (_value < value) return -1;
if (_value > value) return 1;
return 0;
}
[NonVersionable]
public bool Equals(nuint other) => _value == other;
public override string ToString() => ((nuint_t)_value).ToString();
public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format) => ((nuint_t)_value).ToString(format);
public string ToString(IFormatProvider? provider) => ((nuint_t)_value).ToString(provider);
public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format, IFormatProvider? provider) => ((nuint_t)_value).ToString(format, provider);
public bool TryFormat(Span<char> destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null) =>
((nuint_t)_value).TryFormat(destination, out charsWritten, format, provider);
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null) =>
((nuint_t)_value).TryFormat(utf8Destination, out bytesWritten, format, provider);
public static nuint Parse(string s) => (nuint)nuint_t.Parse(s);
public static nuint Parse(string s, NumberStyles style) => (nuint)nuint_t.Parse(s, style);
public static nuint Parse(string s, IFormatProvider? provider) => (nuint)nuint_t.Parse(s, provider);
public static nuint Parse(string s, NumberStyles style, IFormatProvider? provider) => (nuint)nuint_t.Parse(s, style, provider);
public static nuint Parse(ReadOnlySpan<char> s, IFormatProvider? provider) => (nuint)nuint_t.Parse(s, provider);
public static nuint Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) => (nuint)nuint_t.Parse(s, style, provider);
public static bool TryParse([NotNullWhen(true)] string? s, out nuint result)
{
Unsafe.SkipInit(out result);
return nuint_t.TryParse(s, out Unsafe.As<nuint, nuint_t>(ref result));
}
/// <summary>Tries to parse a string into a value.</summary>
/// <param name="s">A read-only span of characters containing a number to convert.</param>
/// <param name="provider">An object that provides culture-specific formatting information about <paramref name="s" />.</param>
/// <param name="result">When this method returns, contains the result of successfully parsing <paramref name="s" /> or an undefined value on failure.</param>
/// <returns><see langword="true" /> if <paramref name="s" /> was converted successfully; otherwise, <see langword="false" />.</returns>
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, out nuint result)
{
Unsafe.SkipInit(out result);
return nuint_t.TryParse(s, provider, out Unsafe.As<nuint, nuint_t>(ref result));
}
public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out nuint result)
{
Unsafe.SkipInit(out result);
return nuint_t.TryParse(s, style, provider, out Unsafe.As<nuint, nuint_t>(ref result));
}
public static bool TryParse(ReadOnlySpan<char> s, out nuint result)
{
Unsafe.SkipInit(out result);
return nuint_t.TryParse(s, out Unsafe.As<nuint, nuint_t>(ref result));
}
/// <summary>Tries to convert a UTF-8 character span containing the string representation of a number to its unsigned integer equivalent.</summary>
/// <param name="utf8Text">A span containing the UTF-8 characters representing the number to convert.</param>
/// <param name="result">When this method returns, contains the unsigned integer value equivalent to the number contained in <paramref name="utf8Text" /> if the conversion succeeded, or zero if the conversion failed. This parameter is passed uninitialized; any value originally supplied in result will be overwritten.</param>
/// <returns><c>true</c> if <paramref name="utf8Text" /> was converted successfully; otherwise, false.</returns>
public static bool TryParse(ReadOnlySpan<byte> utf8Text, out nuint result)
{
Unsafe.SkipInit(out result);
return nuint_t.TryParse(utf8Text, out Unsafe.As<nuint, nuint_t>(ref result));
}
/// <inheritdoc cref="IParsable{TSelf}.TryParse(string?, IFormatProvider?, out TSelf)" />
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out nuint result)
{
Unsafe.SkipInit(out result);
return nuint_t.TryParse(s, provider, out Unsafe.As<nuint, nuint_t>(ref result));
}
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out nuint result)
{
Unsafe.SkipInit(out result);
return nuint_t.TryParse(s, style, provider, out Unsafe.As<nuint, nuint_t>(ref result));
}
//
// IAdditionOperators
//
/// <inheritdoc cref="IAdditionOperators{TSelf, TOther, TResult}.op_Addition(TSelf, TOther)" />
static nuint IAdditionOperators<nuint, nuint, nuint>.operator +(nuint left, nuint right) => left + right;
/// <inheritdoc cref="IAdditionOperators{TSelf, TOther, TResult}.op_Addition(TSelf, TOther)" />
static nuint IAdditionOperators<nuint, nuint, nuint>.operator checked +(nuint left, nuint right) => checked(left + right);
//
// IAdditiveIdentity
//
/// <inheritdoc cref="IAdditiveIdentity{TSelf, TResult}.AdditiveIdentity" />
static nuint IAdditiveIdentity<nuint, nuint>.AdditiveIdentity => 0;
//
// IBinaryInteger
//
/// <inheritdoc cref="IBinaryInteger{TSelf}.DivRem(TSelf, TSelf)" />
public static (nuint Quotient, nuint Remainder) DivRem(nuint left, nuint right) => Math.DivRem(left, right);
/// <inheritdoc cref="IBinaryInteger{TSelf}.LeadingZeroCount(TSelf)" />
[Intrinsic]
public static nuint LeadingZeroCount(nuint value) => (nuint)BitOperations.LeadingZeroCount(value);
/// <inheritdoc cref="IBinaryInteger{TSelf}.PopCount(TSelf)" />
[Intrinsic]
public static nuint PopCount(nuint value) => (nuint)BitOperations.PopCount(value);
/// <inheritdoc cref="IBinaryInteger{TSelf}.RotateLeft(TSelf, int)" />
[Intrinsic]
public static nuint RotateLeft(nuint value, int rotateAmount) => BitOperations.RotateLeft(value, rotateAmount);
/// <inheritdoc cref="IBinaryInteger{TSelf}.RotateRight(TSelf, int)" />
[Intrinsic]
public static nuint RotateRight(nuint value, int rotateAmount) => BitOperations.RotateRight(value, rotateAmount);
/// <inheritdoc cref="IBinaryInteger{TSelf}.TrailingZeroCount(TSelf)" />
[Intrinsic]
public static nuint TrailingZeroCount(nuint value) => (nuint)BitOperations.TrailingZeroCount(value);
/// <inheritdoc cref="IBinaryInteger{TSelf}.TryReadBigEndian(ReadOnlySpan{byte}, bool, out TSelf)" />
static bool IBinaryInteger<nuint>.TryReadBigEndian(ReadOnlySpan<byte> source, bool isUnsigned, out nuint value)
{
nuint result = default;
if (source.Length != 0)
{
if (!isUnsigned && sbyte.IsNegative((sbyte)source[0]))
{
// When we are signed and the sign bit is set, we are negative and therefore
// definitely out of range
value = result;
return false;
}
if ((source.Length > sizeof(nuint_t)) && (source[..^sizeof(nuint_t)].ContainsAnyExcept((byte)0x00)))
{
// When we have any non-zero leading data, we are a large positive and therefore
// definitely out of range
value = result;
return false;
}
ref byte sourceRef = ref MemoryMarshal.GetReference(source);
if (source.Length >= sizeof(nuint_t))
{
sourceRef = ref Unsafe.Add(ref sourceRef, source.Length - sizeof(nuint_t));
// We have at least 4/8 bytes, so just read the ones we need directly
result = Unsafe.ReadUnaligned<nuint>(ref sourceRef);
if (BitConverter.IsLittleEndian)
{
result = BinaryPrimitives.ReverseEndianness(result);
}
}
else
{
// We have between 1 and 3/7 bytes, so construct the relevant value directly
// since the data is in Big Endian format, we can just read the bytes and
// shift left by 8-bits for each subsequent part
for (int i = 0; i < source.Length; i++)
{
result <<= 8;
result |= Unsafe.Add(ref sourceRef, i);
}
}
}
value = result;
return true;
}
/// <inheritdoc cref="IBinaryInteger{TSelf}.TryReadLittleEndian(ReadOnlySpan{byte}, bool, out TSelf)" />
static bool IBinaryInteger<nuint>.TryReadLittleEndian(ReadOnlySpan<byte> source, bool isUnsigned, out nuint value)
{
nuint result = default;
if (source.Length != 0)
{
if (!isUnsigned && sbyte.IsNegative((sbyte)source[^1]))
{
// When we are signed and the sign bit is set, we are negative and therefore
// definitely out of range
value = result;
return false;
}
if ((source.Length > sizeof(nuint_t)) && (source[sizeof(nuint_t)..].ContainsAnyExcept((byte)0x00)))
{
// When we have any non-zero leading data, we are a large positive and therefore
// definitely out of range
value = result;
return false;
}
ref byte sourceRef = ref MemoryMarshal.GetReference(source);
if (source.Length >= sizeof(nuint_t))
{
// We have at least 4/8 bytes, so just read the ones we need directly
result = Unsafe.ReadUnaligned<nuint>(ref sourceRef);
if (!BitConverter.IsLittleEndian)
{
result = BinaryPrimitives.ReverseEndianness(result);
}
}
else
{
// We have between 1 and 3/7 bytes, so construct the relevant value directly
// since the data is in Little Endian format, we can just read the bytes and
// shift left by 8-bits for each subsequent part, then reverse endianness to
// ensure the order is correct. This is more efficient than iterating in reverse
// due to current JIT limitations
for (int i = 0; i < source.Length; i++)
{
nuint part = Unsafe.Add(ref sourceRef, i);
part <<= (i * 8);
result |= part;
}
}
}
value = result;
return true;
}
/// <inheritdoc cref="IBinaryInteger{TSelf}.GetShortestBitLength()" />
int IBinaryInteger<nuint>.GetShortestBitLength() => (sizeof(nuint_t) * 8) - BitOperations.LeadingZeroCount(_value);
/// <inheritdoc cref="IBinaryInteger{TSelf}.GetByteCount()" />
int IBinaryInteger<nuint>.GetByteCount() => sizeof(nuint_t);
/// <inheritdoc cref="IBinaryInteger{TSelf}.TryWriteBigEndian(Span{byte}, out int)" />
bool IBinaryInteger<nuint>.TryWriteBigEndian(Span<byte> destination, out int bytesWritten)
{
if (BinaryPrimitives.TryWriteUIntPtrBigEndian(destination, _value))
{
bytesWritten = sizeof(nuint_t);
return true;
}
bytesWritten = 0;
return false;
}
/// <inheritdoc cref="IBinaryInteger{TSelf}.TryWriteLittleEndian(Span{byte}, out int)" />
bool IBinaryInteger<nuint>.TryWriteLittleEndian(Span<byte> destination, out int bytesWritten)
{
if (BinaryPrimitives.TryWriteUIntPtrLittleEndian(destination, _value))
{
bytesWritten = sizeof(nuint_t);
return true;
}
bytesWritten = 0;
return false;
}
//
// IBinaryNumber
//
/// <inheritdoc cref="IBinaryNumber{TSelf}.AllBitsSet" />
static nuint IBinaryNumber<nuint>.AllBitsSet
{
#if TARGET_64BIT
[NonVersionable]
get => unchecked((nuint)0xFFFF_FFFF_FFFF_FFFF);
#else
[NonVersionable]
get => (nuint)0xFFFF_FFFF;
#endif
}
/// <inheritdoc cref="IBinaryNumber{TSelf}.IsPow2(TSelf)" />
public static bool IsPow2(nuint value) => BitOperations.IsPow2(value);
/// <inheritdoc cref="IBinaryNumber{TSelf}.Log2(TSelf)" />
[Intrinsic]
public static nuint Log2(nuint value) => (nuint)BitOperations.Log2(value);
//
// IBitwiseOperators
//
/// <inheritdoc cref="IBitwiseOperators{TSelf, TOther, TResult}.op_BitwiseAnd(TSelf, TOther)" />
static nuint IBitwiseOperators<nuint, nuint, nuint>.operator &(nuint left, nuint right) => left & right;
/// <inheritdoc cref="IBitwiseOperators{TSelf, TOther, TResult}.op_BitwiseOr(TSelf, TOther)" />
static nuint IBitwiseOperators<nuint, nuint, nuint>.operator |(nuint left, nuint right) => left | right;
/// <inheritdoc cref="IBitwiseOperators{TSelf, TOther, TResult}.op_ExclusiveOr(TSelf, TOther)" />
static nuint IBitwiseOperators<nuint, nuint, nuint>.operator ^(nuint left, nuint right) => left ^ right;
/// <inheritdoc cref="IBitwiseOperators{TSelf, TOther, TResult}.op_OnesComplement(TSelf)" />
static nuint IBitwiseOperators<nuint, nuint, nuint>.operator ~(nuint value) => ~value;
//
// IComparisonOperators
//
/// <inheritdoc cref="IComparisonOperators{TSelf, TOther, TResult}.op_LessThan(TSelf, TOther)" />
static bool IComparisonOperators<nuint, nuint, bool>.operator <(nuint left, nuint right) => left < right;
/// <inheritdoc cref="IComparisonOperators{TSelf, TOther, TResult}.op_LessThanOrEqual(TSelf, TOther)" />
static bool IComparisonOperators<nuint, nuint, bool>.operator <=(nuint left, nuint right) => left <= right;
/// <inheritdoc cref="IComparisonOperators{TSelf, TOther, TResult}.op_GreaterThan(TSelf, TOther)" />
static bool IComparisonOperators<nuint, nuint, bool>.operator >(nuint left, nuint right) => left > right;
/// <inheritdoc cref="IComparisonOperators{TSelf, TOther, TResult}.op_GreaterThanOrEqual(TSelf, TOther)" />
static bool IComparisonOperators<nuint, nuint, bool>.operator >=(nuint left, nuint right) => left >= right;
//
// IDecrementOperators
//
/// <inheritdoc cref="IDecrementOperators{TSelf}.op_Decrement(TSelf)" />
static nuint IDecrementOperators<nuint>.operator --(nuint value) => --value;
/// <inheritdoc cref="IDecrementOperators{TSelf}.op_Decrement(TSelf)" />
static nuint IDecrementOperators<nuint>.operator checked --(nuint value) => checked(--value);
//
// IDivisionOperators
//
/// <inheritdoc cref="IDivisionOperators{TSelf, TOther, TResult}.op_Division(TSelf, TOther)" />
static nuint IDivisionOperators<nuint, nuint, nuint>.operator /(nuint left, nuint right) => left / right;
//
// IIncrementOperators
//
/// <inheritdoc cref="IIncrementOperators{TSelf}.op_Increment(TSelf)" />
static nuint IIncrementOperators<nuint>.operator ++(nuint value) => ++value;
/// <inheritdoc cref="IIncrementOperators{TSelf}.op_CheckedIncrement(TSelf)" />
static nuint IIncrementOperators<nuint>.operator checked ++(nuint value) => checked(++value);
//
// IMinMaxValue
//
/// <inheritdoc cref="IMinMaxValue{TSelf}.MinValue" />
static nuint IMinMaxValue<nuint>.MinValue => MinValue;
/// <inheritdoc cref="IMinMaxValue{TSelf}.MaxValue" />
static nuint IMinMaxValue<nuint>.MaxValue => MaxValue;
//
// IModulusOperators
//
/// <inheritdoc cref="IModulusOperators{TSelf, TOther, TResult}.op_Modulus(TSelf, TOther)" />
static nuint IModulusOperators<nuint, nuint, nuint>.operator %(nuint left, nuint right) => left % right;
//
// IMultiplicativeIdentity
//
/// <inheritdoc cref="IMultiplicativeIdentity{TSelf, TResult}.MultiplicativeIdentity" />
static nuint IMultiplicativeIdentity<nuint, nuint>.MultiplicativeIdentity => 1;
//
// IMultiplyOperators
//
/// <inheritdoc cref="IMultiplyOperators{TSelf, TOther, TResult}.op_Multiply(TSelf, TOther)" />
static nuint IMultiplyOperators<nuint, nuint, nuint>.operator *(nuint left, nuint right) => left * right;
/// <inheritdoc cref="IMultiplyOperators{TSelf, TOther, TResult}.op_CheckedMultiply(TSelf, TOther)" />
static nuint IMultiplyOperators<nuint, nuint, nuint>.operator checked *(nuint left, nuint right) => checked(left * right);
//
// INumber
//
/// <inheritdoc cref="INumber{TSelf}.Clamp(TSelf, TSelf, TSelf)" />
public static nuint Clamp(nuint value, nuint min, nuint max) => Math.Clamp(value, min, max);
/// <inheritdoc cref="INumber{TSelf}.CopySign(TSelf, TSelf)" />
static nuint INumber<nuint>.CopySign(nuint value, nuint sign) => value;
/// <inheritdoc cref="INumber{TSelf}.Max(TSelf, TSelf)" />
public static nuint Max(nuint x, nuint y) => Math.Max(x, y);
/// <inheritdoc cref="INumber{TSelf}.MaxNumber(TSelf, TSelf)" />
static nuint INumber<nuint>.MaxNumber(nuint x, nuint y) => Max(x, y);
/// <inheritdoc cref="INumber{TSelf}.Min(TSelf, TSelf)" />
public static nuint Min(nuint x, nuint y) => Math.Min(x, y);
/// <inheritdoc cref="INumber{TSelf}.MinNumber(TSelf, TSelf)" />
static nuint INumber<nuint>.MinNumber(nuint x, nuint y) => Min(x, y);
/// <inheritdoc cref="INumber{TSelf}.Sign(TSelf)" />
public static int Sign(nuint value) => (value == 0) ? 0 : 1;
//
// INumberBase
//
/// <inheritdoc cref="INumberBase{TSelf}.One" />
static nuint INumberBase<nuint>.One => 1;
/// <inheritdoc cref="INumberBase{TSelf}.Radix" />
static int INumberBase<nuint>.Radix => 2;
/// <inheritdoc cref="INumberBase{TSelf}.Zero" />
static nuint INumberBase<nuint>.Zero => 0;
/// <inheritdoc cref="INumberBase{TSelf}.Abs(TSelf)" />
static nuint INumberBase<nuint>.Abs(nuint value) => value;
/// <inheritdoc cref="INumberBase{TSelf}.CreateChecked{TOther}(TOther)" />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static nuint CreateChecked<TOther>(TOther value)
where TOther : INumberBase<TOther>
{
nuint result;
if (typeof(TOther) == typeof(nuint))
{
result = (nuint)(object)value;
}
else if (!TryConvertFromChecked(value, out result) && !TOther.TryConvertToChecked(value, out result))
{
ThrowHelper.ThrowNotSupportedException();
}
return result;
}
/// <inheritdoc cref="INumberBase{TSelf}.CreateSaturating{TOther}(TOther)" />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static nuint CreateSaturating<TOther>(TOther value)
where TOther : INumberBase<TOther>
{
nuint result;
if (typeof(TOther) == typeof(nuint))
{
result = (nuint)(object)value;
}
else if (!TryConvertFromSaturating(value, out result) && !TOther.TryConvertToSaturating(value, out result))
{
ThrowHelper.ThrowNotSupportedException();
}
return result;
}
/// <inheritdoc cref="INumberBase{TSelf}.CreateTruncating{TOther}(TOther)" />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static nuint CreateTruncating<TOther>(TOther value)
where TOther : INumberBase<TOther>
{
nuint result;
if (typeof(TOther) == typeof(nuint))
{
result = (nuint)(object)value;
}
else if (!TryConvertFromTruncating(value, out result) && !TOther.TryConvertToTruncating(value, out result))
{
ThrowHelper.ThrowNotSupportedException();
}
return result;
}
/// <inheritdoc cref="INumberBase{TSelf}.IsCanonical(TSelf)" />
static bool INumberBase<nuint>.IsCanonical(nuint value) => true;
/// <inheritdoc cref="INumberBase{TSelf}.IsComplexNumber(TSelf)" />
static bool INumberBase<nuint>.IsComplexNumber(nuint value) => false;
/// <inheritdoc cref="INumberBase{TSelf}.IsEvenInteger(TSelf)" />
public static bool IsEvenInteger(nuint value) => (value & 1) == 0;
/// <inheritdoc cref="INumberBase{TSelf}.IsFinite(TSelf)" />
static bool INumberBase<nuint>.IsFinite(nuint value) => true;
/// <inheritdoc cref="INumberBase{TSelf}.IsImaginaryNumber(TSelf)" />
static bool INumberBase<nuint>.IsImaginaryNumber(nuint value) => false;
/// <inheritdoc cref="INumberBase{TSelf}.IsInfinity(TSelf)" />
static bool INumberBase<nuint>.IsInfinity(nuint value) => false;
/// <inheritdoc cref="INumberBase{TSelf}.IsInteger(TSelf)" />
static bool INumberBase<nuint>.IsInteger(nuint value) => true;
/// <inheritdoc cref="INumberBase{TSelf}.IsNaN(TSelf)" />
static bool INumberBase<nuint>.IsNaN(nuint value) => false;
/// <inheritdoc cref="INumberBase{TSelf}.IsNegative(TSelf)" />
static bool INumberBase<nuint>.IsNegative(nuint value) => false;
/// <inheritdoc cref="INumberBase{TSelf}.IsNegativeInfinity(TSelf)" />
static bool INumberBase<nuint>.IsNegativeInfinity(nuint value) => false;
/// <inheritdoc cref="INumberBase{TSelf}.IsNormal(TSelf)" />
static bool INumberBase<nuint>.IsNormal(nuint value) => value != 0;
/// <inheritdoc cref="INumberBase{TSelf}.IsOddInteger(TSelf)" />
public static bool IsOddInteger(nuint value) => (value & 1) != 0;
/// <inheritdoc cref="INumberBase{TSelf}.IsPositive(TSelf)" />
static bool INumberBase<nuint>.IsPositive(nuint value) => true;
/// <inheritdoc cref="INumberBase{TSelf}.IsPositiveInfinity(TSelf)" />
static bool INumberBase<nuint>.IsPositiveInfinity(nuint value) => false;
/// <inheritdoc cref="INumberBase{TSelf}.IsRealNumber(TSelf)" />
static bool INumberBase<nuint>.IsRealNumber(nuint value) => true;
/// <inheritdoc cref="INumberBase{TSelf}.IsSubnormal(TSelf)" />
static bool INumberBase<nuint>.IsSubnormal(nuint value) => false;
/// <inheritdoc cref="INumberBase{TSelf}.IsZero(TSelf)" />
static bool INumberBase<nuint>.IsZero(nuint value) => (value == 0);
/// <inheritdoc cref="INumberBase{TSelf}.MaxMagnitude(TSelf, TSelf)" />
static nuint INumberBase<nuint>.MaxMagnitude(nuint x, nuint y) => Max(x, y);
/// <inheritdoc cref="INumberBase{TSelf}.MaxMagnitudeNumber(TSelf, TSelf)" />
static nuint INumberBase<nuint>.MaxMagnitudeNumber(nuint x, nuint y) => Max(x, y);
/// <inheritdoc cref="INumberBase{TSelf}.MinMagnitude(TSelf, TSelf)" />
static nuint INumberBase<nuint>.MinMagnitude(nuint x, nuint y) => Min(x, y);
/// <inheritdoc cref="INumberBase{TSelf}.MinMagnitudeNumber(TSelf, TSelf)" />
static nuint INumberBase<nuint>.MinMagnitudeNumber(nuint x, nuint y) => Min(x, y);
/// <inheritdoc cref="INumberBase{TSelf}.MultiplyAddEstimate(TSelf, TSelf, TSelf)" />
static nuint INumberBase<nuint>.MultiplyAddEstimate(nuint left, nuint right, nuint addend) => (nuint)((left * right) + addend);
/// <inheritdoc cref="INumberBase{TSelf}.TryConvertFromChecked{TOther}(TOther, out TSelf)" />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool INumberBase<nuint>.TryConvertFromChecked<TOther>(TOther value, out nuint result) => TryConvertFromChecked(value, out result);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool TryConvertFromChecked<TOther>(TOther value, out nuint result)
where TOther : INumberBase<TOther>
{
// 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 `nuint` 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(decimal))
{
decimal actualValue = (decimal)(object)value;
result = checked((nuint)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 = checked((nuint)actualValue);
return true;
}
else if (typeof(TOther) == typeof(UInt128))
{
UInt128 actualValue = (UInt128)(object)value;
result = checked((nuint)actualValue);
return true;
}
else
{
result = default;
return false;
}
}
/// <inheritdoc cref="INumberBase{TSelf}.TryConvertFromSaturating{TOther}(TOther, out TSelf)" />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool INumberBase<nuint>.TryConvertFromSaturating<TOther>(TOther value, out nuint result) => TryConvertFromSaturating(value, out result);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool TryConvertFromSaturating<TOther>(TOther value, out nuint result)
where TOther : INumberBase<TOther>
{
// 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 `nuint` 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(decimal))
{
decimal actualValue = (decimal)(object)value;
result = (actualValue >= nuint_t.MaxValue) ? unchecked((nuint)nuint_t.MaxValue) :
(actualValue <= nuint_t.MinValue) ? unchecked((nuint)nuint_t.MinValue) : (nuint)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 >= nuint_t.MaxValue) ? unchecked((nuint)nuint_t.MaxValue) : (nuint)actualValue;
return true;
}
else if (typeof(TOther) == typeof(UInt128))
{
UInt128 actualValue = (UInt128)(object)value;
result = (actualValue >= nuint_t.MaxValue) ? unchecked((nuint)nuint_t.MaxValue) : (nuint)actualValue;
return true;
}
else
{
result = default;
return false;
}
}
/// <inheritdoc cref="INumberBase{TSelf}.TryConvertFromTruncating{TOther}(TOther, out TSelf)" />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool INumberBase<nuint>.TryConvertFromTruncating<TOther>(TOther value, out nuint result) => TryConvertFromTruncating(value, out result);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool TryConvertFromTruncating<TOther>(TOther value, out nuint result)
where TOther : INumberBase<TOther>
{
// 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 `nuint` 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(decimal))
{
decimal actualValue = (decimal)(object)value;
result = (actualValue >= nuint_t.MaxValue) ? unchecked((nuint)nuint_t.MaxValue) :
(actualValue <= nuint_t.MinValue) ? unchecked((nuint)nuint_t.MinValue) : (nuint)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 = (nuint)actualValue;
return true;
}
else if (typeof(TOther) == typeof(UInt128))
{
UInt128 actualValue = (UInt128)(object)value;
result = (nuint)actualValue;
return true;
}
else
{
result = default;
return false;
}
}
/// <inheritdoc cref="INumberBase{TSelf}.TryConvertToChecked{TOther}(TSelf, out TOther)" />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool INumberBase<nuint>.TryConvertToChecked<TOther>(nuint value, [MaybeNullWhen(false)] 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 `nuint` will handle the other unsigned types and
// `ConvertTo` will handle the signed types
if (typeof(TOther) == typeof(double))
{
double actualResult = value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(Half))
{
Half actualResult = (Half)value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(short))
{
short actualResult = checked((short)value);
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(int))
{
int actualResult = checked((int)value);
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(long))
{
long actualResult = checked((long)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))
{
nint actualResult = checked((nint)value);
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(sbyte))
{
sbyte actualResult = checked((sbyte)value);
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(float))
{
float actualResult = value;
result = (TOther)(object)actualResult;
return true;
}
else
{
result = default;
return false;
}
}
/// <inheritdoc cref="INumberBase{TSelf}.TryConvertToSaturating{TOther}(TSelf, out TOther)" />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool INumberBase<nuint>.TryConvertToSaturating<TOther>(nuint value, [MaybeNullWhen(false)] 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 `nuint` will handle the other unsigned types and
// `ConvertTo` will handle the signed types
if (typeof(TOther) == typeof(double))
{
double actualResult = value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(Half))
{
Half actualResult = (Half)value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(short))
{
short actualResult = (value >= (nuint)short.MaxValue) ? short.MaxValue : (short)value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(int))
{
int actualResult = (value >= int.MaxValue) ? int.MaxValue : (int)value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(long))
{
long actualResult = (value >= long.MaxValue) ? long.MaxValue : (long)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))
{
nint actualResult = (value >= (nuint)nint.MaxValue) ? nint.MaxValue : (nint)value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(sbyte))
{
sbyte actualResult = (value >= (nuint)sbyte.MaxValue) ? sbyte.MaxValue : (sbyte)value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(float))
{
float actualResult = value;
result = (TOther)(object)actualResult;
return true;
}
else
{
result = default;
return false;
}
}
/// <inheritdoc cref="INumberBase{TSelf}.TryConvertToTruncating{TOther}(TSelf, out TOther)" />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool INumberBase<nuint>.TryConvertToTruncating<TOther>(nuint value, [MaybeNullWhen(false)] 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 `nuint` will handle the other unsigned types and
// `ConvertTo` will handle the signed types
if (typeof(TOther) == typeof(double))
{
double actualResult = value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(Half))
{
Half actualResult = (Half)value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(short))
{
short actualResult = (short)value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(int))
{
int actualResult = (int)value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(long))
{
long actualResult = (long)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))
{
nint actualResult = (nint)value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(sbyte))
{
sbyte actualResult = (sbyte)value;
result = (TOther)(object)actualResult;
return true;
}
else if (typeof(TOther) == typeof(float))
{
float actualResult = value;
result = (TOther)(object)actualResult;
return true;
}
else
{
result = default;
return false;
}
}
//
// IShiftOperators
//
/// <inheritdoc cref="IShiftOperators{TSelf, TOther, TResult}.op_LeftShift(TSelf, TOther)" />
static nuint IShiftOperators<nuint, int, nuint>.operator <<(nuint value, int shiftAmount) => value << shiftAmount;
/// <inheritdoc cref="IShiftOperators{TSelf, TOther, TResult}.op_RightShift(TSelf, TOther)" />
static nuint IShiftOperators<nuint, int, nuint>.operator >>(nuint value, int shiftAmount) => value >> shiftAmount;
/// <inheritdoc cref="IShiftOperators{TSelf, TOther, TResult}.op_UnsignedRightShift(TSelf, TOther)" />
static nuint IShiftOperators<nuint, int, nuint>.operator >>>(nuint value, int shiftAmount) => value >>> shiftAmount;
//
// ISubtractionOperators
//
/// <inheritdoc cref="ISubtractionOperators{TSelf, TOther, TResult}.op_Subtraction(TSelf, TOther)" />
static nuint ISubtractionOperators<nuint, nuint, nuint>.operator -(nuint left, nuint right) => left - right;
/// <inheritdoc cref="ISubtractionOperators{TSelf, TOther, TResult}.op_CheckedSubtraction(TSelf, TOther)" />
static nuint ISubtractionOperators<nuint, nuint, nuint>.operator checked -(nuint left, nuint right) => checked(left - right);
//
// IUnaryNegationOperators
//
/// <inheritdoc cref="IUnaryNegationOperators{TSelf, TResult}.op_UnaryNegation(TSelf)" />
static nuint IUnaryNegationOperators<nuint, nuint>.operator -(nuint value) => (nuint)0 - value;
/// <inheritdoc cref="IUnaryNegationOperators{TSelf, TResult}.op_CheckedUnaryNegation(TSelf)" />
static nuint IUnaryNegationOperators<nuint, nuint>.operator checked -(nuint value) => checked((nuint)0 - value);
//
// IUnaryPlusOperators
//
/// <inheritdoc cref="IUnaryPlusOperators{TSelf, TResult}.op_UnaryPlus(TSelf)" />
static nuint IUnaryPlusOperators<nuint, nuint>.operator +(nuint value) => +value;
//
// IUtf8SpanParsable
//
/// <inheritdoc cref="INumberBase{TSelf}.Parse(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?)" />
public static nuint Parse(ReadOnlySpan<byte> utf8Text, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) => (nuint)nuint_t.Parse(utf8Text, style, provider);
/// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?, out TSelf)" />
public static bool TryParse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out nuint result)
{
Unsafe.SkipInit(out result);
return nuint_t.TryParse(utf8Text, style, provider, out Unsafe.As<nuint, nuint_t>(ref result));
}
/// <inheritdoc cref="IUtf8SpanParsable{TSelf}.Parse(ReadOnlySpan{byte}, IFormatProvider?)" />
public static nuint Parse(ReadOnlySpan<byte> utf8Text, IFormatProvider? provider) => (nuint)nuint_t.Parse(utf8Text, provider);
/// <inheritdoc cref="IUtf8SpanParsable{TSelf}.TryParse(ReadOnlySpan{byte}, IFormatProvider?, out TSelf)" />
public static bool TryParse(ReadOnlySpan<byte> utf8Text, IFormatProvider? provider, out nuint result)
{
Unsafe.SkipInit(out result);
return nuint_t.TryParse(utf8Text, provider, out Unsafe.As<nuint, nuint_t>(ref result));
}
}
}
|