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)); }
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)); }