{"id":504,"date":"2021-07-24T00:45:50","date_gmt":"2021-07-24T00:45:50","guid":{"rendered":"https:\/\/michaeljohnsteiner.com\/?p=504"},"modified":"2021-07-27T10:16:54","modified_gmt":"2021-07-27T10:16:54","slug":"ccdictionary-cs","status":"publish","type":"post","link":"https:\/\/michaeljohnsteiner.com\/index.php\/2021\/07\/24\/ccdictionary-cs\/","title":{"rendered":"CcDictionary.cs"},"content":{"rendered":"\n<p>Concurrent Dictionary Class without Blocking<\/p>\n\n\n\n<p>Updated: July-27,2021<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading;\n[DebuggerDisplay(\"Count = {\" + nameof(Count) + \"}\")]\npublic class CcDictionary&lt;TKey, TValue> : IEnumerable&lt;KeyValuePair&lt;TKey, TValue>>\n{\n    private readonly int                     _size;\n    private volatile int[]                   _activeThreads;\n    private          DicA&lt;TKey, TValue>[]    _array;\n    private volatile int                     _bP;\n    internal         IEqualityComparer&lt;TKey> _comparer;\n    public volatile  int                     NumberOfActiveThreads;\n    public CcDictionary() : this(1024, null)\n    {\n    }\n    public CcDictionary(int size) : this(size, null)\n    {\n    }\n    public CcDictionary(int size, IEqualityComparer&lt;TKey> comparer)\n    {\n        ThreadPool.GetMaxThreads(out var nW, out var nI);\n        _array                = new DicA&lt;TKey, TValue>[nW];\n        _size                 = size;\n        NumberOfActiveThreads = 0;\n        _bP                   = 0;\n        _activeThreads        = new int[Environment.ProcessorCount];\n        _activeThreads.Fill(-1);\n        if (comparer == null)\n            _comparer = EqualityComparer&lt;TKey>.Default;\n        else\n            _comparer = comparer;\n    }\n    public CcDictionary(IEnumerable&lt;KeyValuePair&lt;TKey, TValue>> collection, int concurrencyLevel = 0)\n    {\n        ThreadPool.GetMaxThreads(out var nW, out var nI);\n        _array = new DicA&lt;TKey, TValue>[nW];\n        var col = collection.ToList();\n        _size                 = col.Count;\n        NumberOfActiveThreads = 0;\n        _bP                   = 0;\n        _activeThreads        = new int[Environment.ProcessorCount];\n        _activeThreads.Fill(-1);\n        _comparer = EqualityComparer&lt;TKey>.Default;\n        var ccl = Environment.ProcessorCount;\n        if (concurrencyLevel != 0)\n            ccl = concurrencyLevel;\n        col.AsParallel().WithDegreeOfParallelism(ccl).ForAll(i =>\n        {\n            Add(i.Key, i.Value);\n        });\n    }\n    public int Count\n    {\n        get\n        {\n            var totalCount = 0;\n            for (var i = 0; i &lt; _activeThreads.Length; ++i)\n                if (_activeThreads[i] != -1)\n                    if (_array[_activeThreads[i]] != null)\n                        totalCount += _array[_activeThreads[i]].Count;\n            return totalCount;\n        }\n    }\n    public TValue this[TKey key]\n    {\n        get\n        {\n           ProcessThread();\n            var rv = FindKey(key);\n            return rv.idx != -1 ? _array[rv.trd][key] : default;\n        }\n        set => Add(key, value, true);\n    }\n    public IEnumerator&lt;KeyValuePair&lt;TKey, TValue>> GetEnumerator()\n    {\n        return GetEnum();\n    }\n    IEnumerator IEnumerable.GetEnumerator()\n    {\n        return GetEnum();\n    }\n    public bool TryGetValue(TKey key, out TValue value)\n    {\n        var (idx, trd) = FindKey(key);\n        if (idx == -1)\n        {\n            value = default;\n            return false;\n        }\n        value = _array[trd][key];\n        return true;\n    }\n    public void Clear()\n    {\n        ThreadPool.GetMaxThreads(out var nW, out var nI);\n        _array                = new DicA&lt;TKey, TValue>[nW];\n        NumberOfActiveThreads = 0;\n        _bP                   = 0;\n        _activeThreads        = new int[Environment.ProcessorCount];\n        _activeThreads.Fill(-1);\n    }\n    public void AddRange(IEnumerable&lt;KeyValuePair&lt;TKey, TValue>> collection, int concurrencyLevel = 0)\n    {\n        var ccl = Environment.ProcessorCount;\n        if (concurrencyLevel != 0)\n            ccl = concurrencyLevel;\n        collection.AsParallel().WithDegreeOfParallelism(ccl).ForAll(i =>\n        {\n            Add(i.Key, i.Value);\n        });\n    }\n    public void Add(TKey key, TValue value, bool updateValue = false)\n    {\n        var id  = ProcessThread();\n        var idx = FindKey(key);\n        if (idx.idx == -1)\n            _array[id].Add(key, value);\n        else if (updateValue)\n            _array[idx.trd].Values[idx.idx] = value;\n    }\n    private int ProcessThread()\n    {\n        var id = Thread.CurrentThread.ManagedThreadId;\n        if (_array[id] == null)\n        {\n            _array[id] = new DicA&lt;TKey, TValue>(_size, _comparer);\n            Interlocked.Increment(ref NumberOfActiveThreads);\n            if (_bP >= _activeThreads.Length)\n            {\n                var nAtA = new int[_activeThreads.Length &lt;&lt; 1];\n                nAtA.Fill(-1);\n                for (var i = 0; i &lt; _activeThreads.Length; ++i)\n                    if (_activeThreads[i] != -1)\n                        nAtA[i] = _activeThreads[i];\n                _activeThreads = nAtA;\n            }\n            _activeThreads[_bP] = id;\n            Interlocked.Increment(ref _bP);\n        }\n        return id;\n    }\n    public bool TryAdd(TKey key, TValue value)\n    {\n        Add(key, value);\n        return true;\n    }\n    public bool ContainsKey(TKey key)\n    {\n        for (var i = 0; i &lt; _activeThreads.Length; ++i)\n            if (_activeThreads[i] != -1)\n                if (_array[_activeThreads[i]] != null)\n                    if (_array[_activeThreads[i]].ContainsKey(key))\n                        return true;\n        return false;\n    }\n    public bool ContainsValue(TValue value)\n    {\n        var eComparer = EqualityComparer&lt;TValue>.Default;\n        for (var i = 0; i &lt; _activeThreads.Length; ++i)\n            if (_activeThreads[i] != -1)\n                if (_array[_activeThreads[i]] != null)\n                    for (var j = 0; j &lt; _array[_activeThreads[i]].Count; ++j)\n                        if (eComparer.Equals(_array[_activeThreads[i]].Values[j], value))\n                            return true;\n        return false;\n    }\n    public (int idx, int trd) FindKey(TKey key)\n    {\n        for (var i = 0; i &lt; _activeThreads.Length; ++i)\n            if (_activeThreads[i] != -1)\n                if (_array[_activeThreads[i]] != null)\n                {\n                    var idx = _array[_activeThreads[i]].FindKeyIndex(key);\n                    if (idx != -1)\n                        return (idx, _activeThreads[i]);\n                }\n        return (-1, -1);\n    }\n    public bool Remove(TKey key)\n    {\n        var (idx, trd) = FindKey(key);\n        if (idx == -1)\n            return false;\n        _array[_activeThreads[trd]].Remove(key);\n        return true;\n    }\n    private IEnumerator&lt;KeyValuePair&lt;TKey, TValue>> GetEnum()\n    {\n        foreach (var i in ToArray())\n            yield return new KeyValuePair&lt;TKey, TValue>(i.Key, i.Value);\n    }\n    public KeyValuePair&lt;TKey, TValue>[] ToArray()\n    {\n        var totalCount = 0;\n        for (var i = 0; i &lt; _activeThreads.Length; ++i)\n            if (_activeThreads[i] != -1)\n                if (_array[_activeThreads[i]] != null)\n                    totalCount += _array[_activeThreads[i]].Count;\n        var ta  = new KeyValuePair&lt;TKey, TValue>[totalCount];\n        var ptr = 0;\n        for (var i = 0; i &lt; _activeThreads.Length; ++i)\n            if (_activeThreads[i] != -1)\n                if (_array[_activeThreads[i]] != null)\n                    foreach (var v in _array[_activeThreads[i]])\n                        ta[ptr++] = new KeyValuePair&lt;TKey, TValue>(v.Key, v.Value);\n        return ta;\n    }\n    public class DicA&lt;TKey, TValue> : IEnumerable&lt;KeyValuePair&lt;TKey, TValue>>\n    {\n        public MSet15&lt;TKey> Keys;\n        public int          Resizes;\n        public TValue[]     Values;\n        public DicA() : this(101, EqualityComparer&lt;TKey>.Default)\n        {\n        }\n        public DicA(int size) : this(size, EqualityComparer&lt;TKey>.Default)\n        {\n        }\n        public DicA(int size, IEqualityComparer&lt;TKey> comparer)\n        {\n            if (comparer == null)\n                comparer = EqualityComparer&lt;TKey>.Default;\n            Keys          = new MSet15&lt;TKey>(size);\n            Values        = new TValue[size];\n            Keys.Comparer = comparer;\n        }\n        public DicA(IEnumerable&lt;KeyValuePair&lt;TKey, TValue>> collection, IEqualityComparer&lt;TKey> comparer = null)\n        {\n            if (comparer == null)\n                comparer = EqualityComparer&lt;TKey>.Default;\n            Keys.Comparer = comparer;\n            foreach (var kp in collection)\n                Add(kp.Key, kp.Value);\n        }\n        public int Count => Keys.Count;\n        public TValue this[TKey key]\n        {\n            get\n            {\n                var pos = Keys.FindEntry(key);\n                return pos == -1 ? default : Values[pos];\n            }\n            set => Add(key, value);\n        }\n        public IEnumerator&lt;KeyValuePair&lt;TKey, TValue>> GetEnumerator()\n        {\n            for (var i = 0; i &lt; Count; i++)\n                if (Keys.Slots[i].HashCode > 0)\n                    yield return new KeyValuePair&lt;TKey, TValue>(Keys.Slots[i].Value, Values[i]);\n        }\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return GetEnumerator();\n        }\n        public bool Add(TKey key, TValue value)\n        {\n            if (!Keys.Add(key))\n            {\n                if (Values.Length != Keys.Slots.Length)\n                {\n                    var nValues = new TValue[Keys.Slots.Length];\n                    Array.Copy(Values, nValues, Values.Length);\n                    Values = nValues;\n                    Resizes++;\n                }\n                Values[Keys.Position] = value;\n                return false;\n            }\n            Values[Keys.Position] = value;\n            return true;\n        }\n        public void Remove(TKey key)\n        {\n            var pos = Keys.FindEntry(key);\n            if (pos != -1)\n            {\n                Values[pos] = default;\n                Keys.Remove(key);\n            }\n        }\n        public bool ContainsKey(TKey key)\n        {\n            return Keys.FindEntry(key) != -1;\n        }\n        public int FindKeyIndex(TKey key)\n        {\n            return Keys.FindEntry(key);\n        }\n    }\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Concurrent Dictionary Class without Blocking Updated: July-27,2021<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[84,59,207],"_links":{"self":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/504"}],"collection":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/comments?post=504"}],"version-history":[{"count":4,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/504\/revisions"}],"predecessor-version":[{"id":510,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/504\/revisions\/510"}],"wp:attachment":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/media?parent=504"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/categories?post=504"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/tags?post=504"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}