CcArray.cs

Concurrent Array (Ordered) Class with Indexing, and without Blocking

Updated: Aug-2,2021

        RandomBigInt rng  = new RandomBigInt(64);
        ulong[]      sla1 = Enumerable.Range(0, 1000000).AsParallel().WithDegreeOfParallelism(10).Select(i => (ulong)rng.Next()).ToArray();
        CcArray<ulong> ccl = new CcArray<ulong>(1000000);

Example 1:       
        Parallel.ForEach(sla1, new ParallelOptions { MaxDegreeOfParallelism = 10 }, (v, p, i) =>
        {
            ccl.Add(v, (int)i);
        });

Example 2:
        Parallel.For(0,sla1.Length,i=>
        {
            ccl.Add(sla1[i], (int)i);
        });

Example 3:
        sla1.AsEnumerable().Select( (v,i)=> new {value=v,index=i}).AsParallel().WithDegreeOfParallelism(10).ForAll(x=>
        {
            ccl[x.index] = x.value;
        });

       Var asa = new ulong[1000000];
       for (var i = 0; i < 1000000; ++i)
          asa[i] = ccl[i];
       var exc = sla1.Except(asa).ToArray();
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
public class CcArray<T> : IEnumerable<T>
{
    private readonly int           _size;
    private volatile int           _activeThreadPosition;
    private volatile int[]         _activeThreads;
    private volatile IntSet18<T>[] _array;
    public volatile  int           NumberOfActiveThreads;
    public CcArray(int size)
    {
        ThreadPool.GetMaxThreads(out var nW, out var nI);
        _array                = new IntSet18<T>[nW];
        _size                 = size;
        NumberOfActiveThreads = 0;
        _activeThreadPosition = 0;
        _activeThreads        = new int[Environment.ProcessorCount];
        _activeThreads.Fill(-1);
    }
    public T this[int index]
    {
        get
        {
            var (idx, trd) = FindIndex(index);
            return idx != -1 ? _array[trd].Slots[idx].Value : default;
        }
        set
        {
            var (idx, trd) = FindIndex(index);
            if (idx != -1)
                _array[trd].Slots[idx].Value = value;
            else Add(value, index);
        }
    }
    public int Count
    {
        get
        {
            if (_activeThreads == null)
                throw new Exception("Initialization has not completed. Note: The constructor cannot be void.");
            var totalCount = 0;
            for (var i = 0; i < _activeThreads.Length; ++i)
                if (_activeThreads[i] != -1)
                    if (_array[_activeThreads[i]].Allocated)
                        totalCount += _array[_activeThreads[i]].Count;
            return totalCount;
        }
    }
    public IEnumerator<T> GetEnumerator()
    {
        return GetEnum();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnum();
    }
    public void Add(T item, int index, bool updateValue = false)
    {
        if (_activeThreads == null)
            throw new Exception("Initialization has not completed. Note: The constructor cannot be void.");
        var id = ProcessThread();
        var (idx, trd) = FindIndex(index);
        if (idx == -1)
            _array[id].Add(index, item);
        else if (updateValue)
            _array[trd].Slots[idx].Value = item;
    }
    public (int idx, int trd) FindIndex(int index)
    {
        if (_activeThreads == null)
            throw new Exception("Initialization has not completed. Note: The constructor cannot be void.");
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]].Allocated)
                {
                    var idx = _array[_activeThreads[i]].FindKey(index);
                    if (idx != -1)
                        return (idx, _activeThreads[i]);
                }
        return (-1, -1);
    }
    private int ProcessThread()
    {
        var id = Thread.CurrentThread.ManagedThreadId;
        if (!_array[id].Allocated)
        {
            Interlocked.Increment(ref NumberOfActiveThreads);
            _array[id] = new IntSet18<T>(_size / NumberOfActiveThreads);
            if (_activeThreadPosition >= _activeThreads.Length)
            {
                var newActiveThreads = new int[_activeThreads.Length << 1];
                newActiveThreads.Fill(-1);
                for (var i = 0; i < _activeThreads.Length; ++i)
                    if (_activeThreads[i] != -1)
                        newActiveThreads[i] = _activeThreads[i];
                _activeThreads = newActiveThreads;
            }
            _activeThreads[_activeThreadPosition] = id;
            Interlocked.Increment(ref _activeThreadPosition);
        }
        return id;
    }
    public bool Contains(T item)
    {
        if (_activeThreads == null)
            throw new Exception("Initialization has not completed. Note: The constructor cannot be void.");
        var eComparer = EqualityComparer<T>.Default;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]].Allocated)
                    for (var j = 0; j < _array[_activeThreads[i]].Count; ++j)
                        if (eComparer.Equals(_array[_activeThreads[i]].Slots[j].Value, item))
                            return true;
        return false;
    }
    public T[] ToArray()
    {
        if (_activeThreads == null)
            throw new Exception("Initialization has not completed. Note: The constructor cannot be void.");
        var outputArray = new T[Count];
        var ptr         = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]].Allocated)
                    foreach (var v in _array[_activeThreads[i]])
                        outputArray[ptr++] = v.Value;
        return outputArray;
    }
    private IEnumerator<T> GetEnum()
    {
        var array = ToArray();
        foreach (var i in array)
            yield return i;
    }
    [DebuggerDisplay("Count = {" + nameof(Count) + "}")]
    internal struct IntSet18<T1>
    {
        private  int[]  _buckets;
        internal Slot[] Slots;
        public   bool   Allocated;
        public IntSet18(int size)
        {
            _buckets  = new int[size];
            Slots     = new Slot[size];
            Count     = 0;
            Allocated = true;
        }
        public int Count
        {
            get;
            private set;
        }
        public IEnumerator<KeyValuePair<int, T1>> GetEnumerator()
        {
            for (var i = 0; i < Count; i++)
                if (Slots[i].Key >= 0)
                    yield return new KeyValuePair<int, T1>(Slots[i].Key, Slots[i].Value);
        }
        public bool Add(int key, T1 value)
        {
            if (FindKey(key) != -1)
                return true;
            if (Count >= Slots.Length)
                Resize();
            var pos = key % _buckets.Length;
            Slots[Count].Next  = _buckets[pos] - 1;
            Slots[Count].Key   = key;
            Slots[Count].Value = value;
            _buckets[pos]      = Count + 1;
            ++Count;
            return false;
        }
        private void Resize()
        {
            var newSize    = _buckets.Length + _buckets.Length / 4 * 3;
            var newSlots   = new Slot[newSize];
            var newBuckets = new int[newSize];
            var newCount   = 0;
            var en         = GetEnumerator();
            while (en.MoveNext())
            {
                var key   = en.Current.Key;
                var value = en.Current.Value;
                var pos   = key % newBuckets.Length;
                newSlots[newCount].Next  = newBuckets[pos] - 1;
                newSlots[newCount].Key   = key;
                newSlots[newCount].Value = value;
                newBuckets[pos]          = newCount + 1;
                ++newCount;
            }
            Slots    = newSlots;
            _buckets = newBuckets;
            Count    = newCount;
        }
        public int FindKey(int key)
        {
            for (var position = _buckets[key % _buckets.Length] - 1; position >= 0; position = Slots[position].Next)
                if (Equals(Slots[position].Key, key))
                    return position;
            return -1;
        }
        internal struct Slot
        {
            public int Next;
            public int Key;
            public T1  Value;
        }
    }
}

SegmentedArray.cs

Segmented Array Class

I wrote this array class while investigating the error curve in Prime Number Theorem. I wanted to avoid using blocking while using parallel invoke, while using as little memory as possible.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
public struct SegmentedArray<T>
{
    private readonly IntA<T>[] _array;
    private readonly int       _size;
    public SegmentedArray(int length, int size)
    {
        _array = new IntA<T>[16];
        _size  = size;
    }
    public void Add(T item, int index, long range, long total)
    {
        if (!_array[index].Allocated)
            _array[index] = new IntA<T>(_size);
        var density = (float)_array[index].Count / range;
        var ssic    = total                      * density;
        _array[index].Add(item, (int)ssic);
    }
    public T[] ToArray()
    {
        var totalCount = 0;
        for (var i = 0; i < 16; ++i)
            if (_array[i].Allocated)
                totalCount += _array[i].Count;
        var ta  = new T[totalCount];
        var ptr = 0;
        for (var i = 0; i < 16; ++i)
            if (_array[i].Allocated)
            {
                var it = _array[i].ToArray();
                _array[i].Zero();
                for (var j = 0; j < it.Length; ++j)
                    ta[ptr++] = it[j];
            }
        return ta;
    }
    [DebuggerDisplay("Count = {Count}")]
    internal struct IntA<T> : IEnumerable<T>
    {
        internal T[]  _array;
        internal bool Allocated;
        public IntA(int cap)
        {
            Count     = 0;
            _array    = new T[cap];
            Allocated = true;
        }
        public int Count
        {
            get;
            private set;
        }
        public T this[int index]
        {
            get
            {
                if (index > _array.Length)
                    throw new Exception("Error: Index out of range.");
                return _array[index];
            }
            set
            {
                if (index > _array.Length)
                    throw new Exception("Error: Index out of range.");
                _array[index] = value;
            }
        }
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        public void Add(T item, int suggestedSize)
        {
            if (Count >= _array.Length)
                Array.Resize(ref _array, suggestedSize);
            _array[Count] = item;
            Count++;
        }
        public T[] ToArray()
        {
            var newtArray = new T[Count];
            Array.Copy(_array, 0, newtArray, 0, Count);
            return newtArray;
        }
        public void Clean()
        {
            var newtArray = new T[Count];
            Array.Copy(_array, 0, newtArray, 0, Count);
            _array = newtArray;
        }
        public void Clear()
        {
            Array.Clear(_array, 0, Count);
            Count = 0;
        }
        public void Zero()
        {
            _array = Array.Empty<T>();
            Count  = 0;
        }
        public IEnumerator<T> GetEnumerator()
        {
            return GetEnum();
        }
        public IEnumerator<T> GetEnum()
        {
            for (var i = 0; i < Count; i++)
                yield return _array[i];
        }
    }
}

ObjectAssociativeArray.cs

Key based, Fast Searchable Values, Multiple Value Arrays.

Key, Values, Values,… All Comparisons are done at the byte level, no need for custom comparator. Keys and all values are searchable, using (Indexed) variable bit width map hashing (Default is 64 Bits, can go up to 512 bits).

using System;
using System.Diagnostics;
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
[Serializable]
public class ObjectAssociativeArray : MonitorActionFuncWrapper
{
    private ObjectBase   _keys;
    private ObjectBase[] _values;
    public ObjectAssociativeArray() : this(1024)
    {
    }
    public ObjectAssociativeArray(int size, int order = 1)
    {
        _keys   = new ObjectBase(size);
        _values = new ObjectBase[order];
        for (var i = 0; i < order; ++i)
            _values[i] = new ObjectBase(size);
    }
    public int Count => _keys.Count;
    public bool Add(object key, params object[] value)
    {
        if (key == null)
            throw new ArgumentException("Key cannot be null.");
        if (value == null)
            throw new ArgumentException("There must be a least one value.");
        return Lock(this, () =>
        {
            for (var p = 0; p < value.Length; ++p)
                if (_keys.Contains(key) || _values[p].Contains(value[p]))
                    return false;
            var ka = _keys.Add(key);
            var va = false;
            for (var p = 0; p < value.Length; ++p)
            {
                va = _values[p].Add(value[p]);
                if (!va)
                    throw new Exception($"the nth parameter {p} could not be added.");
            }
            return ka && va;
        });
    }
    public (object[] key, object value) GetKeysAndValues(int index)
    {
        return (_keys.ToArray(), _values[index].ToArray());
    }
    #region Generic
    public bool Contains(object key)
    {
        return _keys.Contains(key);
    }
    public bool ContainsValue(object value, int index = 0)
    {
        return _values[index].Contains(value);
    }
    #endregion
}

BigHashsetSa.cs

Big Hash Set based onĀ BigArray.cs

Uses a single array.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
[Serializable]
public class BigHashsetSa<T> : MonitorActionFunc, IEnumerable
{
    public enum Method
    {
        Grow,
        Compress
    }
    private volatile BigArray<Bucket>        _buckets;
    private          long                    _count;
    private          Method                  _method;
    internal         IBigEqualityComparer<T> Comparer;
    public BigHashsetSa(long size, Method method = Method.Grow) : this(size, new BigComparer<T>(), method)
    {
    }
    public BigHashsetSa(long size, IBigEqualityComparer<T> comparer, Method method = Method.Grow)
    {
        if (comparer == null)
            comparer = new BigComparer<T>();
        Comparer = comparer;
        _buckets = new BigArray<Bucket>(size);
        Count    = 0;
        _method  = method;
    }
    public long Count
    {
        get
        {
            return Lock(this, () =>
            {
                return _count;
            });
        }
        private set
        {
            Lock(this, () =>
            {
                _count = value;
            });
        }
    }
    public long                       ElementCount         => GetElementCount();
    public long                       NumberOfEmptyBuckets => GetNumberOfEmptyBuckets();
    public (long mDepth, long index)  MaximumBucketDepth   => GetMaximumBucketDepth();
    public float                      LoadRatio            => GetLoadRatio();
    public KeyValuePair<long, long>[] BucketDepthList      => GetBucketDepthList();
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Clear()
    {
        _buckets.Clear();
    }
    public bool Add(T item)
    {
        return Lock(this, () =>
        {
            if (_method == Method.Grow)
                EnsureSize();
            var hashCode = Comparer.GetHashCode(item) & long.MaxValue;
            if (FindEntry(item, hashCode).APos != -1)
                return false;
            var pos = hashCode % _buckets.Length;
            if (_buckets[pos] == null)
                _buckets[pos] = new Bucket();
            _buckets[pos].Add(item);
            Count++;
            return true;
        });
    }
    public T[] ToArray()
    {
        var newArray = new T[Count];
        using (var en = GetEnumerator())
        {
            var ptr = 0;
            while (en.MoveNext())
            {
                var value = en.Current;
                if (value == null)
                    break;
                newArray[ptr++] = value;
            }
            return newArray;
        }
    }
    private (long APos, long BPos) FindEntry(T item, long hashCode)
    {
        if (Count == 0)
            return (-1, -1);
        if (hashCode == 0)
        {
            var a = 0;
        }
        var aPos = hashCode % _buckets.Length;
        var bPos = 0;
        if (_buckets[aPos] == null)
        {
            _buckets[aPos] = new Bucket();
            return (-1, -1);
        }
        foreach (var i in _buckets[aPos].Values)
        {
            if (Comparer.Equals(i, item))
                return (aPos, bPos);
            bPos++;
        }
        return (-1, -1);
    }
    private void EnsureSize()
    {
        if (Count >= _buckets.Length)
        {
            var cArray = ToArray();
            _buckets = new BigArray<Bucket>(_buckets.Length + BigArray<T>.Granularity);
            foreach (var i in cArray)
            {
                var hashCode = Comparer.GetHashCode(i) & long.MaxValue;
                var pos      = hashCode % _buckets.Length;
                if (_buckets[pos] == null)
                    _buckets[pos] = new Bucket();
                _buckets[pos].Add(i);
            }
        }
    }
    public bool Contains(T item)
    {
        return Lock(this, () =>
        {
            var hashCode = Comparer.GetHashCode(item) & long.MaxValue;
            return FindEntry(item, hashCode).APos != -1;
        });
    }
    public IEnumerator<T> GetEnumerator()
    {
        return Lock(this, () =>
        {
            return GetEnum();
        });
    }
    public IEnumerator<T> GetEnum()
    {
        for (var i = 0; i < _buckets.Length; i++)
            if (_buckets[i] != null)
                for (var j = 0; j < _buckets[i].Count; ++j)
                    yield return _buckets[i].Values[j];
    }
    public long GetElementCount()
    {
        var count = 0;
        for (var i = 0; i < _buckets.Length; i++)
            if (_buckets[i] != null)
            {
                var c = _buckets[i].Count;
                count += c;
            }
        return count;
    }
    public long GetNumberOfEmptyBuckets()
    {
        var count = 0;
        for (var i = 0; i < _buckets.Length; i++)
            if (_buckets[i] == null)
                count++;
        return count;
    }
    public long GetNumberOfFilledBuckets()
    {
        var count = 0;
        for (var i = 0; i < _buckets.Length; i++)
            if (_buckets[i] != null)
                count++;
        return count;
    }
    public (long mDepth, long index) GetMaximumBucketDepth()
    {
        var max = 0;
        var j   = 0;
        for (var i = 0; i < _buckets.Length; i++)
            if (_buckets[i] != null)
            {
                var count = _buckets[i].Count;
                if (count > max)
                {
                    max = count;
                    j   = i;
                }
            }
        return (max, j);
    }
    public KeyValuePair<long, long>[] GetBucketDepthList()
    {
        var bdic = new Dictionary<long, long>();
        for (var i = 0; i < _buckets.Length; i++)
            if (_buckets[i] != null)
            {
                var count = _buckets[i].Count;
                if (!bdic.ContainsKey(count))
                {
                    bdic.Add(count, 0);
                    bdic[count]++;
                }
                else
                {
                    bdic[count]++;
                }
            }
        return bdic.OrderByDescending(x => x.Value).ToArray();
    }
    public float GetLoadRatio()
    {
        var x = Count;
        var y = _buckets.Length;
        var r = x / (float) y;
        return r;
    }
    internal class Bucket
    {
        public int Count;
        public T[] Values;
        public Bucket()
        {
            Values = new T[2];
            Count  = 0;
        }
        public void Add(T item)
        {
            if (Count >= Values.Length)
            {
                var ta = new T[Values.Length + 1];
                Array.Copy(Values, 0, ta, 0, Count);
                Values = ta;
            }
            Values[Count++] = item;
        }
    }
}

BigArray.cs

Big Array Class Arrays Over 2GB Limit

Updated: Dec-14,2020

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Microsoft.VisualBasic.Devices;
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public class BigArray<T> : MonitorActionFunc, IEnumerable<T>, IDisposable
{
    public const     int   ShiftCount  = 19;
    public const     int   Granularity = 1 << ShiftCount;
    private          bool  _disposed;
    private volatile T[][] _mdArray;
    private volatile Table _table = new Table();
    private volatile bool  _writing;
    public BigArray() : this(0)
    {
    }
    public BigArray(long size)
    {
        if (size < Granularity)
            size = Granularity;
        var i = 0;
        try
        {
            _table.MaximumNumberOfArrays = (int) (new ComputerInfo().AvailablePhysicalMemory / Granularity);
            _table.NumberOfActiveArrays  = (int) ((size + (Granularity - 1))                 / Granularity);
            var val = (long) _table.NumberOfActiveArrays                                     * Granularity;
            _table.Length = Interlocked.Read(ref val);
            var ms  = new MeasureSize<T>();
            var oas = ms.GetByteSize(Granularity);
            var am  = new ComputerInfo().AvailablePhysicalMemory;
            var rm  = (ulong) (oas * _table.NumberOfActiveArrays * Granularity);
            var maa = am / (ulong) (oas * Granularity);
            if (rm > am || (ulong) _table.NumberOfActiveArrays > maa)
                throw new Exception($"Requested memory {rm} exceeds available memory {am}");
            _mdArray = new T[maa][];
            for (i = 0; i < _table.NumberOfActiveArrays; ++i)
                _mdArray[i] = new T[Granularity];
            _writing = false;
        }
        catch (Exception ex)
        {
            throw new Exception($"Exception: {ex.Message}");
        }
    }
    public long Count
    {
        get
        {
            return Lock(_table.Count, () =>
            {
                return _table.Count;
            });
        }
    }
    public long Length
    {
        get
        {
            return Lock(_table.Length, () =>
            {
                return _table.Length;
            });
        }
    }
    public T this[long index]
    {
        get
        {
            while (_writing)
                new SpinWait().SpinOnce();
            if (index >= _table.Length)
                throw new Exception($"Getter: Index out of bounds, Index: '{index}' must be less than the Length: '{Length}'.");
            return _mdArray[index >> ShiftCount][index & (Granularity - 1)];
        }
        set
        {
            Lock(this, () =>
            {
                if (index + 1 > _table.Length)
                    ResizeArray();
                _writing                                                 = true;
                _mdArray[index >> ShiftCount][index & (Granularity - 1)] = value;
                _table.Count++;
                _writing = false;
            });
        }
    }
    public void Dispose()
    {
        Dispose(true);
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Add(T Item)
    {
        Lock(this, () =>
        {
            if (_table.Count + 1 > _table.Length)
                ResizeArray();
            _writing = true;
            var x = _table.Count >> ShiftCount;
            var y = _table.Count & (Granularity - 1);
            _mdArray[x][y] = Item;
            _table.Count++;
            _writing = false;
        });
    }
    private void ResizeArray()
    {
        try
        {
            Interlocked.Increment(ref _table.NumberOfActiveArrays);
            var val = (long) _table.NumberOfActiveArrays * Granularity;
            _table.Length = Interlocked.Read(ref val);
            var ms  = new MeasureSize<T>();
            var oas = ms.GetByteSize(Granularity);
            var am  = new ComputerInfo().AvailablePhysicalMemory;
            var rm  = (ulong) (oas * _table.NumberOfActiveArrays * Granularity);
            var maa = am / (ulong) (oas * Granularity);
            if (rm > am || (ulong) _table.NumberOfActiveArrays > maa)
                throw new Exception($"Requested memory {rm} exceeds available memory {am}");
            _mdArray                                  = new T[maa][];
            _mdArray[_table.NumberOfActiveArrays - 1] = new T[Granularity];
        }
        catch (Exception ex)
        {
            throw new Exception($"Exception: {ex.Message}");
        }
    }
    public void Clear()
    {
        Lock(this, () =>
        {
            _writing = true;
            for (var a = 0L; a < _table.NumberOfActiveArrays; a++)
                Array.Clear(_mdArray[a], 0, Granularity);
            _table.Count = 0;
            _writing     = false;
        });
    }
    public long IndexOf(T item)
    {
        return Lock(this, () =>
        {
            var i = 0L;
            for (; i < _table.NumberOfActiveArrays; i++)
            {
                while (_writing)
                    new SpinWait().SpinOnce();
                var pos = Array.IndexOf(_mdArray[i], item, 0);
                if (pos != -1)
                    return i * Granularity + pos;
            }
            return -1;
        });
    }
    public BigArray<T> Copy(long newsize)
    {
        return Lock(this, () =>
        {
            var temp = new BigArray<T>(newsize);
            for (var a = 0L; a < _table.NumberOfActiveArrays; a++)
            {
                while (_writing)
                    new SpinWait().SpinOnce();
                Array.Copy(_mdArray[a], temp._mdArray[a], Granularity);
            }
            temp._table.Count = Count;
            return temp;
        });
    }
    public void FromArray(T[][] array)
    {
        Lock(this, () =>
        {
            _table.NumberOfActiveArrays = array.GetUpperBound(0) + 1;
            var val = (long) _table.NumberOfActiveArrays * Granularity;
            _table.Length = Interlocked.Read(ref val);
            _mdArray      = new T[_table.NumberOfActiveArrays][];
            for (var i = 0; i < _table.NumberOfActiveArrays; ++i)
                _mdArray[i] = new T[Granularity];
            for (var a = 0L; a < _table.NumberOfActiveArrays; a++)
                Array.Copy(array[a], _mdArray[a], Granularity);
        });
    }
    public T[][] ToArray()
    {
        return Lock(this, () =>
        {
            var ta = new T[_table.NumberOfActiveArrays][];
            for (var i = 0; i < _table.NumberOfActiveArrays; ++i)
                ta[i] = new T[Granularity];
            for (var a = 0L; a < _table.NumberOfActiveArrays; a++)
                Array.Copy(_mdArray[a], ta[a], Granularity);
            return ta;
        });
    }
    private void Dispose(bool disposing)
    {
        if (!_disposed)
            if (disposing)
                _mdArray = null;
        _disposed = true;
    }
    public IEnumerator<T> GetEnumerator()
    {
        return Lock(this, () =>
        {
            return GetEnum();
        });
    }
    public IEnumerator<T> GetEnum()
    {
        for (var i = 0; i < Count; i++)
            yield return this[i];
    }
    private class Table
    {
        public          long Count;
        public          long Length;
        public volatile int  MaximumNumberOfArrays;
        public volatile int  NumberOfActiveArrays;
    }
}

MiniArray.cs

A Small Generic Array Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
[Serializable]
public class MiniArray<T> : IEnumerable<T>
{
    public T[] Array;
    public MiniArray() : this(101)
    {
    }
    public MiniArray(int cap)
    {
        Count = 0;
        Array = new T[cap];
    }
    public int Count
    {
        get;
        private set;
    }
    public T this[int index]
    {
        get
        {
            if (index > Array.Length)
                throw new Exception("Error: Index out of range.");
            return Array[index];
        }
        set
        {
            EnsureSize();
            Array[index] = value;
            Count++;
        }
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return new Enumerator<T>(this);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return new Enumerator<T>(this);
    }
    private void EnsureSize()
    {
        if (Count >= Array.Length)
        {
            var NewLength = Array.Length == 0 ? 1 : Array.Length * 2;
            var newtArray = new T[NewLength];
            System.Array.Copy(Array, 0, newtArray, 0, Array.Length);
            Array = newtArray;
        }
    }
    public void Add(T item)
    {
        EnsureSize();
        Array[Count] = item;
        Count++;
    }
    public T[] ToArray()
    {
        var newtArray = new T[Count];
        System.Array.Copy(Array, 0, newtArray, 0, Count);
        return newtArray;
    }
    public IEnumerable<T> All()
    {
        for (var i = 0; i < Count; ++i)
            yield return Array[i];
    }
    public void Clean()
    {
        var newtArray = new T[Count];
        System.Array.Copy(Array, 0, newtArray, 0, Count);
        Array = newtArray;
    }
    public void Clear()
    {
        System.Array.Clear(Array, 0, Count);
        Count = 0;
    }
}
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Enumerator<T> : IEnumerator<T>
{
    private readonly MiniArray<T> thing;
    private          int          index;
    internal Enumerator(MiniArray<T> thing)
    {
        this.thing = thing;
        index      = 0;
        Current    = default;
    }
    public void Dispose()
    {
    }
    public bool MoveNext()
    {
        var tthing = thing;
        if (index < tthing.Count)
        {
            Current = tthing[index];
            index++;
            return true;
        }
        index   = thing.Count + 1;
        Current = default;
        return false;
    }
    public T Current
    {
        get;
        private set;
    }
    object IEnumerator.Current => Current;
    void IEnumerator.Reset()
    {
        index   = 0;
        Current = default;
    }
}

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},";
    }
}

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();
    }
}

EntropyGeneric.cs

Detect Entropy Levels from Primitive Data Arrays

using System;
using System.Collections.Generic;
public class EntropyGeneric<T>
{
    private const    double             NaturalLogOfTwo = 0.69314718055994530941723212145818;
    private readonly Dictionary<T, int> _hist           = new Dictionary<T, int>();
    private          bool               _mapStatus;
    public EntropyGeneric()
    {
        _hist.Clear();
        _mapStatus = false;
    }
    public (double entropy, int perfect) Entropy(T[] s)
    {
        if (_mapStatus)
        {
            _hist.Clear();
            _mapStatus = false;
        }
        foreach (var c in s)
            if (!_hist.ContainsKey(c))
                _hist.Add(c, 1);
            else
                _hist[c] += 1;
        _mapStatus = true;
        var e = 0.0;
        foreach (var v in _hist.Values)
        {
            if (v <= 0)
                continue;
            var r = v             / (double) s.Length;
            e -= r * (Math.Log(r) / NaturalLogOfTwo);
        }
        return (e, GetSize());
    }
    private byte[] ConvertTypeByteArray(T[] ia)
    {
        switch (Type.GetTypeCode(typeof(T)))
        {
            case TypeCode.Boolean:
                break;
            case TypeCode.Char:
                break;
            case TypeCode.SByte:
                break;
            case TypeCode.Byte:
                break;
            case TypeCode.Int16:
                break;
            case TypeCode.UInt16:
                break;
            case TypeCode.Int32:
                break;
            case TypeCode.UInt32:
                break;
            case TypeCode.Single:
                break;
            case TypeCode.String:
                break;
            case TypeCode.Decimal:
                break;
            case TypeCode.Int64:
                break;
            case TypeCode.UInt64:
                break;
            case TypeCode.Double:
                break;
            case TypeCode.DateTime:
                break;
            default:
                throw new ArgumentException("Type is not a valid primitive.");
        }
        return ia.GetBytesObject();
    }
    private int GetSize()
    {
        var size = 0;
        switch (Type.GetTypeCode(typeof(T)))
        {
            case TypeCode.Boolean:
                size = 8;
                break;
            case TypeCode.Char:
                size = 16;
                break;
            case TypeCode.SByte:
                size = 8;
                break;
            case TypeCode.Byte:
                size = 8;
                break;
            case TypeCode.Int16:
                size = 16;
                break;
            case TypeCode.UInt16:
                size = 16;
                break;
            case TypeCode.Int32:
                size = 32;
                break;
            case TypeCode.UInt32:
                size = 32;
                break;
            case TypeCode.Single:
                size = 32;
                break;
            case TypeCode.String:
                size = 32;
                break;
            case TypeCode.Decimal:
                size = 96;
                break;
            case TypeCode.Int64:
                size = 64;
                break;
            case TypeCode.UInt64:
                size = 64;
                break;
            case TypeCode.Double:
                size = 64;
                break;
            case TypeCode.DateTime:
                size = 64;
                break;
            default:
                throw new ArgumentException("Type is not a valid primitive.");
        }
        return size;
    }
}

ByteArraySegment.cs

Segment a byte array to 16, 32, 64 bit Arrays

using System;
using System.Collections.Generic;
using System.Numerics;
public class ByteArraySegment
{
    public IEnumerable<T[]> SegmentEnum<T>(T[] buffer, int size)
    {
        var idx = 0;
        var ptr = buffer.Length;
        while (ptr >= size)
        {
            var array = new T[size];
            Buffer.BlockCopy(buffer, idx, array, 0, size);
            ptr -= size;
            idx += size;
            yield return array;
        }
    }
    public List<byte[]> SegmentList(byte[] buffer, int size)
    {
        var list = new List<byte[]>(buffer.Length >> 2);
        var idx  = 0;
        var ptr  = buffer.Length;
        while (ptr >= size)
        {
            var _result = new byte[size];
            Buffer.BlockCopy(buffer, idx, _result, 0, size);
            list.Add(_result);
            ptr -= size;
            idx += size;
        }
        return list;
    }
    public char[] SegmentChar(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 2 != 0)
            throw new Exception("Buffer must be a multiple of 2.");
        var array = new char[len >> 1];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public short[] Segment16(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 2 != 0)
            throw new Exception("Buffer must be a multiple of 2.");
        var array = new short[len >> 1];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public ushort[] SegmentU16(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 2 != 0)
            throw new Exception("Buffer must be a multiple of 2.");
        var array = new ushort[len >> 1];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public int[] Segment32(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 4 != 0)
            throw new Exception("Buffer must be a multiple of 4.");
        var array = new int[len >> 2];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public float[] SegmentFloat(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 4 != 0)
            throw new Exception("Buffer must be a multiple of 4.");
        var array = new float[len >> 2];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public uint[] SegmentU32(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 4 != 0)
            throw new Exception("Buffer must be a multiple of 4.");
        var array = new uint[len >> 2];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public long[] Segment64(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 8 != 0)
            throw new Exception("Buffer must be a multiple of 8.");
        var array = new long[len >> 3];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public double[] SegmentDouble(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 8 != 0)
            throw new Exception("Buffer must be a multiple of 8.");
        var array = new double[len >> 3];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public ulong[] SegmentU64(byte[] buffer)
    {
        var len = buffer.Length;
        if (len % 8 != 0)
            throw new Exception("Buffer must be a multiple of 8.");
        var array = new ulong[len >> 3];
        Buffer.BlockCopy(buffer, 0, array, 0, len);
        return array;
    }
    public BigInteger[] SegmentBI(byte[] buffer, int size)
    {
        var idx  = 0;
        var ptr  = buffer.Length;
        var bi   = new BigInteger[buffer.Length / size];
        var ptr1 = 0;
        while (ptr >= size)
        {
            var array = new byte[size];
            Buffer.BlockCopy(buffer, idx, array, 0, size);
            ptr      -= size;
            idx      += size;
            bi[ptr1++] =  new BigInteger(array);
        }
        return bi;
    }
}