(Obsolete) Int128.cs

Int128 Bit Class

Jun-11,2021: Obsolete Use xIntX Instead.

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
[Serializable]
[StructLayout(LayoutKind.Sequential)]
[TypeConverter(typeof(Int128Converter))]
[DebuggerDisplay("{DDisplay}")]
public struct Int128 : IComparable<Int128>, IComparable, IEquatable<Int128>, IConvertible, IFormattable
{
    public        ulong _hi;
    public        ulong _lo;
    private const ulong HiNeg = 0x8000000000000000;
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string DDisplay => "0x" + ToString("X1");
    public static Int128 Zero;
    public static Int128 Ten      = new Int128(10);
    public static Int128 One      = new Int128(1);
    public static Int128 MaxValue = GetMaxValue();
    public static Int128 MinValue = GetMinValue();
    private static Int128 GetMaxValue()
    {
        return new Int128(long.MaxValue, ulong.MaxValue);
    }
    private static Int128 GetMinValue()
    {
        return new Int128(0x8000000000000000, 0);
    }
    /// <summary>
    ///     Either base10 or base 16
    /// </summary>
    public Int128(string value)
    {
        TryParse(value, out var result);
        _hi = result._hi;
        _lo = result._lo;
    }
    public Int128(byte value)
    {
        _hi = 0;
        _lo = value;
    }
    public Int128(bool value)
    {
        _hi = 0;
        _lo = (ulong) (value ? 1 : 0);
    }
    public Int128(char value)
    {
        _hi = 0;
        _lo = value;
    }
    public Int128(decimal value)
    {
        if (value < 0)
        {
            var n = -new Int128(-value);
            _hi = n._hi;
            _lo = n._lo;
            return;
        }
        var bits = decimal.GetBits(value);
        _hi = (uint) bits[2];
        _lo = (uint) bits[0] | ((ulong) bits[1] << 32);
    }
    public Int128(double value)
        : this((decimal) value)
    {
    }
    public Int128(float value)
        : this((decimal) value)
    {
    }
    public Int128(short value)
    {
        if (value < 0)
        {
            var n = -new Int128(-(value + 1)) - 1;
            _hi = n._hi;
            _lo = n._lo;
            return;
        }
        _hi = 0;
        _lo = (ulong) value;
    }
    public Int128(int value)
    {
        if (value < 0)
        {
            var n = -new Int128(-(value + 1)) - 1;
            _hi = n._hi;
            _lo = n._lo;
            return;
        }
        _hi = 0;
        _lo = (ulong) value;
    }
    public Int128(long value)
    {
        if (value < 0)
        {
            var n = -new Int128(-(value + 1)) - 1;
            _hi = n._hi;
            _lo = n._lo;
            return;
        }
        _hi = 0;
        _lo = (ulong) value;
    }
    public Int128(sbyte value)
    {
        if (value < 0)
        {
            var n = -new Int128(-(value + 1)) - 1;
            _hi = n._hi;
            _lo = n._lo;
            return;
        }
        _hi = 0;
        _lo = (ulong) value;
    }
    public Int128(ushort value)
    {
        _hi = 0;
        _lo = value;
    }
    public Int128(uint value)
    {
        _hi = 0;
        _lo = value;
    }
    public Int128(ulong value)
    {
        _hi = 0;
        _lo = value;
    }
    public Int128(Guid value)
        : this(value.ToByteArray())
    {
    }
    public Int128(byte[] value)
    {
        if (value == null)
            throw new ArgumentNullException("value");
        if (value.Length != 16)
            throw new ArgumentException(null, "value");
        _hi = BitConverter.ToUInt64(value, 8);
        _lo = BitConverter.ToUInt64(value, 0);
    }
    public Int128(ulong hi, ulong lo)
    {
        _hi = hi;
        _lo = lo;
    }
    public Int128(int sign, uint[] ints)
    {
        if (ints == null)
            throw new ArgumentNullException("ints");
        var lo = new byte[8];
        var hi = new byte[8];
        if (ints.Length > 0)
        {
            Array.Copy(BitConverter.GetBytes(ints[0]), 0, lo, 0, 4);
            if (ints.Length > 1)
            {
                Array.Copy(BitConverter.GetBytes(ints[1]), 0, lo, 4, 4);
                if (ints.Length > 2)
                {
                    Array.Copy(BitConverter.GetBytes(ints[2]), 0, hi, 0, 4);
                    if (ints.Length > 3)
                        Array.Copy(BitConverter.GetBytes(ints[3]), 0, hi, 4, 4);
                }
            }
        }
        _lo = BitConverter.ToUInt64(lo, 0);
        _hi = BitConverter.ToUInt64(hi, 0);
        if (sign < 0)
            _hi |= HiNeg;
        else
            _hi &= ~HiNeg;
    }
    public int BitWidth
    {
        get
        {
            Int128 bitWidth = 1;
            var    v        = this;
            while ((v >>= 1) > 0)
                bitWidth++;
            if (bitWidth < 8)
                bitWidth = 8;
            while (bitWidth % 8 != 0)
                bitWidth++;
            return (int) bitWidth;
        }
    }
    public int Sign
    {
        get
        {
            if (_hi == 0 && _lo == 0)
                return 0;
            return (_hi & HiNeg) == 0 ? 1 : -1;
        }
    }
    public override int GetHashCode()
    {
        return _hi.GetHashCode() ^ _lo.GetHashCode();
    }
    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }
    public bool Equals(Int128 obj)
    {
        return _hi == obj._hi && _lo == obj._lo;
    }
    public override string ToString()
    {
        return ToString(null, null);
    }
    public string ToString(string format)
    {
        return ToString(format, null);
    }
    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (formatProvider == null)
            formatProvider = CultureInfo.CurrentCulture;
        if (!string.IsNullOrEmpty(format))
        {
            var ch = format[0];
            if (ch == 'x' || ch == 'X')
            {
                int min;
                int.TryParse(format.Substring(1).Trim(), out min);
                return ToHexString(ch == 'X', min);
            }
            if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd')
                throw new NotSupportedException("Not supported format: " + format);
        }
        return ToString((NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo)));
    }
    private string ToHexString(bool caps, int min)
    {
        var sb = new StringBuilder();
        var x  = caps ? "X" : "x";
        if (min < 0 || min > 16 || _hi != 0)
        {
            sb.Append(min > 16 ? _hi.ToString(x + (min - 16)) : _hi.ToString(x));
            sb.Append(_lo.ToString(x + "16"));
        }
        else
        {
            sb.Append(_lo.ToString(x + min));
        }
        return sb.ToString();
    }
    private string ToString(NumberFormatInfo info)
    {
        if (Sign == 0)
            return "0";
        var sb      = new StringBuilder();
        var current = this;
        current._hi &= ~HiNeg;
        Int128 r;
        while (true)
        {
            current = DivRem(current, Ten, out r);
            if (r._lo > 0 || current.Sign != 0 || sb.Length == 0)
                sb.Insert(0, (char) ('0' + r._lo));
            if (current.Sign == 0)
                break;
        }
        var s = sb.ToString();
        if (Sign < 0 && s != "0")
            return info.NegativeSign + s;
        return s;
    }
    TypeCode IConvertible.GetTypeCode()
    {
        return TypeCode.Object;
    }
    bool IConvertible.ToBoolean(IFormatProvider provider)
    {
        return (bool) this;
    }
    byte IConvertible.ToByte(IFormatProvider provider)
    {
        return (byte) this;
    }
    char IConvertible.ToChar(IFormatProvider provider)
    {
        return (char) this;
    }
    DateTime IConvertible.ToDateTime(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
    decimal IConvertible.ToDecimal(IFormatProvider provider)
    {
        return (decimal) this;
    }
    double IConvertible.ToDouble(IFormatProvider provider)
    {
        return (double) this;
    }
    short IConvertible.ToInt16(IFormatProvider provider)
    {
        return (short) this;
    }
    int IConvertible.ToInt32(IFormatProvider provider)
    {
        return (int) this;
    }
    long IConvertible.ToInt64(IFormatProvider provider)
    {
        return (int) this;
    }
    sbyte IConvertible.ToSByte(IFormatProvider provider)
    {
        return (sbyte) this;
    }
    float IConvertible.ToSingle(IFormatProvider provider)
    {
        return (float) this;
    }
    string IConvertible.ToString(IFormatProvider provider)
    {
        return ToString(null, provider);
    }
    public bool TryConvert(Type conversionType, IFormatProvider provider, out object value)
    {
        if (conversionType == typeof(bool))
        {
            value = (bool) this;
            return true;
        }
        if (conversionType == typeof(byte))
        {
            value = (byte) this;
            return true;
        }
        if (conversionType == typeof(char))
        {
            value = (char) this;
            return true;
        }
        if (conversionType == typeof(decimal))
        {
            value = (decimal) this;
            return true;
        }
        if (conversionType == typeof(double))
        {
            value = (double) this;
            return true;
        }
        if (conversionType == typeof(short))
        {
            value = (short) this;
            return true;
        }
        if (conversionType == typeof(int))
        {
            value = (int) this;
            return true;
        }
        if (conversionType == typeof(long))
        {
            value = (long) this;
            return true;
        }
        if (conversionType == typeof(sbyte))
        {
            value = (sbyte) this;
            return true;
        }
        if (conversionType == typeof(float))
        {
            value = (float) this;
            return true;
        }
        if (conversionType == typeof(string))
        {
            value = ToString(null, provider);
            return true;
        }
        if (conversionType == typeof(ushort))
        {
            value = (ushort) this;
            return true;
        }
        if (conversionType == typeof(uint))
        {
            value = (uint) this;
            return true;
        }
        if (conversionType == typeof(ulong))
        {
            value = (ulong) this;
            return true;
        }
        if (conversionType == typeof(byte[]))
        {
            value = ToByteArray();
            return true;
        }
        if (conversionType == typeof(Guid))
        {
            value = new Guid(ToByteArray());
            return true;
        }
        value = null;
        return false;
    }
    public static Int128 Parse(string value)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
    }
    public static Int128 Parse(string value, NumberStyles style)
    {
        return Parse(value, style, NumberFormatInfo.CurrentInfo);
    }
    public static Int128 Parse(string value, IFormatProvider provider)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
    }
    public static Int128 Parse(string value, NumberStyles style, IFormatProvider provider)
    {
        Int128 result;
        if (!TryParse(value, style, provider, out result))
            throw new ArgumentException(null, "value");
        return result;
    }
    public static bool TryParse(string value, out Int128 result)
    {
        return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
    }
    public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out Int128 result)
    {
        result = Zero;
        if (string.IsNullOrEmpty(value))
            return false;
        if (value.StartsWith("x", StringComparison.OrdinalIgnoreCase))
        {
            style |= NumberStyles.AllowHexSpecifier;
            value =  value.Substring(1);
        }
        else
        {
            if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
            {
                style |= NumberStyles.AllowHexSpecifier;
                value =  value.Substring(2);
            }
        }
        if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier)
            return TryParseHex(value, out result);
        return TryParseNum(value, out result);
    }
    private static bool TryParseHex(string value, out Int128 result)
    {
        if (value.Length > 32)
            throw new OverflowException();
        result = Zero;
        var hi  = false;
        var pos = 0;
        for (var i = value.Length - 1; i >= 0; i--)
        {
            var   ch = value[i];
            ulong b;
            if (ch >= '0' && ch <= '9')
                b = (ulong) (ch - '0');
            else if (ch >= 'A' && ch <= 'F')
                b = (ulong) (ch - 'A' + 10);
            else if (ch >= 'a' && ch <= 'f')
                b = (ulong) (ch - 'a' + 10);
            else
                return false;
            if (hi)
            {
                result._hi |= b << pos;
                pos        += 4;
            }
            else
            {
                result._lo |= b << pos;
                pos        += 4;
                if (pos == 64)
                {
                    pos = 0;
                    hi  = true;
                }
            }
        }
        return true;
    }
    private static bool TryParseNum(string value, out Int128 result)
    {
        result = Zero;
        foreach (var ch in value)
        {
            byte b;
            if (ch >= '0' && ch <= '9')
                b = (byte) (ch - '0');
            else
                return false;
            result =  Ten * result;
            result += b;
        }
        return true;
    }
    public object ToType(Type conversionType, IFormatProvider provider)
    {
        object value;
        if (TryConvert(conversionType, provider, out value))
            return value;
        throw new InvalidCastException();
    }
    ushort IConvertible.ToUInt16(IFormatProvider provider)
    {
        if (_hi != 0)
            throw new OverflowException();
        return Convert.ToUInt16(_lo);
    }
    uint IConvertible.ToUInt32(IFormatProvider provider)
    {
        if (_hi != 0)
            throw new OverflowException();
        return Convert.ToUInt32(_lo);
    }
    ulong IConvertible.ToUInt64(IFormatProvider provider)
    {
        if (_hi != 0)
            throw new OverflowException();
        return _lo;
    }
    int IComparable.CompareTo(object obj)
    {
        return Compare(this, obj);
    }
    public static int Compare(Int128 left, object right)
    {
        if (right is Int128)
            return Compare(left, (Int128) right);
        if (right is bool)
            return Compare(left, new Int128((bool) right));
        if (right is byte)
            return Compare(left, new Int128((byte) right));
        if (right is char)
            return Compare(left, new Int128((char) right));
        if (right is decimal)
            return Compare(left, new Int128((decimal) right));
        if (right is double)
            return Compare(left, new Int128((double) right));
        if (right is short)
            return Compare(left, new Int128((short) right));
        if (right is int)
            return Compare(left, new Int128((int) right));
        if (right is long)
            return Compare(left, new Int128((long) right));
        if (right is sbyte)
            return Compare(left, new Int128((sbyte) right));
        if (right is float)
            return Compare(left, new Int128((float) right));
        if (right is ushort)
            return Compare(left, new Int128((ushort) right));
        if (right is uint)
            return Compare(left, new Int128((uint) right));
        if (right is ulong)
            return Compare(left, new Int128((ulong) right));
        var bytes = right as byte[];
        if (bytes != null && bytes.Length != 16)
            return Compare(left, new Int128(bytes));
        if (right is Guid)
            return Compare(left, new Int128((Guid) right));
        throw new ArgumentException();
    }
    public byte[] ToByteArray()
    {
        var bytes = new byte[16];
        Buffer.BlockCopy(BitConverter.GetBytes(_lo), 0, bytes, 0, 8);
        Buffer.BlockCopy(BitConverter.GetBytes(_hi), 0, bytes, 8, 8);
        return bytes;
    }
    public static int Compare(Int128 left, Int128 right)
    {
        if (left.Sign < 0)
        {
            if (right.Sign >= 0)
                return -1;
            var xhi = left._hi  & ~HiNeg;
            var yhi = right._hi & ~HiNeg;
            if (xhi != yhi)
                return -xhi.CompareTo(yhi);
            return -left._lo.CompareTo(right._lo);
        }
        if (right.Sign < 0)
            return 1;
        if (left._hi != right._hi)
            return left._hi.CompareTo(right._hi);
        return left._lo.CompareTo(right._lo);
    }
    public int CompareTo(Int128 value)
    {
        return Compare(this, value);
    }
    public static implicit operator Int128(bool value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(byte value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(char value)
    {
        return new Int128(value);
    }
    public static explicit operator Int128(decimal value)
    {
        return new Int128(value);
    }
    public static explicit operator Int128(double value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(short value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(int value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(long value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(sbyte value)
    {
        return new Int128(value);
    }
    public static explicit operator Int128(float value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(ushort value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(uint value)
    {
        return new Int128(value);
    }
    public static implicit operator Int128(ulong value)
    {
        return new Int128(value);
    }
    public static explicit operator bool(Int128 value)
    {
        return value.Sign != 0;
    }
    public static explicit operator byte(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Sign < 0 || value._lo > 0xFF)
            throw new OverflowException();
        return (byte) value._lo;
    }
    public static explicit operator char(Int128 value)
    {
        if (value.Sign == 0)
            return (char) 0;
        if (value.Sign < 0 || value._lo > 0xFFFF)
            throw new OverflowException();
        return (char) (ushort) value._lo;
    }
    public static explicit operator decimal(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        return new decimal((int) (value._lo & 0xFFFFFFFF), (int) (value._lo >> 32), (int) (value._hi & 0xFFFFFFFF),
            value.Sign < 0, 0);
    }
    public static explicit operator double(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        double d;
        var    nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!double.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out d))
            throw new OverflowException();
        return d;
    }
    public static explicit operator float(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        float f;
        var   nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!float.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out f))
            throw new OverflowException();
        return f;
    }
    public static explicit operator short(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value._lo > 0x8000)
            throw new OverflowException();
        if (value._lo == 0x8000 && value.Sign > 0)
            throw new OverflowException();
        return (short) ((int) value._lo * value.Sign);
    }
    public static explicit operator int(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value._lo > 0x80000000)
            throw new OverflowException();
        if (value._lo == 0x80000000 && value.Sign > 0)
            throw new OverflowException();
        return (int) value._lo * value.Sign;
    }
    public static explicit operator long(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value._lo > long.MaxValue)
            throw new OverflowException();
        return (long) value._lo * value.Sign;
    }
    public static explicit operator uint(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Sign < 0 || value._lo > uint.MaxValue)
            throw new OverflowException();
        return (uint) value._lo;
    }
    public static explicit operator ushort(Int128 value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Sign < 0 || value._lo > ushort.MaxValue)
            throw new OverflowException();
        return (ushort) value._lo;
    }
    public static explicit operator ulong(Int128 value)
    {
        if (value.Sign < 0 || value._hi != 0)
            throw new OverflowException();
        return value._lo;
    }
    public static bool operator >(Int128 left, Int128 right)
    {
        return Compare(left, right) > 0;
    }
    public static bool operator <(Int128 left, Int128 right)
    {
        return Compare(left, right) < 0;
    }
    public static bool operator >=(Int128 left, Int128 right)
    {
        return Compare(left, right) >= 0;
    }
    public static bool operator <=(Int128 left, Int128 right)
    {
        return Compare(left, right) <= 0;
    }
    public static bool operator !=(Int128 left, Int128 right)
    {
        return Compare(left, right) != 0;
    }
    public static bool operator ==(Int128 left, Int128 right)
    {
        return Compare(left, right) == 0;
    }
    public static Int128 operator +(Int128 value)
    {
        return value;
    }
    public static Int128 operator -(Int128 value)
    {
        return Negate(value);
    }
    public static Int128 operator ~(Int128 value)
    {
        return -(value + One);
    }
    public static Int128 operator ++(Int128 value)
    {
        return value + 1;
    }
    public static Int128 operator --(Int128 value)
    {
        return value - 1;
    }
    public static Int128 Negate(Int128 value)
    {
        return new Int128(~value._hi, ~value._lo) + 1;
    }
    public Int128 ToAbs()
    {
        return Abs(this);
    }
    public static Int128 Abs(Int128 value)
    {
        if (value.Sign < 0)
            return -value;
        return value;
    }
    public static Int128 operator +(Int128 left, Int128 right)
    {
        var add = left;
        add._hi += right._hi;
        add._lo += right._lo;
        if (add._lo < left._lo)
            add._hi++;
        return add;
    }
    public static Int128 operator -(Int128 left, Int128 right)
    {
        return left + -right;
    }
    public static Int128 Add(Int128 left, Int128 right)
    {
        return left + right;
    }
    public static Int128 Subtract(Int128 left, Int128 right)
    {
        return left - right;
    }
    public static Int128 Divide(Int128 dividend, Int128 divisor)
    {
        Int128 integer;
        return DivRem(dividend, divisor, out integer);
    }
    public static Int128 DivRem(Int128 dividend, Int128 divisor, out Int128 remainder)
    {
        if (divisor == 0)
            throw new DivideByZeroException();
        uint[] quotient;
        uint[] rem;
        DivRem(dividend.ToUIn32Array(), divisor.ToUIn32Array(), out quotient, out rem);
        remainder = new Int128(1, rem);
        return new Int128(dividend.Sign * divisor.Sign, quotient);
    }
    private static void DivRem(uint[] dividend, uint[] divisor, out uint[] quotient, out uint[] remainder)
    {
        const ulong hiBit       = 0x100000000;
        var         divisorLen  = GetLength(divisor);
        var         dividendLen = GetLength(dividend);
        if (divisorLen <= 1)
        {
            ulong rem = 0;
            var   div = divisor[0];
            quotient  = new uint[dividendLen];
            remainder = new uint[1];
            for (var i = dividendLen - 1; i >= 0; i--)
            {
                rem *= hiBit;
                rem += dividend[i];
                var q = rem / div;
                rem         -= q * div;
                quotient[i] =  (uint) q;
            }
            remainder[0] = (uint) rem;
            return;
        }
        if (dividendLen >= divisorLen)
        {
            var shift        = GetNormalizeShift(divisor[divisorLen - 1]);
            var normDividend = new uint[dividendLen + 1];
            var normDivisor  = new uint[divisorLen];
            Normalize(dividend, dividendLen, normDividend, shift);
            Normalize(divisor,  divisorLen,  normDivisor,  shift);
            quotient = new uint[dividendLen - divisorLen + 1];
            for (var j = dividendLen - divisorLen; j >= 0; j--)
            {
                var dx = hiBit * normDividend[j + divisorLen] + normDividend[j + divisorLen - 1];
                var qj = dx / normDivisor[divisorLen                                        - 1];
                dx -= qj * normDivisor[divisorLen - 1];
                do
                {
                    if (qj < hiBit && qj * normDivisor[divisorLen - 2] <= dx * hiBit + normDividend[j + divisorLen - 2])
                        break;
                    qj -= 1L;
                    dx += normDivisor[divisorLen - 1];
                } while (dx < hiBit);
                long di = 0;
                long dj;
                var  index = 0;
                while (index < divisorLen)
                {
                    var dqj = normDivisor[index] * qj;
                    dj                      = normDividend[index + j] - (uint) dqj - di;
                    normDividend[index + j] = (uint) dj;
                    dqj                     = dqj >> 32;
                    dj                      = dj  >> 32;
                    di                      = (long) dqj - dj;
                    index++;
                }
                dj                           = normDividend[j + divisorLen] - di;
                normDividend[j + divisorLen] = (uint) dj;
                quotient[j]                  = (uint) qj;
                if (dj < 0)
                {
                    quotient[j]--;
                    ulong sum = 0;
                    for (index = 0; index < divisorLen; index++)
                    {
                        sum                     = normDivisor[index] + normDividend[j + index] + sum;
                        normDividend[j + index] = (uint) sum;
                        sum                     = sum >> 32;
                    }
                    sum += normDividend[j + divisorLen];
                    normDividend[j        + divisorLen] = (uint) sum;
                }
            }
            remainder = Unnormalize(normDividend, shift);
            return;
        }
        quotient  = new uint[0];
        remainder = dividend;
    }
    private static int GetLength(uint[] uints)
    {
        var index = uints.Length - 1;
        while (index >= 0 && uints[index] == 0)
            index--;
        return index + 1;
    }
    private static int GetNormalizeShift(uint ui)
    {
        var shift = 0;
        if ((ui & 0xffff0000) == 0)
        {
            ui    =  ui << 16;
            shift += 16;
        }
        if ((ui & 0xff000000) == 0)
        {
            ui    =  ui << 8;
            shift += 8;
        }
        if ((ui & 0xf0000000) == 0)
        {
            ui    =  ui << 4;
            shift += 4;
        }
        if ((ui & 0xc0000000) == 0)
        {
            ui    =  ui << 2;
            shift += 2;
        }
        if ((ui & 0x80000000) == 0)
            shift++;
        return shift;
    }
    private static uint[] Unnormalize(uint[] normalized, int shift)
    {
        var len         = GetLength(normalized);
        var unormalized = new uint[len];
        if (shift > 0)
        {
            var  rshift = 32 - shift;
            uint r      = 0;
            for (var i = len - 1; i >= 0; i--)
            {
                unormalized[i] = (normalized[i] >> shift) | r;
                r              = normalized[i] << rshift;
            }
        }
        else
        {
            for (var j = 0; j < len; j++)
                unormalized[j] = normalized[j];
        }
        return unormalized;
    }
    private static void Normalize(uint[] unormalized, int len, uint[] normalized, int shift)
    {
        int  i;
        uint n = 0;
        if (shift > 0)
        {
            var rshift = 32 - shift;
            for (i = 0; i < len; i++)
            {
                normalized[i] = (unormalized[i] << shift) | n;
                n             = unormalized[i] >> rshift;
            }
        }
        else
        {
            i = 0;
            while (i < len)
            {
                normalized[i] = unormalized[i];
                i++;
            }
        }
        while (i < normalized.Length)
            normalized[i++] = 0;
        if (n != 0)
            normalized[len] = n;
    }
    public static Int128 Remainder(Int128 dividend, Int128 divisor)
    {
        Int128 remainder;
        DivRem(dividend, divisor, out remainder);
        return remainder;
    }
    public static Int128 operator %(Int128 dividend, Int128 divisor)
    {
        return Remainder(dividend, divisor);
    }
    public static Int128 operator /(Int128 dividend, Int128 divisor)
    {
        return Divide(dividend, divisor);
    }
    public ulong[] ToUIn64Array()
    {
        return new[] {_hi, _lo};
    }
    public uint[] ToUIn32Array()
    {
        var ints = new uint[4];
        var lob  = BitConverter.GetBytes(_lo);
        var hib  = BitConverter.GetBytes(_hi);
        Buffer.BlockCopy(lob, 0, ints, 0,  4);
        Buffer.BlockCopy(lob, 4, ints, 4,  4);
        Buffer.BlockCopy(hib, 0, ints, 8,  4);
        Buffer.BlockCopy(hib, 4, ints, 12, 4);
        return ints;
    }
    public static Int128 Multiply(Int128 left, Int128 right)
    {
        var xInts   = left.ToUIn32Array();
        var yInts   = right.ToUIn32Array();
        var mulInts = new uint[8];
        for (var i = 0; i < xInts.Length; i++)
        {
            var   index     = i;
            ulong remainder = 0;
            foreach (var yi in yInts)
            {
                remainder        = remainder + (ulong) xInts[i] * yi + mulInts[index];
                mulInts[index++] = (uint) remainder;
                remainder        = remainder >> 32;
            }
            while (remainder != 0)
            {
                remainder        += mulInts[index];
                mulInts[index++] =  (uint) remainder;
                remainder        =  remainder >> 32;
            }
        }
        return new Int128(left.Sign * right.Sign, mulInts);
    }
    public static Int128 operator *(Int128 left, Int128 right)
    {
        return Multiply(left, right);
    }
    public static Int128 operator >>(Int128 value, int shift)
    {
        if (shift == 0)
            return value;
        if (shift < 0)
            return value << -shift;
        shift = shift % 128;
        var shifted = new Int128();
        if (shift > 63)
        {
            shifted._lo = value._hi >> (shift - 64);
            shifted._hi = 0;
        }
        else
        {
            shifted._hi = value._hi >> shift;
            shifted._lo = (value._hi << (64 - shift)) | (value._lo >> shift);
        }
        return shifted;
    }
    public static Int128 operator <<(Int128 value, int shift)
    {
        if (shift == 0)
            return value;
        if (shift < 0)
            return value >> -shift;
        shift = shift % 128;
        var shifted = new Int128();
        if (shift > 63)
        {
            shifted._hi = value._lo << (shift - 64);
            shifted._lo = 0;
        }
        else
        {
            var ul = value._lo            >> (64 - shift);
            shifted._hi = ul | (value._hi << shift);
            shifted._lo = value._lo << shift;
        }
        return shifted;
    }
    public static Int128 operator |(Int128 left, Int128 right)
    {
        if (left == 0)
            return right;
        if (right == 0)
            return left;
        var x       = left.ToUIn32Array();
        var y       = right.ToUIn32Array();
        var z       = new uint[Math.Max(x.Length, y.Length)];
        var xExtend = left.Sign  < 0 ? uint.MaxValue : 0;
        var yExtend = right.Sign < 0 ? uint.MaxValue : 0;
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : xExtend;
            var yu = i < y.Length ? y[i] : yExtend;
            z[i] = xu | yu;
        }
        return new Int128(left.Sign * right.Sign, z);
    }
    public static Int128 operator ^(Int128 left, Int128 right)
    {
        var x       = left.ToUIn32Array();
        var y       = right.ToUIn32Array();
        var z       = new uint[Math.Max(x.Length, y.Length)];
        var xExtend = left.Sign  < 0 ? uint.MaxValue : 0;
        var yExtend = right.Sign < 0 ? uint.MaxValue : 0;
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : xExtend;
            var yu = i < y.Length ? y[i] : yExtend;
            z[i] = xu ^ yu;
        }
        return new Int128(left.Sign * right.Sign, z);
    }
    public static Int128 operator &(Int128 left, Int128 right)
    {
        if (left == 0 || right == 0)
            return Zero;
        var x       = left.ToUIn32Array();
        var y       = right.ToUIn32Array();
        var z       = new uint[Math.Max(x.Length, y.Length)];
        var xExtend = left.Sign  < 0 ? uint.MaxValue : 0;
        var yExtend = right.Sign < 0 ? uint.MaxValue : 0;
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : xExtend;
            var yu = i < y.Length ? y[i] : yExtend;
            z[i] = xu & yu;
        }
        return new Int128(left.Sign * right.Sign, z);
    }
    public class Int128Converter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
                return true;
            return base.CanConvertFrom(context, sourceType);
        }
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value != null)
            {
                Int128 i;
                if (TryParse($"{value}", out i))
                    return i;
            }
            return new Int128();
        }
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(string))
                return true;
            return base.CanConvertTo(context, destinationType);
        }
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value,
            Type                                                destinationType)
        {
            if (destinationType == typeof(string))
                return $"{value}";
            return base.ConvertTo(context, culture, value, destinationType);
        }
        
    }
}

Mapping64BitToHash32Bit.cs

Maps a 64-Bit Hash Into a 32-Bit Space

using System.Security.Cryptography;
/// <summary>
///     Pros: ~no Collisions within int bit space ~(2,147,483,647)
///     Cons: Maintains a TinyDictionary(byte[],byte[]), non-deterministic across application or
///     method domains
///     Cannot Transform or reuse.
/// </summary>
public class Mapping64BitToHash32Bit : HashAlgorithm
{
    private readonly FNV1a64                        hasher = new FNV1a64();
    public readonly  TinyDictionary<byte[], byte[]> map    = new TinyDictionary<byte[], byte[]>(101, new ArrayComparer());
    private          byte[]                         h64;
    public override  int                            HashSize => 32;
    public override void Initialize()
    {
    }
    /// <inheritdoc />
    /// <summary>
    ///     Compute the 64 Bit hash value and add it and the original array to the map to create a unique position within the
    ///     TinyDictionary.
    /// </summary>
    protected override void HashCore(byte[] bytes, int ibStart, int cbSize)
    {
        h64 = hasher.ComputeHash(bytes, ibStart, cbSize);
        map.Add(h64, bytes);
    }
    /// <inheritdoc />
    /// <summary>
    ///     Return the unique position within the TinyDictionary as the hash value (index).
    /// </summary>
    protected override byte[] HashFinal()
    {
        HashValue = (byte[]) map.FindKeyIndex(h64).GetBytes().Clone();
        return HashValue;
    }
}

FNV1a64.cs

Fowler–Noll–Vo hash function 64-Bit

Updated: Jan-3,2021

using System;
using System.Security.Cryptography;
[Serializable]
public class FNV1a64 : HashAlgorithm
{
    private const ulong K = 0x100000001B3;
    private const ulong M = 0x1000000000000000;
    public        ulong _hash;
    public        ulong Hash;
    public        ulong Seed = 0xCBF29CE484222325;
    public FNV1a64()
    {
        _hash = Seed;
    }
    public FNV1a64(ulong seed)
    {
        Seed  = seed;
        _hash = Seed;
    }
    public override int HashSize => 64;
    public override void Initialize()
    {
        _hash = Seed;
    }
    protected override void HashCore(byte[] bytes, int ibStart, int cbSize)
    {
        Hash64(bytes, ibStart, cbSize);
    }
    private unsafe void Hash64(byte[] bytes, int ibStart, int cbSize)
    {
        if (bytes == null)
            return;
        if (ibStart >= bytes.Length || cbSize > bytes.Length)
            return;
        fixed (byte* pb = bytes)
        {
            var nb = pb + ibStart;
            while (cbSize >= 8)
            {
                _hash  ^= *(ulong*) nb;
                nb     += 8;
                cbSize -= 8;
                _hash  *= K;
                _hash  %= M;
            }
            switch (cbSize & 7)
            {
                case 7:
                    _hash ^= *(ulong*) (nb + 6);
                    _hash *= K;
                    _hash %= M;
                    goto case 6;
                case 6:
                    _hash ^= *(ulong*) (nb + 5);
                    _hash *= K;
                    _hash %= M;
                    goto case 5;
                case 5:
                    _hash ^= *(ulong*) (nb + 4);
                    _hash *= K;
                    _hash %= M;
                    goto case 4;
                case 4:
                    _hash ^= *(ulong*) (nb + 3);
                    _hash *= K;
                    _hash %= M;
                    goto case 3;
                case 3:
                    _hash ^= *(ulong*) (nb + 2);
                    _hash *= K;
                    _hash %= M;
                    goto case 2;
                case 2:
                    _hash ^= *(ulong*) (nb + 1);
                    _hash *= K;
                    _hash %= M;
                    goto case 1;
                case 1:
                    _hash ^= *nb;
                    _hash *= K;
                    _hash %= M;
                    break;
            }
        }
    }
    public unsafe ulong Hash64(byte[] bytes)
    {
        var cbSize = bytes.Length;
        _hash = Seed;
        fixed (byte* pb = bytes)
        {
            var nb = pb;
            while (cbSize >= 8)
            {
                _hash  ^= *(ulong*) nb;
                nb     += 8;
                cbSize -= 8;
                _hash  *= K;
                _hash  %= M;
            }
            switch (cbSize & 7)
            {
                case 7:
                    _hash ^= *(ulong*) (nb + 6);
                    _hash *= K;
                    _hash %= M;
                    goto case 6;
                case 6:
                    _hash ^= *(ulong*) (nb + 5);
                    _hash *= K;
                    _hash %= M;
                    goto case 5;
                case 5:
                    _hash ^= *(ulong*) (nb + 4);
                    _hash *= K;
                    _hash %= M;
                    goto case 4;
                case 4:
                    _hash ^= *(ulong*) (nb + 3);
                    _hash *= K;
                    _hash %= M;
                    goto case 3;
                case 3:
                    _hash ^= *(ulong*) (nb + 2);
                    _hash *= K;
                    _hash %= M;
                    goto case 2;
                case 2:
                    _hash ^= *(ulong*) (nb + 1);
                    _hash *= K;
                    _hash %= M;
                    goto case 1;
                case 1:
                    _hash ^= *nb;
                    _hash *= K;
                    _hash %= M;
                    break;
            }
        }
        return _hash;
    }
    protected override byte[] HashFinal()
    {
        Hash = _hash;
        return _hash.GetBytes();
    }
}

Mapping160BitTo64BitHash.cs

Maps a 160-Bit Hash Into a 64-Bit Space

using System.Security.Cryptography;
/// <summary>
///     Pros: ~no Collisions within long bit space ~(9,223,372,036,854,775,807)
///     Cons: Maintains a TinyDictionary(byte[],byte[]), non-deterministic across application or
///     method domains
///     Cannot Transform or reuse.
/// </summary>
public class Mapping160BitTo64BitHash : HashAlgorithm
{
    public readonly  TinyDictionary<byte[], byte[]> map = new TinyDictionary<byte[], byte[]>(101, new ArrayComparer());
    private          byte[]                         h160;
    private readonly SHA1Managed                    hasher = new SHA1Managed();
    public override  int                            HashSize => 64;
    public override void Initialize()
    {
    }
    /// <inheritdoc />
    /// <summary>
    ///     Compute the 64 Bit hash value and add it and the original array to the map to create a unique position within the
    ///     TinyDictionary.
    /// </summary>
    protected override void HashCore(byte[] bytes, int ibStart, int cbSize)
    {
        h160 = hasher.ComputeHash(bytes, ibStart, cbSize);
        map.Add(h160, bytes);
    }
    /// <inheritdoc />
    /// <summary>
    ///     Return the unique position within the TinyDictionary as the hash value (index).
    /// </summary>
    protected override byte[] HashFinal()
    {
        HashValue = (byte[])map.FindKeyIndex(h160).GetBytes().Clone();
        return HashValue;
    }
}

ArrayComparer.cs

Byte Array Comparer Class

Updated: Dec-22,2020
Updated: May-04,2021

using System;
using System.Collections.Generic;
[Serializable]
public class ArrayComparer : IEqualityComparer<byte[]>
{
    private const ulong M = 0x10000000;
    public bool Equals(byte[] x, byte[] y)
    {
        if (x == null || y == null)
            return false;
        if (x.Length != y.Length)
            return false;
        return x.Compare(y);
    }
    public unsafe int GetHashCode(byte[] obj)
    {
        var cbSize = obj.Length;
        var hash   = 0x811C9DC5;
        fixed (byte* pb = obj)
        {
            var nb = pb;
            while (cbSize >= 4)
            {
                hash   ^= *(uint*) nb;
                hash   *= 0x1000193;
                hash   %= 0x10000000;
                nb     += 4;
                cbSize -= 4;
            }
            switch (cbSize & 3)
            {
                case 3:
                    hash ^= *(uint*) (nb + 2);
                    hash *= 0x1000193;
                    hash %= 0x10000000;
                    goto case 2;
                case 2:
                    hash ^= *(uint*) (nb + 1);
                    hash *= 0x1000193;
                    hash %= 0x10000000;
                    goto case 1;
                case 1:
                    hash ^= *nb;
                    hash *= 0x1000193;
                    hash %= 0x10000000;
                    break;
            }
        }
        return (int) hash;
    }
}

TinyDictionary.cs

A Small Dictionary Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public class TinyDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
    public MSet15<TKey> Keys;
    public int          Resizes;
    public TValue[]     Values;
    public TinyDictionary() : this(101, EqualityComparer<TKey>.Default)
    {
    }
    public TinyDictionary(int size) : this(size, EqualityComparer<TKey>.Default)
    {
    }
    public TinyDictionary(int size, IEqualityComparer<TKey> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<TKey>.Default;
        Keys          = new MSet15<TKey>(size);
        Values        = new TValue[size];
        Keys.Comparer = comparer;
    }
    public TinyDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer = null)
    {
        if (comparer == null)
            comparer = EqualityComparer<TKey>.Default;
        Keys.Comparer = comparer;
        foreach (var kp in collection)
            Add(kp.Key, kp.Value);
    }
    public int Count => Keys.Count;
    public TValue this[TKey key]
    {
        get
        {
            var pos = Keys.FindEntry(key);
            return pos == -1 ? default : Values[pos];
        }
        set => Add(key, value);
    }
    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        for (var i = 0; i < Count; i++)
            if (Keys.Slots[i].HashCode > 0)
                yield return new KeyValuePair<TKey, TValue>(Keys.Slots[i].Value, Values[i]);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public bool Add(TKey key, TValue value)
    {
        if (!Keys.Add(key))
        {
            if (Values.Length != Keys.Slots.Length)
            {
                var nValues = new TValue[Keys.Slots.Length];
                Array.Copy(Values, nValues, Values.Length);
                Values = nValues;
                Resizes++;
            }
            Values[Keys.Position] = value;
            return false;
        }
        Values[Keys.Position] = value;
        return true;
    }
    public void Remove(TKey key)
    {
        var pos = Keys.FindEntry(key);
        if (pos != -1)
        {
            Values[pos] = default;
            Keys.Remove(key);
        }
    }
    public bool ContainsKey(TKey key)
    {
        return Keys.FindEntry(key) != -1;
    }
    public int FindKeyIndex(TKey key)
    {
        return Keys.FindEntry(key);
    }
}

TinySet.cs

A Small HashSet Class

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
[DebuggerTypeProxy(typeof(HashSetDebugView<>))]
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
[Serializable]
public class TinySet<T>
{
    private  int[]                _hashBuckets;
    private  SizeHelper<T>        _newSize = new SizeHelper<T>();
    internal IEqualityComparer<T> Comparer;
    public   int                  Position;
    internal Slot[]               Slots;
    public TinySet() : this(101, EqualityComparer<T>.Default)
    {
    }
    public TinySet(int size) : this(size, EqualityComparer<T>.Default)
    {
    }
    public TinySet(IEqualityComparer<T> comparer) : this(101, comparer)
    {
    }
    public TinySet(int size, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<T>.Default;
        Comparer     = comparer;
        _hashBuckets = new int[size];
        Slots        = new Slot[size];
        Count        = 0;
        Position     = -1;
    }
    public TinySet(IEnumerable<T> collection, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<T>.Default;
        Comparer = comparer;
        if (!(collection is ICollection<T> coll))
            return;
        var size = coll.Count;
        _hashBuckets = new int[size];
        Slots        = new Slot[size];
        UnionWith(coll);
    }
    public int Count
    {
        get;
        private set;
    }
    public T[] ToArray()
    {
        var newArray = new T[Count];
        var copied   = 0;
        for (var i = 0; i < Count && copied < Count; i++)
            if (Slots[i].HashCode > 0)
                newArray[copied++] = Slots[i].Value;
        return newArray;
    }
    public void Create(int size, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<T>.Default;
        Comparer     = comparer;
        _hashBuckets = new int[size];
        Slots        = new Slot[size];
        Count        = 0;
        Position     = -1;
    }
    public void Clear()
    {
        var size = Slots.Length;
        _hashBuckets = new int[size];
        Slots        = new Slot[size];
        Count        = 0;
        Position     = -1;
    }
    public bool Add(T item)
    {
        return Insert(item, true);
    }
    public bool Contains(T item)
    {
        return Insert(item, false);
    }
    internal bool Insert(T item, bool add)
    {
        var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
        if (FindEntry(item, hashCode) != -1)
            return true;
        if (add)
        {
            if (Count >= Slots.Length)
                SetSizeAndOrForceNewHashCodes(_newSize.GetNewSize(_hashBuckets.Length));
            var hashPos = hashCode % _hashBuckets.Length;
            Slots[Count].Next     = _hashBuckets[hashPos] - 1;
            Slots[Count].Value    = item;
            Slots[Count].HashCode = hashCode;
            _hashBuckets[hashPos] = Count + 1;
            Position              = Count;
            ++Count;
        }
        return false;
    }
    public void ForceNewHashCodes()
    {
        SetSizeAndOrForceNewHashCodes();
    }
    private void SetSizeAndOrForceNewHashCodes(int Size = 0)
    {
        if (Count == 0) return;
        var newSize        = Size == 0 ? Count : Size;
        var newSlots       = new Slot[newSize];
        var newHashBuckets = new int[newSize];
        if (Slots != null)
            Array.Copy(Slots, 0, newSlots, 0, Count);
        for (var i = 0; i < newSize; ++i)
            if (newSlots[i].HashCode > 0 && newSlots[i].Value != null)
                newSlots[i].HashCode = Comparer.GetHashCode(newSlots[i].Value) & int.MaxValue;
        for (var i = 0; i < newSize; ++i)
        {
            var pos = newSlots[i].HashCode % newSize;
            newSlots[i].Next    = newHashBuckets[pos] - 1;
            newHashBuckets[pos] = i                   + 1;
        }
        Slots        = newSlots;
        _hashBuckets = newHashBuckets;
    }
    public void TrimExcess()
    {
        var newHashBuckets = new int[Count];
        var newSlots       = new Slot[Count];
        Array.Copy(Slots, newSlots, Count);
        for (var i = 0; i < Count; i++)
        {
            var pos = newSlots[i].HashCode % Count;
            newSlots[i].Next    = newHashBuckets[pos] - 1;
            newHashBuckets[pos] = i                   + 1;
        }
        _hashBuckets = newHashBuckets;
        Slots        = newSlots;
    }
    public bool Remove(T item)
    {
        if (Count != 0)
        {
            var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
            var iPos     = hashCode % _hashBuckets.Length;
            var tPos     = -1;
            for (var sPos = _hashBuckets[iPos] - 1; sPos >= 0; sPos = Slots[sPos].Next)
            {
                if (Slots[sPos].HashCode == hashCode && Comparer.Equals(Slots[sPos].Value, item))
                {
                    if (tPos < 0)
                        _hashBuckets[iPos] = Slots[sPos].Next + 1;
                    else
                        Slots[tPos].Next = Slots[sPos].Next;
                    Slots[sPos].HashCode = -1;
                    Slots[sPos].Value    = default;
                    Slots[sPos].Next     = 0;
                    --Count;
                    return true;
                }
                tPos = sPos;
            }
        }
        return false;
    }
    private int FindEntry(T item, int hashCode)
    {
        for (var position = _hashBuckets[hashCode % _hashBuckets.Length] - 1; position >= 0; position = Slots[position].Next)
            if (Slots[position].HashCode == hashCode && Comparer.Equals(Slots[position].Value, item))
            {
                Position = position;
                return position;
            }
        return -1;
    }
    public int FindEntry(T item)
    {
        return FindEntry(item, Comparer.GetHashCode(item) & int.MaxValue);
    }
    public void ExceptWith(IEnumerable<T> other)
    {
        if (other == null)
            throw new Exception("The other set must not be null.");
        if (Count == 0)
            return;
        if (Equals(other, this))
            Clear();
        else
            foreach (var obj in other)
                Remove(obj);
    }
    public void UnionWith(IEnumerable<T> other)
    {
        if (other == null)
            throw new Exception("The other set must not be null.");
        foreach (var obj in other)
            Add(obj);
    }
    public bool Overlaps(IEnumerable<T> other)
    {
        if (other == null)
            throw new Exception("The other set must not be null.");
        return Count != 0 && other.Any(Contains);
    }
    public bool ContainsAllElements(IEnumerable<T> other)
    {
        return other.All(Contains);
    }
    public int RemoveWhere(Predicate<T> pred)
    {
        if (pred == null)
            throw new Exception("The Predicate cannot be null.");
        var matches = 0;
        for (var i = 0; i < Count; ++i)
            if (Slots[i].HashCode >= 0)
            {
                var obj = Slots[i].Value;
                if (pred(obj) && Remove(obj))
                    ++matches;
            }
        return matches;
    }
    internal struct Slot
    {
        public int HashCode;
        public int Next;
        public T   Value;
    }
}

SizeHelper.cs

Non-Linear Array Size Adjustment Class

using System;
using System.Collections.Generic;
using Microsoft.VisualBasic.Devices;
public class SizeHelper<T>
{
    private static readonly FixedIntXPrimality bp = new FixedIntXPrimality(64);
    private readonly        int                AllocatedSizeLimit;
    public                  int[]              Curve;
    private                 int                Resizes;
    public SizeHelper()
    {
        var measure   = new MeasureSize<T>();
        var sizeOfOne = measure.GetByteSize();
        var am        = new ComputerInfo().AvailablePhysicalMemory;
        AllocatedSizeLimit = (int) ((long) am / sizeOfOne);
    }
    public int GetNewSize(int currentSize)
    {
        Resizes++;
        if (Curve == null)
            BuildCurve(currentSize);
        foreach (var v in Curve)
            if (v > currentSize)
                return v;
        var nv = GetNextValue(currentSize);
        return nv != -1 ? nv : int.MaxValue;
    }
    private int GetNextValue(int currentValue)
    {
        for (var value = currentValue | 1; value < AllocatedSizeLimit; value += 16384)
        {
            if (value < 0)
                break;
            if (bp.IsPrime(value))
                return value + 1;
        }
        return -1;
    }
    private void BuildCurve(int Size)
    {
        int Sizer(int oldSize)
        {
            try
            {
                oldSize = (int) (uint) oldSize;
                var log     = Math.Log(oldSize);
                var inv     = 1.0 / log * 4;
                var newSize = oldSize   * (1.0 + inv);
                return (int) (uint) newSize;
            }
            catch
            {
                return AllocatedSizeLimit;
            }
        }
        var curlst = new List<int>();
        var value  = Size | 1;
        do
        {
            value = Sizer(value);
            if (value < 0)
                break;
            if (value < AllocatedSizeLimit)
                curlst.Add(value);
        } while (value < AllocatedSizeLimit);
        Curve = curlst.ToArray();
        var dl   = new List<int>();
        var last = 0;
        for (var i = 0; i < Curve.Length; ++i)
        {
            if (i > 0)
                last = Curve[i - 1];
            var v = Curve[i];
            dl.Add(v - last);
        }
        var str = "";
        foreach (var v in dl)
            str += $"{v},";
    }
}

MiscByte.cs

Collection of Miscellaneous Byte Helper Functions

public static class MiscByte
{
 public static byte[] Add(this byte[] left, byte[] right)
        {
            var l1 = left.Length;
            var l2 = right.Length;

            if (l1 > 0 && l2 > 0)
            {
                var ret = new byte[l1 + l2];
                Buffer.BlockCopy(left, 0, ret, 0, l1);
                Buffer.BlockCopy(right, 0, ret, l1, l2);
                return ret;
            }

            if (l1 > 0 && l2 == 0)
                return left;

            if (l2 > 0 && l1 == 0)
                return right;

            return new byte[0];
        }

        public static byte[] XOR(this byte[] left, byte[] right)
        {
            var l1 = left.Length;
            var l2 = right.Length;

            if (l1 != l2)
                throw new Exception("Error: left and right arrays lengths must be equal.");

            var ret = new byte[l1];

            for (var i = 0; i < l1; ++i)
                ret[i] = (byte)((left[i] ^ right[i]) & 0xff);

            return ret;
        }

        public static byte[] OR(this byte[] left, byte[] right)
        {
            var l1 = left.Length;
            var l2 = right.Length;

            if (l1 != l2)
                throw new Exception("Error: left and right arrays lengths must be equal.");

            var ret = new byte[l1];

            for (var i = 0; i < l1; ++i)
                ret[i] = (byte)((left[i] | right[i]) & 0xff);

            return ret;
        }

        public static byte[] AND(this byte[] left, byte[] right)
        {
            var l1 = left.Length;
            var l2 = right.Length;

            if (l1 != l2)
                throw new Exception("Error: left and right arrays lengths must be equal.");

            var ret = new byte[l1];

            for (var i = 0; i < l1; ++i)
                ret[i] = (byte)(left[i] & right[i] & 0xff);

            return ret;
        }

        public static byte[] NOT(this byte[] left)
        {
            var l1 = left.Length;
            var ret = new byte[l1];

            for (var i = 0; i < l1; ++i)
                ret[i] = (byte)((ushort)~left[i] & 0xff);

            return ret;
        }

        [SecuritySafeCritical]
        public static unsafe byte[] Clone(this byte[] a1)
        {
            if (a1 == null)
                return null;

            var a2 = new byte[a1.Length];

            fixed (byte* p1 = a1, p2 = a2)
            {
                var Len = a1.Length;
                byte* x1 = p1, x2 = p2;

                while (Len > 7)
                {
                    *(long*)x2 = *(long*)x1;
                    x1 += 8;
                    x2 += 8;
                    Len -= 8;
                }

                switch (Len % 8)
                {
                    case 0:
                        break;
                    case 7:
                        *(int*)x2 = *(int*)x1;
                        x1 += 4;
                        x2 += 4;
                        *(short*)x2 = *(short*)x1;
                        x1 += 2;
                        x2 += 2;
                        *x2 = *x1;
                        break;
                    case 6:
                        *(int*)x2 = *(int*)x1;
                        x1 += 4;
                        x2 += 4;
                        *(short*)x2 = *(short*)x1;
                        break;
                    case 5:
                        *(int*)x2 = *(int*)x1;
                        x1 += 4;
                        x2 += 4;
                        *x2 = *x1;
                        break;
                    case 4:
                        *(int*)x2 = *(int*)x1;
                        break;
                    case 3:
                        *(short*)x2 = *(short*)x1;
                        x1 += 2;
                        x2 += 2;
                        *x2 = *x1;
                        break;
                    case 2:
                        *(short*)x2 = *(short*)x1;
                        break;
                    case 1:
                        *x2 = *x1;
                        break;
                }

                return a2;
            }
        }

        [SecuritySafeCritical]
        public static unsafe bool Copy(this byte[] a1, int aindex, byte[] a2, int bindex, int length)
        {
            if (a1 == null || a2 == null)
                return false;

            fixed (byte* p1 = a1, p2 = a2)
            {
                var Len = length;
                byte* x1 = p1 + aindex, x2 = p2 + bindex;

                while (Len > 7)
                {
                    *(long*)x2 = *(long*)x1;
                    x1 += 8;
                    x2 += 8;
                    Len -= 8;
                }

                switch (Len % 8)
                {
                    case 0:
                        break;
                    case 7:
                        *(int*)x2 = *(int*)x1;
                        x1 += 4;
                        x2 += 4;
                        *(short*)x2 = *(short*)x1;
                        x1 += 2;
                        x2 += 2;
                        *x2 = *x1;
                        break;
                    case 6:
                        *(int*)x2 = *(int*)x1;
                        x1 += 4;
                        x2 += 4;
                        *(short*)x2 = *(short*)x1;
                        break;
                    case 5:
                        *(int*)x2 = *(int*)x1;
                        x1 += 4;
                        x2 += 4;
                        *x2 = *x1;
                        break;
                    case 4:
                        *(int*)x2 = *(int*)x1;
                        break;
                    case 3:
                        *(short*)x2 = *(short*)x1;
                        x1 += 2;
                        x2 += 2;
                        *x2 = *x1;
                        break;
                    case 2:
                        *(short*)x2 = *(short*)x1;
                        break;
                    case 1:
                        *x2 = *x1;
                        break;
                }

                return true;
            }
        }
        
        [SecuritySafeCritical]
        public static unsafe byte[] SubByte(this byte[] a1, int aindex, int length)
        {
            if (a1 == null)
                return null;

            if (aindex + length > a1.Length)
                throw new Exception("Error: SubByte - index + length exceed source array length.");

            var a2 = new byte[length];

            fixed (byte* p1 = a1, p2 = a2)
            {
                var Len = length;
                byte* x1 = p1 + aindex, x2 = p2;

                while (Len > 7)
                {
                    *(long*)x2 = *(long*)x1;
                    x1 += 8;
                    x2 += 8;
                    Len -= 8;
                }

                switch (Len % 8)
                {
                    case 0:
                        break;
                    case 7:
                        *(int*)x2 = *(int*)x1;
                        x1 += 4;
                        x2 += 4;
                        *(short*)x2 = *(short*)x1;
                        x1 += 2;
                        x2 += 2;
                        *x2 = *x1;
                        break;
                    case 6:
                        *(int*)x2 = *(int*)x1;
                        x1 += 4;
                        x2 += 4;
                        *(short*)x2 = *(short*)x1;
                        break;
                    case 5:
                        *(int*)x2 = *(int*)x1;
                        x1 += 4;
                        x2 += 4;
                        *x2 = *x1;
                        break;
                    case 4:
                        *(int*)x2 = *(int*)x1;
                        break;
                    case 3:
                        *(short*)x2 = *(short*)x1;
                        x1 += 2;
                        x2 += 2;
                        *x2 = *x1;
                        break;
                    case 2:
                        *(short*)x2 = *(short*)x1;
                        break;
                    case 1:
                        *x2 = *x1;
                        break;
                }

                return a2;
            }
        }

       [SecuritySafeCritical]
        public static byte[] CloneTo(this byte[] a1)
        {
            var a1l = a1.Length;
            var copy = new byte[a1l];
            a1.Copy(copy);
            return copy;
        }

        [SecuritySafeCritical]
        public static unsafe bool Copy(this byte[] a1, byte[] a2)
        {
            if (a1 == null || a2 == null || a1.Length != a2.Length)
                return false;

            fixed (byte* p1 = a1, p2 = a2)
            {
                var Len = a1.Length;
                byte* x1 = p1, x2 = p2;

                while (Len > 7)
                {
                    *(long*)x2 = *(long*)x1;
                    x1 += 8;
                    x2 += 8;
                    Len -= 8;
                }

                switch (Len % 8)
                {
                    case 0:
                        break;
                    case 7:
                        *(int*)x2 = *(int*)x1;
                        x1 += 4;
                        x2 += 4;
                        *(short*)x2 = *(short*)x1;
                        x1 += 2;
                        x2 += 2;
                        *x2 = *x1;
                        break;
                    case 6:
                        *(int*)x2 = *(int*)x1;
                        x1 += 4;
                        x2 += 4;
                        *(short*)x2 = *(short*)x1;
                        break;
                    case 5:
                        *(int*)x2 = *(int*)x1;
                        x1 += 4;
                        x2 += 4;
                        *x2 = *x1;
                        break;
                    case 4:
                        *(int*)x2 = *(int*)x1;
                        break;
                    case 3:
                        *(short*)x2 = *(short*)x1;
                        x1 += 2;
                        x2 += 2;
                        *x2 = *x1;
                        break;
                    case 2:
                        *(short*)x2 = *(short*)x1;
                        break;
                    case 1:
                        *x2 = *x1;
                        break;
                }

                return true;
            }
        }

        public static bool Compare(this short[] a1, short[] a2)
        {
            var b1 = a1.GetBytes();
            var b2 = a2.GetBytes();

            return b1.Compare(b2);
        }

        public static bool Compare(this byte[] a1, short[] a2)
        {
            var b2 = a2.GetBytes();

            return a1.Compare(b2);
        }

        public static bool Compare(this ushort[] a1, ushort[] a2)
        {
            var b1 = a1.GetBytes();
            var b2 = a2.GetBytes();

            return b1.Compare(b2);
        }

        public static bool Compare(this int[] a1, int[] a2)
        {
            var b1 = a1.GetBytes();
            var b2 = a2.GetBytes();

            return b1.Compare(b2);
        }

        public static bool Compare(this uint[] a1, uint[] a2)
        {
            var b1 = a1.GetBytes();
            var b2 = a2.GetBytes();

            return b1.Compare(b2);
        }

        public static bool Compare(this long[] a1, long[] a2)
        {
            var b1 = a1.GetBytes();
            var b2 = a2.GetBytes();

            return b1.Compare(b2);
        }

        public static bool Compare(this ulong[] a1, ulong[] a2)
        {
            var b1 = a1.GetBytes();
            var b2 = a2.GetBytes();

            return b1.Compare(b2);
        }

        public static bool Compare(this double[] a1, double[] a2)
        {
            var b1 = a1.GetBytes();
            var b2 = a2.GetBytes();

            return b1.Compare(b2);
        }

        public static bool Compare(this float[] a1, float[] a2)
        {
            var b1 = a1.GetBytes();
            var b2 = a2.GetBytes();

            return b1.Compare(b2);
        }

        [SecuritySafeCritical]
        public static unsafe bool Compare(this byte[] a1, byte[] a2)
        {
            if (a1 == null && a2 == null)
                return true;

            if (a1 == null || a2 == null || a1.Length != a2.Length)
                return false;

            fixed (byte* p1 = a1, p2 = a2)
            {
                var Len = a1.Length;
                byte* x1 = p1, x2 = p2;

                while (Len > 7)
                {
                    if (*(long*)x2 != *(long*)x1)
                        return false;
                    x1 += 8;
                    x2 += 8;
                    Len -= 8;
                }

                switch (Len % 8)
                {
                    case 0:
                        break;
                    case 7:
                        if (*(int*)x2 != *(int*)x1)
                            return false;
                        x1 += 4;
                        x2 += 4;
                        if (*(short*)x2 != *(short*)x1)
                            return false;
                        x1 += 2;
                        x2 += 2;
                        if (*x2 != *x1)
                            return false;
                        break;
                    case 6:
                        if (*(int*)x2 != *(int*)x1)
                            return false;
                        x1 += 4;
                        x2 += 4;
                        if (*(short*)x2 != *(short*)x1)
                            return false;
                        break;
                    case 5:
                        if (*(int*)x2 != *(int*)x1)
                            return false;
                        x1 += 4;
                        x2 += 4;
                        if (*x2 != *x1)
                            return false;
                        break;
                    case 4:
                        if (*(int*)x2 != *(int*)x1)
                            return false;
                        break;
                    case 3:
                        if (*(short*)x2 != *(short*)x1)
                            return false;
                        x1 += 2;
                        x2 += 2;
                        if (*x2 != *x1)
                            return false;
                        break;
                    case 2:
                        if (*(short*)x2 != *(short*)x1)
                            return false;
                        break;
                    case 1:
                        if (*x2 != *x1)
                            return false;
                        break;
                }

                return true;
            }
        }

        [SecuritySafeCritical]
        public static unsafe bool Fill(this byte[] a1, byte b1)
        {
            if (a1 == null)
                return false;

            byte[] fbl = { b1, b1, b1, b1, b1, b1, b1, b1 };
            byte[] fbi = { b1, b1, b1, b1 };
            byte[] fbs = { b1, b1 };
            byte[] fbb = { b1 };

            fixed (byte* p1 = a1, p8 = fbl, p4 = fbi, p2 = fbs, p0 = fbb)
            {
                var Len = a1.Length;
                var x1 = p1;

                while (Len > 7)
                {
                    *(long*)x1 = *(long*)p8;
                    x1 += 8;
                    Len -= 8;
                }

                switch (Len % 8)
                {
                    case 0:
                        break;
                    case 7:
                        *(int*)x1 = *(int*)p4;
                        x1 += 4;
                        *(short*)x1 = *(short*)p2;
                        x1 += 2;
                        *x1 = *p0;
                        break;
                    case 6:
                        *(int*)x1 = *(int*)p4;
                        x1 += 4;
                        *(short*)x1 = *(short*)p2;
                        break;
                    case 5:
                        *(int*)x1 = *(int*)p4;
                        x1 += 4;
                        *x1 = *p0;
                        break;
                    case 4:
                        *(int*)x1 = *(int*)p4;
                        break;
                    case 3:
                        *(short*)x1 = *(short*)p2;
                        x1 += 2;
                        *x1 = *p0;
                        break;
                    case 2:
                        *(short*)x1 = *(short*)p2;
                        break;
                    case 1:
                        *x1 = *p0;
                        break;
                }

                return true;
            }
        }

        [SecuritySafeCritical]
        public static unsafe bool Fill(this int[] a1, int i1)
        {
            if (a1 == null)
                return false;

            int[] fbl = { i1, i1 };
            int[] fbi = { i1 };

            fixed (int* p1 = a1, p8 = fbl, p4 = fbi)
            {
                var Len = a1.Length;
                var x1 = p1;

                while (Len > 1)
                {
                    *(long*)x1 = *(long*)p8;
                    x1 += 2;
                    Len -= 2;
                }

                if (Len == 1)
                    *x1 = *p4;

                return true;
            }
        }

        [SecuritySafeCritical]
        public static unsafe bool Fill(this long[] a1, long i1)
        {
            if (a1 == null)
                return false;

            long[] fbi = { i1 };

            fixed (long* p1 = a1, p = fbi)
            {
                var Len = a1.Length;
                var x1 = p1;

                while (Len > 1)
                {
                    *x1 = *p;
                    x1 += 1;
                    Len -= 1;
                }

                return true;
            }
        }

        [SecuritySafeCritical]
        public static unsafe bool Fill(this ulong[] a1, ulong i1)
        {
            if (a1 == null)
                return false;

            ulong[] fbi = { i1 };

            fixed (ulong* p1 = a1, p = fbi)
            {
                var Len = a1.Length;
                var x1 = p1;

                while (Len > 1)
                {
                    *x1 = *p;
                    x1 += 1;
                    Len -= 1;
                }

                return true;
            }
        }
}

ArrayMixer.cs

Uses Sha3 to Shuffle Primitive Arrays

using System;
public class ArrayMixer
{
    private readonly SHA3ModInt _alg;
    private readonly int        _moveSize;
    public ArrayMixer() : this(256, 24)
    {
    }
    public ArrayMixer(int hashSize) : this(hashSize, 24)
    {
    }
    public ArrayMixer(int hashSize, int rounds)
    {
        _alg      = new SHA3ModInt(hashSize, rounds);
        _moveSize = _alg.ComputeHash(2.GetBytes()).Length;
    }
    public byte[] Mix(byte[] buf, int iterations = 1000)
    {
        var bufferSize = buf.Length;
        var lBuffer    = new byte[_moveSize];
        var oBuffer    = new byte[bufferSize];
        for (var i = 0; i < iterations; ++i)
        {
            var bytesSuffled = 0;
            var moveSize     = _moveSize;
            var p            = 0;
            while (true)
            {
                var rBytesShuffle = bufferSize - bytesSuffled;
                if (rBytesShuffle < moveSize)
                    moveSize = rBytesShuffle;
                if (rBytesShuffle <= 0)
                    break;
                Buffer.BlockCopy(buf, p, lBuffer, 0, moveSize);
                lBuffer = _alg.ComputeHash(lBuffer);
                Buffer.BlockCopy(lBuffer, 0, oBuffer, p, moveSize);
                p            += moveSize;
                bytesSuffled += moveSize;
            }
            Buffer.BlockCopy(oBuffer, 0, buf, 0, bufferSize);
        }
        lBuffer.Fill(0);
        oBuffer.Fill(0);
        return buf;
    }
    public ushort[] Mix(ushort[] buf, int iterations = 1000)
    {
        var bb = buf.GetBytes();
        return Mix(bb, iterations).ToUShortArray();
    }
    public uint[] Mix(uint[] buf, int iterations = 1000)
    {
        var bb = buf.GetBytes();
        return Mix(bb, iterations).ToUIntArray();
    }
    public ulong[] Mix(ulong[] buf, int iterations = 1000)
    {
        var bb = buf.GetBytes();
        return Mix(bb, iterations).ToULongArray();
    }
    /// <summary>
    ///     Will round up finalSize to the nearest 8 byte boundary.
    /// </summary>
    /// <param name="ba"></param>
    /// <param name="finalSize"></param>
    /// <returns></returns>
    private static ulong[] ByteArrayToULongArray(byte[] ba, int finalSize)
    {
        var minSize = ba.Length / 8;
        if (finalSize < minSize)
            finalSize = minSize;
        ba = PadULong(ba);
        var os = finalSize / 8;
        if (os * 8 < finalSize)
            os++;
        var result = new ulong[os];
        for (var i = 0; i < ba.Length; i += 8)
            Buffer.BlockCopy(ba, i, result, i, 8);
        return result;
    }
    private static byte[] PadULong(byte[] ba)
    {
        var s = ba.Length % 8;
        switch (s)
        {
            case 0:
                break;
            case 1:
                Array.Resize(ref ba, ba.Length + 7);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                ba[ba.Length - 4] = 0x80;
                ba[ba.Length - 5] = 0x80;
                ba[ba.Length - 6] = 0x80;
                ba[ba.Length - 7] = 0x80;
                break;
            case 2:
                Array.Resize(ref ba, ba.Length + 6);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                ba[ba.Length - 4] = 0x80;
                ba[ba.Length - 5] = 0x80;
                ba[ba.Length - 6] = 0x80;
                break;
            case 3:
                Array.Resize(ref ba, ba.Length + 5);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                ba[ba.Length - 4] = 0x80;
                ba[ba.Length - 5] = 0x80;
                break;
            case 4:
                Array.Resize(ref ba, ba.Length + 4);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                ba[ba.Length - 4] = 0x80;
                break;
            case 5:
                Array.Resize(ref ba, ba.Length + 3);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                break;
            case 6:
                Array.Resize(ref ba, ba.Length + 2);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                break;
            case 7:
                Array.Resize(ref ba, ba.Length + 1);
                ba[ba.Length - 1] = 0x80;
                break;
        }
        return ba;
    }
    private static void Expand(ulong[] x, int iterations = 1)
    {
        var size = x.Length;
        for (var k = 0; k < iterations; ++k)
        for (var i = 0; i < size; ++i)
        {
            ulong n = 0;
            var   j = 0;
            while (j < size)
            {
                n ^= x[j];
                ++j;
            }
            x[i] = (n << 1) | (n >> 56);
        }
    }
    /// <summary>
    ///     ExpandAndMixArray resizes the array by extrusion then mixes the array using a Sha3 one way hash
    /// </summary>
    /// <param name="ba">The buffer</param>
    /// <param name="size">The final desired size</param>
    /// <param name="iterations">The number of iterations to mix the final array</param>
    public byte[] ExpandAndMixArray(byte[] ba, int size, int iterations = 1000)
    {
        var ula = ByteArrayToULongArray(ba, size);
        Expand(ula, 1);
        var array = ula.GetBytes();
        return Mix(array, iterations);
    }
    public ushort[] ExpandAndMixArray(ushort[] ba, int size, int iterations = 1000)
    {
        var bb = ba.GetBytes();
        return ExpandAndMixArray(bb, size, iterations).ToUShortArray();
    }
    public uint[] ExpandAndMixArray(uint[] ba, int size, int iterations = 1000)
    {
        var bb = ba.GetBytes();
        return ExpandAndMixArray(bb, size, iterations).ToUIntArray();
    }
    public ulong[] ExpandAndMixArray(ulong[] ba, int size, int iterations = 1000)
    {
        var bb = ba.GetBytes();
        return ExpandAndMixArray(bb, size, iterations).ToULongArray();
    }
}