DynArrayStruct32.cs

Dynamic Concurrent Generic Array Structure 32 Bit

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Microsoft.VisualBasic.Devices;
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public struct DynArrayStruct32<T> : IEnumerable<T>
{
    public const     int               ShiftCount  = 20;
    public const     int               Granularity = 1 << ShiftCount;
    private volatile Table             _table;
    public volatile  T[][]             Arrays;
    public volatile  int               MaximumNumberOfArrays;
    private volatile MonitorActionFunc maf;
    public DynArrayStruct32(long size)
    {
        if (size < Granularity)
            size = Granularity;
        try
        {
            maf                         = new MonitorActionFunc();
            _table                      = new 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);
            Arrays        = new T[MaximumNumberOfArrays][];
            for (var i = 0; i < _table.NumberOfActiveArrays; ++i)
                Arrays[i] = new T[Granularity];
        }
        catch (Exception ex)
        {
            throw new Exception($"'Initialize:DynArray' Exception: {ex.Message}");
        }
    }
    public DynArrayStruct32(IEnumerable<T> collection)
    {
        try
        {
            maf                   = new MonitorActionFunc();
            _table                = new Table();
            MaximumNumberOfArrays = (int) (new ComputerInfo().AvailablePhysicalMemory / Granularity);
            var size = Granularity;
            _table.NumberOfActiveArrays = (size + (Granularity - 1)) / Granularity;
            var val = (long) _table.NumberOfActiveArrays * Granularity;
            _table.Length = Interlocked.Read(ref val);
            Arrays        = new T[MaximumNumberOfArrays][];
            for (var i = 0; i < _table.NumberOfActiveArrays; ++i)
                Arrays[i] = new T[Granularity];
        }
        catch (Exception ex)
        {
            throw new Exception($"'Initialize:DynArray' Exception: {ex.Message}");
        }
        foreach (var item in collection)
            Add(item);
    }
    public long Count
    {
        get
        {
            var tmpThis = this;
            return tmpThis.maf.Lock(tmpThis, () =>
            {
                return tmpThis._table.Count;
            });
        }
    }
    public long Length
    {
        get
        {
            var tmpThis = this;
            return tmpThis.maf.Lock(tmpThis, () =>
            {
                return tmpThis._table.Length;
            });
        }
    }
    public T this[long index]
    {
        get
        {
            var tmpThis = this;
            return tmpThis.maf.Lock(tmpThis, () =>
            {
                if (index >= tmpThis._table.Length)
                    throw new Exception($"Getter: Index out of bounds, Index: '{index}' must be less than the Length: '{tmpThis.Length}'.");
                return tmpThis.Arrays[index >> ShiftCount][index & (Granularity - 1)];
            });
        }
        set
        {
            var tmpThis = this;
            tmpThis.maf.Lock(tmpThis, () =>
            {
                if (index + 1 > tmpThis._table.Length)
                    tmpThis.EnsureSize();
                tmpThis.Arrays[index >> ShiftCount][index & (Granularity - 1)] = value;
                tmpThis._table.Count++;
            });
        }
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return new Enumerator(this);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return new Enumerator(this);
    }
    public void Add(T Item)
    {
        var tmpThis = this;
        tmpThis.maf.Lock(tmpThis, () =>
        {
            if (tmpThis._table.Count + 1 > tmpThis._table.Length)
                tmpThis.EnsureSize();
            tmpThis.Arrays[tmpThis._table.Count >> ShiftCount][tmpThis._table.Count & (Granularity - 1)] = Item;
            tmpThis._table.Count++;
        });
    }
    public void AddRange(IEnumerable<T> collection)
    {
        var tmpThis = this;
        tmpThis.maf.Lock(tmpThis, () =>
        {
            foreach (var item in collection)
                tmpThis.Add(item);
        });
    }
    public Enumerator GetEnumerator()
    {
        return new Enumerator(this);
    }
    private void EnsureSize()
    {
        try
        {
            _table.NumberOfActiveArrays++;
            if (_table.NumberOfActiveArrays >= MaximumNumberOfArrays)
                throw new Exception($"Number of active arrays {_table.NumberOfActiveArrays} cannot meet or exceed the maximum number of arrays {MaximumNumberOfArrays} allowed.");
            var val = (long) _table.NumberOfActiveArrays * Granularity;
            _table.Length                           = Interlocked.Read(ref val);
            Arrays[_table.NumberOfActiveArrays - 1] = new T[Granularity];
        }
        catch (Exception ex)
        {
            throw new Exception($"'EnsureSize:DynArray' Exception: {ex.Message}");
        }
    }
    public void Clear()
    {
        var tmpThis = this;
        tmpThis.maf.Lock(tmpThis, () =>
        {
            for (var a = 0L; a < tmpThis._table.NumberOfActiveArrays; a++)
                Array.Clear(tmpThis.Arrays[a], 0, Granularity);
            tmpThis._table.Count = 0;
        });
    }
    public long IndexOf(T item)
    {
        var tmpThis = this;
        return tmpThis.maf.Lock(tmpThis, () =>
        {
            var i = 0L;
            for (; i < tmpThis._table.NumberOfActiveArrays; i++)
            {
                var pos = Array.IndexOf(tmpThis.Arrays[i], item, 0);
                if (pos != -1)
                    return i * Granularity + pos;
            }
            return -1;
        });
    }
    public DynArrayStruct32<T> Copy(int newsize)
    {
        var tmpThis = this;
        return tmpThis.maf.Lock(tmpThis, () =>
        {
            var temp = new DynArrayStruct32<T>(newsize);
            for (var a = 0L; a < tmpThis._table.NumberOfActiveArrays; a++)
                Array.Copy(tmpThis.Arrays[a], temp.Arrays[a], Granularity);
            return temp;
        });
    }
    public DynArrayStruct32<T> CopyOrInsert(T item, int newsize)
    {
        var tmpThis = this;
        return tmpThis.maf.Lock(tmpThis, () =>
        {
            if (newsize > tmpThis._table.Length)
            {
                var temp = new DynArrayStruct32<T>(newsize);
                for (var a = 0L; a < tmpThis._table.NumberOfActiveArrays; a++)
                    Array.Copy(tmpThis.Arrays[a], temp.Arrays[a], Granularity);
                temp._table.Count = tmpThis.Count;
                temp.Add(item);
                return temp;
            }
            tmpThis.Add(item);
            return tmpThis;
        });
    }
    public void FromArray(T[][] array)
    {
        var tmpThis = this;
        tmpThis.maf.Lock(tmpThis, () =>
        {
            tmpThis._table.NumberOfActiveArrays = array.GetUpperBound(0) + 1;
            var val = (long) tmpThis._table.NumberOfActiveArrays * Granularity;
            tmpThis._table.Length = Interlocked.Read(ref val);
            tmpThis.Arrays        = new T[tmpThis._table.NumberOfActiveArrays][];
            for (var i = 0; i < tmpThis._table.NumberOfActiveArrays; ++i)
                tmpThis.Arrays[i] = new T[Granularity];
            for (var a = 0L; a < tmpThis._table.NumberOfActiveArrays; a++)
                Array.Copy(array[a], tmpThis.Arrays[a], Granularity);
        });
    }
    public T[][] ToArray()
    {
        var tmpThis = this;
        return tmpThis.maf.Lock(tmpThis, () =>
        {
            var ta = new T[tmpThis._table.NumberOfActiveArrays][];
            for (var i = 0; i < tmpThis._table.NumberOfActiveArrays; ++i)
                ta[i] = new T[Granularity];
            for (var a = 0L; a < tmpThis._table.NumberOfActiveArrays; a++)
                Array.Copy(tmpThis.Arrays[a], ta[a], Granularity);
            return ta;
        });
    }
    public T[] ToArray32()
    {
        var tmpThis = this;
        return tmpThis.maf.Lock(tmpThis, () =>
        {
            if (tmpThis.Count >= uint.MaxValue)
                throw new Exception("Too many elements to cast to a 32Bit array.");
            var array = new T[tmpThis.Count];
            var cnt   = 0l;
            for (var a = 0L; a < tmpThis._table.NumberOfActiveArrays && cnt < uint.MaxValue; a++, cnt += Granularity)
                Array.Copy(tmpThis.Arrays[a], 0, array, a * Granularity, Granularity);
            return array;
        });
    }
    public (int l, int r) BoundsFromIndex(int index)
    {
        var l = index >> ShiftCount;
        var r = index & (Granularity - 1);
        return (r, r);
    }
    public int IndexFromBounds(int l, int r)
    {
        return l * Granularity + r;
    }
    private class Table
    {
        public          long Count;
        public          long Length;
        public volatile int  NumberOfActiveArrays;
    }
    [Serializable]
    public class Enumerator : IEnumerator<T>
    {
        private readonly DynArrayStruct32<T> _array;
        private volatile eTable              _eTable = new eTable();
        internal Enumerator(DynArrayStruct32<T> array)
        {
            _array         = array;
            _eTable._index = 0;
            Current        = default;
        }
        public T Current
        {
            get;
            private set;
        }
        object IEnumerator.Current
        {
            get
            {
                return _array.maf.Lock(this, () =>
                {
                    if (_eTable._index == _array._table.Count + 1)
                        throw new Exception($"Enumerator out of range: {_eTable._index}");
                    return Current;
                });
            }
        }
        public void Dispose()
        {
        }
        public bool MoveNext()
        {
            return _array.maf.Lock(this, () =>
            {
                for (; _eTable._index < _array._table.Count; ++_eTable._index)
                    if (_eTable._index < _array._table.Count || _eTable._index == 0)
                    {
                        Current = _array[_eTable._index];
                        ++_eTable._index;
                        return true;
                    }
                _eTable._index = _array._table.Count + 1;
                Current        = default;
                return false;
            });
        }
        void IEnumerator.Reset()
        {
            _eTable._index = 0;
            Current        = default;
        }
        private class eTable
        {
            public long _index;
        }
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *