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

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

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

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

BigHashSet.cs

Big Hash Set based on BigArray.cs

Uses two arrays, for a single array use BigHashsetSa.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Threading;
[Serializable]
[DebuggerDisplay("Count = {Count}")]
[Obsolete]
public class BigHashSet<T> : MonitorActionFunc, IEnumerable<T>, ISerializable, IDeserializationCallback
{
private readonly SerializationInfo sInfo;
public volatile Table _table = new Table();
public BigHashSet() : this(BigArray<T>.Granularity, new BigComparer<T>())
{
}
public BigHashSet(long size) : this(size, new BigComparer<T>())
{
}
public BigHashSet(IBigEqualityComparer<T> comparer) : this(BigArray<T>.Granularity, comparer)
{
}
public BigHashSet(long size, IBigEqualityComparer<T> comparer)
{
Lock(this, () =>
{
if (size < BigArray<T>.Granularity)
size = BigArray<T>.Granularity;
if (comparer == null)
comparer = new DynComparer64<T>();
_table.Comparer = comparer;
_table.HashBuckets = new BigArray<long>(size);
_table.Slots = new BigArray<Slot>(size);
_table._count = 0;
_table.Position = -1;
_table.HashBuckets.OverrideAutoConcurrency = true;
_table.Slots.OverrideAutoConcurrency = true;
});
}
public BigHashSet(IEnumerable<T> collection)
{
Lock(this, () =>
{
var size = BigArray<T>.Granularity;
_table.Comparer = new DynComparer64<T>();
_table.HashBuckets = new BigArray<long>(size);
_table.Slots = new BigArray<Slot>(size);
_table._count = 0;
_table.Position = -1;
_table.HashBuckets.OverrideAutoConcurrency = true;
_table.Slots.OverrideAutoConcurrency = true;
foreach (var item in collection)
Insert(item, true);
});
}
public BigHashSet(IEnumerable<T> collection, IBigEqualityComparer<T> comparer)
{
Lock(this, () =>
{
if (comparer == null)
comparer = new DynComparer64<T>();
var size = BigArray<T>.Granularity;
_table.Comparer = comparer;
_table.Comparer = new DynComparer64<T>();
_table.HashBuckets = new BigArray<long>(size);
_table.Slots = new BigArray<Slot>(size);
_table._count = 0;
_table.Position = -1;
_table.HashBuckets.OverrideAutoConcurrency = true;
_table.Slots.OverrideAutoConcurrency = true;
foreach (var item in collection)
Insert(item, true);
});
}
protected BigHashSet(SerializationInfo info, StreamingContext context)
{
sInfo = info;
}
public long Count
{
get
{
return Lock(this, () =>
{
return _table._count;
});
}
private set
{
Lock(this, () =>
{
_table._count = value;
});
}
}
public T this[T item]
{
get
{
return Lock(this, () =>
{
var pos = FindEntry(item);
if (pos == -1)
throw new Exception($"Getter: Index out of bounds {pos} must be contained within set.");
return _table.Slots[pos]._value;
});
}
set => Insert(item, true);
}
public T this[long index]
{
get
{
return Lock(this, () =>
{
if (index > _table._count || _table._count == 0)
SpinWait.SpinUntil(() => index < _table._count && _table._count > 0, 100);
if (index > _table._count)
throw new Exception($"Getter: Index out of bounds {index} must be less than {_table._count}");
return _table.Slots[index]._value;
});
}
}
public void OnDeserialization(object sender)
{
Lock(this, () =>
{
if (sInfo == null)
return;
var size = sInfo.GetInt64("Capacity");
if (size != 0)
{
Clear();
_table.HashBuckets = new BigArray<long>(size);
_table.Slots = new BigArray<Slot>(size);
_table.Comparer = (IBigEqualityComparer<T>) sInfo.GetValue("Comparer", typeof(IBigEqualityComparer<T>));
_table._count = sInfo.GetInt64("Count");
_table.Position = -1;
var array = (Slot[][]) sInfo.GetValue("Elements", typeof(Slot[][]));
if (array == null)
throw new SerializationException("Missing Elements.");
var buckets = (long[][]) sInfo.GetValue("Buckets", typeof(long[][]));
if (buckets == null)
throw new SerializationException("Missing Buckets.");
_table.Slots.FromArray(array);
_table.HashBuckets.FromArray(buckets);
}
});
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
Lock(this, () =>
{
info.AddValue("Comparer", _table.Comparer, typeof(IBigEqualityComparer<T>));
info.AddValue("Capacity", _table.HashBuckets.Length);
info.AddValue("Count", _table._count);
var array = _table.Slots.ToArray();
info.AddValue("Elements", array, typeof(BigArray<Slot>));
var buck = _table.HashBuckets.ToArray();
info.AddValue("Buckets", buck, typeof(BigArray<long>));
});
}
public void Clear()
{
Lock(this, () =>
{
var size = BigArray<T>.Granularity;
_table.HashBuckets = new BigArray<long>(size);
_table.Slots = new BigArray<Slot>(size);
_table._count = 0;
_table.Position = -1;
});
}
public bool Add(T item)
{
return Insert(item, true);
}
public void AddRange(IEnumerable<T> collection)
{
Lock(this, () =>
{
foreach (var item in collection)
Insert(item, true);
});
}
public bool Contains(T item)
{
return Insert(item, false);
}
private long InternalGetHashCode(T item)
{
if (item == null)
return 0;
return _table.Comparer.GetHashCode(item) & long.MaxValue;
}
internal bool Insert(T item, bool add)
{
return Lock(this, () =>
{
var hashCode = InternalGetHashCode(item);
if (FindEntry(item, hashCode) != -1)
return true;
_table.Position = -1;
if (add)
{
if (_table._count >= _table.Slots.Length)
{
var newSize = _table.HashBuckets.Length << 1;
var newHashBuckets = new BigArray<long>(newSize);
var newSlots = new BigArray<Slot>(newSize);
for (var i = 0L; i < _table._count; i++)
{
var pos = _table.Slots[i]._hashCode % newSize;
newSlots[i] = new Slot(_table.Slots[i]._hashCode, newHashBuckets[pos] - 1, _table.Slots[i]._value);
newHashBuckets[pos] = i + 1;
}
_table.HashBuckets = newHashBuckets;
_table.Slots = newSlots;
}
var hashPos = hashCode % _table.HashBuckets.Length;
var news = new Slot(hashCode, _table.HashBuckets[hashPos] - 1, item);
_table.Slots[_table._count] = news;
_table.HashBuckets[hashPos] = _table._count + 1;
_table.Position = _table._count;
_table._count++;
}
return false;
});
}
private long FindEntry(T item, long hashCode)
{
return Lock(this, () =>
{
for (var position = _table.HashBuckets[hashCode % _table.HashBuckets.Length] - 1; position >= 0; position = _table.Slots[position]._next)
if (_table.Slots[position]._hashCode == hashCode && Equals(_table.Slots[position]._value, item))
{
_table.Position = position;
return _table.Position;
}
return -1;
});
}
public T[] ToArray()
{
return Lock(this, () =>
{
var array = new T[Count];
for (var i = 0L; i < Count; i++)
if (_table.Slots[i]._hashCode >= 0)
array[i] = _table.Slots[i]._value;
return array;
});
}
public long FindEntry(T item)
{
return FindEntry(item, InternalGetHashCode(item));
}
public bool Remove(T item)
{
return Lock(this, () =>
{
var hashCode = _table.Comparer.GetHashCode(item) & long.MaxValue;
for (var position = _table.HashBuckets[hashCode % _table.HashBuckets.Length] - 1; position >= 0; position = _table.Slots[position]._next)
if (_table.Slots[position]._hashCode == hashCode && Equals(_table.Slots[position]._value, item))
{
var hashPos = hashCode % _table.HashBuckets.Length;
var news = new Slot(0, -1, default);
_table.Slots[position] = news;
_table.HashBuckets[hashPos] = -1;
return true;
}
return false;
});
}
public IEnumerator<T> GetEnumerator()
{
return Lock(this, () =>
{
return GetEnum();
});
}
public IEnumerator<T> GetEnum()
{
for (var i = 0; i < Count; i++)
if (_table.Slots[i]._hashCode >= 0)
yield return _table.Slots[i]._value;
}
public class Table
{
public long _count;
internal IBigEqualityComparer<T> Comparer;
internal volatile BigArray<long> HashBuckets;
public long Position;
internal volatile BigArray<Slot> Slots;
}
[Serializable]
internal struct Slot
{
public readonly long _hashCode;
public readonly long _next;
public readonly T _value;
public Slot(long hashcode, long next, T value)
{
_hashCode = hashcode;
_next = next;
_value = value;
}
}
}
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.Serialization; using System.Threading; [Serializable] [DebuggerDisplay("Count = {Count}")] [Obsolete] public class BigHashSet<T> : MonitorActionFunc, IEnumerable<T>, ISerializable, IDeserializationCallback { private readonly SerializationInfo sInfo; public volatile Table _table = new Table(); public BigHashSet() : this(BigArray<T>.Granularity, new BigComparer<T>()) { } public BigHashSet(long size) : this(size, new BigComparer<T>()) { } public BigHashSet(IBigEqualityComparer<T> comparer) : this(BigArray<T>.Granularity, comparer) { } public BigHashSet(long size, IBigEqualityComparer<T> comparer) { Lock(this, () => { if (size < BigArray<T>.Granularity) size = BigArray<T>.Granularity; if (comparer == null) comparer = new DynComparer64<T>(); _table.Comparer = comparer; _table.HashBuckets = new BigArray<long>(size); _table.Slots = new BigArray<Slot>(size); _table._count = 0; _table.Position = -1; _table.HashBuckets.OverrideAutoConcurrency = true; _table.Slots.OverrideAutoConcurrency = true; }); } public BigHashSet(IEnumerable<T> collection) { Lock(this, () => { var size = BigArray<T>.Granularity; _table.Comparer = new DynComparer64<T>(); _table.HashBuckets = new BigArray<long>(size); _table.Slots = new BigArray<Slot>(size); _table._count = 0; _table.Position = -1; _table.HashBuckets.OverrideAutoConcurrency = true; _table.Slots.OverrideAutoConcurrency = true; foreach (var item in collection) Insert(item, true); }); } public BigHashSet(IEnumerable<T> collection, IBigEqualityComparer<T> comparer) { Lock(this, () => { if (comparer == null) comparer = new DynComparer64<T>(); var size = BigArray<T>.Granularity; _table.Comparer = comparer; _table.Comparer = new DynComparer64<T>(); _table.HashBuckets = new BigArray<long>(size); _table.Slots = new BigArray<Slot>(size); _table._count = 0; _table.Position = -1; _table.HashBuckets.OverrideAutoConcurrency = true; _table.Slots.OverrideAutoConcurrency = true; foreach (var item in collection) Insert(item, true); }); } protected BigHashSet(SerializationInfo info, StreamingContext context) { sInfo = info; } public long Count { get { return Lock(this, () => { return _table._count; }); } private set { Lock(this, () => { _table._count = value; }); } } public T this[T item] { get { return Lock(this, () => { var pos = FindEntry(item); if (pos == -1) throw new Exception($"Getter: Index out of bounds {pos} must be contained within set."); return _table.Slots[pos]._value; }); } set => Insert(item, true); } public T this[long index] { get { return Lock(this, () => { if (index > _table._count || _table._count == 0) SpinWait.SpinUntil(() => index < _table._count && _table._count > 0, 100); if (index > _table._count) throw new Exception($"Getter: Index out of bounds {index} must be less than {_table._count}"); return _table.Slots[index]._value; }); } } public void OnDeserialization(object sender) { Lock(this, () => { if (sInfo == null) return; var size = sInfo.GetInt64("Capacity"); if (size != 0) { Clear(); _table.HashBuckets = new BigArray<long>(size); _table.Slots = new BigArray<Slot>(size); _table.Comparer = (IBigEqualityComparer<T>) sInfo.GetValue("Comparer", typeof(IBigEqualityComparer<T>)); _table._count = sInfo.GetInt64("Count"); _table.Position = -1; var array = (Slot[][]) sInfo.GetValue("Elements", typeof(Slot[][])); if (array == null) throw new SerializationException("Missing Elements."); var buckets = (long[][]) sInfo.GetValue("Buckets", typeof(long[][])); if (buckets == null) throw new SerializationException("Missing Buckets."); _table.Slots.FromArray(array); _table.HashBuckets.FromArray(buckets); } }); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void GetObjectData(SerializationInfo info, StreamingContext context) { Lock(this, () => { info.AddValue("Comparer", _table.Comparer, typeof(IBigEqualityComparer<T>)); info.AddValue("Capacity", _table.HashBuckets.Length); info.AddValue("Count", _table._count); var array = _table.Slots.ToArray(); info.AddValue("Elements", array, typeof(BigArray<Slot>)); var buck = _table.HashBuckets.ToArray(); info.AddValue("Buckets", buck, typeof(BigArray<long>)); }); } public void Clear() { Lock(this, () => { var size = BigArray<T>.Granularity; _table.HashBuckets = new BigArray<long>(size); _table.Slots = new BigArray<Slot>(size); _table._count = 0; _table.Position = -1; }); } public bool Add(T item) { return Insert(item, true); } public void AddRange(IEnumerable<T> collection) { Lock(this, () => { foreach (var item in collection) Insert(item, true); }); } public bool Contains(T item) { return Insert(item, false); } private long InternalGetHashCode(T item) { if (item == null) return 0; return _table.Comparer.GetHashCode(item) & long.MaxValue; } internal bool Insert(T item, bool add) { return Lock(this, () => { var hashCode = InternalGetHashCode(item); if (FindEntry(item, hashCode) != -1) return true; _table.Position = -1; if (add) { if (_table._count >= _table.Slots.Length) { var newSize = _table.HashBuckets.Length << 1; var newHashBuckets = new BigArray<long>(newSize); var newSlots = new BigArray<Slot>(newSize); for (var i = 0L; i < _table._count; i++) { var pos = _table.Slots[i]._hashCode % newSize; newSlots[i] = new Slot(_table.Slots[i]._hashCode, newHashBuckets[pos] - 1, _table.Slots[i]._value); newHashBuckets[pos] = i + 1; } _table.HashBuckets = newHashBuckets; _table.Slots = newSlots; } var hashPos = hashCode % _table.HashBuckets.Length; var news = new Slot(hashCode, _table.HashBuckets[hashPos] - 1, item); _table.Slots[_table._count] = news; _table.HashBuckets[hashPos] = _table._count + 1; _table.Position = _table._count; _table._count++; } return false; }); } private long FindEntry(T item, long hashCode) { return Lock(this, () => { for (var position = _table.HashBuckets[hashCode % _table.HashBuckets.Length] - 1; position >= 0; position = _table.Slots[position]._next) if (_table.Slots[position]._hashCode == hashCode && Equals(_table.Slots[position]._value, item)) { _table.Position = position; return _table.Position; } return -1; }); } public T[] ToArray() { return Lock(this, () => { var array = new T[Count]; for (var i = 0L; i < Count; i++) if (_table.Slots[i]._hashCode >= 0) array[i] = _table.Slots[i]._value; return array; }); } public long FindEntry(T item) { return FindEntry(item, InternalGetHashCode(item)); } public bool Remove(T item) { return Lock(this, () => { var hashCode = _table.Comparer.GetHashCode(item) & long.MaxValue; for (var position = _table.HashBuckets[hashCode % _table.HashBuckets.Length] - 1; position >= 0; position = _table.Slots[position]._next) if (_table.Slots[position]._hashCode == hashCode && Equals(_table.Slots[position]._value, item)) { var hashPos = hashCode % _table.HashBuckets.Length; var news = new Slot(0, -1, default); _table.Slots[position] = news; _table.HashBuckets[hashPos] = -1; return true; } return false; }); } public IEnumerator<T> GetEnumerator() { return Lock(this, () => { return GetEnum(); }); } public IEnumerator<T> GetEnum() { for (var i = 0; i < Count; i++) if (_table.Slots[i]._hashCode >= 0) yield return _table.Slots[i]._value; } public class Table { public long _count; internal IBigEqualityComparer<T> Comparer; internal volatile BigArray<long> HashBuckets; public long Position; internal volatile BigArray<Slot> Slots; } [Serializable] internal struct Slot { public readonly long _hashCode; public readonly long _next; public readonly T _value; public Slot(long hashcode, long next, T value) { _hashCode = hashcode; _next = next; _value = value; } } }
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Threading;
[Serializable]
[DebuggerDisplay("Count = {Count}")]
[Obsolete]
public class BigHashSet<T> : MonitorActionFunc, IEnumerable<T>, ISerializable, IDeserializationCallback
{
    private readonly SerializationInfo sInfo;
    public volatile  Table             _table = new Table();
    public BigHashSet() : this(BigArray<T>.Granularity, new BigComparer<T>())
    {
    }
    public BigHashSet(long size) : this(size, new BigComparer<T>())
    {
    }
    public BigHashSet(IBigEqualityComparer<T> comparer) : this(BigArray<T>.Granularity, comparer)
    {
    }
    public BigHashSet(long size, IBigEqualityComparer<T> comparer)
    {
        Lock(this, () =>
        {
            if (size < BigArray<T>.Granularity)
                size = BigArray<T>.Granularity;
            if (comparer == null)
                comparer = new DynComparer64<T>();
            _table.Comparer                            = comparer;
            _table.HashBuckets                         = new BigArray<long>(size);
            _table.Slots                               = new BigArray<Slot>(size);
            _table._count                              = 0;
            _table.Position                            = -1;
            _table.HashBuckets.OverrideAutoConcurrency = true;
            _table.Slots.OverrideAutoConcurrency       = true;
        });
    }
    public BigHashSet(IEnumerable<T> collection)
    {
        Lock(this, () =>
        {
            var size = BigArray<T>.Granularity;
            _table.Comparer                            = new DynComparer64<T>();
            _table.HashBuckets                         = new BigArray<long>(size);
            _table.Slots                               = new BigArray<Slot>(size);
            _table._count                              = 0;
            _table.Position                            = -1;
            _table.HashBuckets.OverrideAutoConcurrency = true;
            _table.Slots.OverrideAutoConcurrency       = true;
            foreach (var item in collection)
                Insert(item, true);
        });
    }
    public BigHashSet(IEnumerable<T> collection, IBigEqualityComparer<T> comparer)
    {
        Lock(this, () =>
        {
            if (comparer == null)
                comparer = new DynComparer64<T>();
            var size = BigArray<T>.Granularity;
            _table.Comparer                            = comparer;
            _table.Comparer                            = new DynComparer64<T>();
            _table.HashBuckets                         = new BigArray<long>(size);
            _table.Slots                               = new BigArray<Slot>(size);
            _table._count                              = 0;
            _table.Position                            = -1;
            _table.HashBuckets.OverrideAutoConcurrency = true;
            _table.Slots.OverrideAutoConcurrency       = true;
            foreach (var item in collection)
                Insert(item, true);
        });
    }
    protected BigHashSet(SerializationInfo info, StreamingContext context)
    {
        sInfo = info;
    }
    public long Count
    {
        get
        {
            return Lock(this, () =>
            {
                return _table._count;
            });
        }
        private set
        {
            Lock(this, () =>
            {
                _table._count = value;
            });
        }
    }
    public T this[T item]
    {
        get
        {
            return Lock(this, () =>
            {
                var pos = FindEntry(item);
                if (pos == -1)
                    throw new Exception($"Getter: Index out of bounds {pos} must be contained within set.");
                return _table.Slots[pos]._value;
            });
        }
        set => Insert(item, true);
    }
    public T this[long index]
    {
        get
        {
            return Lock(this, () =>
            {
                if (index > _table._count || _table._count == 0)
                    SpinWait.SpinUntil(() => index < _table._count && _table._count > 0, 100);
                if (index > _table._count)
                    throw new Exception($"Getter: Index out of bounds {index} must be less than {_table._count}");
                return _table.Slots[index]._value;
            });
        }
    }
    public void OnDeserialization(object sender)
    {
        Lock(this, () =>
        {
            if (sInfo == null)
                return;
            var size = sInfo.GetInt64("Capacity");
            if (size != 0)
            {
                Clear();
                _table.HashBuckets = new BigArray<long>(size);
                _table.Slots       = new BigArray<Slot>(size);
                _table.Comparer    = (IBigEqualityComparer<T>) sInfo.GetValue("Comparer", typeof(IBigEqualityComparer<T>));
                _table._count      = sInfo.GetInt64("Count");
                _table.Position    = -1;
                var array = (Slot[][]) sInfo.GetValue("Elements", typeof(Slot[][]));
                if (array == null)
                    throw new SerializationException("Missing Elements.");
                var buckets = (long[][]) sInfo.GetValue("Buckets", typeof(long[][]));
                if (buckets == null)
                    throw new SerializationException("Missing Buckets.");
                _table.Slots.FromArray(array);
                _table.HashBuckets.FromArray(buckets);
            }
        });
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        Lock(this, () =>
        {
            info.AddValue("Comparer", _table.Comparer, typeof(IBigEqualityComparer<T>));
            info.AddValue("Capacity", _table.HashBuckets.Length);
            info.AddValue("Count",    _table._count);
            var array = _table.Slots.ToArray();
            info.AddValue("Elements", array, typeof(BigArray<Slot>));
            var buck = _table.HashBuckets.ToArray();
            info.AddValue("Buckets", buck, typeof(BigArray<long>));
        });
    }
    public void Clear()
    {
        Lock(this, () =>
        {
            var size = BigArray<T>.Granularity;
            _table.HashBuckets = new BigArray<long>(size);
            _table.Slots       = new BigArray<Slot>(size);
            _table._count      = 0;
            _table.Position    = -1;
        });
    }
    public bool Add(T item)
    {
        return Insert(item, true);
    }
    public void AddRange(IEnumerable<T> collection)
    {
        Lock(this, () =>
        {
            foreach (var item in collection)
                Insert(item, true);
        });
    }
    public bool Contains(T item)
    {
        return Insert(item, false);
    }
    private long InternalGetHashCode(T item)
    {
        if (item == null)
            return 0;
        return _table.Comparer.GetHashCode(item) & long.MaxValue;
    }
    internal bool Insert(T item, bool add)
    {
        return Lock(this, () =>
        {
            var hashCode = InternalGetHashCode(item);
            if (FindEntry(item, hashCode) != -1)
                return true;
            _table.Position = -1;
            if (add)
            {
                if (_table._count >= _table.Slots.Length)
                {
                    var newSize        = _table.HashBuckets.Length << 1;
                    var newHashBuckets = new BigArray<long>(newSize);
                    var newSlots       = new BigArray<Slot>(newSize);
                    for (var i = 0L; i < _table._count; i++)
                    {
                        var pos = _table.Slots[i]._hashCode % newSize;
                        newSlots[i]         = new Slot(_table.Slots[i]._hashCode, newHashBuckets[pos] - 1, _table.Slots[i]._value);
                        newHashBuckets[pos] = i + 1;
                    }
                    _table.HashBuckets = newHashBuckets;
                    _table.Slots       = newSlots;
                }
                var hashPos = hashCode % _table.HashBuckets.Length;
                var news    = new Slot(hashCode, _table.HashBuckets[hashPos] - 1, item);
                _table.Slots[_table._count] = news;
                _table.HashBuckets[hashPos] = _table._count + 1;
                _table.Position             = _table._count;
                _table._count++;
            }
            return false;
        });
    }
    private long FindEntry(T item, long hashCode)
    {
        return Lock(this, () =>
        {
            for (var position = _table.HashBuckets[hashCode % _table.HashBuckets.Length] - 1; position >= 0; position = _table.Slots[position]._next)
                if (_table.Slots[position]._hashCode == hashCode && Equals(_table.Slots[position]._value, item))
                {
                    _table.Position = position;
                    return _table.Position;
                }
            return -1;
        });
    }
    public T[] ToArray()
    {
        return Lock(this, () =>
        {
            var array = new T[Count];
            for (var i = 0L; i < Count; i++)
                if (_table.Slots[i]._hashCode >= 0)
                    array[i] = _table.Slots[i]._value;
            return array;
        });
    }
    public long FindEntry(T item)
    {
        return FindEntry(item, InternalGetHashCode(item));
    }
    public bool Remove(T item)
    {
        return Lock(this, () =>
        {
            var hashCode = _table.Comparer.GetHashCode(item) & long.MaxValue;
            for (var position = _table.HashBuckets[hashCode % _table.HashBuckets.Length] - 1; position >= 0; position = _table.Slots[position]._next)
                if (_table.Slots[position]._hashCode == hashCode && Equals(_table.Slots[position]._value, item))
                {
                    var hashPos = hashCode % _table.HashBuckets.Length;
                    var news    = new Slot(0, -1, default);
                    _table.Slots[position]      = news;
                    _table.HashBuckets[hashPos] = -1;
                    return true;
                }
            return false;
        });
    }
    public IEnumerator<T> GetEnumerator()
    {
        return Lock(this, () =>
        {
            return GetEnum();
        });
    }
    public IEnumerator<T> GetEnum()
    {
        for (var i = 0; i < Count; i++)
            if (_table.Slots[i]._hashCode >= 0)
                yield return _table.Slots[i]._value;
    }
    public class Table
    {
        public            long                    _count;
        internal          IBigEqualityComparer<T> Comparer;
        internal volatile BigArray<long>          HashBuckets;
        public            long                    Position;
        internal volatile BigArray<Slot>          Slots;
    }
    [Serializable]
    internal struct Slot
    {
        public readonly long _hashCode;
        public readonly long _next;
        public readonly T    _value;
        public Slot(long hashcode, long next, T value)
        {
            _hashCode = hashcode;
            _next     = next;
            _value    = value;
        }
    }
}

MSet15.cs

Small Hash Set Class (Minimal)

Updated: July-23,2021

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
[Serializable]
public class MSet15<T>
{
private int[] _hashBuckets;
internal IEqualityComparer<T> Comparer;
internal int Position;
internal Slot[] Slots;
public bool SlowGrowth;
public MSet15() : this(101, EqualityComparer<T>.Default)
{
}
public MSet15(int size) : this(size, EqualityComparer<T>.Default)
{
}
public MSet15(IEqualityComparer<T> comparer) : this(31, comparer)
{
}
public MSet15(int size, IEqualityComparer<T> comparer)
{
if (comparer == null)
comparer = EqualityComparer<T>.Default;
Comparer = comparer;
_hashBuckets = new int[size];
Slots = new Slot[size];
Count = 0;
Position = -1;
}
public MSet15(IEnumerable<T> collection, IEqualityComparer<T> comparer)
{
if (comparer == null)
comparer = EqualityComparer<T>.Default;
var enumerable = collection as T[] ?? collection.ToArray();
var size = enumerable.Length;
Comparer = comparer;
_hashBuckets = new int[size];
Slots = new Slot[size];
Count = 0;
Position = -1;
foreach (var i in enumerable)
Add(i);
}
public int Count
{
get;
private set;
}
public IEnumerator<T> GetEnumerator()
{
for (var i = 0; i < Count; i++)
if (Slots[i].HashCode > 0)
yield return Slots[i].Value;
}
public bool Add(T item)
{
var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
if (FindEntry(item, hashCode) != -1)
return true;
if (Count >= Slots.Length)
Resize();
var hashPos = hashCode % _hashBuckets.Length;
Slots[Count].Next = _hashBuckets[hashPos] - 1;
Slots[Count].Value = item;
Slots[Count].HashCode = hashCode;
_hashBuckets[hashPos] = Count + 1;
Position = Count;
++Count;
return false;
}
public void AddRange(IEnumerable<T> collection)
{
foreach (var i in collection)
Add(i);
}
public bool Remove(T item)
{
if (Count != 0)
{
var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
var iPos = hashCode % _hashBuckets.Length;
var tPos = -1;
for (var sPos = _hashBuckets[iPos] - 1; sPos >= 0; sPos = Slots[sPos].Next)
{
if (Slots[sPos].HashCode == hashCode && Comparer.Equals(Slots[sPos].Value, item))
{
if (tPos < 0)
_hashBuckets[iPos] = Slots[sPos].Next + 1;
else
Slots[tPos].Next = Slots[sPos].Next;
Slots[sPos].HashCode = -1;
Slots[sPos].Value = default;
Slots[sPos].Next = 0;
--Count;
return true;
}
tPos = sPos;
}
}
return false;
}
public bool Contains(T item)
{
return FindEntry(item, Comparer.GetHashCode(item) & int.MaxValue) != -1;
}
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 Resize()
{
var newSize = !SlowGrowth ? _hashBuckets.Length + _hashBuckets.Length / 4 * 3 : _hashBuckets.Length + 1;
var newSlots = new Slot[newSize];
var newHashBuckets = new int[newSize];
var newCount = 0;
var en = GetEnumerator();
while (en.MoveNext())
{
var item = en.Current;
var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
var hashPos = hashCode % newHashBuckets.Length;
newSlots[newCount].Next = newHashBuckets[hashPos] - 1;
newSlots[newCount].Value = item;
newSlots[newCount].HashCode = hashCode;
newHashBuckets[hashPos] = newCount + 1;
++newCount;
}
Slots = newSlots;
_hashBuckets = newHashBuckets;
Count = newCount;
}
public int FindEntry(T item, int hashCode)
{
for (var position = _hashBuckets[hashCode % _hashBuckets.Length] - 1; position >= 0; position = Slots[position].Next)
if (Slots[position].HashCode == hashCode && Comparer.Equals(Slots[position].Value, item))
{
Position = position;
return position;
}
return -1;
}
public int FindEntry(T item)
{
return FindEntry(item, Comparer.GetHashCode(item) & int.MaxValue);
}
internal struct Slot
{
public int HashCode;
public int Next;
public T Value;
}
}
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; [DebuggerDisplay("Count = {" + nameof(Count) + "}")] [Serializable] public class MSet15<T> { private int[] _hashBuckets; internal IEqualityComparer<T> Comparer; internal int Position; internal Slot[] Slots; public bool SlowGrowth; public MSet15() : this(101, EqualityComparer<T>.Default) { } public MSet15(int size) : this(size, EqualityComparer<T>.Default) { } public MSet15(IEqualityComparer<T> comparer) : this(31, comparer) { } public MSet15(int size, IEqualityComparer<T> comparer) { if (comparer == null) comparer = EqualityComparer<T>.Default; Comparer = comparer; _hashBuckets = new int[size]; Slots = new Slot[size]; Count = 0; Position = -1; } public MSet15(IEnumerable<T> collection, IEqualityComparer<T> comparer) { if (comparer == null) comparer = EqualityComparer<T>.Default; var enumerable = collection as T[] ?? collection.ToArray(); var size = enumerable.Length; Comparer = comparer; _hashBuckets = new int[size]; Slots = new Slot[size]; Count = 0; Position = -1; foreach (var i in enumerable) Add(i); } public int Count { get; private set; } public IEnumerator<T> GetEnumerator() { for (var i = 0; i < Count; i++) if (Slots[i].HashCode > 0) yield return Slots[i].Value; } public bool Add(T item) { var hashCode = Comparer.GetHashCode(item) & int.MaxValue; if (FindEntry(item, hashCode) != -1) return true; if (Count >= Slots.Length) Resize(); var hashPos = hashCode % _hashBuckets.Length; Slots[Count].Next = _hashBuckets[hashPos] - 1; Slots[Count].Value = item; Slots[Count].HashCode = hashCode; _hashBuckets[hashPos] = Count + 1; Position = Count; ++Count; return false; } public void AddRange(IEnumerable<T> collection) { foreach (var i in collection) Add(i); } public bool Remove(T item) { if (Count != 0) { var hashCode = Comparer.GetHashCode(item) & int.MaxValue; var iPos = hashCode % _hashBuckets.Length; var tPos = -1; for (var sPos = _hashBuckets[iPos] - 1; sPos >= 0; sPos = Slots[sPos].Next) { if (Slots[sPos].HashCode == hashCode && Comparer.Equals(Slots[sPos].Value, item)) { if (tPos < 0) _hashBuckets[iPos] = Slots[sPos].Next + 1; else Slots[tPos].Next = Slots[sPos].Next; Slots[sPos].HashCode = -1; Slots[sPos].Value = default; Slots[sPos].Next = 0; --Count; return true; } tPos = sPos; } } return false; } public bool Contains(T item) { return FindEntry(item, Comparer.GetHashCode(item) & int.MaxValue) != -1; } 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 Resize() { var newSize = !SlowGrowth ? _hashBuckets.Length + _hashBuckets.Length / 4 * 3 : _hashBuckets.Length + 1; var newSlots = new Slot[newSize]; var newHashBuckets = new int[newSize]; var newCount = 0; var en = GetEnumerator(); while (en.MoveNext()) { var item = en.Current; var hashCode = Comparer.GetHashCode(item) & int.MaxValue; var hashPos = hashCode % newHashBuckets.Length; newSlots[newCount].Next = newHashBuckets[hashPos] - 1; newSlots[newCount].Value = item; newSlots[newCount].HashCode = hashCode; newHashBuckets[hashPos] = newCount + 1; ++newCount; } Slots = newSlots; _hashBuckets = newHashBuckets; Count = newCount; } public int FindEntry(T item, int hashCode) { for (var position = _hashBuckets[hashCode % _hashBuckets.Length] - 1; position >= 0; position = Slots[position].Next) if (Slots[position].HashCode == hashCode && Comparer.Equals(Slots[position].Value, item)) { Position = position; return position; } return -1; } public int FindEntry(T item) { return FindEntry(item, Comparer.GetHashCode(item) & int.MaxValue); } internal struct Slot { public int HashCode; public int Next; public T Value; } }
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
[Serializable]
public class MSet15<T>
{
    private  int[]                _hashBuckets;
    internal IEqualityComparer<T> Comparer;
    internal int                  Position;
    internal Slot[]               Slots;
    public   bool                 SlowGrowth;
    public MSet15() : this(101, EqualityComparer<T>.Default)
    {
    }
    public MSet15(int size) : this(size, EqualityComparer<T>.Default)
    {
    }
    public MSet15(IEqualityComparer<T> comparer) : this(31, comparer)
    {
    }
    public MSet15(int size, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<T>.Default;
        Comparer     = comparer;
        _hashBuckets = new int[size];
        Slots        = new Slot[size];
        Count        = 0;
        Position     = -1;
    }
    public MSet15(IEnumerable<T> collection, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<T>.Default;
        var enumerable = collection as T[] ?? collection.ToArray();
        var size       = enumerable.Length;
        Comparer     = comparer;
        _hashBuckets = new int[size];
        Slots        = new Slot[size];
        Count        = 0;
        Position     = -1;
        foreach (var i in enumerable)
            Add(i);
    }
    public int Count
    {
        get;
        private set;
    }
    public IEnumerator<T> GetEnumerator()
    {
        for (var i = 0; i < Count; i++)
            if (Slots[i].HashCode > 0)
                yield return Slots[i].Value;
    }
    public bool Add(T item)
    {
        var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
        if (FindEntry(item, hashCode) != -1)
            return true;
        if (Count >= Slots.Length)
            Resize();
        var hashPos = hashCode % _hashBuckets.Length;
        Slots[Count].Next     = _hashBuckets[hashPos] - 1;
        Slots[Count].Value    = item;
        Slots[Count].HashCode = hashCode;
        _hashBuckets[hashPos] = Count + 1;
        Position              = Count;
        ++Count;
        return false;
    }

    public void AddRange(IEnumerable<T> collection)
    {
        foreach (var i in collection)
            Add(i);
    }
    public bool Remove(T item)
    {
        if (Count != 0)
        {
            var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
            var iPos     = hashCode % _hashBuckets.Length;
            var tPos     = -1;
            for (var sPos = _hashBuckets[iPos] - 1; sPos >= 0; sPos = Slots[sPos].Next)
            {
                if (Slots[sPos].HashCode == hashCode && Comparer.Equals(Slots[sPos].Value, item))
                {
                    if (tPos < 0)
                        _hashBuckets[iPos] = Slots[sPos].Next + 1;
                    else
                        Slots[tPos].Next = Slots[sPos].Next;
                    Slots[sPos].HashCode = -1;
                    Slots[sPos].Value    = default;
                    Slots[sPos].Next     = 0;
                    --Count;
                    return true;
                }
                tPos = sPos;
            }
        }
        return false;
    }
    public bool Contains(T item)
    {
        return FindEntry(item, Comparer.GetHashCode(item) & int.MaxValue) != -1;
    }
    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 Resize()
    {
        var newSize        = !SlowGrowth ? _hashBuckets.Length + _hashBuckets.Length / 4 * 3 : _hashBuckets.Length + 1;
        var newSlots       = new Slot[newSize];
        var newHashBuckets = new int[newSize];
        var newCount       = 0;
        var en             = GetEnumerator();
        while (en.MoveNext())
        {
            var item     = en.Current;
            var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
            var hashPos  = hashCode % newHashBuckets.Length;
            newSlots[newCount].Next     = newHashBuckets[hashPos] - 1;
            newSlots[newCount].Value    = item;
            newSlots[newCount].HashCode = hashCode;
            newHashBuckets[hashPos]     = newCount + 1;
            ++newCount;
        }
        Slots        = newSlots;
        _hashBuckets = newHashBuckets;
        Count        = newCount;
    }
    public int FindEntry(T item, int hashCode)
    {
        for (var position = _hashBuckets[hashCode % _hashBuckets.Length] - 1; position >= 0; position = Slots[position].Next)
            if (Slots[position].HashCode == hashCode && Comparer.Equals(Slots[position].Value, item))
            {
                Position = position;
                return position;
            }
        return -1;
    }
    public int FindEntry(T item)
    {
        return FindEntry(item, Comparer.GetHashCode(item) & int.MaxValue);
    }
    internal struct Slot
    {
        public int HashCode;
        public int Next;
        public T   Value;
    }
}

TinySet.cs

A Small HashSet Class

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