// 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.Versioning; namespace System { [Serializable] [CLSCompliant(false)] [StructLayout(LayoutKind.Sequential)] [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public readonly struct UInt64 : IComparable, IConvertible, ISpanFormattable, IComparable<ulong>, IEquatable<ulong>, IBinaryInteger<ulong>, IMinMaxValue<ulong>, IUnsignedNumber<ulong>, IUtf8SpanFormattable, IBinaryIntegerParseAndFormatInfo<ulong> { private readonly ulong m_value; // Do not rename (binary serialization) public const ulong MaxValue = (ulong)0xffffffffffffffffL; public const ulong MinValue = 0x0; /// <summary>Represents the additive identity (0).</summary> private const ulong AdditiveIdentity = 0; /// <summary>Represents the multiplicative identity (1).</summary> private const ulong MultiplicativeIdentity = 1; /// <summary>Represents the number one (1).</summary> private const ulong One = 1; /// <summary>Represents the number zero (0).</summary> private const ulong Zero = 0; /// <summary>Produces the full product of two unsigned 64-bit numbers.</summary> /// <param name="left">The first number to multiply.</param> /// <param name="right">The second number to multiply.</param> /// <returns>The number containing the product of the specified numbers.</returns> public static UInt128 BigMul(ulong left, ulong right) => Math.BigMul(left, right); // Compares this object to another object, returning an integer that // indicates the relationship. // Returns a value less than zero if this object // null is considered to be less than any instance. // If object is not of type UInt64, this method throws an ArgumentException. // public int CompareTo(object? value) { if (value == null) { return 1; } // Need to use compare because subtraction will wrap // to positive for very large neg numbers, etc. if (value is ulong i) { if (m_value < i) return -1; if (m_value > i) return 1; return 0; } throw new ArgumentException(SR.Arg_MustBeUInt64); } public int CompareTo(ulong value) { // Need to use compare because subtraction will wrap // to positive for very large neg numbers, etc. if (m_value < value) return -1; if (m_value > value) return 1; return 0; } public override bool Equals([NotNullWhen(true)] object? obj) { if (!(obj is ulong)) { return false; } return m_value == ((ulong)obj).m_value; } [NonVersionable] public bool Equals(ulong obj) { return m_value == obj; } // The value of the lower 32 bits XORed with the uppper 32 bits. public override int GetHashCode() { return ((int)m_value) ^ (int)(m_value >> 32); } public override string ToString() { return Number.UInt64ToDecStr(m_value); } public string ToString(IFormatProvider? provider) { return Number.UInt64ToDecStr(m_value); } public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format) { return Number.FormatUInt64(m_value, format, null); } public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format, IFormatProvider? provider) { return Number.FormatUInt64(m_value, format, provider); } public bool TryFormat(Span<char> destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null) { return Number.TryFormatUInt64(m_value, format, provider, destination, out charsWritten); } /// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" /> public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null) { return Number.TryFormatUInt64(m_value, format, provider, utf8Destination, out bytesWritten); } public static ulong Parse(string s) => Parse(s, NumberStyles.Integer, provider: null); public static ulong Parse(string s, NumberStyles style) => Parse(s, style, provider: null); public static ulong Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); public static ulong Parse(string s, NumberStyles style, IFormatProvider? provider) { if (s is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); } return Parse(s.AsSpan(), style, provider); } public static ulong Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); return Number.ParseBinaryInteger<char, ulong>(s, style, NumberFormatInfo.GetInstance(provider)); } public static bool TryParse([NotNullWhen(true)] string? s, out ulong result) => TryParse(s, NumberStyles.Integer, provider: null, out result); public static bool TryParse(ReadOnlySpan<char> s, out ulong result) => TryParse(s, NumberStyles.Integer, provider: null, out result); /// <summary>Tries to convert a UTF-8 character span containing the string representation of a number to its 64-bit unsigned integer equivalent.</summary> /// <param name="utf8Text">A span containing the UTF-8 characters representing the number to convert.</param> /// <param name="result">When this method returns, contains the 64-bit unsigned integer value equivalent to the number contained in <paramref name="utf8Text" /> if the conversion succeeded, or zero if the conversion failed. This parameter is passed uninitialized; any value originally supplied in result will be overwritten.</param> /// <returns><c>true</c> if <paramref name="utf8Text" /> was converted successfully; otherwise, false.</returns> public static bool TryParse(ReadOnlySpan<byte> utf8Text, out ulong result) => TryParse(utf8Text, NumberStyles.Integer, provider: null, out result); public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out ulong result) { NumberFormatInfo.ValidateParseStyleInteger(style); return Number.TryParseBinaryInteger(s.AsSpan(), style, NumberFormatInfo.GetInstance(provider), out result, out _) == Number.ParsingStatus.OK; } public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out ulong result) { NumberFormatInfo.ValidateParseStyleInteger(style); return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result, out _) == Number.ParsingStatus.OK; } // // IConvertible implementation // public TypeCode GetTypeCode() { return TypeCode.UInt64; } bool IConvertible.ToBoolean(IFormatProvider? provider) { return Convert.ToBoolean(m_value); } char IConvertible.ToChar(IFormatProvider? provider) { return Convert.ToChar(m_value); } sbyte IConvertible.ToSByte(IFormatProvider? provider) { return Convert.ToSByte(m_value); } byte IConvertible.ToByte(IFormatProvider? provider) { return Convert.ToByte(m_value); } short IConvertible.ToInt16(IFormatProvider? provider) { return Convert.ToInt16(m_value); } ushort IConvertible.ToUInt16(IFormatProvider? provider) { return Convert.ToUInt16(m_value); } int IConvertible.ToInt32(IFormatProvider? provider) { return Convert.ToInt32(m_value); } uint IConvertible.ToUInt32(IFormatProvider? provider) { return Convert.ToUInt32(m_value); } long IConvertible.ToInt64(IFormatProvider? provider) { return Convert.ToInt64(m_value); } ulong IConvertible.ToUInt64(IFormatProvider? provider) { return m_value; } float IConvertible.ToSingle(IFormatProvider? provider) { return Convert.ToSingle(m_value); } double IConvertible.ToDouble(IFormatProvider? provider) { return Convert.ToDouble(m_value); } decimal IConvertible.ToDecimal(IFormatProvider? provider) { return Convert.ToDecimal(m_value); } DateTime IConvertible.ToDateTime(IFormatProvider? provider) { throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "UInt64", "DateTime")); } object IConvertible.ToType(Type type, IFormatProvider? provider) { return Convert.DefaultToType((IConvertible)this, type, provider); } // // IAdditionOperators // /// <inheritdoc cref="IAdditionOperators{TSelf, TOther, TResult}.op_Addition(TSelf, TOther)" /> static ulong IAdditionOperators<ulong, ulong, ulong>.operator +(ulong left, ulong right) => left + right; /// <inheritdoc cref="IAdditionOperators{TSelf, TOther, TResult}.op_Addition(TSelf, TOther)" /> static ulong IAdditionOperators<ulong, ulong, ulong>.operator checked +(ulong left, ulong right) => checked(left + right); // // IAdditiveIdentity // /// <inheritdoc cref="IAdditiveIdentity{TSelf, TResult}.AdditiveIdentity" /> static ulong IAdditiveIdentity<ulong, ulong>.AdditiveIdentity => AdditiveIdentity; // // IBinaryInteger // /// <inheritdoc cref="IBinaryInteger{TSelf}.DivRem(TSelf, TSelf)" /> public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right) => Math.DivRem(left, right); /// <inheritdoc cref="IBinaryInteger{TSelf}.LeadingZeroCount(TSelf)" /> [Intrinsic] public static ulong LeadingZeroCount(ulong value) => (ulong)BitOperations.LeadingZeroCount(value); /// <inheritdoc cref="IBinaryInteger{TSelf}.Log10(TSelf)" /> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Log10(ulong value) { // Approximate log10 via log2, then correct with a powers of 10 lookup table. // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 value |= 1; uint log2 = (uint)BitOperations.Log2(value) + 1; uint approx = (log2 * 1233) >> 12; return value < PowersOf10[(int)approx] ? approx - 1 : approx; } // Lookup table for the powers of ten representable in a UInt64 (10^0 through 10^19). internal static ReadOnlySpan<ulong> PowersOf10 => [ 1, 10, 100, 1_000, 10_000, 100_000, 1_000_000, 10_000_000, 100_000_000, 1_000_000_000, 10_000_000_000, 100_000_000_000, 1_000_000_000_000, 10_000_000_000_000, 100_000_000_000_000, 1_000_000_000_000_000, 10_000_000_000_000_000, 100_000_000_000_000_000, 1_000_000_000_000_000_000, 10_000_000_000_000_000_000, ]; /// <inheritdoc cref="IBinaryInteger{TSelf}.PopCount(TSelf)" /> [Intrinsic] public static ulong PopCount(ulong value) => (ulong)BitOperations.PopCount(value); /// <inheritdoc cref="IBinaryInteger{TSelf}.RotateLeft(TSelf, int)" /> [Intrinsic] public static ulong RotateLeft(ulong value, int rotateAmount) => BitOperations.RotateLeft(value, rotateAmount); /// <inheritdoc cref="IBinaryInteger{TSelf}.RotateRight(TSelf, int)" /> [Intrinsic] public static ulong RotateRight(ulong value, int rotateAmount) => BitOperations.RotateRight(value, rotateAmount); /// <inheritdoc cref="IBinaryInteger{TSelf}.TrailingZeroCount(TSelf)" /> [Intrinsic] public static ulong TrailingZeroCount(ulong value) => (ulong)BitOperations.TrailingZeroCount(value); /// <inheritdoc cref="IBinaryInteger{TSelf}.TryReadBigEndian(ReadOnlySpan{byte}, bool, out TSelf)" /> static bool IBinaryInteger<ulong>.TryReadBigEndian(ReadOnlySpan<byte> source, bool isUnsigned, out ulong value) { ulong 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(ulong)) && (source[..^sizeof(ulong)].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; } if (source.Length >= sizeof(ulong)) { // We have at least 8 bytes, so just read the ones we need directly result = BinaryPrimitives.ReadUInt64BigEndian(source.Slice(source.Length - sizeof(ulong))); } else { // We have between 1 and 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 |= source[i]; } } } value = result; return true; } /// <inheritdoc cref="IBinaryInteger{TSelf}.TryReadLittleEndian(ReadOnlySpan{byte}, bool, out TSelf)" /> static bool IBinaryInteger<ulong>.TryReadLittleEndian(ReadOnlySpan<byte> source, bool isUnsigned, out ulong value) { ulong 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(ulong)) && (source[sizeof(ulong)..].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; } if (source.Length >= sizeof(ulong)) { // We have at least 8 bytes, so just read the ones we need directly result = BinaryPrimitives.ReadUInt64LittleEndian(source); } else { // We have between 1 and 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++) { ulong part = source[i]; part <<= (i * 8); result |= part; } } } value = result; return true; } /// <inheritdoc cref="IBinaryInteger{TSelf}.GetShortestBitLength()" /> int IBinaryInteger<ulong>.GetShortestBitLength() => (sizeof(ulong) * 8) - BitOperations.LeadingZeroCount(m_value); /// <inheritdoc cref="IBinaryInteger{TSelf}.GetByteCount()" /> int IBinaryInteger<ulong>.GetByteCount() => sizeof(ulong); /// <inheritdoc cref="IBinaryInteger{TSelf}.TryWriteBigEndian(Span{byte}, out int)" /> bool IBinaryInteger<ulong>.TryWriteBigEndian(Span<byte> destination, out int bytesWritten) { if (BinaryPrimitives.TryWriteUInt64BigEndian(destination, m_value)) { bytesWritten = sizeof(ulong); return true; } bytesWritten = 0; return false; } /// <inheritdoc cref="IBinaryInteger{TSelf}.TryWriteLittleEndian(Span{byte}, out int)" /> bool IBinaryInteger<ulong>.TryWriteLittleEndian(Span<byte> destination, out int bytesWritten) { if (BinaryPrimitives.TryWriteUInt64LittleEndian(destination, m_value)) { bytesWritten = sizeof(ulong); return true; } bytesWritten = 0; return false; } // // IBinaryNumber // /// <inheritdoc cref="IBinaryNumber{TSelf}.AllBitsSet" /> static ulong IBinaryNumber<ulong>.AllBitsSet => MaxValue; /// <inheritdoc cref="IBinaryNumber{TSelf}.IsPow2(TSelf)" /> public static bool IsPow2(ulong value) => BitOperations.IsPow2(value); /// <inheritdoc cref="IBinaryNumber{TSelf}.Log2(TSelf)" /> [Intrinsic] public static ulong Log2(ulong value) => (ulong)BitOperations.Log2(value); // // IBitwiseOperators // /// <inheritdoc cref="IBitwiseOperators{TSelf, TOther, TResult}.op_BitwiseAnd(TSelf, TOther)" /> static ulong IBitwiseOperators<ulong, ulong, ulong>.operator &(ulong left, ulong right) => left & right; /// <inheritdoc cref="IBitwiseOperators{TSelf, TOther, TResult}.op_BitwiseOr(TSelf, TOther)" /> static ulong IBitwiseOperators<ulong, ulong, ulong>.operator |(ulong left, ulong right) => left | right; /// <inheritdoc cref="IBitwiseOperators{TSelf, TOther, TResult}.op_ExclusiveOr(TSelf, TOther)" /> static ulong IBitwiseOperators<ulong, ulong, ulong>.operator ^(ulong left, ulong right) => left ^ right; /// <inheritdoc cref="IBitwiseOperators{TSelf, TOther, TResult}.op_OnesComplement(TSelf)" /> static ulong IBitwiseOperators<ulong, ulong, ulong>.operator ~(ulong value) => ~value; // // IComparisonOperators // /// <inheritdoc cref="IComparisonOperators{TSelf, TOther, TResult}.op_LessThan(TSelf, TOther)" /> static bool IComparisonOperators<ulong, ulong, bool>.operator <(ulong left, ulong right) => left < right; /// <inheritdoc cref="IComparisonOperators{TSelf, TOther, TResult}.op_LessThanOrEqual(TSelf, TOther)" /> static bool IComparisonOperators<ulong, ulong, bool>.operator <=(ulong left, ulong right) => left <= right; /// <inheritdoc cref="IComparisonOperators{TSelf, TOther, TResult}.op_GreaterThan(TSelf, TOther)" /> static bool IComparisonOperators<ulong, ulong, bool>.operator >(ulong left, ulong right) => left > right; /// <inheritdoc cref="IComparisonOperators{TSelf, TOther, TResult}.op_GreaterThanOrEqual(TSelf, TOther)" /> static bool IComparisonOperators<ulong, ulong, bool>.operator >=(ulong left, ulong right) => left >= right; // // IDecrementOperators // /// <inheritdoc cref="IDecrementOperators{TSelf}.op_Decrement(TSelf)" /> static ulong IDecrementOperators<ulong>.operator --(ulong value) => --value; /// <inheritdoc cref="IDecrementOperators{TSelf}.op_Decrement(TSelf)" /> static ulong IDecrementOperators<ulong>.operator checked --(ulong value) => checked(--value); // // IDivisionOperators // /// <inheritdoc cref="IDivisionOperators{TSelf, TOther, TResult}.op_Division(TSelf, TOther)" /> static ulong IDivisionOperators<ulong, ulong, ulong>.operator /(ulong left, ulong right) => left / right; // // IEqualityOperators // /// <inheritdoc cref="IEqualityOperators{TSelf, TOther, TResult}.op_Equality(TSelf, TOther)" /> static bool IEqualityOperators<ulong, ulong, bool>.operator ==(ulong left, ulong right) => left == right; /// <inheritdoc cref="IEqualityOperators{TSelf, TOther, TResult}.op_Inequality(TSelf, TOther)" /> static bool IEqualityOperators<ulong, ulong, bool>.operator !=(ulong left, ulong right) => left != right; // // IIncrementOperators // /// <inheritdoc cref="IIncrementOperators{TSelf}.op_Increment(TSelf)" /> static ulong IIncrementOperators<ulong>.operator ++(ulong value) => ++value; /// <inheritdoc cref="IIncrementOperators{TSelf}.op_CheckedIncrement(TSelf)" /> static ulong IIncrementOperators<ulong>.operator checked ++(ulong value) => checked(++value); // // IMinMaxValue // /// <inheritdoc cref="IMinMaxValue{TSelf}.MinValue" /> static ulong IMinMaxValue<ulong>.MinValue => MinValue; /// <inheritdoc cref="IMinMaxValue{TSelf}.MaxValue" /> static ulong IMinMaxValue<ulong>.MaxValue => MaxValue; // // IModulusOperators // /// <inheritdoc cref="IModulusOperators{TSelf, TOther, TResult}.op_Modulus(TSelf, TOther)" /> static ulong IModulusOperators<ulong, ulong, ulong>.operator %(ulong left, ulong right) => left % right; // // IMultiplicativeIdentity // /// <inheritdoc cref="IMultiplicativeIdentity{TSelf, TResult}.MultiplicativeIdentity" /> static ulong IMultiplicativeIdentity<ulong, ulong>.MultiplicativeIdentity => MultiplicativeIdentity; // // IMultiplyOperators // /// <inheritdoc cref="IMultiplyOperators{TSelf, TOther, TResult}.op_Multiply(TSelf, TOther)" /> static ulong IMultiplyOperators<ulong, ulong, ulong>.operator *(ulong left, ulong right) => left * right; /// <inheritdoc cref="IMultiplyOperators{TSelf, TOther, TResult}.op_CheckedMultiply(TSelf, TOther)" /> static ulong IMultiplyOperators<ulong, ulong, ulong>.operator checked *(ulong left, ulong right) => checked(left * right); // // INumber // /// <inheritdoc cref="INumber{TSelf}.Clamp(TSelf, TSelf, TSelf)" /> public static ulong Clamp(ulong value, ulong min, ulong max) => Math.Clamp(value, min, max); /// <inheritdoc cref="INumber{TSelf}.CopySign(TSelf, TSelf)" /> static ulong INumber<ulong>.CopySign(ulong value, ulong sign) => value; /// <inheritdoc cref="INumber{TSelf}.Max(TSelf, TSelf)" /> public static ulong Max(ulong x, ulong y) => Math.Max(x, y); /// <inheritdoc cref="INumber{TSelf}.MaxNumber(TSelf, TSelf)" /> static ulong INumber<ulong>.MaxNumber(ulong x, ulong y) => Max(x, y); /// <inheritdoc cref="INumber{TSelf}.Min(TSelf, TSelf)" /> public static ulong Min(ulong x, ulong y) => Math.Min(x, y); /// <inheritdoc cref="INumber{TSelf}.MinNumber(TSelf, TSelf)" /> static ulong INumber<ulong>.MinNumber(ulong x, ulong y) => Min(x, y); /// <inheritdoc cref="INumber{TSelf}.Sign(TSelf)" /> public static int Sign(ulong value) => (value == 0) ? 0 : 1; // // INumberBase // /// <inheritdoc cref="INumberBase{TSelf}.One" /> static ulong INumberBase<ulong>.One => One; /// <inheritdoc cref="INumberBase{TSelf}.Radix" /> static int INumberBase<ulong>.Radix => 2; /// <inheritdoc cref="INumberBase{TSelf}.Zero" /> static ulong INumberBase<ulong>.Zero => Zero; /// <inheritdoc cref="INumberBase{TSelf}.Abs(TSelf)" /> static ulong INumberBase<ulong>.Abs(ulong value) => value; /// <inheritdoc cref="INumberBase{TSelf}.CreateChecked{TOther}(TOther)" /> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong CreateChecked<TOther>(TOther value) where TOther : INumberBase<TOther> { ulong result; if (typeof(TOther) == typeof(ulong)) { result = (ulong)(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 ulong CreateSaturating<TOther>(TOther value) where TOther : INumberBase<TOther> { ulong result; if (typeof(TOther) == typeof(ulong)) { result = (ulong)(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 ulong CreateTruncating<TOther>(TOther value) where TOther : INumberBase<TOther> { ulong result; if (typeof(TOther) == typeof(ulong)) { result = (ulong)(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<ulong>.IsCanonical(ulong value) => true; /// <inheritdoc cref="INumberBase{TSelf}.IsComplexNumber(TSelf)" /> static bool INumberBase<ulong>.IsComplexNumber(ulong value) => false; /// <inheritdoc cref="INumberBase{TSelf}.IsEvenInteger(TSelf)" /> public static bool IsEvenInteger(ulong value) => (value & 1) == 0; /// <inheritdoc cref="INumberBase{TSelf}.IsFinite(TSelf)" /> static bool INumberBase<ulong>.IsFinite(ulong value) => true; /// <inheritdoc cref="INumberBase{TSelf}.IsImaginaryNumber(TSelf)" /> static bool INumberBase<ulong>.IsImaginaryNumber(ulong value) => false; /// <inheritdoc cref="INumberBase{TSelf}.IsInfinity(TSelf)" /> static bool INumberBase<ulong>.IsInfinity(ulong value) => false; /// <inheritdoc cref="INumberBase{TSelf}.IsInteger(TSelf)" /> static bool INumberBase<ulong>.IsInteger(ulong value) => true; /// <inheritdoc cref="INumberBase{TSelf}.IsNaN(TSelf)" /> static bool INumberBase<ulong>.IsNaN(ulong value) => false; /// <inheritdoc cref="INumberBase{TSelf}.IsNegative(TSelf)" /> static bool INumberBase<ulong>.IsNegative(ulong value) => false; /// <inheritdoc cref="INumberBase{TSelf}.IsNegativeInfinity(TSelf)" /> static bool INumberBase<ulong>.IsNegativeInfinity(ulong value) => false; /// <inheritdoc cref="INumberBase{TSelf}.IsNormal(TSelf)" /> static bool INumberBase<ulong>.IsNormal(ulong value) => value != 0; /// <inheritdoc cref="INumberBase{TSelf}.IsOddInteger(TSelf)" /> public static bool IsOddInteger(ulong value) => (value & 1) != 0; /// <inheritdoc cref="INumberBase{TSelf}.IsPositive(TSelf)" /> static bool INumberBase<ulong>.IsPositive(ulong value) => true; /// <inheritdoc cref="INumberBase{TSelf}.IsPositiveInfinity(TSelf)" /> static bool INumberBase<ulong>.IsPositiveInfinity(ulong value) => false; /// <inheritdoc cref="INumberBase{TSelf}.IsRealNumber(TSelf)" /> static bool INumberBase<ulong>.IsRealNumber(ulong value) => true; /// <inheritdoc cref="INumberBase{TSelf}.IsSubnormal(TSelf)" /> static bool INumberBase<ulong>.IsSubnormal(ulong value) => false; /// <inheritdoc cref="INumberBase{TSelf}.IsZero(TSelf)" /> static bool INumberBase<ulong>.IsZero(ulong value) => (value == 0); /// <inheritdoc cref="INumberBase{TSelf}.MaxMagnitude(TSelf, TSelf)" /> static ulong INumberBase<ulong>.MaxMagnitude(ulong x, ulong y) => Max(x, y); /// <inheritdoc cref="INumberBase{TSelf}.MaxMagnitudeNumber(TSelf, TSelf)" /> static ulong INumberBase<ulong>.MaxMagnitudeNumber(ulong x, ulong y) => Max(x, y); /// <inheritdoc cref="INumberBase{TSelf}.MinMagnitude(TSelf, TSelf)" /> static ulong INumberBase<ulong>.MinMagnitude(ulong x, ulong y) => Min(x, y); /// <inheritdoc cref="INumberBase{TSelf}.MinMagnitudeNumber(TSelf, TSelf)" /> static ulong INumberBase<ulong>.MinMagnitudeNumber(ulong x, ulong y) => Min(x, y); /// <inheritdoc cref="INumberBase{TSelf}.MultiplyAddEstimate(TSelf, TSelf, TSelf)" /> static ulong INumberBase<ulong>.MultiplyAddEstimate(ulong left, ulong right, ulong addend) => (left * right) + addend; /// <inheritdoc cref="INumberBase{TSelf}.TryConvertFromChecked{TOther}(TOther, out TSelf)" /> [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase<ulong>.TryConvertFromChecked<TOther>(TOther value, out ulong result) => TryConvertFromChecked(value, out result); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool TryConvertFromChecked<TOther>(TOther value, out ulong 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 `ulong` 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((ulong)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(UInt128)) { UInt128 actualValue = (UInt128)(object)value; result = checked((ulong)actualValue); return true; } else if (typeof(TOther) == typeof(nuint)) { nuint actualValue = (nuint)(object)value; result = actualValue; return true; } else { result = default; return false; } } /// <inheritdoc cref="INumberBase{TSelf}.TryConvertFromSaturating{TOther}(TOther, out TSelf)" /> [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase<ulong>.TryConvertFromSaturating<TOther>(TOther value, out ulong result) => TryConvertFromSaturating(value, out result); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool TryConvertFromSaturating<TOther>(TOther value, out ulong 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 `ulong` 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 >= MaxValue) ? MaxValue : (actualValue <= MinValue) ? MinValue : (ulong)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(UInt128)) { UInt128 actualValue = (UInt128)(object)value; result = (actualValue >= MaxValue) ? MaxValue : (ulong)actualValue; return true; } else if (typeof(TOther) == typeof(nuint)) { nuint actualValue = (nuint)(object)value; result = actualValue; return true; } else { result = default; return false; } } /// <inheritdoc cref="INumberBase{TSelf}.TryConvertFromTruncating{TOther}(TOther, out TSelf)" /> [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase<ulong>.TryConvertFromTruncating<TOther>(TOther value, out ulong result) => TryConvertFromTruncating(value, out result); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool TryConvertFromTruncating<TOther>(TOther value, out ulong 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 `ulong` 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 >= MaxValue) ? MaxValue : (actualValue <= MinValue) ? MinValue : (ulong)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(UInt128)) { UInt128 actualValue = (UInt128)(object)value; result = (ulong)actualValue; return true; } else if (typeof(TOther) == typeof(nuint)) { nuint actualValue = (nuint)(object)value; result = actualValue; return true; } else { result = default; return false; } } /// <inheritdoc cref="INumberBase{TSelf}.TryConvertToChecked{TOther}(TSelf, out TOther)" /> [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase<ulong>.TryConvertToChecked<TOther>(ulong 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 `ulong` 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 = checked((Int128)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<ulong>.TryConvertToSaturating<TOther>(ulong 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 `ulong` 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 >= (ulong)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 >= (ulong)nint.MaxValue) ? nint.MaxValue : (nint)value; result = (TOther)(object)actualResult; return true; } else if (typeof(TOther) == typeof(sbyte)) { sbyte actualResult = (value >= (ulong)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<ulong>.TryConvertToTruncating<TOther>(ulong 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 `ulong` 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 = (Int128)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; } } /// <inheritdoc cref="INumberBase{TSelf}.TryParsePartial(string, NumberStyles, IFormatProvider?, out TSelf, out int)" /> public static bool TryParsePartial([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out ulong result, out int charsConsumed) { NumberFormatInfo.ValidateParseStyleInteger(style); return Number.TryParseBinaryInteger(s.AsSpan(), style | Number.AllowTrailingInvalidCharacters, NumberFormatInfo.GetInstance(provider), out result, out charsConsumed) == Number.ParsingStatus.OK; } /// <inheritdoc cref="INumberBase{TSelf}.TryParsePartial(ReadOnlySpan{char}, NumberStyles, IFormatProvider?, out TSelf, out int)" /> public static bool TryParsePartial(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out ulong result, out int charsConsumed) { NumberFormatInfo.ValidateParseStyleInteger(style); return Number.TryParseBinaryInteger(s, style | Number.AllowTrailingInvalidCharacters, NumberFormatInfo.GetInstance(provider), out result, out charsConsumed) == Number.ParsingStatus.OK; } /// <inheritdoc cref="INumberBase{TSelf}.TryParsePartial(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?, out TSelf, out int)" /> public static bool TryParsePartial(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out ulong result, out int bytesConsumed) { NumberFormatInfo.ValidateParseStyleInteger(style); return Number.TryParseBinaryInteger(utf8Text, style | Number.AllowTrailingInvalidCharacters, NumberFormatInfo.GetInstance(provider), out result, out bytesConsumed) == Number.ParsingStatus.OK; } // // IParsable // /// <inheritdoc cref="IParsable{TSelf}.TryParse(string?, IFormatProvider?, out TSelf)" /> public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out ulong result) => TryParse(s, NumberStyles.Integer, provider, out result); // // IShiftOperators // /// <inheritdoc cref="IShiftOperators{TSelf, TOther, TResult}.op_LeftShift(TSelf, TOther)" /> static ulong IShiftOperators<ulong, int, ulong>.operator <<(ulong value, int shiftAmount) => value << shiftAmount; /// <inheritdoc cref="IShiftOperators{TSelf, TOther, TResult}.op_RightShift(TSelf, TOther)" /> static ulong IShiftOperators<ulong, int, ulong>.operator >>(ulong value, int shiftAmount) => value >> shiftAmount; /// <inheritdoc cref="IShiftOperators{TSelf, TOther, TResult}.op_UnsignedRightShift(TSelf, TOther)" /> static ulong IShiftOperators<ulong, int, ulong>.operator >>>(ulong value, int shiftAmount) => value >>> shiftAmount; // // ISpanParsable // /// <inheritdoc cref="ISpanParsable{TSelf}.Parse(ReadOnlySpan{char}, IFormatProvider?)" /> public static ulong Parse(ReadOnlySpan<char> s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); /// <inheritdoc cref="ISpanParsable{TSelf}.TryParse(ReadOnlySpan{char}, IFormatProvider?, out TSelf)" /> public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, out ulong result) => TryParse(s, NumberStyles.Integer, provider, out result); // // ISubtractionOperators // /// <inheritdoc cref="ISubtractionOperators{TSelf, TOther, TResult}.op_Subtraction(TSelf, TOther)" /> static ulong ISubtractionOperators<ulong, ulong, ulong>.operator -(ulong left, ulong right) => left - right; /// <inheritdoc cref="ISubtractionOperators{TSelf, TOther, TResult}.op_CheckedSubtraction(TSelf, TOther)" /> static ulong ISubtractionOperators<ulong, ulong, ulong>.operator checked -(ulong left, ulong right) => checked(left - right); // // IUnaryNegationOperators // /// <inheritdoc cref="IUnaryNegationOperators{TSelf, TResult}.op_UnaryNegation(TSelf)" /> static ulong IUnaryNegationOperators<ulong, ulong>.operator -(ulong value) => 0UL - value; /// <inheritdoc cref="IUnaryNegationOperators{TSelf, TResult}.op_CheckedUnaryNegation(TSelf)" /> static ulong IUnaryNegationOperators<ulong, ulong>.operator checked -(ulong value) => checked(0UL - value); // // IUnaryPlusOperators // /// <inheritdoc cref="IUnaryPlusOperators{TSelf, TResult}.op_UnaryPlus(TSelf)" /> static ulong IUnaryPlusOperators<ulong, ulong>.operator +(ulong value) => +value; // // IUtf8SpanParsable // /// <inheritdoc cref="INumberBase{TSelf}.Parse(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?)" /> public static ulong Parse(ReadOnlySpan<byte> utf8Text, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); return Number.ParseBinaryInteger<byte, ulong>(utf8Text, style, NumberFormatInfo.GetInstance(provider)); } /// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?, out TSelf)" /> public static bool TryParse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out ulong result) { NumberFormatInfo.ValidateParseStyleInteger(style); return Number.TryParseBinaryInteger(utf8Text, style, NumberFormatInfo.GetInstance(provider), out result, out _) == Number.ParsingStatus.OK; } /// <inheritdoc cref="IUtf8SpanParsable{TSelf}.Parse(ReadOnlySpan{byte}, IFormatProvider?)" /> public static ulong Parse(ReadOnlySpan<byte> utf8Text, IFormatProvider? provider) => Parse(utf8Text, NumberStyles.Integer, provider); /// <inheritdoc cref="IUtf8SpanParsable{TSelf}.TryParse(ReadOnlySpan{byte}, IFormatProvider?, out TSelf)" /> public static bool TryParse(ReadOnlySpan<byte> utf8Text, IFormatProvider? provider, out ulong result) => TryParse(utf8Text, NumberStyles.Integer, provider, out result); // // IBinaryIntegerParseAndFormatInfo // static bool IBinaryIntegerParseAndFormatInfo<ulong>.IsSigned => false; static int IBinaryIntegerParseAndFormatInfo<ulong>.MaxDigitCount => 20; // 18_446_744_073_709_551_615 static int IBinaryIntegerParseAndFormatInfo<ulong>.MaxHexDigitCount => 16; // 0xFFFF_FFFF_FFFF_FFFF static ulong IBinaryIntegerParseAndFormatInfo<ulong>.MaxValueDiv10 => MaxValue / 10; static string IBinaryIntegerParseAndFormatInfo<ulong>.OverflowMessage => SR.Overflow_UInt64; static bool IBinaryIntegerParseAndFormatInfo<ulong>.IsGreaterThanAsUnsigned(ulong left, ulong right) => left > right; static ulong IBinaryIntegerParseAndFormatInfo<ulong>.MultiplyBy10(ulong value) => value * 10; static ulong IBinaryIntegerParseAndFormatInfo<ulong>.MultiplyBy16(ulong value) => value * 16; } }