{"id":336,"date":"2020-12-30T09:20:06","date_gmt":"2020-12-30T09:20:06","guid":{"rendered":"https:\/\/michaeljohnsteiner.com\/?p=336"},"modified":"2021-01-07T10:16:51","modified_gmt":"2021-01-07T10:16:51","slug":"objectindexer-cs","status":"publish","type":"post","link":"https:\/\/michaeljohnsteiner.com\/index.php\/2020\/12\/30\/objectindexer-cs\/","title":{"rendered":"ObjectIndexer.cs"},"content":{"rendered":"\n<p>Sequential Ordering Object Indexer<\/p>\n\n\n\n<p>Pass in an object get back it is sequential index 0\u2026n. Session specific indexing.<\/p>\n\n\n\n<p>Example Classes at the bottom.<\/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.Generic;\nusing System.Diagnostics;\nusing System.Linq;\n[DebuggerTypeProxy(typeof(HashSetDebugView&lt;>))]\n[DebuggerDisplay(\"Count = {\" + nameof(Count) + \"}\")]\npublic class ObjectIndexer\n{\n    private const    int       BitWidth    = 64;\n    private const    int       BucketDepth = 3;\n    private readonly FNV1a64   hasher;\n    internal         int       Count;\n    private          long[]    Indices;\n    internal         int       Length;\n    public           List&lt;int> loopcntlst = new List&lt;int>();\n    internal         object[]  Objects;\n    private          int       Resizes;\n    public ObjectIndexer(int size = 0)\n    {\n        if (size == 0)\n            Length = 1607;\n        else\n            Length = size;\n        Count   = 0;\n        Indices = new long[Length * BucketDepth];\n        Indices.Fill(-1);\n        Objects = new object[Length * BucketDepth];\n        Resizes = 0;\n        hasher  = new FNV1a64();\n    }\n    public void Clear()\n    {\n        Count   = 0;\n        Indices = new long[Length   * BucketDepth];\n        Objects = new object[Length * BucketDepth];\n    }\n    private static bool IsPrimitive(object obj)\n    {\n        switch (Type.GetTypeCode(obj.GetType()))\n        {\n            case TypeCode.Boolean:\n            case TypeCode.Char:\n            case TypeCode.SByte:\n            case TypeCode.Byte:\n            case TypeCode.Int16:\n            case TypeCode.UInt16:\n            case TypeCode.Int32:\n            case TypeCode.UInt32:\n            case TypeCode.Single:\n            case TypeCode.String:\n            case TypeCode.Decimal:\n            case TypeCode.DateTime:\n            case TypeCode.Int64:\n            case TypeCode.UInt64:\n            case TypeCode.Double:\n                return true;\n            default:\n                return false;\n        }\n    }\n    private new bool Equals(object x, object y)\n    {\n        if (x == null || y == null)\n            return false;\n        var xp = IsPrimitive(x);\n        var yp = IsPrimitive(y);\n        if (xp != yp)\n            return false;\n        if (xp &amp;&amp; yp)\n            return x.Equals(y);\n        var xb = x.GetBytes();\n        var yb = y.GetBytes();\n        if (xb.Length != yb.Length)\n            return false;\n        return xb.Compare(yb);\n    }\n    public long FindObject(object obj, out bool found)\n    {\n        var hashCode = hasher.ComputeHash(obj.GetBytes()).ToLong();\n        var StepPos  = (hashCode &amp; long.MaxValue) % Length;\n        var loopCnt  = 0;\n        while (true)\n        {\n            loopCnt++;\n            if (loopCnt > BucketDepth * 8)\n                throw new Exception(\"Bucket Depth too low.\");\n            var StartPos = (hashCode &amp; long.MaxValue) % Length * BucketDepth;\n            for (var i = StartPos; i &lt; StartPos + BucketDepth; ++i)\n            {\n                if (Objects[i] == null)\n                {\n                    found = false;\n                    loopcntlst.Add(loopCnt);\n                    return i;\n                }\n                if (Equals(Objects[i], obj))\n                {\n                    found = true;\n                    loopcntlst.Add(loopCnt);\n                    return i;\n                }\n            }\n            hashCode += StepPos;\n        }\n    }\n    public bool Contains(object item)\n    {\n        FindObject(item, out var found);\n        return found;\n    }\n    public long FindIndex(object obj)\n    {\n        long position;\n        bool found;\n        if (obj != null)\n            position = FindObject(obj, out found);\n        else\n            throw new ArgumentException(\"Object cannot be null.\");\n        return found ? Indices[position] : -1;\n    }\n    public (long idx, bool found) GetIndex(object obj)\n    {\n        long position;\n        bool found;\n        if (obj != null)\n            position = FindObject(obj, out found);\n        else\n            throw new ArgumentException(\"Object cannot be null.\");\n        long index;\n        if (!found)\n        {\n            Objects[position] = obj;\n            Indices[position] = Count++;\n            index             = Indices[position];\n            if (Count > Length)\n                Resize();\n        }\n        else\n        {\n            index = Indices[position];\n        }\n        return (index, found);\n    }\n    public bool Add(object obj)\n    {\n        long position;\n        bool found;\n        if (obj != null)\n            position = FindObject(obj, out found);\n        else\n            throw new ArgumentException(\"Object cannot be null.\");\n        if (!found)\n            if (Objects[position] == null)\n            {\n                Objects[position] = obj;\n                Indices[position] = Count++;\n                if (Count > Length)\n                    Resize();\n            }\n        return found;\n    }\n    public int AddRange(IEnumerable&lt;object> items)\n    {\n        return items.Sum(i => !Add(i) ? 0 : 1);\n    }\n    private void Resize()\n    {\n        Resizes++;\n        Length += Length * 2; \n        var idxArray = new long[Length * BucketDepth];\n        idxArray.Fill(-1);\n        var objArray = new object[Length * BucketDepth];\n        var cidx     = Indices;\n        var cobjs    = Objects;\n        Indices = idxArray;\n        Objects = objArray;\n        for (var i = 0; i &lt; cobjs.Length; ++i)\n            if (cobjs[i] != null)\n            {\n                var position = FindObject(cobjs[i], out var D);\n                Objects[position] = cobjs[i];\n                Indices[position] = cidx[i];\n            }\n    }\n    public void TrimExcess()\n    {\n        var hi = 0;\n        for (var i = Length * BucketDepth - 1; i >= 0; --i)\n            if (Indices[i] != -1)\n                break;\n            else\n                hi = i;\n        Array.Resize(ref Objects, hi);\n        Array.Resize(ref Indices, hi);\n        Length = hi;\n        Recalculate();\n    }\n    private void Recalculate()\n    {\n        var idxArray = new long[Length * BucketDepth];\n        idxArray.Fill(-1);\n        var objArray = new object[Length * BucketDepth];\n        var cidx     = Indices;\n        var cobjs    = Objects;\n        Indices = idxArray;\n        Objects = objArray;\n        for (var i = 0; i &lt; cobjs.Length; ++i)\n            if (cobjs[i] != null)\n            {\n                var position = FindObject(cobjs[i], out var D);\n                Objects[position] = cobjs[i];\n                Indices[position] = cidx[i];\n            }\n    }\n    public object[] ToArray()\n    {\n        var array = new object[Count];\n        var ptr   = 0;\n        for (var i = 0; i &lt; Objects.Length; ++i)\n            if (Objects[i] != null)\n                array[ptr++] = Objects[i];\n        return array;\n    }\n    public void ExceptWith(IEnumerable&lt;object> other)\n    {\n        if (other == null)\n            throw new Exception(\"The other set must not be null.\");\n        if (Count == 0)\n            return;\n        if (Equals(other, this))\n            Clear();\n        else\n            foreach (var obj in other)\n                Remove(obj);\n    }\n    public void UnionWith(IEnumerable&lt;object> other)\n    {\n        if (other == null)\n            throw new Exception(\"The other set must not be null.\");\n        foreach (var obj in other)\n            Add(obj);\n    }\n    public bool Overlaps(IEnumerable&lt;object> other)\n    {\n        if (other == null)\n            throw new Exception(\"The other set must not be null.\");\n        return Count != 0 &amp;&amp; other.Any(Contains);\n    }\n    public bool ContainsAllElements(IEnumerable&lt;object> other)\n    {\n        return other.All(Contains);\n    }\n    public int RemoveWhere(Predicate&lt;object> pred)\n    {\n        if (pred == null)\n            throw new Exception(\"The Predicate cannot be null.\");\n        var matches = 0;\n        for (var i = 0; i &lt; Objects.Length; ++i)\n            if (Objects[i] != null)\n            {\n                var obj = Objects[i];\n                if (pred(obj) &amp;&amp; Remove(obj))\n                    ++matches;\n            }\n        return matches;\n    }\n    public bool Remove(object oldItem)\n    {\n        var pos = FindObject(oldItem, out var D);\n        if (!D)\n            return false;\n        Objects[pos] = null;\n        Indices[pos] = -1;\n        Count--;\n        return true;\n    }\n}<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Example HashSet Class Using Indexing.\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\n[DebuggerTypeProxy(typeof(HashSetDebugView&lt;>))]\n[DebuggerDisplay(\"Count = {\" + nameof(Count) + \"}\")]\n[Serializable]\npublic class TestHashSetObjectIndexerIdx&lt;T> : IEnumerable&lt;T>\n{\n    private T[]           _array;\n    private ObjectIndexer Oi;\n    public TestHashSetObjectIndexerIdx(int size = 0)\n    {\n        Oi     = new ObjectIndexer(size);\n        _array = new T[size];\n    }\n    public int Count => Oi.Count;\n    IEnumerator&lt;T> IEnumerable&lt;T>.GetEnumerator()\n    {\n        return GetEnumerator();\n    }\n    IEnumerator IEnumerable.GetEnumerator()\n    {\n        return GetEnumerator();\n    }\n    public T[] ToArray()\n    {\n        return (T[]) _array.Clone();\n    }\n    public void Clear()\n    {\n        Oi.Clear();\n        Array.Clear(_array, 0, Oi.Length);\n    }\n    public bool Add(T item)\n    {\n        var idx = Oi.GetIndex(item);\n        if (_array.Length != Oi.Length)\n            Array.Resize(ref _array, Oi.Length);\n        _array[idx.idx] = item;\n        return idx.found;\n    }\n    public int AddRange(IEnumerable&lt;T> items)\n    {\n        return items.Sum(i => !Add(i) ? 0 : 1);\n    }\n    public bool Contains(T item)\n    {\n        return Oi.ContainsObject(item);\n    }\n    public int FindEntry(T item)\n    {\n        return (int)Oi.FindIndex(item);\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; Count; i++)\n            if (_array[i] != null)\n                yield return _array[i];\n    }\n}<\/pre>\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=\"\">Example HashSet Class Using Object Indexer as a Base Class:\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\n[DebuggerTypeProxy(typeof(HashSetDebugView&lt;>))]\n[DebuggerDisplay(\"Count = {\" + nameof(Count) + \"}\")]\n[Serializable]\npublic class TestHashSetObjectIndexer&lt;T> : IEnumerable&lt;T>\n{\n    private  ObjectIndexer Oi;\n    public TestHashSetObjectIndexer(int size = 0)\n    {\n        Oi = new ObjectIndexer(size);\n    }\n    public int Count => Oi.Count;\n    IEnumerator&lt;T> IEnumerable&lt;T>.GetEnumerator()\n    {\n        return GetEnumerator();\n    }\n    IEnumerator IEnumerable.GetEnumerator()\n    {\n        return GetEnumerator();\n    }\n    public T[] ToArray()\n    {\n        var newArray = new T[Count];\n        var copied   = 0;\n        var a        = (object[]) Oi.Objects.Clone();\n        for (var i = 0; i &lt; Count &amp;&amp; copied &lt; Count; i++)\n            if (a[i] != null)\n                newArray[copied++] = (T)Convert.ChangeType(a[i], typeof(T));\n        return newArray;\n    }\n    public void Clear()\n    {\n        Oi.Clear();\n    }\n    public bool Add(T item)\n    {\n\n        return Oi.Add(item);\n    }\n    public int AddRange(IEnumerable&lt;T> items)\n    {\n        return items.Sum(i => !Add(i) ? 0 : 1);\n    }\n    public bool Contains(T item)\n    {\n        return Oi.ContainsObject(item);\n    }\n    public int FindEntry(T item)\n    {\n        var i = Oi.FindObject(item, out var d);\n        return d ? (int) i : -1;\n    }\n    public IEnumerator&lt;T> GetEnumerator()\n    {\n        return GetEnum();\n    }\n    public IEnumerator&lt;T> GetEnum()\n    {\n        var a = (T[]) Oi.Objects.Clone();\n        for (var i = 0; i &lt; Count; i++)\n            if (a[i] != null)\n                yield return (T)Convert.ChangeType(a[i], typeof(T));\n    }\n}<\/pre>\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=\"\">Example Dictionary Class Using Object Indexer as a Base Class:\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics;\n[DebuggerTypeProxy(typeof(HashSetDebugView&lt;>))]\n[DebuggerDisplay(\"Count = {\" + nameof(Count) + \"}\")]\n[Serializable]\npublic class TestDictionaryObjectIndexer&lt;TKey, TValue> : IEnumerable&lt;KeyValuePair&lt;TKey, TValue>>\n{\n    private ObjectIndexer _oi;\n    private TValue[]      _values;\n    public TestDictionaryObjectIndexer(int size = 0)\n    {\n        _oi     = new ObjectIndexer(size);\n        _values = new TValue[size];\n    }\n    public int      Count  => _oi.Count;\n    public IEnumerator&lt;KeyValuePair&lt;TKey, TValue>> GetEnumerator()\n    {\n        return GetEnum();\n    }\n    IEnumerator IEnumerable.GetEnumerator()\n    {\n        return GetEnumerator();\n    }\n    public TKey[] GetKeys()\n    {\n        var kp   = ToArray();\n        var keys = new TKey[Count];\n        for (var i = 0; i &lt; Count; ++i)\n            keys[i] = kp[i].Key;\n        return keys;\n    }\n    public TValue[] GetValues()\n    {\n        var kp     = ToArray();\n        var values = new TValue[Count];\n        for (var i = 0; i &lt; Count; ++i)\n            values[i] = kp[i].Value;\n        return values;\n    }\n    public void Clear()\n    {\n        _oi.Clear();\n    }\n    public bool Add(TKey key, TValue value)\n    {\n        var pi = _oi.GetIndex(key);\n        if (!pi.found)\n        {\n            if (_values.Length != _oi.Length)\n            {\n                var nValues = new TValue[_oi.Length];\n                Array.Copy(_values, nValues, _values.Length);\n                _values = nValues;\n            }\n            _values[pi.idx] = value;\n            return false;\n        }\n        _values[pi.idx] = value;\n        return true;\n    }\n    public bool Contains(TKey item)\n    {\n        return _oi.ContainsObject(item);\n    }\n    public IEnumerator&lt;KeyValuePair&lt;TKey, TValue>> GetEnum()\n    {\n        var a = (object[]) _oi.Objects.Clone();\n        for (var i = 0; i &lt; Count; i++)\n            if (a[i] != null)\n            {\n                var k = (TKey) Convert.ChangeType(a[i], typeof(TKey));\n                var p = _oi.GetIndex(k);\n                var v = _values[p.idx];\n                yield return new KeyValuePair&lt;TKey, TValue>((TKey) Convert.ChangeType(a[i], typeof(TKey)), v);\n            }\n    }\n    public KeyValuePair&lt;TKey, TValue>[] ToArray()\n    {\n        var a     = (object[]) _oi.Objects.Clone();\n        var array = new KeyValuePair&lt;TKey, TValue>[Count];\n        var ptr   = 0;\n        for (var i = 0; i &lt; Count; i++)\n            if (a[i] != null)\n            {\n                var k = (TKey) Convert.ChangeType(a[i], typeof(TKey));\n                var p = _oi.GetIndex(k);\n                var v = _values[p.idx];\n                array[ptr++] = new KeyValuePair&lt;TKey, TValue>((TKey) Convert.ChangeType(a[i], typeof(TKey)), v);\n            }\n        return array;\n    }\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Sequential Ordering Object Indexer Pass in an object get back it is sequential index 0\u2026n. Session specific indexing. Example Classes at the bottom.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[163,26,165,164],"_links":{"self":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/336"}],"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=336"}],"version-history":[{"count":16,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/336\/revisions"}],"predecessor-version":[{"id":365,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/336\/revisions\/365"}],"wp:attachment":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/media?parent=336"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/categories?post=336"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/tags?post=336"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}