FNV1aFbi.cs

Fowler–Noll–Vo hash function 32-1024 Bit Adjustable

using System.Security.Cryptography;
public class FNV1aFbi : HashAlgorithm
{
    private readonly int     _bitWidth;
    private          UIntX   _hash;
    private          int     _hashSize;
    private          UIntX   _k;
    public           UIntX   Seed;
    public FNV1aFbi(int bitWidth)
    {
        _bitWidth = bitWidth;
        SetValues();
    }
    public override int HashSize => _hashSize;
    private void SetValues()
    {
        switch (_bitWidth)
        {
            case 32:
                _k        = new UIntX("16777619",   32);
                Seed      = new UIntX("2166136261", 32);
                _hashSize = 32;
                break;
            case 64:
                _k        = new UIntX("1099511628211",        64);
                Seed      = new UIntX("14695981039346656037", 64);
                _hashSize = 64;
                break;
            case 128:
                _k        = new UIntX("309485009821345068724781371",             128);
                Seed      = new UIntX("144066263297769815596495629667062367629", 128);
                _hashSize = 128;
                break;
            case 256:
                _k        = new UIntX("374144419156711147060143317175368453031918731002211",                            256);
                Seed      = new UIntX("100029257958052580907070968620625704837092796014241193945225284501741471925557", 256);
                _hashSize = 256;
                break;
            case 512:
                _k = new UIntX("35835915874844867368919076489095108449946327955754392558399825615420669938882575126094039892345713852759", 512);
                Seed = new UIntX(
                    "9659303129496669498009435400716310466090418745672637896108374329434462657994582932197716438449813051892206539805784495328239340083876191928701583869517785",
                    512);
                _hashSize = 512;
                break;
            case 1024:
                _k = new UIntX(
                    "5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082573",
                    1024);
                Seed = new UIntX(
                    "14197795064947621068722070641403218320880622795441933960878474914617582723252296732303717722150864096521202355549365628174669108571814760471015076148029755969804077320157692458563003215304957150157403644460363550505412711285966361610267868082893823963790439336411086884584107735010676915",
                    1024);
                _hashSize = 1024;
                break;
        }
        _hash = Seed;
    }
    public override void Initialize()
    {
        _hash = Seed;
    }
    protected override void HashCore(byte[] bytes, int ibStart, int cbSize)
    {
        Hash128(bytes, ibStart, cbSize);
    }
    protected override byte[] HashFinal()
    {
        return _hash.ToByteArray();
    }
    public unsafe void Hash128(byte[] bytes, int ibStart, int cbSize)
    {
        var dwordCount = cbSize / 8;
        fixed (byte* pb = bytes)
        {
            var np = pb;
            for (; dwordCount > 0; --dwordCount, np += 8)
                _hash = (_hash ^ *(ulong*) np) * _k;
            if (cbSize % 8 > 0)
                _hash = (_hash ^ *(ulong*) np) * _k;
        }
    }
    
}

UIntX.cs

Adjustable Bit Width Unsigned Integer 32,64,128,256,512,1024,2048…

using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
[TypeConverter(typeof(FixedUIntXIntConverter))]
[DebuggerDisplay("{DDisplay}")]
public class UIntX : IComparable<UIntX>, IComparable, IEquatable<UIntX>, IConvertible, IFormattable
{
    private const  int    DataSize = sizeof(uint);
    private static int    DataBitLength;
    private static int    DataLength;
    public static  UIntX  Zero = new UIntX("0",  32);
    public static  UIntX  Ten  = new UIntX("10", 32);
    public static  UIntX  One  = new UIntX("1",  32);
    private        uint[] data;
    public UIntX(UIntX value, int bitLength)
    {
        if (value == null)
            return;
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        data          = new uint[DataLength];
        value.data.CopyTo(data, 0);
    }
    public UIntX(string value, int bitLength)
    {
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        if (!TryParse(value, out var result))
            throw new Exception("TryParse Failed.");
        data = new uint[DataLength];
        result.data.CopyTo(data, 0);
    }
    public UIntX(byte value, int bitLength)
    {
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        data          = new uint[DataLength];
        data[0]       = value;
    }
    public UIntX(bool value, int bitLength)
    {
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        data          = new uint[DataLength];
        data[0]       = (uint) (value ? 1 : 0);
    }
    public UIntX(char value, int bitLength)
    {
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        data          = new uint[DataLength];
        data[0]       = value;
    }
    public UIntX(BigDecimal value, int bitLength)
    {
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        var ba = value.UnscaledValue.ToByteArray();
        data = new uint[DataLength];
        for (var i = 0; i < DataLength; i++)
            data[i] = BitConverter.ToUInt32(ba, i * DataSize);
    }
    public UIntX(decimal value, int bitLength)
    {
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        data          = new uint[DataLength];
        if (value < 0)
        {
            var n = -new UIntX(-value, DataBitLength);
            n.data.CopyTo(data, 0);
            return;
        }
        var bits = decimal.GetBits(value);
        data[2] = (uint) bits[2];
        data[1] = (uint) bits[1];
        data[0] = (uint) bits[0];
    }
    public UIntX(double value, int bitLength) : this((decimal) value, bitLength)
    {
    }
    public UIntX(float value, int bitLength) : this((decimal) value, bitLength)
    {
    }
    public UIntX(short value, int bitLength) : this((int) value, bitLength)
    {
    }
    public UIntX(int value, int bitLength)
    {
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        data          = new uint[DataLength];
        data[0]       = (uint) value;
    }
    public UIntX(long value, int bitLength) : this((ulong) value, bitLength)
    {
    }
    public UIntX(sbyte value, int bitLength) : this((int) value, bitLength)
    {
    }
    public UIntX(ushort value, int bitLength)
    {
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        data          = new uint[DataLength];
        data[0]       = value;
    }
    public UIntX(uint value, int bitLength)
    {
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        data          = new uint[DataLength];
        data[0]       = value;
    }
    public UIntX(ulong value, int bitLength)
    {
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        data          = new uint[DataLength];
        data[0]       = (uint) ((value >> 32) & 0xffffffff);
        data[1]       = (uint) (value         & 0xffffffff);
    }
    public UIntX(BigInteger value, int bitLength) : this(value.ToByteArray(), bitLength)
    {
    }
    public UIntX(Guid value, int bitLength) : this(value.ToByteArray(), bitLength)
    {
    }
    public UIntX(byte[] value, int bitLength)
    {
        if (value == null)
            throw new ArgumentNullException("value");
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        var minSize        = value.Length / DataSize;
        var byteCount      = value.Length;
        var isNegative     = byteCount > 0 && (value[byteCount - 1] & 0x80) == 0x80;
        var unalignedBytes = byteCount % DataSize;
        var dwordCount     = byteCount / DataSize + (unalignedBytes == 0 ? 0 : 1);
        data = new uint[Math.Max(dwordCount, minSize)];
        if (byteCount == 0)
            return;
        int curDword, curByte, byteInDword;
        curByte = 3;
        for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++)
        {
            byteInDword = 0;
            while (byteInDword < DataSize)
            {
                data[curDword] <<= 8;
                data[curDword] |=  value[curByte];
                curByte--;
                byteInDword++;
            }
            curByte += 8;
        }
        if (unalignedBytes != 0)
        {
            if (isNegative)
                data[dwordCount - 1] = 0xffffffff;
            for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--)
            {
                data[curDword] <<= 8;
                data[curDword] |=  value[curByte];
            }
        }
    }
    public UIntX(uint[] array, int bitLength)
    {
        if (array == null)
            throw new Exception("Array cannot be null.");
        DataBitLength = bitLength;
        DataLength    = DataBitLength >> 5;
        data          = new uint[DataLength];
        var ba = new byte[4];
        for (var i = 0; i < Math.Min(DataLength, array.Length); i++)
        {
            Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize);
            data[i] = BitConverter.ToUInt32(ba, 0);
        }
    }
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string DDisplay => ToString();
    public UIntX MaxValue => (One << DataBitLength) - 1;
    public bool  IsOne    => this     == One;
    public bool  IsEven   => this % 2 == 0;
    public bool IsZero
    {
        get
        {
            for (var i = 0; i < data.Length; i++)
                if (data[i] != 0)
                    return false;
            return true;
        }
    }
    int IComparable.CompareTo(object obj)
    {
        return Compare(this, obj);
    }
    public int CompareTo(UIntX value)
    {
        return Compare(this, value);
    }
    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 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 (data[1] != 0)
            throw new OverflowException();
        return Convert.ToUInt16(data[0]);
    }
    uint IConvertible.ToUInt32(IFormatProvider provider)
    {
        if (data[1] != 0)
            throw new OverflowException();
        return Convert.ToUInt32(data[0]);
    }
    ulong IConvertible.ToUInt64(IFormatProvider provider)
    {
        if (data[1] != 0)
            throw new OverflowException();
        return data[0];
    }
    public bool Equals(UIntX obj)
    {
        if (ReferenceEquals(obj, null))
            return false;
        if (ReferenceEquals(this, obj))
            return true;
        if (data.Length != obj.data.Length)
            return false;
        for (var i = 0; i < data.Length; i++)
            if (data[i] != obj.data[i])
                return false;
        return true;
    }
    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.TryParse(format.Substring(1).Trim(), out var 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)), 10);
    }
    private static byte[] ToByteArray(ulong[] value)
    {
        var ba = new byte[value.Length << 3];
        Buffer.BlockCopy(value, 0, ba, 0, value.Length << 3);
        return ba;
    }
    private static byte[] ToByteArray(uint[] value)
    {
        var ba = new byte[value.Length << 2];
        Buffer.BlockCopy(value, 0, ba, 0, value.Length << 2);
        return ba;
    }
    public override int GetHashCode()
    {
        var hash = 0x811c9dc5;
        for (var i = 0; i < DataLength; i++)
        {
            hash ^= ((hash << 13) | (hash >> 19)) ^ data[i];
            hash *= 0x1000193;
        }
        return (int) hash;
    }
    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }
    public override string ToString()
    {
        return ToString(null, null);
    }
    public string ToString(string format)
    {
        return ToString(format, null);
    }
    private string ToHexString(bool caps, int min)
    {
        var bytes = ToByteArray().Invert();
        var sb    = new StringBuilder();
        var x     = caps ? "X" : "x";
        foreach (var b in bytes)
        {
            var hex = b.ToString($"{x}2");
            sb.Append(hex);
        }
        return sb.ToString();
    }
    private string ToString(NumberFormatInfo info, int radix)
    {
        if (radix < 2 || radix > 36)
            throw new ArgumentOutOfRangeException("radix");
        if (IsZero)
            return "0";
        var          a       = new UIntX(this,  DataBitLength);
        var          biRadix = new UIntX(radix, DataBitLength);
        const string charSet = "0123456789abcdefghijklmnopqrstuvwxyz";
        var          al      = new ArrayList();
        while (a > 0)
            try
            {
                Divide(a, biRadix, out var remainder, out var quotient);
                al.Insert(0, charSet[(int) remainder.data[0]]);
                a = quotient;
            }
            catch (Exception ex)
            {
                break;
            }
        var result = new string((char[]) al.ToArray(typeof(char)));
        return result;
    }
    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 UIntX Parse(string value)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
    }
    public static UIntX Parse(string value, NumberStyles style)
    {
        return Parse(value, style, NumberFormatInfo.CurrentInfo);
    }
    public static UIntX Parse(string value, IFormatProvider provider)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
    }
    public static UIntX Parse(string value, NumberStyles style, IFormatProvider provider)
    {
        if (!TryParse(value, style, provider, out var result))
            throw new Exception($"TryParse value {value} failure.");
        return result;
    }
    public static bool TryParse(string value, out UIntX result)
    {
        return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
    }
    public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out UIntX 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 TryParseNum(value, 16, out result);
        return TryParseNum(value, 10, out result);
    }
    public static bool TryParseNum(string digits, int radix, out UIntX result)
    {
        result = new UIntX(0, DataBitLength);
        if (digits == null)
            return false;
        var multiplier = new UIntX(1, DataBitLength);
        digits = digits.ToUpper(CultureInfo.CurrentCulture).Trim();
        var nDigits = digits[0] == '-' ? 1 : 0;
        for (var idx = digits.Length - 1; idx >= nDigits; idx--)
        {
            var d = (int) digits[idx];
            if (d >= '0' && d <= '9')
                d -= '0';
            else if (d >= 'A' && d <= 'Z')
                d = d - 'A' + 10;
            else
                return false;
            if (d >= radix)
                return false;
            result     += multiplier * d;
            multiplier *= radix;
        }
        if (digits[0] == '-')
            result = -result;
        return true;
    }
    public static int Compare(UIntX left, object right)
    {
        if (right is UIntX)
            return Compare(left, (UIntX) right);
        if (right is bool)
            return Compare(left, new UIntX((bool) right, DataBitLength));
        if (right is byte)
            return Compare(left, new UIntX((byte) right, DataBitLength));
        if (right is char)
            return Compare(left, new UIntX((char) right, DataBitLength));
        if (right is decimal)
            return Compare(left, new UIntX((decimal) right, DataBitLength));
        if (right is double)
            return Compare(left, new UIntX((double) right, DataBitLength));
        if (right is short)
            return Compare(left, new UIntX((short) right, DataBitLength));
        if (right is int)
            return Compare(left, new UIntX((int) right, DataBitLength));
        if (right is long)
            return Compare(left, new UIntX((long) right, DataBitLength));
        if (right is sbyte)
            return Compare(left, new UIntX((sbyte) right, DataBitLength));
        if (right is float)
            return Compare(left, new UIntX((float) right, DataBitLength));
        if (right is ushort)
            return Compare(left, new UIntX((ushort) right, DataBitLength));
        if (right is uint)
            return Compare(left, new UIntX((uint) right, DataBitLength));
        if (right is ulong)
            return Compare(left, new UIntX((ulong) right, DataBitLength));
        var bytes = right as byte[];
        if (bytes != null && bytes.Length != 64)
            return Compare(left, new UIntX(bytes, DataBitLength));
        if (right is Guid)
            return Compare(left, new UIntX((Guid) right, DataBitLength));
        throw new ArgumentException();
    }
    public static int Compare(UIntX left, UIntX right)
    {
        if (left.data.Length < right.data.Length)
            return -1;
        if (ReferenceEquals(left, right))
            return 0;
        if (ReferenceEquals(left, null))
            throw new ArgumentNullException("left");
        if (ReferenceEquals(right, null))
            throw new ArgumentNullException("right");
        if (left > right) return 1;
        if (left == right) return 0;
        return -1;
    }
    public static implicit operator UIntX(bool value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static implicit operator UIntX(byte value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static implicit operator UIntX(char value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static explicit operator UIntX(decimal value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static explicit operator UIntX(double value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static implicit operator UIntX(short value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static implicit operator UIntX(int value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static implicit operator UIntX(long value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static implicit operator UIntX(sbyte value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static explicit operator UIntX(float value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static implicit operator UIntX(ushort value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static implicit operator UIntX(uint value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static implicit operator UIntX(ulong value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static implicit operator UIntX(BigInteger value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static implicit operator UIntX(BigDecimal value)
    {
        return new UIntX(value, DataBitLength);
    }
    public static explicit operator bool(UIntX value)
    {
        return (byte) value.data[0] != 0;
    }
    public static explicit operator byte(UIntX value)
    {
        return (byte) value.data[0];
    }
    public static explicit operator char(UIntX value)
    {
        return (char) (ushort) value.data[0];
    }
    public static explicit operator decimal(UIntX value)
    {
        return new decimal((int) value.data[0], (int) value.data[1], (int) value.data[2], false, 0);
    }
    public static explicit operator double(UIntX value)
    {
        var nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!double.TryParse(value.ToString(nfi, 10), NumberStyles.Number, nfi, out var d))
            throw new OverflowException();
        return d;
    }
    public static explicit operator float(UIntX value)
    {
        var nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!float.TryParse(value.ToString(nfi, 10), NumberStyles.Number, nfi, out var f))
            throw new OverflowException();
        return f;
    }
    public static explicit operator short(UIntX value)
    {
        return (short) (int) value.data[0];
    }
    public static explicit operator int(UIntX value)
    {
        return (int) value.data[0];
    }
    public static explicit operator long(UIntX value)
    {
        if (value.data[1] != 0)
            return (long) (((ulong) value.data[1] << 32) | value.data[0]);
        return value.data[0];
    }
    public static explicit operator uint(UIntX value)
    {
        return value.data[0];
    }
    public static explicit operator ushort(UIntX value)
    {
        return (ushort) value.data[0];
    }
    public static explicit operator ulong(UIntX value)
    {
        if (value.data[1] != 0)
            return ((ulong) value.data[1] << 32) | value.data[0];
        return value.data[0];
    }
    public static explicit operator BigInteger(UIntX value)
    {
        return new BigInteger(value.ToByteArray());
    }
    public static bool operator >(UIntX left, UIntX right)
    {
        if (left.data.Length > right.data.Length)
            return false;
        if (left.data.Length < right.data.Length)
            return true;
        if (ReferenceEquals(left, null))
            throw new ArgumentNullException("left");
        if (ReferenceEquals(right, null))
            throw new ArgumentNullException("right");
        for (var i = 0; i < DataLength; i++)
            if (left.data[i] != right.data[i])
                return left.data[i] > right.data[i];
        return false;
    }
    public static bool operator <(UIntX left, UIntX right)
    {
        return Compare(left, right) < 0;
    }
    public static bool operator >=(UIntX left, UIntX right)
    {
        return Compare(left, right) >= 0;
    }
    public static bool operator <=(UIntX left, UIntX right)
    {
        return Compare(left, right) <= 0;
    }
    public static bool operator !=(UIntX left, UIntX right)
    {
        return Compare(left, right) != 0;
    }
    public static bool operator ==(UIntX left, UIntX right)
    {
        if (ReferenceEquals(left, right))
            return true;
        if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
            return false;
        return left.Equals(right);
    }
    public static UIntX operator +(UIntX value)
    {
        return value;
    }
    public static UIntX operator ~(UIntX value)
    {
        var da = new uint[DataLength];
        for (var idx = 0; idx < DataLength; idx++)
            da[idx] = ~value.data[idx];
        return new UIntX(da, DataBitLength);
    }
    public static UIntX operator -(UIntX value)
    {
        return Negate(value);
    }
    public static UIntX operator ++(UIntX value)
    {
        return value + 1;
    }
    public static UIntX operator --(UIntX value)
    {
        return value - 1;
    }
    public static UIntX Negate(UIntX value)
    {
        for (var i = 0; i < DataLength; i++)
            value.data[i] = ~value.data[i];
        return new UIntX(value, DataBitLength);
    }
    public static UIntX operator +(UIntX left, UIntX right)
    {
        var  dl     = left.data.Length > right.data.Length ? left.data.Length : right.data.Length;
        var  result = new uint[dl];
        long carry  = 0;
        for (var i = 0; i < dl; i++)
        {
            var sum = left.data[i] + (long) right.data[i] + carry;
            carry     = sum >> 32;
            result[i] = (uint) (sum & 0xFFFFFFFF);
        }
        if (carry != 0)
        {
            var idx = 0;
            while (idx < result.Length - 1)
            {
                if (result[idx] == 0)
                    break;
                idx++;
            }
            result[idx] = (uint) carry;
        }
        return new UIntX(result, DataBitLength);
    }
    public static UIntX operator -(UIntX left, UIntX right)
    {
        var  size  = Math.Max(left.data.Length, right.data.Length) + 1;
        var  da    = new uint[size];
        long carry = 0;
        for (var i = 0; i < da.Length - 1; i++)
        {
            var diff = left.data[i] - (long) right.data[i] - carry;
            da[i] = (uint) (diff & DigitsArray.AllBits);
            carry = diff < 0 ? 1 : 0;
        }
        return new UIntX(da, DataBitLength);
    }
    public static UIntX Add(UIntX left, UIntX right)
    {
        return left + right;
    }
    public static UIntX Subtract(UIntX left, UIntX right)
    {
        return left - right;
    }
    public static UIntX Divide(UIntX dividend, UIntX divisor)
    {
        return DivRem(dividend, divisor, out var integer);
    }
    public static void Divide(UIntX dividend, UIntX divisor, out UIntX remainder, out UIntX quotient)
    {
        if (divisor == 0)
            throw new DivideByZeroException();
        DivRem(dividend.data, divisor.data, out var quo, out var rem);
        remainder = new UIntX(rem, DataBitLength);
        quotient  = new UIntX(quo, DataBitLength);
    }
    public static UIntX DivRem(UIntX dividend, UIntX divisor, out UIntX remainder)
    {
        if (divisor == 0)
            throw new DivideByZeroException();
        DivRem(dividend.data, divisor.data, out var quotient, out var rem);
        remainder = new UIntX(rem, DataBitLength);
        return new UIntX(quotient, DataBitLength);
    }
    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);
                ulong di = 0;
                ulong 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                      = dqj - dj;
                    index++;
                }
                dj                           = normDividend[j + divisorLen] - di;
                normDividend[j + divisorLen] = (uint) dj;
                quotient[j]                  = (uint) qj;
                if ((long) 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[1];
        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 unnormalized = new uint[len];
        if (shift > 0)
        {
            var  rshift = 32 - shift;
            uint r      = 0;
            for (var i = len - 1; i >= 0; i--)
            {
                unnormalized[i] = (normalized[i] >> shift) | r;
                r               = normalized[i] << rshift;
            }
        }
        else
        {
            for (var j = 0; j < len; j++)
                unnormalized[j] = normalized[j];
        }
        return unnormalized;
    }
    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 UIntX Remainder(UIntX dividend, UIntX divisor)
    {
        DivRem(dividend, divisor, out var remainder);
        return remainder;
    }
    public static UIntX Max(UIntX left, UIntX right)
    {
        return left.CompareTo(right) < 0 ? right : left;
    }
    public static UIntX Min(UIntX left, UIntX right)
    {
        return left.CompareTo(right) <= 0 ? left : right;
    }
    public static UIntX operator %(UIntX dividend, UIntX divisor)
    {
        return Remainder(dividend, divisor);
    }
    public static UIntX operator /(UIntX dividend, UIntX divisor)
    {
        return Divide(dividend, divisor);
    }
    public ulong[] ToUIn64Array()
    {
        var al = data.Length >> 1;
        if (al * 2 != data.Length)
            al++;
        var arr = new ulong[al];
        Buffer.BlockCopy(data, 0, arr, 0, data.Length << 2);
        return arr;
    }
    public uint[] ToUIn32Array()
    {
        return data;
    }
    public byte[] ToByteArray()
    {
        var ba = new byte[data.Length * DataSize];
        Buffer.BlockCopy(data, 0, ba, 0, data.Length * DataSize);
        return ba;
    }
    public byte[] ToByteArray(int length)
    {
        if (length <= 0 || length > data.Length * DataSize)
            throw new ArgumentException($"Length {length} out of range length > 0 or length <= {data.Length * DataSize}");
        var ba = new byte[length];
        Buffer.BlockCopy(data, 0, ba, 0, length);
        return ba;
    }
    public static UIntX Multiply(UIntX left, UIntX right)
    {
        var xInts   = left.data;
        var yInts   = right.data;
        var mulInts = new uint[Math.Max(xInts.Length, yInts.Length) << 1];
        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 UIntX(mulInts, DataBitLength);
    }
    public static UIntX operator *(UIntX left, UIntX right)
    {
        return Multiply(left, right);
    }
    public static UIntX operator >>(UIntX value, int shift)
    {
        if (value == Zero)
            return Zero;
        var xd          = (uint[]) value.data.Clone();
        var shiftAmount = 32;
        var invShift    = 0;
        var bufLen      = xd.Length;
        while (bufLen > 1 && xd[bufLen - 1] == 0)
            bufLen--;
        for (var count = shift; count > 0; count -= shiftAmount)
        {
            if (count < shiftAmount)
            {
                shiftAmount = count;
                invShift    = 32 - shiftAmount;
            }
            ulong carry = 0;
            for (var i = bufLen - 1; i >= 0; i--)
            {
                var val = (ulong) xd[i] >> shiftAmount;
                val   |= carry;
                carry =  (ulong) xd[i] << invShift;
                xd[i] =  (uint) val;
            }
        }
        return new UIntX(xd, DataBitLength);
    }
    public static UIntX operator <<(UIntX value, int shift)
    {
        if (value == Zero)
            return Zero;
        var digitShift = shift / 32;
        var smallShift = shift - digitShift * 32;
        var xd         = (uint[]) value.data.Clone();
        var xl         = xd.Length;
        var zd         = new uint[xl + digitShift + 1];
        if (smallShift == 0)
        {
            for (var index = 0; index < xl; ++index)
                zd[index + digitShift] = xd[index];
        }
        else
        {
            var  carryShift = 32 - smallShift;
            uint carry      = 0;
            int  index;
            for (index = 0; index < xl; ++index)
            {
                var rot = xd[index];
                zd[index + digitShift] = (rot << smallShift) | carry;
                carry                  = rot >> carryShift;
            }
            zd[index + digitShift] = carry;
        }
        return new UIntX(zd, DataBitLength);
    }
    public static UIntX operator |(UIntX left, UIntX right)
    {
        if (left == 0)
            return right;
        if (right == 0)
            return left;
        var z = new uint[Math.Max(left.data.Length, right.data.Length)];
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < left.data.Length ? left.data[i] : 0U;
            var yu = i < right.data.Length ? right.data[i] : 0U;
            z[i] = xu | yu;
        }
        return new UIntX(z, DataBitLength);
    }
    public static UIntX operator ^(UIntX left, UIntX right)
    {
        var z = new uint[Math.Max(left.data.Length, right.data.Length)];
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < left.data.Length ? left.data[i] : 0U;
            var yu = i < right.data.Length ? right.data[i] : 0U;
            z[i] = xu ^ yu;
        }
        return new UIntX(z, DataBitLength);
    }
    public static UIntX operator &(UIntX left, UIntX right)
    {
        if (left == 0 || right == 0)
            return Zero;
        var z = new uint[Math.Max(left.data.Length, right.data.Length)];
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < left.data.Length ? left.data[i] : 0U;
            var yu = i < right.data.Length ? right.data[i] : 0U;
            z[i] = xu & yu;
        }
        return new UIntX(z, DataBitLength);
    }
    private class UIntXConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
        }
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value != null)
                if (TryParse($"{value}", out var i))
                    return i;
            return new UIntX("0", DataBitLength);
        }
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
        }
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            return destinationType == typeof(string) ? $"{value}" : base.ConvertTo(context, culture, value, destinationType);
        }
    }
}

DynConcurrentSet.cs

Dynamic Concurrent Set Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
[DebuggerTypeProxy(typeof(HashSetDebugView<>))]
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
[Serializable]
public class DynConcurrentSet<T> : MonitorActionFunc, IEnumerable<T>
{
    private         int[]                _hashBuckets;
    internal        IEqualityComparer<T> Comparer;
    public volatile int                  Count;
    internal        Slot[]               Slots;
    public DynConcurrentSet() : this(101, EqualityComparer<T>.Default)
    {
    }
    public DynConcurrentSet(int size) : this(size, EqualityComparer<T>.Default)
    {
    }
    public DynConcurrentSet(IEqualityComparer<T> comparer) : this(101, comparer)
    {
    }
    public DynConcurrentSet(int size, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<T>.Default;
        Comparer     = comparer;
        _hashBuckets = new int[size];
        Slots        = new Slot[size];
        Count        = 0;
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public IEnumerator<T> GetEnumerator()
    {
        return GetEnum();
    }
    public IEnumerator<T> GetEnum()
    {
        var slots = Slots;
        var count = Count;
        for (var i = 0; i < count; i++)
            if (slots[i].HashCode > 0)
                yield return slots[i].Value;
    }
    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;
    }
    public void Clear()
    {
        var tmpThis = this;
        tmpThis.Lock(tmpThis, () =>
        {
            var size = Slots.Length;
            _hashBuckets = new int[size];
            Slots        = new Slot[size];
            Count        = 0;
        });
    }
    public bool Add(T item)
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            return Insert(item, true);
        });
    }
    public int AddRange(IEnumerable<T> items)
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            return items.Sum(i => !Add(i) ? 0 : 1);
        });
    }
    public bool Contains(T item)
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            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(_hashBuckets.Length + _hashBuckets.Length / 4 * 3);
            var hashPos = hashCode % _hashBuckets.Length;
            Slots[Count].Next     = _hashBuckets[hashPos] - 1;
            Slots[Count].Value    = item;
            Slots[Count].HashCode = hashCode;
            _hashBuckets[hashPos] = Count + 1;
            Interlocked.Increment(ref Count);
        }
        return false;
    }
    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;
    }
    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))
                return position;
        return -1;
    }
    internal struct Slot
    {
        public int HashCode;
        public int Next;
        public T   Value;
    }
}

DynConcurrentList.cs

Dynamic Concurrent Generic List

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public class DynConcurrentList<T> : MonitorActionFunc, IEnumerable<T>
{
    private          T[]        _array;
    private volatile MiniSet<T> _mSet;
    public volatile  int        Count;
    public DynConcurrentList() : this(101)
    {
    }
    public DynConcurrentList(IEnumerable<T> collection)
    {
        var enumerable = collection as T[] ?? collection.ToArray();
        Count  = enumerable.Length;
        _array = new T[Count];
        Array.Copy(enumerable, 0, _array, 0, Count);
    }
    public DynConcurrentList(int cap)
    {
        _array = new T[cap];
        Count  = 0;
    }
    public int Capacity
    {
        get
        {
            var tmpThis = this;
            return tmpThis.Lock(tmpThis, () =>
            {
                return _array.Length;
            });
        }
        set
        {
            var tmpThis = this;
            tmpThis.Lock(tmpThis, () =>
            {
                Array.Resize(ref _array, value);
            });
        }
    }
    public T this[int index]
    {
        get
        {
            var array   = _array;
            var idx     = index;
            var tmpThis = this;
            return tmpThis.Lock(tmpThis, () =>
            {
                if (idx > array.Length)
                    throw new Exception("Error: Index out of range.");
                return array[idx];
            });
        }
        set
        {
            var tmpThis = this;
            var idx     = index;
            tmpThis.Lock(tmpThis, () =>
            {
                if (idx >= _array.Length)
                    Array.Resize(ref _array, _array.Length + _array.Length / 4 * 3);
                _array[idx] = value;
            });
        }
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Add(T item)
    {
        var tmpThis = this;
        tmpThis.Lock(tmpThis, () =>
        {
            if (Count >= _array.Length)
                Array.Resize(ref _array, _array.Length + _array.Length / 4 * 3);
            _array[Count] = item;
            Interlocked.Increment(ref Count);
        });
    }
    public void AddRange(IEnumerable<T> col)
    {
        var tmpThis = this;
        tmpThis.Lock(tmpThis, () =>
        {
            var enumerable = col as T[] ?? col.ToArray();
            for (var i = 0; i < enumerable.Length; ++i)
            {
                if (Count >= _array.Length)
                    Array.Resize(ref _array, _array.Length + _array.Length / 4 * 3);
                _array[Count] = enumerable[i];
                Interlocked.Increment(ref Count);
            }
        });
    }
    public void Clear()
    {
        var tmpThis = this;
        tmpThis.Lock(tmpThis, () =>
        {
            Array.Clear(_array, 0, _array.Length);
            Count = 0;
        });
    }
    public void Clean()
    {
        var tmpThis = this;
        tmpThis.Lock(tmpThis, () =>
        {
            var newtArray = new T[Count];
            Array.Copy(_array, 0, newtArray, 0, Count);
            _array = newtArray;
        });
    }
    public bool Contains(T item, IEqualityComparer<T> comparer = null)
    {
        if (comparer == null)
            comparer = EqualityComparer<T>.Default;
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            if (_mSet != null && _mSet.Count != Count)
            {
                _mSet = new MiniSet<T>(_array, comparer);
            }
            else
            {
                _mSet = new MiniSet<T>(Count, comparer);
                Clean();
                _mSet.AddRange(_array);
            }
            return _mSet.Contains(item);
        });
    }
    public void CopyTo(int index, T[] array, int arrayIndex, int count)
    {
        if (Capacity - index < count)
            throw new Exception("Collection too small.");
        var tmpThis = this;
        tmpThis.Lock(tmpThis, () =>
        {
            Array.Copy(_array, index, array, arrayIndex, count);
        });
    }
    public void ForEach(Action<T> action)
    {
        if (action == null)
            throw new Exception("Action cannot be null.");
        for (var index = 0; index < Count; ++index)
            action(_array[index]);
    }
    public void ParallelForEach(Action<T> action)
    {
        _array.AsParallel().ForAll(i =>
        {
            if (action == null)
                throw new Exception("Action cannot be null.");
            action(i);
        });
    }
    public int IndexOf(T item, int index)
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            if (index > Count)
                throw new Exception("Index out of range.");
            return Array.IndexOf(_array, item, index, Count - index);
        });
    }
    public void RemoveAt(int index)
    {
        var tmpThis = this;
        tmpThis.Lock(tmpThis, () =>
        {
            if ((uint) index >= (uint) Count)
                throw new Exception("Index out of range.");
            Interlocked.Decrement(ref Count);
            if (index < Count)
                Array.Copy(_array, index + 1, _array, index, Count - index);
            _array[Count] = default;
        });
    }
    public void Reverse()
    {
        Reverse(0, Count);
    }
    public void Reverse(int index, int count)
    {
        var tmpThis = this;
        tmpThis.Lock(tmpThis, () =>
        {
            if (index < 0)
                throw new Exception("Index out of range.");
            if (count < 0)
                throw new Exception("Count out of range.");
            if (Count - index < count)
                throw new Exception("Invalid offset.");
            Clean();
            Array.Reverse(_array, index, count);
        });
    }
    public void Sort()
    {
        Sort(0, Count, null);
    }
    public void Sort(IComparer<T> comparer)
    {
        Sort(0, Count, comparer);
    }
    public void Sort(int index, int count, IComparer<T> comparer)
    {
        var tmpThis = this;
        tmpThis.Lock(tmpThis, () =>
        {
            if (index < 0)
                throw new Exception("Index out of range.");
            if (count < 0)
                throw new Exception("Count out of range.");
            if (Count - index < count)
                throw new Exception("Invalid offset.");
            Array.Sort(_array, index, count, comparer);
        });
    }
    public IEnumerator<T> GetEnumerator()
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            return GetEnum();
        });
    }
    public T[] ToArray()
    {
        Array.Resize(ref _array, Count);
        return _array;
    }
    private IEnumerator<T> GetEnum()
    {
        var array = _array;
        var count = Count;
        for (var i = 0; i < count; i++)
            yield return array[i];
    }
}

TDStack.cs

Custom Dynamic Concurrent Stack Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public class TDStack<T> : IEnumerable<T>
{
    private          T[]               _array;
    private volatile MonitorActionFunc _maf;
    public volatile  int               Count;
    public TDStack(int sizeHint)
    {
        if (sizeHint < 4)
            throw new Exception("Size must be greater than or equal to 4.");
        _array = new T[sizeHint];
        _maf   = new MonitorActionFunc();
        Count  = 0;
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public IEnumerator<T> GetEnumerator()
    {
        var tmpThis = this;
        return tmpThis._maf.Lock(tmpThis, () =>
        {
            return GetEnum();
        });
    }
    public void Clear()
    {
        var tmpThis = this;
        tmpThis._maf.Lock(tmpThis, () =>
        {
            Array.Clear(_array, 0, _array.Length);
            Count = 0;
        });
    }
    public T Pop()
    {
        var tmpThis = this;
        return tmpThis._maf.Lock(tmpThis, () =>
        {
            Interlocked.Decrement(ref Count);
            var TVal = _array[Count];
            _array[Count] = default;
            return TVal;
        });
    }
    private IEnumerator<T> GetEnum()
    {
        var array = _array;
        var count = Count;
        for (var i = 0; i < count; i++)
            yield return array[i];
    }
    public void Push(T item)
    {
        var tmpThis = this;
        tmpThis._maf.Lock(tmpThis, () =>
        {
            if (Count == _array.Length)
                Array.Resize(ref _array, _array.Length + _array.Length / 4 * 3);
            _array[Count] = item;
            Interlocked.Increment(ref Count);
        });
    }
}

CustomArray.cs

Custom Array Class

using System;
using System.Collections;
using System.Collections.Generic;
public class CustomArray<T> : IEnumerable<T>
{
    private          T[]               _array;
    private volatile MonitorActionFunc _maf;
    public volatile  int               Count;
    public CustomArray(int cap)
    {
        _array = new T[cap];
        _maf   = new MonitorActionFunc();
        Count  = 0;
    }
    public int Length
    {
        get
        {
            var tmpThis = this;
            return tmpThis._maf.Lock(tmpThis, () => _array.Length);
        }
    }
    public T this[int index]
    {
        get
        {
            var array   = _array;
            var idx     = index;
            var tmpThis = this;
            return tmpThis._maf.Lock(tmpThis, () =>
            {
                if (idx > array.Length)
                    throw new Exception($"Error: Index {idx} out of range {array.Length}");
                return array[idx];
            });
        }
        set
        {
            var tmpThis = this;
            var idx     = index;
            tmpThis._maf.Lock(tmpThis, () =>
            {
                if (idx >= _array.Length)
                    Array.Resize(ref _array, idx + idx / 4 * 3);
                _array[idx] = value;
                Count++;
            });
        }
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Clear()
    {
        var tmpThis = this;
        tmpThis._maf.Lock(tmpThis, () =>
        {
            Array.Clear(_array, 0, _array.Length);
            Count = 0;
        });
    }
    public IEnumerator<T> GetEnumerator()
    {
        var tmpThis = this;
        return tmpThis._maf.Lock(tmpThis, () =>
        {
            return GetEnum();
        });
    }
    private IEnumerator<T> GetEnum()
    {
        var array = _array;
        var count = Count;
        for (var i = 0; i < count; i++)
            yield return array[i];
    }
    public T[] ToArray()
    {
        var tmpThis = this;
        return tmpThis._maf.Lock(tmpThis, () =>
        {
            var newtArray = new T[Count];
            Array.Copy(_array, 0, newtArray, 0, Count);
            return newtArray;
        });
    }
}

LinqHelper.cs

Custom Linq Range Class

using System;
using System.Collections.Generic;
using System.Numerics;
public static class LinqHelper
{
    /// <summary>
    ///     Generates a sequence of character values within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<char> Range(char from, char to, char step = '\x0001')
    {
        var d = '\x0';
        while((char) (from + (uint) d) < to)
        {
            yield return(char) (from + (uint) d);
            d += step;
        }
    }
    /// <summary>
    ///     Generates a sequence of 8-bit signed numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<sbyte> Range(sbyte from, sbyte to, sbyte step = 1)
    {
        var d = 0;
        while((sbyte) (from + d) < to)
        {
            yield return(sbyte) (from + d);
            d += step;
        }
    }
    /// <summary>
    ///     Generates a sequence of 8-bit unsigned numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<byte> Range(byte from, byte to, byte step = 1)
    {
        var d = 0;
        while((byte) (from + d) < to)
        {
            yield return(byte) (from + d);
            d += step;
        }
    }
    /// <summary>
    ///     Generates a sequence of 16-bit signed numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<short> Range(short from, short to, short step = 1)
    {
        var d = 0;
        while((short) (from + d) < to)
        {
            yield return(short) (from + d);
            d += step;
        }
    }
    /// <summary>
    ///     Generates a sequence of 16-bit unsigned numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<ushort> Range(ushort from, ushort to, ushort step = 1)
    {
        var d = 0;
        while((ushort) (from + d) < to)
        {
            yield return(ushort) (from + d);
            d += step;
        }
    }
    /// <summary>
    ///     Generates a sequence of 32-bit signed numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<int> Range(int from, int to, int step = 1)
    {
        var d = 0;
        while(from + d < to)
        {
            yield return from + d;
            d += step;
        }
    }
    /// <summary>
    ///     Generates a sequence of 32-bit unsigned numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<uint> Range(uint from, uint to, uint step = 1)
    {
        var d = 0u;
        while(from + d < to)
        {
            yield return from + d;
            d += step;
        }
    }
    /// <summary>
    ///     Generates a sequence of 64-bit signed numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<long> Range(long from, long to, long step = 1)
    {
        var d = 0l;
        while(from + d < to)
        {
            yield return from + d;
            d += step;
        }
    }
    /// <summary>
    ///     Generates a sequence of 64-bit unsigned numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<ulong> Range(ulong from, ulong to, ulong step = 1)
    {
        var d = 0ul;
        while(from + d < to)
        {
            yield return from + d;
            d += step;
        }
    }
    /// <summary>
    ///     Generates a sequence of arbitrarily large signed numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<BigInteger> Range(BigInteger from, BigInteger to, BigInteger step)
    {
        var count = to - from;
        for(var i = BigInteger.Zero; i < count; i = i + step)
            yield return from + i;
    }
    /// <summary>
    ///     Generates a sequence of arbitrarily large floating point precision numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<BigRational> Range(BigRational from, BigRational to, BigRational step)
    {
        if(step == 0)
            step = 1;
        var count = to - from;
        for(BigRational i = 0; i < count; i = +step)
            yield return from + i;
    }
    /// <summary>
    ///     Generates a sequence of single precision floating-point numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<float> Range(float from, float to, float step = 1)
    {
        var d = 0f;
        while(from + d < to)
        {
            yield return from + d;
            d += step;
        }
    }
    /// <summary>
    ///     Generates a sequence of double precision floating-point numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<double> Range(double from, double to, double step = 1)
    {
        var d = 0d;
        while(from + d < to)
        {
            yield return from + d;
            d += step;
        }
    }
    /// <summary>
    ///     Generates a sequence of decimal numbers within a specified range starting at
    ///     'form' through 'to' with a given step value.
    /// </summary>
    public static IEnumerable<decimal> Range(decimal from, decimal to, decimal step = 1)
    {
        decimal d = 0;
        while(from + d < to)
        {
            yield return from + d;
            d += step;
        }
    }
    /// <summary>
    ///     Generates a sequence of DateTime numbers within a specified range starting at
    ///     'form' through 'to' with a given step value in days.
    /// </summary>
    public static IEnumerable<DateTime> Range(DateTime from, DateTime to, double step = 1)
    {
        var d = from;
        while(d < to)
        {
            yield return d;
            d = d.AddDays(step);
        }
    }
}

TDArray.cs

Simple Concurrent Array Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
[Serializable]
public class TDArray<T> : IEnumerable<T>
{
    private          T[]               _array;
    private volatile MonitorActionFunc _maf;
    public volatile  int               Count;
    public TDArray(int cap)
    {
        _array = new T[cap];
        _maf   = new MonitorActionFunc();
        Count  = 0;
    }
    public int Length
    {
        get
        {
            var tmpThis = this;
            return tmpThis._maf.Lock(tmpThis, () => _array.Length);
        }
    }
    public T this[int index]
    {
        get
        {
            var array   = _array;
            var idx = index;
            var tmpThis = this;
            return tmpThis._maf.Lock(tmpThis, () =>
            {
                if (idx > array.Length)
                    throw new Exception("Error: Index out of range.");
                return array[idx];
            });
        }
        set
        {
            var tmpThis = this;
            var idx     = index;
            tmpThis._maf.Lock(tmpThis, () =>
            {
                if (idx >= _array.Length)
                    Array.Resize(ref _array, idx * 2);
                _array[idx] = value;
            });
        }
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Add(T item)
    {
        var tmpThis = this;
        tmpThis._maf.Lock(tmpThis, () =>
        {
            if (Count >= _array.Length)
                Array.Resize(ref _array, _array.Length + _array.Length / 4 * 3);
            _array[Count] = item;
            Interlocked.Increment(ref Count);
        });
    }
    public void Clear()
    {
        var tmpThis = this;
        tmpThis._maf.Lock(tmpThis, () =>
        {
            Array.Clear(_array, 0, _array.Length);
            Count = 0;
        });
    }
    public IEnumerator<T> GetEnumerator()
    {
        var tmpThis = this;
        return tmpThis._maf.Lock(tmpThis, () =>
        {
            return GetEnum();
        });
    }
    private IEnumerator<T> GetEnum()
    {
        var array = _array;
        var count = Count;
        for (var i = 0; i < count; i++)
            yield return array[i];
    }
}

BigIntegerPrime.cs

Generate or Test BigInteger Primes

using System;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
public class BigIntegerPrime
{
    private readonly int _bitWidth;
    private readonly int[] _lowPrimes =
    {
        2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
        157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
        317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491,
        499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677,
        683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881,
        883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997
    };
    private readonly BigIntegerRng _rng;
    private readonly BigInteger    _twosixtyfour = "18446744073709551616".BigIntegerBase10();
    private readonly uint[]        _w0           = {2};
    private readonly uint[]        _w1           = {2, 3};
    private readonly uint[]        _w10          = {2, 3, 5, 7, 11, 13, 17, 19, 23};
    private readonly uint[]        _w11          = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
    private readonly uint[]        _w12          = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41};
    private readonly uint[]        _w2           = {31, 73};
    private readonly uint[]        _w3           = {2, 3, 5};
    private readonly uint[]        _w4           = {2, 3, 5, 7};
    private readonly uint[]        _w5           = {2, 7, 61};
    private readonly uint[]        _w6           = {2, 13, 23, 1662803};
    private readonly uint[]        _w7           = {2, 3, 5, 7, 11};
    private readonly uint[]        _w8           = {2, 3, 5, 7, 11, 13};
    private readonly uint[]        _w9           = {2, 3, 5, 7, 11, 13, 17};
    private          BigInteger    _nextPrime;
    public BigIntegerPrime(int BitWidthHint)
    {
        _rng          = new BigIntegerRng(BitWidthHint);
        _rng.Unsigned = true;
        _rng.OddsOnly = true;
        _bitWidth     = BitWidthHint;
    }
    public bool IsPrime(BigInteger candidate)
    {
        if (candidate == 1)
            return false;
        if (candidate == 2 || candidate == 3 || candidate == 5)
            return true;
        if (candidate <= 1000)
            return CheckLowPrimes(candidate);
        if (!PrimeCheckM10LD(candidate))
            return false;
        if (!PrimeCheckM6(candidate))
            return false;
        if (!TrialDivision(candidate))
            return false;
        if (candidate < 2047)
        {
            if (!MillerRabin(candidate, _w0))
                return false;
        }
        else if (candidate > 2047 && candidate <= 1373653)
        {
            if (!MillerRabin(candidate, _w1))
                return false;
        }
        else if (candidate > 1373653 && candidate <= 9080191)
        {
            if (!MillerRabin(candidate, _w2))
                return false;
        }
        else if (candidate > 9080191 && candidate <= 25326001)
        {
            if (!MillerRabin(candidate, _w3))
                return false;
        }
        else if (candidate > 25326001 && candidate <= 3215031751)
        {
            if (!MillerRabin(candidate, _w4))
                return false;
        }
        else if (candidate > 3215031751 && candidate <= 4759123141)
        {
            if (!MillerRabin(candidate, _w5))
                return false;
        }
        else if (candidate > 4759123141 && candidate <= 1122004669633)
        {
            if (!MillerRabin(candidate, _w6))
                return false;
        }
        else if (candidate > 1122004669633 && candidate <= 2152302898747)
        {
            if (!MillerRabin(candidate, _w7))
                return false;
        }
        else if (candidate > 2152302898747 && candidate <= 3474749660383)
        {
            if (!MillerRabin(candidate, _w8))
                return false;
        }
        else if (candidate > 3474749660383 && candidate <= 341550071728321)
        {
            if (!MillerRabin(candidate, _w9))
                return false;
        }
        else if (candidate > 341550071728321 && candidate <= 3825123056546413051)
        {
            if (!MillerRabin(candidate, _w10))
                return false;
        }
        else if (candidate > 3825123056546413051 && candidate < _twosixtyfour)
        {
            if (!MillerRabin(candidate, _w11))
                return false;
        }
        else if (candidate > _twosixtyfour)
        {
            if (!MillerRabin(candidate, _w12))
                return false;
        }
        return true;
    }
    private bool MillerRabin(BigInteger candidate, uint[] w)
    {
        var s = 0;
        var d = candidate - BigInteger.One;
        while ((d & 1) == 0)
        {
            d >>= 1;
            s++;
        }
        if (s == 0)
            return false;
        var nmo = candidate - BigInteger.One;
        for (var i = 0; i < w.Length; ++i)
        {
            BigInteger a;
            if (candidate > _twosixtyfour)
                a = _rng.Next(3, nmo);
            else
                a = w[i];
            var x = BigInteger.ModPow(a, d, candidate);
            if (x == 1 || x == nmo)
                continue;
            for (var r = 1; r < s; ++r)
            {
                x = BigInteger.ModPow(x, 2, candidate);
                if (x == 1)
                    return false;
                if (x == nmo)
                    break;
            }
            if (x == nmo)
                continue;
            return false;
        }
        return true;
    }
    private bool TrialDivision(BigInteger candidate)
    {
        for (var i = 0; i < _lowPrimes.Length; i++)
        {
            var p = _lowPrimes[i];
            if (i < p)
            {
                if (candidate % p != 0)
                    continue;
                return false;
            }
            break;
        }
        return true;
    }
    private static bool PrimeCheckM10LD(BigInteger n)
    {
        var d1 = (int) (n % 10);
        return d1 == 1 || d1 == 3 || d1 == 7 || d1 == 9;
    }
    private static bool PrimeCheckM6(BigInteger n)
    {
        var d1 = (int) (n % 6);
        return d1 == 1 || d1 == 5;
    }
    private bool CheckLowPrimes(BigInteger val)
    {
        foreach (var v in _lowPrimes)
            if (val == v)
                return true;
        return false;
    }
    private void NextPrime(int t)
    {
        if (t > Environment.ProcessorCount - 1)
            return;
        var MaxValue = (BigInteger.One << _bitWidth) - 1;
        while (true)
        {
            if (_nextPrime != 0)
                return;
            var n = _rng.NextFast(_bitWidth);
            if (_nextPrime != 0)
                return;
            if (n == 1)
                continue;
            if (n > MaxValue)
                continue;
            if (!IsPrime(n))
                continue;
            _nextPrime = n;
        }
    }
    public BigInteger GetPrime()
    {
        void invoke()
        {
            Parallel.Invoke(new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount},
                () => NextPrime(1),
                () => NextPrime(2),
                () => NextPrime(3),
                () => NextPrime(4),
                () => NextPrime(5),
                () => NextPrime(6),
                () => NextPrime(7),
                () => NextPrime(8),
                () => NextPrime(9),
                () => NextPrime(10),
                () => NextPrime(11),
                () => NextPrime(12),
                () => NextPrime(13),
                () => NextPrime(14),
                () => NextPrime(15),
                () => NextPrime(16)
            );
        }
        _nextPrime = 0;
        var thread = new Thread(invoke) {Priority = ThreadPriority.Highest};
        thread.Start();
        thread.Join();
        return _nextPrime;
    }
}

BigIntegerRng.cs

Fast Balanced Distribution BigInteger Rng

using System;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
[Serializable]
public class BigIntegerRng : RandomNumberGenerator
{
    private int                      _bitWidth;
    private byte[]                   _buffer;
    public  RNGCryptoServiceProvider _crng;
    private BigDecimal               _dBi;
    private BigInteger               _upperLimit;
    public BigIntegerRng(int bitWidthHint)
    {
        _crng       = new RNGCryptoServiceProvider();
        _upperLimit = (BigInteger.One << bitWidthHint) - 1;
        _dBi        = new BigDecimal(1) / _upperLimit;
        _buffer     = new byte[bitWidthHint >> 3];
        _bitWidth   = bitWidthHint;
    }
    public bool OddsOnly
    {
        get;
        set;
    }
    public bool Unsigned
    {
        get;
        set;
    }
    private BigDecimal Sample(BigDecimal weight)
    {
        BigInteger Internal()
        {
            _crng.GetBytes(_buffer);
            return new BigInteger(!Unsigned ? _buffer : _buffer.Concat(new byte[] {0}).ToArray());
        }
        var        rat  = Internal() * _dBi;
        BigDecimal tens = 10;
        if (weight != 0 && weight > .9)
        {
            if (rat < weight)
            {
                var or = rat / tens + weight;
                while (or > 1)
                {
                    tens *= 10;
                    or   =  rat / tens + weight;
                }
                return or;
            }
            return rat;
        }
        return rat;
    }
    public BigInteger Next(BigInteger minValue, BigInteger maxValue)
    {
        BestBitWidth(maxValue);
        var sa = Sample(0);
        var fi = (BigDecimal) (maxValue - minValue + minValue);
        var n  = (BigInteger) (sa * fi);
        n = !OddsOnly ? n : n | 1;
        return n < minValue ? SpecialRange(minValue, maxValue) : n;
    }
    private BigInteger SpecialRange(BigInteger minValue, BigInteger maxValue)
    {
        BigInteger res;
        var        fi     = (BigDecimal) (maxValue - minValue + minValue);
        var        weight = (BigDecimal) minValue / _upperLimit;
        do
        {
            var n = (BigInteger) (Sample(weight) * fi);
            res = !OddsOnly ? n : n | 1;
        } while (res > maxValue || res < minValue);
        return res;
    }
    private void BestBitWidth(BigInteger maxValue)
    {
        var bitWidth = maxValue.GetBitWidth();
        if (_bitWidth != bitWidth)
        {
            _upperLimit = (BigInteger.One << bitWidth) - 1;
            _dBi        = new BigDecimal(1) / _upperLimit;
            _buffer     = new byte[bitWidth >> 3];
            _bitWidth   = bitWidth;
        }
    }
    public BigInteger Next(BigInteger maxValue)
    {
        return Next(0, maxValue);
    }
    public BigInteger Next()
    {
        return Next(0, _upperLimit);
    }
    public BigDecimal NextBigDecimal()
    {
        return Sample(0) * _upperLimit;
    }
    public override void GetBytes(byte[] data)
    {
        if (data == null)
            throw new ArgumentException("The buffer cannot be null.");
        _crng.GetBytes(data);
    }
    public BigInteger NextFast(int bitWidth)
    {
        if (_bitWidth != bitWidth)
        {
            _buffer   = new byte[bitWidth >> 3];
            _bitWidth = bitWidth;
        }
        _crng.GetBytes(_buffer);
        return new BigInteger(!Unsigned ? _buffer : _buffer.Concat(new byte[] {0}).ToArray());
    }
}