{"id":460,"date":"2021-06-20T12:28:05","date_gmt":"2021-06-20T12:28:05","guid":{"rendered":"https:\/\/michaeljohnsteiner.com\/?p=460"},"modified":"2021-06-20T12:28:05","modified_gmt":"2021-06-20T12:28:05","slug":"segmentedhashset-cs","status":"publish","type":"post","link":"https:\/\/michaeljohnsteiner.com\/index.php\/2021\/06\/20\/segmentedhashset-cs\/","title":{"rendered":"SegmentedHashSet.cs"},"content":{"rendered":"\n<p>Segmented Hashset Class<\/p>\n\n\n\n<p>Useful for input or output buffer for use in parallel invoke operations where unique values are needed.<\/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;\npublic class SegmentedHashSet&lt;T> : IEnumerable&lt;T>\n{\n    private readonly IntHs&lt;T>[] _array;\n    private readonly int        _size;\n    private          int        _length;\n    public SegmentedHashSet(int length, int size)\n    {\n        _array = new IntHs&lt;T>[4096];\n        for (var i = 0; i &lt; length; ++i)\n            _array[i] = new IntHs&lt;T>(size);\n        _length = length;\n        _size   = size;\n    }\n    public IEnumerator&lt;T> GetEnumerator()\n    {\n        throw new NotImplementedException();\n    }\n    IEnumerator IEnumerable.GetEnumerator()\n    {\n        return GetEnumerator();\n    }\n    public void Add(T item, int index)\n    {\n        if (index >= _length)\n            for (var i = _length; i &lt;= index; ++i)\n            {\n                _array[i] = new IntHs&lt;T>(_size);\n                _length++;\n            }\n        if (!ContainedInArray(item))\n            _array[index].Add(item);\n    }\n    private bool ContainedInArray(T item)\n    {\n        for (var i = 0; i &lt; _length; ++i)\n            if (_array[i].Contains(item))\n                return true;\n        return false;\n    }\n    public T[] CombineToArray()\n    {\n        var totalCount = 0;\n        for (var i = 0; i &lt; _length; ++i)\n            totalCount += _array[i].Count;\n        var ta  = new T[totalCount];\n        var ptr = 0;\n        for (var i = 0; i &lt; _length; ++i)\n        {\n            var it = _array[i].ToArray();\n            _array[i].Zero();\n            for (var j = 0; j &lt; it.Length; ++j)\n                ta[ptr++] = it[j];\n        }\n        return ta;\n    }\n    [DebuggerDisplay(\"Count = {Count}\")]\n    internal class IntHs&lt;T> : IEnumerable\n    {\n        private  Bucket[]             _buckets;\n        internal IEqualityComparer&lt;T> Comparer;\n        public IntHs(int size) : this(size, null)\n        {\n        }\n        public IntHs(int size, IEqualityComparer&lt;T> comparer)\n        {\n            if (comparer == null)\n                comparer = EqualityComparer&lt;T>.Default;\n            Comparer = comparer;\n            _buckets = new Bucket[size];\n            Count    = 0;\n        }\n        public int Count\n        {\n            get;\n            private set;\n        }\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return GetEnumerator();\n        }\n        public void Zero()\n        {\n            _buckets = null;\n            Count    = 0;\n        }\n        public bool Add(T item)\n        {\n            if (Count >= _buckets.Length)\n                EnsureSize();\n            var hashCode = Comparer.GetHashCode(item) &amp; int.MaxValue;\n            var apos     = FindEntry(item, hashCode).APos;\n            if (apos != -1)\n                return false;\n            var pos = hashCode % _buckets.Length;\n            if (_buckets[pos] == null)\n                _buckets[pos] = new Bucket();\n            _buckets[pos].Add(item);\n            Count++;\n            return true;\n        }\n        public T[] ToArray()\n        {\n            var newArray = new T[Count];\n            using (var en = GetEnumerator())\n            {\n                var ptr = 0;\n                while (en.MoveNext())\n                {\n                    var value = en.Current;\n                    if (value == null)\n                        break;\n                    newArray[ptr++] = value;\n                }\n                return newArray;\n            }\n        }\n        private (int APos, int BPos) FindEntry(T item, int hashCode)\n        {\n            if (Count == 0)\n                return (-1, -1);\n            var aPos = hashCode % _buckets.Length;\n            var bPos = 0;\n            if (_buckets[aPos] == null)\n            {\n                _buckets[aPos] = new Bucket();\n                return (-1, -1);\n            }\n            foreach (var i in _buckets[aPos].Values)\n            {\n                if (Equals(i, item))\n                    return (aPos, bPos);\n                bPos++;\n            }\n            return (-1, -1);\n        }\n        private void EnsureSize()\n        {\n            var cArray = ToArray();\n            _buckets = new Bucket[_buckets.Length + _buckets.Length \/ 4 * 3];\n            foreach (var i in cArray)\n            {\n                var hashCode = Comparer.GetHashCode(i) &amp; int.MaxValue;\n                var pos      = hashCode % _buckets.Length;\n                if (_buckets[pos] == null)\n                    _buckets[pos] = new Bucket();\n                _buckets[pos].Add(i);\n            }\n        }\n        public bool Contains(T item)\n        {\n            var hashCode = Comparer.GetHashCode(item) &amp; int.MaxValue;\n            return FindEntry(item, hashCode).APos != -1;\n        }\n        public IEnumerator&lt;T> GetEnumerator()\n        {\n            return GetEnum();\n        }\n        public IEnumerator&lt;T> GetEnum()\n        {\n            for (var i = 0; i &lt; _buckets.Length; i++)\n                if (_buckets[i] != null)\n                    for (var j = 0; j &lt; _buckets[i].Count; ++j)\n                        yield return _buckets[i].Values[j];\n        }\n        internal class Bucket\n        {\n            public int Count;\n            public T[] Values;\n            public Bucket()\n            {\n                Values = new T[1];\n                Count  = 0;\n            }\n            public void Add(T item)\n            {\n                if (Count >= Values.Length)\n                    Array.Resize(ref Values, Values.Length + 1);\n                Values[Count++] = item;\n            }\n        }\n    }\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Segmented Hashset Class Useful for input or output buffer for use in parallel invoke operations where unique values are needed.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[58,192,191,68],"_links":{"self":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/460"}],"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=460"}],"version-history":[{"count":1,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/460\/revisions"}],"predecessor-version":[{"id":461,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/460\/revisions\/461"}],"wp:attachment":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/media?parent=460"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/categories?post=460"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/tags?post=460"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}