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