Skip to content

Instantly share code, notes, and snippets.

@Kittoes0124
Last active May 6, 2024 19:04
Show Gist options
  • Save Kittoes0124/125912c902a476384f3d8a8ca4cbc3fb to your computer and use it in GitHub Desktop.
Save Kittoes0124/125912c902a476384f3d8a8ca4cbc3fb to your computer and use it in GitHub Desktop.
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