Esempio n. 1
0
        public IntHashTrie <V> AddOrUpdate(int hash, V value, Update <V> updateValue = null)
        {
            var index      = hash & 31; // index from 0 to 31
            var restOfHash = hash >> 5;

            var newNodes = new object[32];

            if (_indexBitmap == 0)
            {
                newNodes[index] = restOfHash == 0 ? (object)value : HashTrieNode <V> .Empty.AddOrUpdate(restOfHash, value);

                return(new IntHashTrie <V>(1u << index, newNodes));
            }

            Array.Copy(_nodes, 0, newNodes, 0, newNodes.Length);

            if ((_indexBitmap & (1u << index)) == 0) // no nodes at the index, could be inserted.
            {
                newNodes[index] = restOfHash == 0 ? (object)value : Empty.AddOrUpdate(restOfHash, value);
                return(new IntHashTrie <V>(_indexBitmap | (1u << index), newNodes));
            }

            var updatedNode = _nodes[index];

            if (updatedNode is HashTrieNode <V> )
            {
                updatedNode = ((HashTrieNode <V>)updatedNode).AddOrUpdate(restOfHash, value, updateValue);
            }
            else if (restOfHash != 0) // if we need to update value with node we will move value down to new node sub-nodes at index 0.
            {
                updatedNode = new HashTrieNode <V>(1u, updatedNode).AddOrUpdate(restOfHash, value, updateValue);
            }
            else // here the actual update should go, cause old and new nodes contain values.
            {
                updatedNode = updateValue == null ? value : updateValue((V)updatedNode, value);
            }
            newNodes[index] = updatedNode;
            return(new IntHashTrie <V>(_indexBitmap, newNodes));
        }
Esempio n. 2
0
        public HashTrieNode <V> AddOrUpdate(int hash, V value, Update <V> updateValue = null)
        {
            var index      = hash & LEVEL_MASK; // index from 0 to 31
            var restOfHash = hash >> LEVEL_BITS;

            if (_indexBitmap == 0)
            {
                return(new HashTrieNode <V>(1u << index,
                                            restOfHash == 0 ? (object)value : Empty.AddOrUpdate(restOfHash, value)));
            }

            var pastIndexBitmap = _indexBitmap >> index;

            if ((pastIndexBitmap & 1) == 0) // no nodes at the index, could be inserted.
            {
                var subnode = restOfHash == 0 ? (object)value : Empty.AddOrUpdate(restOfHash, value);

                var pastIndexCount = pastIndexBitmap == 0 ? 0 : GetSetBitsCount(pastIndexBitmap);
                var insertIndex    = _nodes.Length - pastIndexCount;

                var nodesToInsert = new object[_nodes.Length + 1];
                if (insertIndex != 0)
                {
                    Array.Copy(_nodes, 0, nodesToInsert, 0, insertIndex);
                }
                nodesToInsert[insertIndex] = subnode;
                if (pastIndexCount != 0)
                {
                    Array.Copy(_nodes, insertIndex, nodesToInsert, insertIndex + 1, pastIndexCount);
                }

                return(new HashTrieNode <V>(_indexBitmap | (1u << index), nodesToInsert));
            }

            var updateIndex = _nodes.Length == 1 ? 0
                : _nodes.Length - (pastIndexBitmap == 1 ? 1 : GetSetBitsCount(pastIndexBitmap));

            var updatedNode = _nodes[updateIndex];

            if (updatedNode is HashTrieNode <V> )
            {
                updatedNode = ((HashTrieNode <V>)updatedNode).AddOrUpdate(restOfHash, value, updateValue);
            }
            else if (restOfHash != 0) // if we need to update value with node we will move value down to new node sub-nodes at index 0.
            {
                updatedNode = new HashTrieNode <V>(1u, updatedNode).AddOrUpdate(restOfHash, value, updateValue);
            }
            else // here the actual update should go, cause old and new nodes contain values.
            {
                updatedNode = updateValue == null ? value : updateValue((V)updatedNode, value);
            }

            var nodesToUpdate = new object[_nodes.Length];

            if (nodesToUpdate.Length > 1)
            {
                Array.Copy(_nodes, 0, nodesToUpdate, 0, nodesToUpdate.Length);
            }
            nodesToUpdate[updateIndex] = updatedNode;

            return(new HashTrieNode <V>(_indexBitmap, nodesToUpdate));
        }