Last active
May 6, 2024 19:04
-
-
Save Kittoes0124/125912c902a476384f3d8a8ca4cbc3fb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Diagnostics.CodeAnalysis; | |
using System.Globalization; | |
using System.Numerics; | |
using System.Runtime.InteropServices; | |
namespace Sandbox; | |
[CLSCompliant(isCompliant: false)] | |
[StructLayout(layoutKind: LayoutKind.Sequential)] | |
public readonly struct UnsignedBinaryInteger<T> : | |
IBinaryInteger<UnsignedBinaryInteger<T>>, | |
IMinMaxValue<UnsignedBinaryInteger<T>>, | |
IUnsignedNumber<UnsignedBinaryInteger<T>> | |
where T : IBinaryInteger<T>, IUnsignedNumber<T> | |
{ | |
static UnsignedBinaryInteger<T> IAdditiveIdentity<UnsignedBinaryInteger<T>, UnsignedBinaryInteger<T>>.AdditiveIdentity => Zero; | |
static UnsignedBinaryInteger<T> IBinaryNumber<UnsignedBinaryInteger<T>>.AllBitsSet => MaxValue; | |
static UnsignedBinaryInteger<T> IMultiplicativeIdentity<UnsignedBinaryInteger<T>, UnsignedBinaryInteger<T>>.MultiplicativeIdentity => One; | |
static int INumberBase<UnsignedBinaryInteger<T>>.Radix => 2; | |
public static UnsignedBinaryInteger<T> One => T.One; | |
public static UnsignedBinaryInteger<T> MaxValue => new(lower: T.AllBitsSet, upper: T.AllBitsSet); | |
public static UnsignedBinaryInteger<T> MinValue => T.Zero; | |
public static UnsignedBinaryInteger<T> Zero => MinValue; | |
private static TOther ConvertToTruncating<TOther>(UnsignedBinaryInteger<T> value) where TOther : IBinaryInteger<TOther> { | |
var lower = TOther.CreateTruncating(value: value.m_lower); | |
return ((BinaryIntegerConstants<TOther>.SizeAsInt > BinaryIntegerConstants<T>.SizeAsInt) ? (lower + TOther.CreateTruncating(value: value.m_upper)) : lower); | |
} | |
static UnsignedBinaryInteger<T> INumberBase<UnsignedBinaryInteger<T>>.Abs(UnsignedBinaryInteger<T> value) => value; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsCanonical(UnsignedBinaryInteger<T> value) => true; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsComplexNumber(UnsignedBinaryInteger<T> value) => false; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsFinite(UnsignedBinaryInteger<T> value) => true; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsImaginaryNumber(UnsignedBinaryInteger<T> value) => false; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsInfinity(UnsignedBinaryInteger<T> value) => false; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsInteger(UnsignedBinaryInteger<T> value) => true; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsNaN(UnsignedBinaryInteger<T> value) => false; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsNegative(UnsignedBinaryInteger<T> value) => false; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsNegativeInfinity(UnsignedBinaryInteger<T> value) => false; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsNormal(UnsignedBinaryInteger<T> value) => (Zero != value); | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsPositive(UnsignedBinaryInteger<T> value) => true; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsPositiveInfinity(UnsignedBinaryInteger<T> value) => false; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsRealNumber(UnsignedBinaryInteger<T> value) => true; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsSubnormal(UnsignedBinaryInteger<T> value) => false; | |
static bool INumberBase<UnsignedBinaryInteger<T>>.IsZero(UnsignedBinaryInteger<T> value) => (Zero == value); | |
static UnsignedBinaryInteger<T> INumberBase<UnsignedBinaryInteger<T>>.MaxMagnitude(UnsignedBinaryInteger<T> x, UnsignedBinaryInteger<T> y) => Max(x: x, y: y); | |
static UnsignedBinaryInteger<T> INumberBase<UnsignedBinaryInteger<T>>.MaxMagnitudeNumber(UnsignedBinaryInteger<T> x, UnsignedBinaryInteger<T> y) => Max(x: x, y: y); | |
static UnsignedBinaryInteger<T> INumberBase<UnsignedBinaryInteger<T>>.MinMagnitude(UnsignedBinaryInteger<T> x, UnsignedBinaryInteger<T> y) => Min(x: x, y: y); | |
static UnsignedBinaryInteger<T> INumberBase<UnsignedBinaryInteger<T>>.MinMagnitudeNumber(UnsignedBinaryInteger<T> x, UnsignedBinaryInteger<T> y) => Min(x: x, y: y); | |
static bool INumberBase<UnsignedBinaryInteger<T>>.TryConvertFromChecked<TOther>(TOther value, out UnsignedBinaryInteger<T> result) { | |
throw new NotImplementedException(); | |
} | |
static bool INumberBase<UnsignedBinaryInteger<T>>.TryConvertFromSaturating<TOther>(TOther value, out UnsignedBinaryInteger<T> result) { | |
throw new NotImplementedException(); | |
} | |
static bool INumberBase<UnsignedBinaryInteger<T>>.TryConvertFromTruncating<TOther>(TOther value, out UnsignedBinaryInteger<T> result) { | |
throw new NotImplementedException(); | |
} | |
static bool INumberBase<UnsignedBinaryInteger<T>>.TryConvertToChecked<TOther>(UnsignedBinaryInteger<T> value, out TOther result) { | |
throw new NotImplementedException(); | |
} | |
static bool INumberBase<UnsignedBinaryInteger<T>>.TryConvertToSaturating<TOther>(UnsignedBinaryInteger<T> value, out TOther result) { | |
throw new NotImplementedException(); | |
} | |
static bool INumberBase<UnsignedBinaryInteger<T>>.TryConvertToTruncating<TOther>(UnsignedBinaryInteger<T> value, out TOther result) { | |
throw new NotImplementedException(); | |
} | |
#if BIGENDIAN | |
private readonly T m_upper; | |
private readonly T m_lower; | |
#else | |
private readonly T m_lower; | |
private readonly T m_upper; | |
#endif | |
public UnsignedBinaryInteger(T upper, T lower) { | |
m_lower = lower; | |
m_upper = upper; | |
} | |
int IBinaryInteger<UnsignedBinaryInteger<T>>.GetByteCount() => (BinaryIntegerConstants<T>.SizeAsInt >> 2); | |
int IBinaryInteger<UnsignedBinaryInteger<T>>.GetShortestBitLength() => (BinaryIntegerConstants<T>.SizeAsInt * 8) - int.CreateTruncating(value: LeadingZeroCount(value: this)); | |
public int CompareTo(UnsignedBinaryInteger<T> value) { | |
if (this < value) { | |
return -1; | |
} | |
else if (this > value) { | |
return 1; | |
} | |
else { | |
return 0; | |
} | |
} | |
public int CompareTo(object? value) { | |
if (value is UnsignedBinaryInteger<T> other) { | |
return CompareTo(value: other); | |
} | |
else if (value is null) { | |
return 1; | |
} | |
else { | |
throw new ArgumentException(); | |
} | |
} | |
public bool Equals(UnsignedBinaryInteger<T> other) => (this == other); | |
public override bool Equals([NotNullWhen(true)] object? obj) => ((obj is UnsignedBinaryInteger<T> other) && Equals(other)); | |
public override int GetHashCode() => HashCode.Combine(value1: m_lower, value2: m_upper); | |
public string ToString(string? format, IFormatProvider? formatProvider) { | |
throw new NotImplementedException(); | |
} | |
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) { | |
throw new NotImplementedException(); | |
} | |
public bool TryWriteBigEndian(Span<byte> destination, out int bytesWritten) { | |
throw new NotImplementedException(); | |
} | |
public bool TryWriteLittleEndian(Span<byte> destination, out int bytesWritten) { | |
throw new NotImplementedException(); | |
} | |
public static bool IsEvenInteger(UnsignedBinaryInteger<T> value) => (T.Zero == (value.m_lower & T.One)); | |
public static bool IsOddInteger(UnsignedBinaryInteger<T> value) => (T.Zero != (value.m_lower & T.One)); | |
public static bool IsPow2(UnsignedBinaryInteger<T> value) => (T.One == PopCount(value: value)); | |
public static UnsignedBinaryInteger<T> LeadingZeroCount(UnsignedBinaryInteger<T> value) { | |
if (T.Zero == value.m_upper) { | |
return (BinaryIntegerConstants<T>.Size + T.LeadingZeroCount(value: value.m_lower)); | |
} | |
return T.LeadingZeroCount(value: value.m_upper); | |
} | |
public static UnsignedBinaryInteger<T> Log2(UnsignedBinaryInteger<T> value) { | |
if (value.m_upper == T.Zero) { | |
return T.Log2(value: value.m_lower); | |
} | |
return (BinaryIntegerConstants<T>.Size + T.Log2(value: value.m_upper)); | |
} | |
public static UnsignedBinaryInteger<T> Max(UnsignedBinaryInteger<T> x, UnsignedBinaryInteger<T> y) => ((x >= y) ? x : y); | |
public static UnsignedBinaryInteger<T> Min(UnsignedBinaryInteger<T> x, UnsignedBinaryInteger<T> y) => ((x <= y) ? x : y); | |
public static UnsignedBinaryInteger<T> Parse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider) { | |
throw new NotImplementedException(); | |
} | |
public static UnsignedBinaryInteger<T> Parse(ReadOnlySpan<char> s, IFormatProvider? provider) { | |
throw new NotImplementedException(); | |
} | |
public static UnsignedBinaryInteger<T> Parse(string s, NumberStyles style, IFormatProvider? provider) { | |
throw new NotImplementedException(); | |
} | |
public static UnsignedBinaryInteger<T> Parse(string s, IFormatProvider? provider) { | |
throw new NotImplementedException(); | |
} | |
public static UnsignedBinaryInteger<T> PopCount(UnsignedBinaryInteger<T> value) => (T.PopCount(value: value.m_lower) + T.PopCount(value: value.m_upper)); | |
public static UnsignedBinaryInteger<T> TrailingZeroCount(UnsignedBinaryInteger<T> value) { | |
if (T.Zero == value.m_lower) { | |
return (BinaryIntegerConstants<T>.Size + T.TrailingZeroCount(value: value.m_upper)); | |
} | |
return T.TrailingZeroCount(value: value.m_lower); | |
} | |
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out UnsignedBinaryInteger<T> result) { | |
throw new NotImplementedException(); | |
} | |
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, [MaybeNullWhen(false)] out UnsignedBinaryInteger<T> result) { | |
throw new NotImplementedException(); | |
} | |
public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out UnsignedBinaryInteger<T> result) { | |
throw new NotImplementedException(); | |
} | |
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out UnsignedBinaryInteger<T> result) { | |
throw new NotImplementedException(); | |
} | |
public static bool TryReadBigEndian(ReadOnlySpan<byte> source, bool isUnsigned, out UnsignedBinaryInteger<T> value) { | |
throw new NotImplementedException(); | |
} | |
public static bool TryReadLittleEndian(ReadOnlySpan<byte> source, bool isUnsigned, out UnsignedBinaryInteger<T> value) { | |
throw new NotImplementedException(); | |
} | |
public static UnsignedBinaryInteger<T> operator +(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) { | |
var lower = (left.m_lower + right.m_lower); | |
var carry = ((lower < left.m_lower) ? T.One : T.Zero); | |
var upper = ((left.m_upper + right.m_upper) + carry); | |
return new UnsignedBinaryInteger<T>( | |
lower: lower, | |
upper: upper | |
); | |
} | |
public static UnsignedBinaryInteger<T> operator checked +(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) { | |
var lower = (left.m_lower + right.m_lower); | |
var carry = ((lower < left.m_lower) ? T.One : T.Zero); | |
var upper = checked((left.m_upper + right.m_upper) + carry); | |
return new UnsignedBinaryInteger<T>( | |
lower: lower, | |
upper: upper | |
); | |
} | |
public static UnsignedBinaryInteger<T> operator +(UnsignedBinaryInteger<T> value) => value; | |
public static UnsignedBinaryInteger<T> operator ++(UnsignedBinaryInteger<T> value) => (value + One); | |
public static UnsignedBinaryInteger<T> operator checked ++(UnsignedBinaryInteger<T> value) => checked(value + One); | |
public static UnsignedBinaryInteger<T> operator -(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) { | |
var lower = (left.m_lower - right.m_lower); | |
var borrow = ((lower > left.m_lower) ? T.One : T.Zero); | |
var upper = ((left.m_upper - right.m_upper) - borrow); | |
return new UnsignedBinaryInteger<T>( | |
lower: lower, | |
upper: upper | |
); | |
} | |
public static UnsignedBinaryInteger<T> operator checked -(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) { | |
var lower = (left.m_lower - right.m_lower); | |
var borrow = ((lower > left.m_lower) ? T.One : T.Zero); | |
var upper = checked((left.m_upper - right.m_upper) - borrow); | |
return new UnsignedBinaryInteger<T>( | |
lower: lower, | |
upper: upper | |
); | |
} | |
public static UnsignedBinaryInteger<T> operator -(UnsignedBinaryInteger<T> value) => (Zero - value); | |
public static UnsignedBinaryInteger<T> operator checked -(UnsignedBinaryInteger<T> value) => checked(Zero - value); | |
public static UnsignedBinaryInteger<T> operator --(UnsignedBinaryInteger<T> value) => (value - One); | |
public static UnsignedBinaryInteger<T> operator checked --(UnsignedBinaryInteger<T> value) => checked(value - One); | |
public static UnsignedBinaryInteger<T> operator *(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) { | |
throw new NotImplementedException(); | |
} | |
public static UnsignedBinaryInteger<T> operator /(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) { | |
throw new NotImplementedException(); | |
} | |
public static UnsignedBinaryInteger<T> operator %(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) { | |
throw new NotImplementedException(); | |
} | |
public static UnsignedBinaryInteger<T> operator &(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) => new(lower: (left.m_lower & right.m_lower), upper: (left.m_upper & right.m_upper)); | |
public static UnsignedBinaryInteger<T> operator |(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) => new(lower: (left.m_lower | right.m_lower), upper: (left.m_upper | right.m_upper)); | |
public static UnsignedBinaryInteger<T> operator ^(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) => new(lower: (left.m_lower ^ right.m_lower), upper: (left.m_upper ^ right.m_upper)); | |
public static UnsignedBinaryInteger<T> operator ~(UnsignedBinaryInteger<T> value) => new(lower: ~value.m_lower, upper: ~value.m_upper); | |
public static UnsignedBinaryInteger<T> operator <<(UnsignedBinaryInteger<T> value, int shiftAmount) { | |
var halfSize = BinaryIntegerConstants<T>.SizeAsInt; | |
if (0 == shiftAmount) { | |
return value; | |
} | |
else if (shiftAmount < halfSize) { | |
return new( | |
lower: (value.m_lower << shiftAmount), | |
upper: ((value.m_upper << shiftAmount) | (value.m_lower >> (halfSize - shiftAmount))) | |
); | |
} | |
else if ((shiftAmount >= halfSize) && (shiftAmount < (halfSize << 1))) { | |
return new( | |
lower: T.Zero, | |
upper: (value.m_lower << (shiftAmount - halfSize)) | |
); | |
} | |
return Zero; | |
} | |
public static UnsignedBinaryInteger<T> operator >>(UnsignedBinaryInteger<T> value, int shiftAmount) { | |
var halfSize = BinaryIntegerConstants<T>.SizeAsInt; | |
if (0 == shiftAmount) { | |
return value; | |
} | |
else if (shiftAmount < halfSize) { | |
return new( | |
lower: ((value.m_lower >> shiftAmount) | (value.m_upper << (halfSize - shiftAmount))), | |
upper: (value.m_upper >> shiftAmount) | |
); | |
} | |
else if ((shiftAmount >= halfSize) && (shiftAmount < (halfSize << 1))) { | |
return new( | |
lower: (value.m_upper >> (shiftAmount - halfSize)), | |
upper: T.Zero | |
); | |
} | |
return Zero; | |
} | |
public static UnsignedBinaryInteger<T> operator >>>(UnsignedBinaryInteger<T> value, int shiftAmount) => (value >> shiftAmount); | |
public static bool operator ==(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) => ((left.m_lower == right.m_lower) && (left.m_upper == right.m_upper)); | |
public static bool operator !=(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) => ((left.m_lower != right.m_lower) || (left.m_upper != right.m_upper)); | |
public static bool operator <(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) => ((left.m_upper < right.m_upper) || ((left.m_lower < right.m_lower) && (left.m_upper == right.m_upper))); | |
public static bool operator <=(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) => ((left.m_upper < right.m_upper) || ((left.m_lower <= right.m_lower) && (left.m_upper == right.m_upper))); | |
public static bool operator >(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) => ((left.m_upper > right.m_upper) || ((left.m_lower > right.m_lower) && (left.m_upper == right.m_upper))); | |
public static bool operator >=(UnsignedBinaryInteger<T> left, UnsignedBinaryInteger<T> right) => ((left.m_upper > right.m_upper) || ((left.m_lower >= right.m_lower) && (left.m_upper == right.m_upper))); | |
public static explicit operator byte(UnsignedBinaryInteger<T> value) => ConvertToTruncating<byte>(value: value); | |
public static explicit operator ushort(UnsignedBinaryInteger<T> value) => ConvertToTruncating<ushort>(value: value); | |
public static explicit operator uint(UnsignedBinaryInteger<T> value) => ConvertToTruncating<uint>(value: value); | |
public static explicit operator ulong(UnsignedBinaryInteger<T> value) => ConvertToTruncating<ulong>(value: value); | |
public static explicit operator UInt128(UnsignedBinaryInteger<T> value) => ConvertToTruncating<UInt128>(value: value); | |
public static implicit operator UnsignedBinaryInteger<T>(T value) => new(lower: value, upper: T.Zero); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment