2023-08-04 12:24:49 -04:00
using System.Buffers.Binary ;
2019-08-17 18:07:02 -04:00
using System.ComponentModel ;
2022-05-16 15:14:38 -04:00
using System.Diagnostics ;
2023-08-04 12:24:49 -04:00
using System.Diagnostics.CodeAnalysis ;
2019-08-17 18:07:02 -04:00
using System.Globalization ;
2023-08-04 12:24:49 -04:00
using System.Numerics ;
2023-02-25 22:36:12 -05:00
using System.Runtime.CompilerServices ;
using System.Runtime.Serialization ;
2018-05-13 23:39:36 -04:00
2023-02-18 21:31:48 -05:00
namespace Vanara.PInvoke ;
/// <summary>Managed instance of the SIZE_T type.</summary>
[StructLayout(LayoutKind.Sequential), Serializable]
[TypeConverter(typeof(SizeTTypeConverter))]
[DebuggerDisplay("{Value}")]
2023-02-25 22:36:12 -05:00
public struct SizeT : IEquatable < SizeT > , IComparable < SizeT > , IConvertible , IComparable , ISerializable
#if NET7_0_OR_GREATER
, IParsable < SizeT > , ISpanParsable < SizeT > , IBinaryInteger < SizeT > , IUnsignedNumber < SizeT >
# endif
2018-05-13 23:39:36 -04:00
{
2023-02-25 22:36:12 -05:00
/// <summary>
/// Represents the largest possible value of <see cref="SizeT"/>. This property is determined by the maximum bit-size of a pointer.
/// </summary>
public static readonly SizeT MaxValue =
#if NET6_0_OR_GREATER
nuint . MaxValue ;
# else
UIntPtr . Size = = 8 ? new ( ulong . MaxValue ) : new ( uint . MaxValue ) ;
# endif
2023-02-18 21:31:48 -05:00
/// <summary>Represents the smallest possible value of <see cref="SizeT"/>. This field is constant.</summary>
public static readonly SizeT MinValue = 0 ;
/// <summary>Represents the zero value of <see cref="SizeT"/>. This field is constant.</summary>
public static readonly SizeT Zero = default ;
2023-02-25 22:36:12 -05:00
private nuint val ;
2023-02-18 21:31:48 -05:00
/// <summary>Initializes a new instance of the <see cref="SizeT"/> struct.</summary>
/// <param name="value">The value.</param>
2023-02-25 22:36:12 -05:00
public SizeT ( uint value ) = > val = value ;
2023-02-18 21:31:48 -05:00
/// <summary>Initializes a new instance of the <see cref="SizeT"/> struct.</summary>
/// <param name="value">The value.</param>
public SizeT ( ulong value ) = > val = new UIntPtr ( value ) ;
2023-02-25 22:36:12 -05:00
/// <summary>Initializes a new instance of the <see cref="SizeT"/> struct.</summary>
/// <param name="value">The value.</param>
public unsafe SizeT ( void * value ) = > val = ( nuint ) value ;
private SizeT ( SerializationInfo info , StreamingContext context ) = > val = ( nuint ) info . GetUInt64 ( "value" ) ;
/// <inheritdoc/>
void ISerializable . GetObjectData ( SerializationInfo info , StreamingContext context )
{
if ( info is null ) throw new ArgumentNullException ( nameof ( info ) ) ;
info . AddValue ( "value" , ( ulong ) val ) ;
}
2023-02-18 21:31:48 -05:00
/// <summary>Gets the value.</summary>
/// <value>The value.</value>
2023-02-25 22:36:12 -05:00
public ulong Value { get = > val ; private set = > val = new UIntPtr ( value ) ; }
#if NET7_0_OR_GREATER
/// <inheritdoc/>
static SizeT IAdditiveIdentity < SizeT , SizeT > . AdditiveIdentity = > Zero ;
/// <inheritdoc/>
static SizeT IMultiplicativeIdentity < SizeT , SizeT > . MultiplicativeIdentity = > new ( 1 UL ) ;
/// <inheritdoc/>
static SizeT INumberBase < SizeT > . One = > new ( 1 UL ) ;
/// <inheritdoc/>
static int INumberBase < SizeT > . Radix = > 2 ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <inheritdoc/>
static SizeT INumberBase < SizeT > . Zero = > Zero ;
# endif
/// <summary>Performs an implicit conversion from <see cref="SizeT"/> to <see cref="int"/>.</summary>
2023-02-18 21:31:48 -05:00
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
2023-02-25 22:36:12 -05:00
public static implicit operator int ( SizeT value ) = > ( ( IConvertible ) value ) . ToInt32 ( null ) ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <summary>Performs an implicit conversion from <see cref="SizeT"/> to <see cref="long"/>.</summary>
2023-02-18 21:31:48 -05:00
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
2023-02-25 22:36:12 -05:00
public static implicit operator long ( SizeT value ) = > ( ( IConvertible ) value ) . ToInt64 ( null ) ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <summary>Performs an implicit conversion from <see cref="int"/> to <see cref="SizeT"/>.</summary>
2023-02-18 21:31:48 -05:00
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
2023-02-25 22:36:12 -05:00
public static implicit operator SizeT ( int value ) = > value > = 0 ? new SizeT ( ( uint ) value ) : throw new ArgumentOutOfRangeException ( nameof ( value ) ) ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <summary>Performs an implicit conversion from <see cref="uint"/> to <see cref="SizeT"/>.</summary>
2023-02-18 21:31:48 -05:00
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
2023-02-25 22:36:12 -05:00
public static implicit operator SizeT ( uint value ) = > new ( value ) ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <summary>Performs an implicit conversion from <see cref="long"/> to <see cref="SizeT"/>.</summary>
2023-02-18 21:31:48 -05:00
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
2023-02-25 22:36:12 -05:00
public static implicit operator SizeT ( long value ) = > value > = 0 ? new SizeT ( ( ulong ) value ) : throw new ArgumentOutOfRangeException ( nameof ( value ) ) ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <summary>Performs an implicit conversion from <see cref="ulong"/> to <see cref="SizeT"/>.</summary>
2023-02-18 21:31:48 -05:00
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
2023-02-25 22:36:12 -05:00
public static implicit operator SizeT ( ulong value ) = > new ( value ) ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <summary>Performs an implicit conversion from <see cref="SizeT"/> to <see cref="uint"/>.</summary>
2023-02-18 21:31:48 -05:00
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
2023-03-31 11:47:53 -04:00
public static implicit operator uint ( SizeT value ) = > ( uint ) value . val ;
2023-02-25 22:36:12 -05:00
/// <summary>Performs an implicit conversion from <see cref="SizeT"/> to <see cref="ulong"/>.</summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
2023-03-31 11:47:53 -04:00
public static implicit operator ulong ( SizeT value ) = > value . val ;
2023-02-25 22:36:12 -05:00
/// <summary>Subtracts two specified <see cref="SizeT"/> values.</summary>
/// <param name="s1">The minuend.</param>
/// <param name="s2">The subtrahend.</param>
/// <returns>The result of subtracting <paramref name="s2"/> from <paramref name="s1"/>.</returns>
public static SizeT operator - ( SizeT s1 , SizeT s2 ) = > s1 . Value - s2 . Value ;
/// <inheritdoc/>
public static SizeT operator - ( SizeT value ) = > UIntPtr . Zero - value . val ;
/// <summary>Decrements the <see cref="SizeT"/> by 1.</summary>
/// <param name="s1">The value to decrement.</param>
/// <returns>The value of <paramref name="s1"/> decremented by 1.</returns>
public static SizeT operator - - ( SizeT s1 ) = > s1 . Value + = 1 ;
2023-02-18 21:31:48 -05:00
/// <summary>Indicates whether two <see cref="SizeT"/> instances are not equal.</summary>
/// <param name="s1">The first integral size to compare.</param>
/// <param name="s2">The second integral size to compare.</param>
/// <returns>
/// <see langword="true"/> if the value of <paramref name="s1"/> is not equal to the value of <paramref name="s2"/>; otherwise, <see langword="false"/>.
/// </returns>
public static bool operator ! = ( SizeT s1 , SizeT s2 ) = > ! s1 . Equals ( s2 ) ;
2023-02-25 22:36:12 -05:00
/// <summary>Returns the remainder resulting from dividing two specified <see cref="SizeT"/> values.</summary>
/// <param name="s1">The divident.</param>
/// <param name="s2">The divisor.</param>
/// <returns>The remainder resulting from dividing <paramref name="s1"/> by <paramref name="s2"/>.</returns>
public static SizeT operator % ( SizeT s1 , SizeT s2 ) = > s1 . Value % s2 . Value ;
/// <inheritdoc/>
public static SizeT operator & ( SizeT left , SizeT right ) = > left . Value & right . Value ;
/// <summary>Multiplies two specified <see cref="SizeT"/> values.</summary>
/// <param name="s1">The first value to multiply.</param>
/// <param name="s2">The second value to multiply.</param>
/// <returns>The result of multiplying <paramref name="s1"/> by <paramref name="s2"/>.</returns>
public static SizeT operator * ( SizeT s1 , SizeT s2 ) = > s1 . Value * s2 . Value ;
/// <summary>Divides two specified <see cref="SizeT"/> values.</summary>
/// <param name="s1">The divident.</param>
/// <param name="s2">The divisor.</param>
/// <returns>The result of dividing <paramref name="s1"/> by <paramref name="s2"/>.</returns>
public static SizeT operator / ( SizeT s1 , SizeT s2 ) = > s1 . Value / s2 . Value ;
/// <inheritdoc/>
public static SizeT operator ^ ( SizeT left , SizeT right ) = > left . Value ^ right . Value ;
/// <inheritdoc/>
public static SizeT operator ~ ( SizeT value ) = > ~ value . Value ;
/// <summary>Adds two specified <see cref="SizeT"/> values.</summary>
/// <param name="s1">The first value to add.</param>
/// <param name="s2">The second value to add.</param>
/// <returns>The result of adding <paramref name="s1"/> and <paramref name="s2"/>.</returns>
public static SizeT operator + ( SizeT s1 , SizeT s2 ) = > s1 . Value + s2 . Value ;
/// <inheritdoc/>
public static SizeT operator + ( SizeT value ) = > + value . Value ;
/// <summary>Increments the <see cref="SizeT"/> by 1.</summary>
/// <param name="s1">The value to increment.</param>
/// <returns>The value of <paramref name="s1"/> incremented by 1.</returns>
public static SizeT operator + + ( SizeT s1 ) = > s1 . Value + = 1 ;
2023-02-18 21:31:48 -05:00
/// <summary>Indicates whether a specified <see cref="SizeT"/> is less than another specified <see cref="SizeT"/>.</summary>
/// <param name="s1">The first integral size to compare.</param>
/// <param name="s2">The second integral size to compare.</param>
/// <returns>
/// <see langword="true"/> if the value of <paramref name="s1"/> is less than the value of <paramref name="s2"/>; otherwise, <see langword="false"/>.
/// </returns>
public static bool operator < ( SizeT s1 , SizeT s2 ) = > s1 . CompareTo ( s2 ) < 0 ;
2023-02-25 22:36:12 -05:00
/// <inheritdoc/>
public static SizeT operator < < ( SizeT value , int shiftAmount ) = > value . Value < < shiftAmount ;
2023-02-18 21:31:48 -05:00
/// <summary>Indicates whether a specified <see cref="SizeT"/> is less than or equal to another specified <see cref="SizeT"/>.</summary>
/// <param name="s1">The first integral size to compare.</param>
/// <param name="s2">The second integral size to compare.</param>
/// <returns>
/// <see langword="true"/> if the value of <paramref name="s1"/> is less than or equal to the value of <paramref name="s2"/>;
/// otherwise, <see langword="false"/>.
/// </returns>
public static bool operator < = ( SizeT s1 , SizeT s2 ) = > s1 . CompareTo ( s2 ) < = 0 ;
/// <summary>Indicates whether two <see cref="SizeT"/> instances are equal.</summary>
/// <param name="s1">The first integral size to compare.</param>
/// <param name="s2">The second integral size to compare.</param>
/// <returns>
/// <see langword="true"/> if the value of <paramref name="s1"/> is equal to the value of <paramref name="s2"/>; otherwise, <see langword="false"/>.
/// </returns>
public static bool operator = = ( SizeT s1 , SizeT s2 ) = > s1 . Equals ( s2 ) ;
/// <summary>Indicates whether a specified <see cref="SizeT"/> is greater than another specified <see cref="SizeT"/>.</summary>
/// <param name="s1">The first integral size to compare.</param>
/// <param name="s2">The second integral size to compare.</param>
/// <returns>
/// <see langword="true"/> if the value of <paramref name="s1"/> is greater than the value of <paramref name="s2"/>; otherwise, <see langword="false"/>.
/// </returns>
public static bool operator > ( SizeT s1 , SizeT s2 ) = > s1 . CompareTo ( s2 ) > 0 ;
/// <summary>Indicates whether a specified <see cref="SizeT"/> is greater than or equal to another specified <see cref="SizeT"/>.</summary>
/// <param name="s1">The first integral size to compare.</param>
/// <param name="s2">The second integral size to compare.</param>
/// <returns>
/// <see langword="true"/> if the value of <paramref name="s1"/> is greater than or equal to the value of <paramref name="s2"/>;
/// otherwise, <see langword="false"/>.
/// </returns>
public static bool operator > = ( SizeT s1 , SizeT s2 ) = > s1 . CompareTo ( s2 ) > = 0 ;
2023-02-25 22:36:12 -05:00
/// <inheritdoc/>
public static SizeT operator > > ( SizeT value , int shiftAmount ) = > value . Value > > shiftAmount ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <inheritdoc/>
public static SizeT operator > > > ( SizeT value , int shiftAmount ) = > value . Value > > > shiftAmount ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <inheritdoc/>
public static SizeT Parse ( string s , IFormatProvider ? provider = null ) = > Parse ( s , NumberStyles . Any , provider ) ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <inheritdoc/>
public static SizeT Parse ( string s , NumberStyles style , IFormatProvider ? provider ) = > ulong . Parse ( s , style , provider ) ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <inheritdoc/>
public static SizeT Parse ( ReadOnlySpan < char > s , IFormatProvider ? provider ) = > Parse ( s . ToString ( ) , NumberStyles . Any , provider ) ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <inheritdoc/>
public static SizeT Parse ( ReadOnlySpan < char > s , NumberStyles style , IFormatProvider ? provider ) = > Parse ( s . ToString ( ) , style , provider ) ;
2023-02-18 21:31:48 -05:00
2023-02-25 22:36:12 -05:00
/// <inheritdoc/>
public static bool TryParse ( string? s , IFormatProvider ? provider , out SizeT result ) = > TryParse ( s , NumberStyles . Any , provider , out result ) ;
/// <inheritdoc/>
public static bool TryParse ( ReadOnlySpan < char > s , IFormatProvider ? provider , out SizeT result ) = > TryParse ( s . ToString ( ) , NumberStyles . Any , provider , out result ) ;
/// <inheritdoc/>
public static bool TryParse ( string? s , NumberStyles style , IFormatProvider ? provider , out SizeT result ) { var b = ulong . TryParse ( s , style , provider , out var r ) ; result = b ? r : default ; return b ; }
/// <inheritdoc/>
public static bool TryParse ( ReadOnlySpan < char > s , NumberStyles style , IFormatProvider ? provider , out SizeT result ) = > TryParse ( s . ToString ( ) , style , provider , out result ) ;
2023-02-18 21:31:48 -05:00
/// <inheritdoc/>
public int CompareTo ( SizeT other ) = > Value . CompareTo ( other . Value ) ;
/// <inheritdoc/>
public override bool Equals ( object? obj ) = > obj is SizeT s ? Equals ( s ) : Value . Equals ( obj ) ;
/// <inheritdoc/>
public bool Equals ( SizeT other ) = > Value . Equals ( other . Value ) ;
/// <inheritdoc/>
public override int GetHashCode ( ) = > Value . GetHashCode ( ) ;
/// <inheritdoc/>
public TypeCode GetTypeCode ( ) = > Value . GetTypeCode ( ) ;
/// <inheritdoc/>
public override string ToString ( ) = > Value . ToString ( ) ;
/// <inheritdoc/>
public string ToString ( IFormatProvider ? provider ) = > Value . ToString ( provider ) ;
2023-02-25 22:36:12 -05:00
/// <inheritdoc/>
public string ToString ( string? format , IFormatProvider ? formatProvider ) = > Value . ToString ( format , formatProvider ) ;
#if NET6_0_OR_GREATER || NETCOREAPP3_1_OR_GREATER
/// <inheritdoc/>
public bool TryFormat ( Span < char > destination , out int charsWritten , ReadOnlySpan < char > format , IFormatProvider ? provider ) = >
Value . TryFormat ( destination , out charsWritten , format , provider ) ;
# endif
#if NET7_0_OR_GREATER
/// <inheritdoc/>
static SizeT INumberBase < SizeT > . Abs ( SizeT value ) = > value ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsCanonical ( SizeT value ) = > true ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsComplexNumber ( SizeT value ) = > false ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsEvenInteger ( SizeT value ) = > ( value . Value & 1 ) = = 0 ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsFinite ( SizeT value ) = > true ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsImaginaryNumber ( SizeT value ) = > false ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsInfinity ( SizeT value ) = > false ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsInteger ( SizeT value ) = > true ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsNaN ( SizeT value ) = > false ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsNegative ( SizeT value ) = > false ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsNegativeInfinity ( SizeT value ) = > false ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsNormal ( SizeT value ) = > value . Value ! = 0 ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsOddInteger ( SizeT value ) = > ( value . Value & 1 ) ! = 0 ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsPositive ( SizeT value ) = > true ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsPositiveInfinity ( SizeT value ) = > false ;
/// <inheritdoc/>
static bool IBinaryNumber < SizeT > . IsPow2 ( SizeT value ) = > nuint . IsPow2 ( value . val ) ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsRealNumber ( SizeT value ) = > true ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsSubnormal ( SizeT value ) = > false ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . IsZero ( SizeT value ) = > value . val = = nuint . Zero ;
/// <inheritdoc/>
static SizeT IBinaryNumber < SizeT > . Log2 ( SizeT value ) = > nuint . Log2 ( value . val ) ;
/// <inheritdoc/>
static SizeT INumberBase < SizeT > . MaxMagnitude ( SizeT x , SizeT y ) = > Math . Max ( x . Value , y . Value ) ;
/// <inheritdoc/>
static SizeT INumberBase < SizeT > . MaxMagnitudeNumber ( SizeT x , SizeT y ) = > Math . Max ( x . Value , y . Value ) ;
/// <inheritdoc/>
static SizeT INumberBase < SizeT > . MinMagnitude ( SizeT x , SizeT y ) = > Math . Min ( x . Value , y . Value ) ;
/// <inheritdoc/>
static SizeT INumberBase < SizeT > . MinMagnitudeNumber ( SizeT x , SizeT y ) = > Math . Min ( x . Value , y . Value ) ;
/// <inheritdoc/>
public static SizeT operator | ( SizeT left , SizeT right ) = > left . Value | right . Value ;
/// <inheritdoc/>
static SizeT IBinaryInteger < SizeT > . PopCount ( SizeT value ) = > nuint . PopCount ( value . val ) ;
/// <inheritdoc/>
static SizeT IBinaryInteger < SizeT > . TrailingZeroCount ( SizeT value ) = > nuint . TrailingZeroCount ( value . val ) ;
/// <inheritdoc/>
static bool INumberBase < SizeT > . TryConvertFromChecked < TOther > ( TOther value , out SizeT 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 ( byte ) )
{
byte actualValue = ( byte ) ( object ) value ;
result = ( ulong ) actualValue ;
return true ;
}
else if ( typeof ( TOther ) = = typeof ( char ) )
{
char actualValue = ( char ) ( object ) value ;
result = ( ulong ) 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 = ( ulong ) 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 ( ( 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/>
static bool INumberBase < SizeT > . TryConvertFromSaturating < TOther > ( TOther value , out SizeT 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 ( byte ) )
{
byte actualValue = ( byte ) ( object ) value ;
result = ( uint ) actualValue ;
return true ;
}
else if ( typeof ( TOther ) = = typeof ( char ) )
{
char actualValue = ( char ) ( object ) value ;
result = ( uint ) actualValue ;
return true ;
}
else if ( typeof ( TOther ) = = typeof ( decimal ) )
{
decimal actualValue = ( decimal ) ( object ) value ;
result = ( actualValue > = ( ulong ) MaxValue ) ? MaxValue :
( actualValue < = ( ulong ) MinValue ) ? MinValue : ( ulong ) actualValue ;
return true ;
}
else if ( typeof ( TOther ) = = typeof ( ushort ) )
{
ushort actualValue = ( ushort ) ( object ) value ;
result = ( uint ) 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 = ( actualValue > = ( ulong ) 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/>
static bool INumberBase < SizeT > . TryConvertFromTruncating < TOther > ( TOther value , out SizeT 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 ( byte ) )
{
byte actualValue = ( byte ) ( object ) value ;
result = ( uint ) actualValue ;
return true ;
}
else if ( typeof ( TOther ) = = typeof ( char ) )
{
char actualValue = ( char ) ( object ) value ;
result = ( uint ) actualValue ;
return true ;
}
else if ( typeof ( TOther ) = = typeof ( decimal ) )
{
decimal actualValue = ( decimal ) ( object ) value ;
result = ( actualValue > = ( ulong ) MaxValue ) ? MaxValue :
( actualValue < = ( ulong ) MinValue ) ? MinValue : ( ulong ) actualValue ;
return true ;
}
else if ( typeof ( TOther ) = = typeof ( ushort ) )
{
ushort actualValue = ( ushort ) ( object ) value ;
result = ( uint ) 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 = ( 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/>
static bool INumberBase < SizeT > . TryConvertToChecked < TOther > ( SizeT 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 . val ;
result = ( TOther ) ( object ) actualResult ;
return true ;
}
else if ( typeof ( TOther ) = = typeof ( Half ) )
{
Half actualResult = ( Half ) value . val ;
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 . val ;
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 . val ;
result = ( TOther ) ( object ) actualResult ;
return true ;
}
else
{
result = default ;
return false ;
}
}
/// <inheritdoc/>
static bool INumberBase < SizeT > . TryConvertToSaturating < TOther > ( SizeT value , [ MaybeNullWhen ( false ) ] out TOther result )
{
if ( typeof ( TOther ) = = typeof ( double ) )
{
double actualResult = value . val ;
result = ( TOther ) ( object ) actualResult ;
return true ;
}
else if ( typeof ( TOther ) = = typeof ( Half ) )
{
Half actualResult = ( Half ) value . val ;
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 . val ;
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 . val ;
result = ( TOther ) ( object ) actualResult ;
return true ;
}
else
{
result = default ;
return false ;
}
}
/// <inheritdoc/>
static bool INumberBase < SizeT > . TryConvertToTruncating < TOther > ( SizeT 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 . val ;
result = ( TOther ) ( object ) actualResult ;
return true ;
}
else if ( typeof ( TOther ) = = typeof ( Half ) )
{
Half actualResult = ( Half ) value . val ;
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 . val ;
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 . val ;
result = ( TOther ) ( object ) actualResult ;
return true ;
}
else
{
result = default ;
return false ;
}
}
/// <inheritdoc/>
static bool IBinaryInteger < SizeT > . TryReadBigEndian ( ReadOnlySpan < byte > source , bool isUnsigned , out SizeT 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 ) ] . IndexOfAnyExcept ( ( byte ) 0x00 ) > = 0 ) )
{
// 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 ( ulong ) )
{
sourceRef = ref Unsafe . Add ( ref sourceRef , source . Length - sizeof ( ulong ) ) ;
// We have at least 8 bytes, so just read the ones we need directly
result = Unsafe . ReadUnaligned < ulong > ( ref sourceRef ) ;
if ( BitConverter . IsLittleEndian )
{
result = BinaryPrimitives . ReverseEndianness ( result ) ;
}
}
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 | = Unsafe . Add ( ref sourceRef , i ) ;
}
}
}
value = result ;
return true ;
}
/// <inheritdoc/>
static bool IBinaryInteger < SizeT > . TryReadLittleEndian ( ReadOnlySpan < byte > source , bool isUnsigned , out SizeT 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 ) . . ] . IndexOfAnyExcept ( ( byte ) 0x00 ) > = 0 ) )
{
// 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 ( ulong ) )
{
// We have at least 8 bytes, so just read the ones we need directly
result = Unsafe . ReadUnaligned < ulong > ( ref sourceRef ) ;
if ( ! BitConverter . IsLittleEndian )
{
result = BinaryPrimitives . ReverseEndianness ( result ) ;
}
}
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 = Unsafe . Add ( ref sourceRef , i ) ;
part < < = ( i * 8 ) ;
result | = part ;
}
}
}
value = result ;
return true ;
}
/// <inheritdoc/>
int IBinaryInteger < SizeT > . GetByteCount ( ) = > ( ( IBinaryInteger < nuint > ) val ) . GetByteCount ( ) ;
/// <inheritdoc/>
int IBinaryInteger < SizeT > . GetShortestBitLength ( ) = > ( ( IBinaryInteger < nuint > ) val ) . GetShortestBitLength ( ) ;
/// <inheritdoc/>
bool IBinaryInteger < SizeT > . TryWriteBigEndian ( Span < byte > destination , out int bytesWritten ) = > ( ( IBinaryInteger < nuint > ) val ) . TryWriteBigEndian ( destination , out bytesWritten ) ;
/// <inheritdoc/>
bool IBinaryInteger < SizeT > . TryWriteLittleEndian ( Span < byte > destination , out int bytesWritten ) = > ( ( IBinaryInteger < nuint > ) val ) . TryWriteLittleEndian ( destination , out bytesWritten ) ;
# endif
2023-02-18 21:31:48 -05:00
/// <inheritdoc/>
int IComparable . CompareTo ( object? obj ) = > Value . CompareTo ( Convert . ChangeType ( obj , typeof ( ulong ) ) ) ;
/// <inheritdoc/>
bool IConvertible . ToBoolean ( IFormatProvider ? provider ) = > ( ( IConvertible ) Value ) . ToBoolean ( provider ) ;
/// <inheritdoc/>
byte IConvertible . ToByte ( IFormatProvider ? provider )
{
var ul = Value ;
2023-02-25 22:36:12 -05:00
if ( ul < byte . MaxValue )
2023-02-18 21:31:48 -05:00
return ( byte ) ul ;
if ( ul is uint . MaxValue or ulong . MaxValue )
return byte . MaxValue ;
throw new OverflowException ( ) ;
}
/// <inheritdoc/>
char IConvertible . ToChar ( IFormatProvider ? provider ) = > ( ( IConvertible ) Value ) . ToChar ( provider ) ;
/// <inheritdoc/>
DateTime IConvertible . ToDateTime ( IFormatProvider ? provider ) = > ( ( IConvertible ) Value ) . ToDateTime ( provider ) ;
/// <inheritdoc/>
decimal IConvertible . ToDecimal ( IFormatProvider ? provider )
{
var ul = Value ;
if ( ul < decimal . MaxValue )
2023-02-25 22:36:12 -05:00
return ul ;
2023-02-18 21:31:48 -05:00
if ( ul is uint . MaxValue or ulong . MaxValue )
return decimal . MaxValue ;
throw new OverflowException ( ) ;
}
/// <inheritdoc/>
double IConvertible . ToDouble ( IFormatProvider ? provider )
{
var ul = Value ;
if ( ul < double . MaxValue )
return ul ;
if ( ul is uint . MaxValue or ulong . MaxValue )
return double . MaxValue ;
throw new OverflowException ( ) ;
}
/// <inheritdoc/>
short IConvertible . ToInt16 ( IFormatProvider ? provider )
{
var ul = Value ;
if ( ul < ( ulong ) short . MaxValue )
return ( short ) ul ;
if ( ul is uint . MaxValue or ulong . MaxValue )
return short . MaxValue ;
throw new OverflowException ( ) ;
}
/// <inheritdoc/>
int IConvertible . ToInt32 ( IFormatProvider ? provider )
{
var ul = Value ;
if ( ul < int . MaxValue )
return ( int ) ul ;
if ( ul is uint . MaxValue or ulong . MaxValue )
return int . MaxValue ;
throw new OverflowException ( ) ;
}
/// <inheritdoc/>
long IConvertible . ToInt64 ( IFormatProvider ? provider )
2018-05-13 23:39:36 -04:00
{
2023-02-18 21:31:48 -05:00
var ul = Value ;
if ( ul < long . MaxValue )
return ( long ) ul ;
if ( ul is uint . MaxValue or ulong . MaxValue )
return long . MaxValue ;
throw new OverflowException ( ) ;
}
/// <inheritdoc/>
sbyte IConvertible . ToSByte ( IFormatProvider ? provider )
{
var ul = Value ;
if ( ul < ( ulong ) sbyte . MaxValue )
return ( sbyte ) ul ;
if ( ul is uint . MaxValue or ulong . MaxValue )
return sbyte . MaxValue ;
throw new OverflowException ( ) ;
}
/// <inheritdoc/>
float IConvertible . ToSingle ( IFormatProvider ? provider )
{
var ul = Value ;
if ( ul < float . MaxValue )
return ul ;
if ( ul is uint . MaxValue or ulong . MaxValue )
return float . MaxValue ;
throw new OverflowException ( ) ;
}
/// <inheritdoc/>
object IConvertible . ToType ( Type conversionType , IFormatProvider ? provider ) = > ( ( IConvertible ) Value ) . ToType ( conversionType , provider ) ;
/// <inheritdoc/>
ushort IConvertible . ToUInt16 ( IFormatProvider ? provider )
{
var ul = Value ;
2023-02-25 22:36:12 -05:00
if ( ul < ushort . MaxValue )
2023-02-18 21:31:48 -05:00
return ( ushort ) ul ;
if ( ul is uint . MaxValue or ulong . MaxValue )
return ushort . MaxValue ;
throw new OverflowException ( ) ;
}
/// <inheritdoc/>
uint IConvertible . ToUInt32 ( IFormatProvider ? provider )
{
var ul = Value ;
if ( ul < uint . MaxValue )
return ( uint ) ul ;
if ( ul is uint . MaxValue or ulong . MaxValue )
return uint . MaxValue ;
throw new OverflowException ( ) ;
}
/// <inheritdoc/>
ulong IConvertible . ToUInt64 ( IFormatProvider ? provider ) = > Value ;
internal class SizeTTypeConverter : UInt64Converter
{
public override object? ConvertFrom ( ITypeDescriptorContext ? context , CultureInfo ? culture , object value ) = >
new SizeT ( ( ulong ) base . ConvertFrom ( context , culture , value ) ! ) ;
2023-02-25 22:36:12 -05:00
public override object? ConvertTo ( ITypeDescriptorContext ? context , CultureInfo ? culture , object? value , Type destinationType ) = >
value is SizeT sz ? base . ConvertTo ( context , culture , sz . Value , destinationType ) : throw new NotSupportedException ( ) ;
2018-05-13 23:39:36 -04:00
}
}