DynConcurrentSet.cs

Dynamic Concurrent Set Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
[DebuggerTypeProxy(typeof(HashSetDebugView<>))]
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
[Serializable]
public class DynConcurrentSet<T> : MonitorActionFunc, IEnumerable<T>
{
    private         int[]                _hashBuckets;
    internal        IEqualityComparer<T> Comparer;
    public volatile int                  Count;
    internal        Slot[]               Slots;
    public DynConcurrentSet() : this(101, EqualityComparer<T>.Default)
    {
    }
    public DynConcurrentSet(int size) : this(size, EqualityComparer<T>.Default)
    {
    }
    public DynConcurrentSet(IEqualityComparer<T> comparer) : this(101, comparer)
    {
    }
    public DynConcurrentSet(int size, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<T>.Default;
        Comparer     = comparer;
        _hashBuckets = new int[size];
        Slots        = new Slot[size];
        Count        = 0;
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public IEnumerator<T> GetEnumerator()
    {
        return GetEnum();
    }
    public IEnumerator<T> GetEnum()
    {
        var slots = Slots;
        var count = Count;
        for (var i = 0; i < count; i++)
            if (slots[i].HashCode > 0)
                yield return slots[i].Value;
    }
    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;
    }
    public void Clear()
    {
        var tmpThis = this;
        tmpThis.Lock(tmpThis, () =>
        {
            var size = Slots.Length;
            _hashBuckets = new int[size];
            Slots        = new Slot[size];
            Count        = 0;
        });
    }
    public bool Add(T item)
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            return Insert(item, true);
        });
    }
    public int AddRange(IEnumerable<T> items)
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            return items.Sum(i => !Add(i) ? 0 : 1);
        });
    }
    public bool Contains(T item)
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            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(_hashBuckets.Length + _hashBuckets.Length / 4 * 3);
            var hashPos = hashCode % _hashBuckets.Length;
            Slots[Count].Next     = _hashBuckets[hashPos] - 1;
            Slots[Count].Value    = item;
            Slots[Count].HashCode = hashCode;
            _hashBuckets[hashPos] = Count + 1;
            Interlocked.Increment(ref Count);
        }
        return false;
    }
    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;
    }
    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))
                return position;
        return -1;
    }
    internal struct Slot
    {
        public int HashCode;
        public int Next;
        public T   Value;
    }
}

Leave a Reply

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