BoyerMooreString.cs

BoyerMoore String Searching Algorithm

using System;
using System.Collections.Generic;
public class BoyerMooreString
{
    private       int[]  _jumpTable;
    private       string _pattern;
    private       int    _patternLength;
    public BoyerMooreString()
    {
    }
    public BoyerMooreString(string pattern)
    {
        SetPattern(pattern);
    }
    public void SetPattern(string pattern)
    {
        _pattern       = pattern;
        _jumpTable     = new int[ushort.MaxValue];
        _patternLength = _pattern.Length;
        for (var index = 0; index < ushort.MaxValue; ++index)
            _jumpTable[index] = _patternLength;
        for (var index = 0; index < _patternLength - 1; ++index)
            _jumpTable[_pattern[index]] = _patternLength - index - 1;
    }
    public unsafe int Search(string searray, int startIndex = 0)
    {
        if (_pattern == null)
            throw new Exception("Pattern has not been set.");
        if (_patternLength > searray.Length)
            throw new Exception("Search Pattern length exceeds search array length.");
        var num1 = startIndex;
        var num2 = searray.Length - _patternLength;
        var num3 = _patternLength - 1;
        var num4 = 0;
        fixed (char* chPtr1 = searray)
        {
            var chPtr2 = chPtr1 + startIndex;
            fixed (char* chPtr3 = _pattern)
            {
                while (num1 <= num2)
                {
                    var index = num3;
                    while (index >= 0 && chPtr3[index] == chPtr2[num1 + index])
                        --index;
                    if (index < 0)
                        return num1;
                    num1 += _jumpTable[chPtr2[num1 + index]];
                    ++num4;
                }
            }
        }
        return -1;
    }
    public unsafe (List<int>, int) SearchAll(string searray, int startIndex = 0)
    {
        if (_pattern == null)
            throw new Exception("Pattern has not been set.");
        if (_patternLength > searray.Length)
            throw new Exception("Search Pattern length exceeds search array length.");
        var num1    = startIndex;
        var num2    = searray.Length - _patternLength;
        var num3    = _patternLength - 1;
        var intList = new List<int>();
        var num4    = 0;
        fixed (char* chPtr1 = searray)
        {
            var chPtr2 = chPtr1 + startIndex;
            fixed (char* chPtr3 = _pattern)
            {
                while (num1 <= num2)
                {
                    var index = num3;
                    while (index >= 0 && chPtr3[index] == chPtr2[num1 + index])
                        --index;
                    if (index < 0)
                        intList.Add(num1);
                    num1 += _jumpTable[chPtr2[num1 + index]];
                    ++num4;
                }
            }
        }
        return (intList, num4);
    }
    public int SuperSearch(string searray, int nth, int start = 0)
    {
        var startIndex = start;
        var num1       = 0;
        do
        {
            var num2 = Search(searray, startIndex);
            if (num2 == -1)
                return -1;
            ++num1;
            startIndex = num2 + 1;
        } while (num1 < nth);
        return startIndex - 1;
    }
    public class BMPartialPatternSearchString
    {
        public int MinimumSearchLength;
        public BMPartialPatternSearchString(int min = 5)
        {
            MinimumSearchLength = min;
        }
        public (string partialPattern, int idx) SearchPartial(string pattern, string searray)
        {
            BoyerMooreString boyerMooreString = new BoyerMooreString(pattern);
            var              length           = pattern.Length;
            var              stringList       = new List<string>();
            if (length < MinimumSearchLength)
                throw new Exception("Search Pattern less than minimum search length.");
            var startIndex          = 0;
            var minimumSearchLength = MinimumSearchLength;
            do
            {
                var pattern1 = pattern.Substring(startIndex, minimumSearchLength);
                stringList.Add(pattern1);
                boyerMooreString.SetPattern(pattern1);
                int num = boyerMooreString.Search(searray);
                if (num != -1)
                    return (pattern1, num);
                if (startIndex + minimumSearchLength >= length)
                {
                    startIndex = 0;
                    ++minimumSearchLength;
                }
                else
                {
                    ++startIndex;
                }
            } while (minimumSearchLength != length + 1);
            return (pattern, -1);
        }
        public List<(string partialPattern, int idx)> SearchPartialFirst(
            string pattern,
            string searray)
        {
            BoyerMooreString boyerMooreString = new BoyerMooreString(pattern);
            var              length           = pattern.Length;
            var              valueTupleList   = new List<(string, int)>();
            var              stringList       = new List<string>();
            if (length < MinimumSearchLength)
                throw new Exception("Search Pattern less than minimum search length.");
            var startIndex          = 0;
            var minimumSearchLength = MinimumSearchLength;
            do
            {
                var pattern1 = pattern.Substring(startIndex, minimumSearchLength);
                stringList.Add(pattern1);
                boyerMooreString.SetPattern(pattern1);
                int num = boyerMooreString.Search(searray);
                if (num != -1)
                    valueTupleList.Add((pattern1, num));
                if (startIndex + minimumSearchLength >= length)
                {
                    startIndex = 0;
                    ++minimumSearchLength;
                }
                else
                {
                    ++startIndex;
                }
            } while (minimumSearchLength != length + 1);
            return new List<(string, int)>
                { (pattern, -1) };
        }
        public List<(string partialPattern, int idx)> SearchPartialAll(
            string pattern,
            string searray)
        {
            BoyerMooreString boyerMooreString = new BoyerMooreString(pattern);
            var              length           = pattern.Length;
            var              valueTupleList   = new List<(string, int)>();
            var              stringList       = new List<string>();
            if (length < MinimumSearchLength)
                throw new Exception("Search Pattern less than minimum search length.");
            var startIndex          = 0;
            var minimumSearchLength = MinimumSearchLength;
            do
            {
                var pattern1 = pattern.Substring(startIndex, minimumSearchLength);
                stringList.Add(pattern1);
                boyerMooreString.SetPattern(pattern1);
                (List<int>, int) tuple = boyerMooreString.SearchAll(searray);
                if (tuple.Item1.Count > 0)
                    foreach (var num in tuple.Item1)
                        valueTupleList.Add((pattern1, num));
                if (startIndex + minimumSearchLength >= length)
                {
                    startIndex = 0;
                    ++minimumSearchLength;
                }
                else
                {
                    ++startIndex;
                }
            } while (minimumSearchLength != length + 1);
            return valueTupleList;
        }
    }
}

BoyerMooreGeneric.cs

C# Boyer Moore Generic Search Algorithm

Updated: March 13, 2022

using System;
using System.Collections.Generic;
public class BoyerMooreGeneric<T>
{
    private readonly IEqualityComparer<T> _comparer;
    private          Dictionary<T, int>   _jumpTable;
    private          T[]                  _pattern;
    private          int                  _patternLength;
    public BoyerMooreGeneric()
    {
        _comparer = EqualityComparer<T>.Default;
    }
    public BoyerMooreGeneric(T[] pattern)
    {
        _comparer = EqualityComparer<T>.Default;
        SetPattern(pattern);
    }
    public BoyerMooreGeneric(T[] pattern, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            _comparer = EqualityComparer<T>.Default;
        else
            _comparer = comparer;
        SetPattern(pattern);
    }
    public BoyerMooreGeneric(IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            _comparer = EqualityComparer<T>.Default;
        else
            _comparer = comparer;
    }
    public void SetPattern(T[] pattern)
    {
        _pattern       = pattern;
        _jumpTable     = new Dictionary<T, int>();
        _patternLength = _pattern.Length;
        for (var index = 0; index < _patternLength - 1; index++)
            _jumpTable[_pattern[index]] = _patternLength - index - 1;
    }
    public int Search(T[] searchArray, int startIndex = 0)
    {
        if (_pattern == null)
            throw new Exception("Pattern has not been set.");
        if (_patternLength > searchArray.Length)
            throw new Exception("Search Pattern length exceeds search array length.");
        var scArr                 = searchArray.SubArray(startIndex, searchArray.Length - startIndex);
        var index                 = startIndex;
        var limit                 = searchArray.Length - _patternLength;
        var patternLengthMinusOne = _patternLength     - 1;
        var Moves                 = 0;
        var a0                    = 0;
        var b0                    = 0;
        while (index <= limit)
        {
            var j = patternLengthMinusOne;
            while (j >= 0 && _comparer.Equals(_pattern[j], scArr[index + j]))
                j--;
            if (j < 0)
                return index;
            if (_jumpTable.TryGetValue(scArr[index + j], out var j0))
            {
                index += j0;
                a0++;
            }
            else
            {
                index += _patternLength;
                b0++;
            }
            Moves++;
        }
        return -1;
    }
    public List<int> SearchAll(T[] searchArray, int startIndex = 0)
    {
        if (searchArray == null)
            throw new Exception("Search array has not been set.");
        if (_pattern == null)
            throw new Exception("Pattern has not been set.");
        var scArr = searchArray.SubArray(startIndex, searchArray.Length - startIndex);
        var scLen = searchArray.Length;
        if (_patternLength > scArr.Length)
            throw new Exception("Search Pattern length exceeds search array length.");
        var index = 0;
        var lst   = new List<int>();
        while (index <= scLen - _patternLength)
        {
            var j = _patternLength - 1;
            while (j >= 0 && _comparer.Equals(_pattern[j], scArr[index + j]))
                j--;
            if (j < 0)
                lst.Add(index);
            if (_jumpTable.TryGetValue(scArr[index + j], out var j0))
                index += j0;
            else
                index += _patternLength;
        }
        return lst;
    }
    public int SuperSearch(T[] searchArray, int nth, int start = 0)
    {
        var e = start;
        var c = 0;
        do
        {
            e = Search(searchArray, e);
            if (e == -1)
                return -1;
            c++;
            e++;
        } while (c < nth);
        return e - 1;
    }
    public IEnumerable<(T[] partialPattern, int idx)> SearchPartialAll(T[] pattern, T[] searchArray, int MinimumSearchLength = 3)
    {
        SetPattern(pattern);
        var len = searchArray.Length;
        var lst = new List<(T[] partialPattern, int idx)>();
        if (len < MinimumSearchLength)
            throw new Exception("Search Pattern less than minimum search length.");
        var offset = 0;
        var wl     = MinimumSearchLength;
        var pDic   = new Dictionary<int, int>();
        int ol     = 0, il = 0;
        do
        {
            ol++;
            var tpat = new T[wl];
            Array.Copy(searchArray, offset, tpat, 0, wl);
            SetPattern(tpat);
            var idxl = SearchAll(searchArray);
            if (idxl.Count > 0)
                foreach (var idx in idxl)
                    lst.Add((tpat, idx));
            if (pDic.ContainsKey(wl))
                pDic[wl] += idxl.Count;
            else
                pDic.Add(wl, idxl.Count);
            if (offset + wl >= len)
            {
                il++;
                if (pDic.ContainsKey(wl))
                    if (pDic[wl] == 0)
                    {
                        pDic.Remove(wl);
                        break;
                    }
                offset = 0;
                ol     = 0;
                wl++;
                continue;
            }
            offset++;
        } while (wl != len + 1);
        return lst;
    }
}

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

CcDictionary.cs

Concurrent Dictionary Class without Blocking

Updated: July-27,2021

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
public class CcDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
    private readonly int                     _size;
    private volatile int[]                   _activeThreads;
    private          DicA<TKey, TValue>[]    _array;
    private volatile int                     _bP;
    internal         IEqualityComparer<TKey> _comparer;
    public volatile  int                     NumberOfActiveThreads;
    public CcDictionary() : this(1024, null)
    {
    }
    public CcDictionary(int size) : this(size, null)
    {
    }
    public CcDictionary(int size, IEqualityComparer<TKey> comparer)
    {
        ThreadPool.GetMaxThreads(out var nW, out var nI);
        _array                = new DicA<TKey, TValue>[nW];
        _size                 = size;
        NumberOfActiveThreads = 0;
        _bP                   = 0;
        _activeThreads        = new int[Environment.ProcessorCount];
        _activeThreads.Fill(-1);
        if (comparer == null)
            _comparer = EqualityComparer<TKey>.Default;
        else
            _comparer = comparer;
    }
    public CcDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, int concurrencyLevel = 0)
    {
        ThreadPool.GetMaxThreads(out var nW, out var nI);
        _array = new DicA<TKey, TValue>[nW];
        var col = collection.ToList();
        _size                 = col.Count;
        NumberOfActiveThreads = 0;
        _bP                   = 0;
        _activeThreads        = new int[Environment.ProcessorCount];
        _activeThreads.Fill(-1);
        _comparer = EqualityComparer<TKey>.Default;
        var ccl = Environment.ProcessorCount;
        if (concurrencyLevel != 0)
            ccl = concurrencyLevel;
        col.AsParallel().WithDegreeOfParallelism(ccl).ForAll(i =>
        {
            Add(i.Key, i.Value);
        });
    }
    public int Count
    {
        get
        {
            var totalCount = 0;
            for (var i = 0; i < _activeThreads.Length; ++i)
                if (_activeThreads[i] != -1)
                    if (_array[_activeThreads[i]] != null)
                        totalCount += _array[_activeThreads[i]].Count;
            return totalCount;
        }
    }
    public TValue this[TKey key]
    {
        get
        {
           ProcessThread();
            var rv = FindKey(key);
            return rv.idx != -1 ? _array[rv.trd][key] : default;
        }
        set => Add(key, value, true);
    }
    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return GetEnum();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnum();
    }
    public bool TryGetValue(TKey key, out TValue value)
    {
        var (idx, trd) = FindKey(key);
        if (idx == -1)
        {
            value = default;
            return false;
        }
        value = _array[trd][key];
        return true;
    }
    public void Clear()
    {
        ThreadPool.GetMaxThreads(out var nW, out var nI);
        _array                = new DicA<TKey, TValue>[nW];
        NumberOfActiveThreads = 0;
        _bP                   = 0;
        _activeThreads        = new int[Environment.ProcessorCount];
        _activeThreads.Fill(-1);
    }
    public void AddRange(IEnumerable<KeyValuePair<TKey, TValue>> collection, int concurrencyLevel = 0)
    {
        var ccl = Environment.ProcessorCount;
        if (concurrencyLevel != 0)
            ccl = concurrencyLevel;
        collection.AsParallel().WithDegreeOfParallelism(ccl).ForAll(i =>
        {
            Add(i.Key, i.Value);
        });
    }
    public void Add(TKey key, TValue value, bool updateValue = false)
    {
        var id  = ProcessThread();
        var idx = FindKey(key);
        if (idx.idx == -1)
            _array[id].Add(key, value);
        else if (updateValue)
            _array[idx.trd].Values[idx.idx] = value;
    }
    private int ProcessThread()
    {
        var id = Thread.CurrentThread.ManagedThreadId;
        if (_array[id] == null)
        {
            _array[id] = new DicA<TKey, TValue>(_size, _comparer);
            Interlocked.Increment(ref NumberOfActiveThreads);
            if (_bP >= _activeThreads.Length)
            {
                var nAtA = new int[_activeThreads.Length << 1];
                nAtA.Fill(-1);
                for (var i = 0; i < _activeThreads.Length; ++i)
                    if (_activeThreads[i] != -1)
                        nAtA[i] = _activeThreads[i];
                _activeThreads = nAtA;
            }
            _activeThreads[_bP] = id;
            Interlocked.Increment(ref _bP);
        }
        return id;
    }
    public bool TryAdd(TKey key, TValue value)
    {
        Add(key, value);
        return true;
    }
    public bool ContainsKey(TKey key)
    {
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                    if (_array[_activeThreads[i]].ContainsKey(key))
                        return true;
        return false;
    }
    public bool ContainsValue(TValue value)
    {
        var eComparer = EqualityComparer<TValue>.Default;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                    for (var j = 0; j < _array[_activeThreads[i]].Count; ++j)
                        if (eComparer.Equals(_array[_activeThreads[i]].Values[j], value))
                            return true;
        return false;
    }
    public (int idx, int trd) FindKey(TKey key)
    {
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                {
                    var idx = _array[_activeThreads[i]].FindKeyIndex(key);
                    if (idx != -1)
                        return (idx, _activeThreads[i]);
                }
        return (-1, -1);
    }
    public bool Remove(TKey key)
    {
        var (idx, trd) = FindKey(key);
        if (idx == -1)
            return false;
        _array[_activeThreads[trd]].Remove(key);
        return true;
    }
    private IEnumerator<KeyValuePair<TKey, TValue>> GetEnum()
    {
        foreach (var i in ToArray())
            yield return new KeyValuePair<TKey, TValue>(i.Key, i.Value);
    }
    public KeyValuePair<TKey, TValue>[] ToArray()
    {
        var totalCount = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                    totalCount += _array[_activeThreads[i]].Count;
        var ta  = new KeyValuePair<TKey, TValue>[totalCount];
        var ptr = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                    foreach (var v in _array[_activeThreads[i]])
                        ta[ptr++] = new KeyValuePair<TKey, TValue>(v.Key, v.Value);
        return ta;
    }
    public class DicA<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
    {
        public MSet15<TKey> Keys;
        public int          Resizes;
        public TValue[]     Values;
        public DicA() : this(101, EqualityComparer<TKey>.Default)
        {
        }
        public DicA(int size) : this(size, EqualityComparer<TKey>.Default)
        {
        }
        public DicA(int size, IEqualityComparer<TKey> comparer)
        {
            if (comparer == null)
                comparer = EqualityComparer<TKey>.Default;
            Keys          = new MSet15<TKey>(size);
            Values        = new TValue[size];
            Keys.Comparer = comparer;
        }
        public DicA(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer = null)
        {
            if (comparer == null)
                comparer = EqualityComparer<TKey>.Default;
            Keys.Comparer = comparer;
            foreach (var kp in collection)
                Add(kp.Key, kp.Value);
        }
        public int Count => Keys.Count;
        public TValue this[TKey key]
        {
            get
            {
                var pos = Keys.FindEntry(key);
                return pos == -1 ? default : Values[pos];
            }
            set => Add(key, value);
        }
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            for (var i = 0; i < Count; i++)
                if (Keys.Slots[i].HashCode > 0)
                    yield return new KeyValuePair<TKey, TValue>(Keys.Slots[i].Value, Values[i]);
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        public bool Add(TKey key, TValue value)
        {
            if (!Keys.Add(key))
            {
                if (Values.Length != Keys.Slots.Length)
                {
                    var nValues = new TValue[Keys.Slots.Length];
                    Array.Copy(Values, nValues, Values.Length);
                    Values = nValues;
                    Resizes++;
                }
                Values[Keys.Position] = value;
                return false;
            }
            Values[Keys.Position] = value;
            return true;
        }
        public void Remove(TKey key)
        {
            var pos = Keys.FindEntry(key);
            if (pos != -1)
            {
                Values[pos] = default;
                Keys.Remove(key);
            }
        }
        public bool ContainsKey(TKey key)
        {
            return Keys.FindEntry(key) != -1;
        }
        public int FindKeyIndex(TKey key)
        {
            return Keys.FindEntry(key);
        }
    }
}

CcHashSet.cs

Concurrent HashSet Class without Blocking

Updated: July-23,2021

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
public class CcHashSet<T> : IEnumerable
{
    private readonly HashSet<T>[]         _array;
    private readonly int                  _size;
    private volatile int[]                _activeThreads;
    private volatile int                  _bP;
    private readonly IEqualityComparer<T> _comparer;
    public volatile  int                  NumberOfActiveThreads;
    public CcHashSet() : this(1024, null)
    {
    }
    public CcHashSet(int size) : this(size, null)
    {
    }
    public CcHashSet(int size, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            _comparer = EqualityComparer<T>.Default;
        else
            _comparer = comparer;
        ThreadPool.GetMaxThreads(out var nW, out var nI);
        _array                = new HashSet<T>[nW];
        _size                 = size;
        NumberOfActiveThreads = 0;
        _bP                   = 0;
        _activeThreads        = new int[Environment.ProcessorCount];
        _activeThreads.Fill(-1);
    }
    public int Count
    {
        get
        {
            var totalCount = 0;
            for (var i = 0; i < _activeThreads.Length; ++i)
                if (_activeThreads[i] != -1)
                    if (_array[_activeThreads[i]] != null)
                        totalCount += _array[_activeThreads[i]].Count;
            return totalCount;
        }
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnum();
    }
    public IEnumerator<T> GetEnumerator()
    {
        return GetEnum();
    }
    public void Add(T item)
    {
        var id = Thread.CurrentThread.ManagedThreadId;
        if (_array[id] == null)
        {
            _array[id] = new HashSet<T>(_size, _comparer);
            Interlocked.Increment(ref NumberOfActiveThreads);
            if (_bP >= _activeThreads.Length)
            {
                var nAtA = new int[_activeThreads.Length << 1];
                nAtA.Fill(-1);
                for (var i = 0; i < _activeThreads.Length; ++i)
                    if (_activeThreads[i] != -1)
                        nAtA[i] = _activeThreads[i];
                _activeThreads = nAtA;
            }
            _activeThreads[_bP] = id;
            Interlocked.Increment(ref _bP);
        }
        if (!Contains(item))
            _array[id].Add(item);
    }
    public bool Contains(T item)
    {
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                    if (_array[_activeThreads[i]].Contains(item))
                        return true;
        return false;
    }
    public IEnumerator<T> GetEnum()
    {
        var arr = ToArray();
        foreach (var i in arr)
            yield return i;
    }
    public T[] ToArray()
    {
        var totalCount = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                    totalCount += _array[_activeThreads[i]].Count;
        var ta  = new T[totalCount];
        var ptr = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]] != null)
                {
                    var it = _array[_activeThreads[i]].ToArray();
                    for (var j = 0; j < it.Length; ++j)
                        ta[ptr++] = it[j];
                }
        return ta;
    }
}

CcCollection.cs

Concurrent Collection Class without Blocking

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
public class CcCollection<T> : IEnumerable<T>
{
    private readonly IntA<T>[] _array;
    private readonly int       _size;
    private volatile int[]     _activeThreads;
    private volatile int       _bP;
    public volatile  int       NumberOfActiveThreads;
    public CcCollection() : this(1024)
    {
    }
    public CcCollection(int size)
    {
        ThreadPool.GetMaxThreads(out var nW, out var nI);
        _array                = new IntA<T>[nW];
        _size                 = size;
        NumberOfActiveThreads = 0;
        _bP                   = 0;
        _activeThreads        = new int[Environment.ProcessorCount];
        _activeThreads.Fill(-1);
    }
    public int Count
    {
        get
        {
            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)
    {
        var id = Thread.CurrentThread.ManagedThreadId;
        if (!_array[id].Allocated)
        {
            _array[id] = new IntA<T>(_size);
            Interlocked.Increment(ref NumberOfActiveThreads);
            if (_bP >= _activeThreads.Length)
            {
                var nAtA = new int[_activeThreads.Length << 1];
                nAtA.Fill(-1);
                for (var i = 0; i < _activeThreads.Length; ++i)
                    if (_activeThreads[i] != -1)
                        nAtA[i] = _activeThreads[i];
                _activeThreads = nAtA;
            }
            _activeThreads[_bP] = id;
            Interlocked.Increment(ref _bP);
        }
        _array[id].Add(item);
    }
    public IEnumerator<T> GetEnum()
    {
        var arr = ToArray();
        foreach (var i in arr)
            yield return i;
    }
    public T[] ToArray()
    {
        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;
        var ta  = new T[totalCount];
        var ptr = 0;
        for (var i = 0; i < _activeThreads.Length; ++i)
            if (_activeThreads[i] != -1)
                if (_array[_activeThreads[i]].Allocated)
                {
                    var it = _array[_activeThreads[i]].ToArray();
                    for (var j = 0; j < it.Length; ++j)
                        ta[ptr++] = it[j];
                }
        return ta;
    }
    internal struct IntA<T> : IEnumerable<T>
    {
        private T[]  _array;
        public  bool Allocated;
        public IntA(int cap)
        {
            Count     = 0;
            _array    = new T[cap];
            Allocated = true;
        }
        public int Count
        {
            get;
            private set;
        }
        public int Length => _array.Length;
        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)
        {
            if (Count >= _array.Length)
                Array.Resize(ref _array, _array.Length << 1);
            _array[Count] = item;
            Count++;
        }
        public T[] ToArray()
        {
            var newtArray = new T[Count];
            Array.Copy(_array, 0, newtArray, 0, Count);
            return newtArray;
        }
        public void Trim()
        {
            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];
        }
    }
}

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];
        }
    }
}

SegmentedHashSet.cs

Segmented Hashset Class

Useful for input or output buffer for use in parallel invoke operations where unique values are needed.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
public class SegmentedHashSet<T> : IEnumerable<T>
{
    private readonly IntHs<T>[] _array;
    private readonly int        _size;
    private          int        _length;
    public SegmentedHashSet(int length, int size)
    {
        _array = new IntHs<T>[4096];
        for (var i = 0; i < length; ++i)
            _array[i] = new IntHs<T>(size);
        _length = length;
        _size   = size;
    }
    public IEnumerator<T> GetEnumerator()
    {
        throw new NotImplementedException();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Add(T item, int index)
    {
        if (index >= _length)
            for (var i = _length; i <= index; ++i)
            {
                _array[i] = new IntHs<T>(_size);
                _length++;
            }
        if (!ContainedInArray(item))
            _array[index].Add(item);
    }
    private bool ContainedInArray(T item)
    {
        for (var i = 0; i < _length; ++i)
            if (_array[i].Contains(item))
                return true;
        return false;
    }
    public T[] CombineToArray()
    {
        var totalCount = 0;
        for (var i = 0; i < _length; ++i)
            totalCount += _array[i].Count;
        var ta  = new T[totalCount];
        var ptr = 0;
        for (var i = 0; i < _length; ++i)
        {
            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 class IntHs<T> : IEnumerable
    {
        private  Bucket[]             _buckets;
        internal IEqualityComparer<T> Comparer;
        public IntHs(int size) : this(size, null)
        {
        }
        public IntHs(int size, IEqualityComparer<T> comparer)
        {
            if (comparer == null)
                comparer = EqualityComparer<T>.Default;
            Comparer = comparer;
            _buckets = new Bucket[size];
            Count    = 0;
        }
        public int Count
        {
            get;
            private set;
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        public void Zero()
        {
            _buckets = null;
            Count    = 0;
        }
        public bool Add(T item)
        {
            if (Count >= _buckets.Length)
                EnsureSize();
            var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
            var apos     = FindEntry(item, hashCode).APos;
            if (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 (int APos, int BPos) FindEntry(T item, int hashCode)
        {
            if (Count == 0)
                return (-1, -1);
            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 (Equals(i, item))
                    return (aPos, bPos);
                bPos++;
            }
            return (-1, -1);
        }
        private void EnsureSize()
        {
            var cArray = ToArray();
            _buckets = new Bucket[_buckets.Length + _buckets.Length / 4 * 3];
            foreach (var i in cArray)
            {
                var hashCode = Comparer.GetHashCode(i) & int.MaxValue;
                var pos      = hashCode % _buckets.Length;
                if (_buckets[pos] == null)
                    _buckets[pos] = new Bucket();
                _buckets[pos].Add(i);
            }
        }
        public bool Contains(T item)
        {
            var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
            return FindEntry(item, hashCode).APos != -1;
        }
        public IEnumerator<T> GetEnumerator()
        {
            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];
        }
        internal class Bucket
        {
            public int Count;
            public T[] Values;
            public Bucket()
            {
                Values = new T[1];
                Count  = 0;
            }
            public void Add(T item)
            {
                if (Count >= Values.Length)
                    Array.Resize(ref Values, Values.Length + 1);
                Values[Count++] = item;
            }
        }
    }
}

JaggedArray.cs

Jagged Array Collection Class (No Copy Resize)

Updated: Jun-21,2021

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
/// <summary>
///     Uses a multidimensional array to create a growable array with out copy or re-allocation.
/// </summary>
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public struct JaggedArray<T> : IEnumerable<T>, IDisposable
{
    private const int   FirstDimensionMax = 4096;
    public const  int   ShiftCount        = 19;
    public const  int   Granularity       = 1 << ShiftCount;
    private       bool  _disposed;
    private       T[][] _array;
    public        int   Count;
    public        int   Length;
    public        int   NumberOfActiveArrays;
    public        bool  Allocated;
    public JaggedArray(int size)
    {
        if (size < Granularity)
            size = Granularity;
        try
        {
            NumberOfActiveArrays = (size + (Granularity - 1)) / Granularity;
            Length               = NumberOfActiveArrays       * Granularity;
            _array               = new T[FirstDimensionMax][];
            for (var i = 0; i < NumberOfActiveArrays; ++i)
                _array[i] = new T[Granularity];
        }
        catch (Exception ex)
        {
            throw new Exception($"Exception: {ex.Message}");
        }
        Count     = 0;
        _disposed = false;
        Allocated = true;
    }
    public T this[int index]
    {
        get
        {
            if (index >= Length)
                throw new Exception($"Getter: Index out of bounds, Index: '{index}' must be less than the Length: '{Length}'.");
            return _array[index >> ShiftCount][index & (Granularity - 1)];
        }
        set
        {
            if (index >= Length)
                ResizeArray();
            _array[index >> ShiftCount][index & (Granularity - 1)] = value;
            Count++;
        }
    }
    public void Dispose()
    {
        Dispose(true);
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Add(T Item)
    {
        if (Count >= Length)
            ResizeArray();
        var x = Count >> ShiftCount;
        var y = Count & (Granularity - 1);
        _array[x][y] = Item;
        Count++;
    }
    private void ResizeArray()
    {
        try
        {
            _array[NumberOfActiveArrays] = new T[Granularity];
            NumberOfActiveArrays++;
        }
        catch (Exception ex)
        {
            throw new Exception($"Exception: {ex.Message}");
        }
    }
    public void Zero()
    {
        for (var a = 0L; a < NumberOfActiveArrays; a++)
            _array[a] = Array.Empty<T>();
        Count = 0;
    }
    public void Clear()
    {
        for (var a = 0L; a < NumberOfActiveArrays; a++)
            Array.Clear(_array[a], 0, Granularity);
        Count = 0;
    }
    public int IndexOf(T item)
    {
        var i = 0;
        for (; i < NumberOfActiveArrays; i++)
        {
            var pos = Array.IndexOf(_array[i], item, 0);
            if (pos != -1)
                return i * Granularity + pos;
        }
        return -1;
    }
    public JaggedArray<T> Copy(int newsize)
    {
        var temp = new JaggedArray<T>(newsize);
        for (var a = 0L; a < NumberOfActiveArrays; a++)
            Array.Copy(_array[a], temp._array[a], Granularity);
        temp.Count = Count;
        return temp;
    }
    public void FromArray(T[][] array)
    {
        NumberOfActiveArrays = array.GetUpperBound(0) + 1;
        Length               = NumberOfActiveArrays * Granularity;
        _array               = new T[NumberOfActiveArrays][];
        for (var i = 0; i < NumberOfActiveArrays; ++i)
            _array[i] = new T[Granularity];
        for (var a = 0L; a < NumberOfActiveArrays; a++)
            Array.Copy(array[a], _array[a], Granularity);
    }
    public T[][] ToRawArray()
    {
        var ta = new T[NumberOfActiveArrays][];
        for (var i = 0; i < NumberOfActiveArrays; ++i)
            ta[i] = new T[Granularity];
        for (var a = 0L; a < NumberOfActiveArrays; a++)
            Array.Copy(_array[a], ta[a], Granularity);
        return ta;
    }
    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 void Dispose(bool disposing)
    {
        if (!_disposed)
            if (disposing)
                _array = null;
        _disposed = true;
    }
    public IEnumerator<T> GetEnumerator()
    {
        return GetEnum();
    }
    public IEnumerator<T> GetEnum()
    {
        for (var i = 0; i < Count; i++)
            yield return this[i];
    }
}

BucketHashSet3.cs

Single Array HashSet Class

Uses only a single array for tracking and storage.

Updated: July-11,2021

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
[DebuggerDisplay("Count = {Count}")]
public class BucketHashSet3<T> : IEnumerable
{
    private  Bucket[]             _buckets;
    internal IEqualityComparer<T> Comparer;
    private  int                  HiBucketCount;
    public BucketHashSet3() : this(1_000_000, 10, null)
    {
    }
    public BucketHashSet3(int sizeHint, int sizeHintBucket) : this(sizeHint, sizeHintBucket, null)
    {
    }
    public BucketHashSet3(int sizeHint, int sizeHintBucket, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<T>.Default;
        Comparer      = comparer;
        _buckets      = new Bucket[sizeHint];
        Count         = 0;
        HiBucketCount = 0;
        for (var i = 0; i < _buckets.Length; ++i)
            _buckets[i].Allocate(sizeHintBucket);
    }
    public int Count
    {
        get;
        private set;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Zero()
    {
        _buckets = null;
        Count    = 0;
    }
    public bool Add(T item)
    {
        var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
        var apos     = FindEntry(item, hashCode);
        if (apos != -1)
            return false;
        var pos = hashCode % _buckets.Length;
        _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 int FindEntry(T item, int hashCode)
    {
        if (Count == 0)
            return -1;
        var Pos = hashCode % _buckets.Length;
        if (_buckets[Pos].Count == 0)
            return -1;
        var cnt = _buckets[Pos].Count;
        if (cnt > HiBucketCount)
            HiBucketCount = cnt;
        if (HiBucketCount >= 100)
        {
            Resize();
            HiBucketCount = 0;
            return FindEntry(item, hashCode);
        }
        for (var i = 0; i < cnt; ++i)
        {
            var v = _buckets[Pos].Values[i];
            if (Comparer.Equals(v, item))
                return Pos;
        }
        return -1;
    }
    private void Resize()
    {
        var cArray  = ToArray();
        var newSize = _buckets.Length << 1;
        _buckets = new Bucket[newSize];
        for (var i = 0; i < newSize; ++i)
            _buckets[i].Allocate();
        foreach (var i in cArray)
            _buckets[BucketPosition(i)].Add(i);
    }
    private int BucketPosition(T item)
    {
        var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
        var pos      = hashCode % _buckets.Length;
        return pos;
    }
    public bool Contains(T item)
    {
        var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
        return FindEntry(item, hashCode) != -1;
    }
    public IEnumerator<T> GetEnumerator()
    {
        return GetEnum();
    }
    public IEnumerator<T> GetEnum()
    {
        for (var i = 0; i < _buckets.Length; i++)
        for (var j = 0; j < _buckets[i].Count; ++j)
            yield return _buckets[i].Values[j];
    }
    internal struct Bucket
    {
        public int Count;
        public T[] Values;
        public void Add(T item)
        {
            if (Count >= Values.Length)
                Array.Resize(ref Values, Values.Length << 1);
            Values[Count++] = item;
        }
        public void Allocate(int size = 10)
        {
            Values = new T[size];
        }
    }
}