private ulong ModifyInternalNode(ulong id, InternalNode node, byte h, ulong value, byte[]?valueHash) { if (value == 0 && node.GetChildByHash(h) != 0 && node.Children.Count() == 2) { // we have to handle case when one of two children is deleted and internal node is folded to leaf var secondChild = node.Children.First(child => child != node.GetChildByHash(h)); // fold only if secondChild is also a leaf if (GetNodeById(secondChild).Type == NodeType.Leaf) { return(secondChild); } } if (value != 0 && node.GetChildByHash(h) != 0 && node.Children.Count() == 1 && GetNodeById(value).Type == NodeType.Leaf) { return(value); } var modified = InternalNode.ModifyChildren( node, h, value, node.Children.Select(id => GetNodeById(id)?.Hash ?? throw new InvalidOperationException()), valueHash ); if (modified == null) { return(0u); } var newId = _versionFactory.NewVersion(); _nodeCache[newId] = modified; return(newId); }
public static IHashTrieNode?ModifyChildren( InternalNode node, byte h, ulong value, IEnumerable <byte[]> childrenHashes, byte[]?valueHash ) { if (node == null) { throw new ArgumentNullException(nameof(node)); } var was = node.GetChildByHash(h); if (was == value) { return(node); } List <byte[]> newHashes; var newNode = new InternalNode(); var pos = (int)BitsUtils.PositionOf(node.ChildrenMask, h); if (was == 0) { if (valueHash is null) { throw new ArgumentNullException(nameof(valueHash)); } newNode._children = new ulong[node._children.Length + 1]; for (var i = 0; i <= node._children.Length; ++i) { newNode._children[i] = i < pos ? node._children[i] : (i == pos ? value : node._children[i - 1]); } newNode.ChildrenMask = node.ChildrenMask | (1u << h); newHashes = childrenHashes.ToList(); newHashes.Insert(pos, valueHash); newNode.UpdateHash(newHashes, GetChildrenLabels(newNode.ChildrenMask)); return(newNode); } if (value == 0) { if (node._children.Length == 1) { return(null); } newNode._children = new ulong[node._children.Length - 1]; for (var i = 0; i + 1 < node._children.Length; ++i) { newNode._children[i] = i < pos ? node._children[i] : node._children[i + 1]; } newNode.ChildrenMask = node.ChildrenMask ^ (1u << h); newHashes = childrenHashes.ToList(); newHashes.RemoveAt(pos); newNode.UpdateHash(newHashes, GetChildrenLabels(newNode.ChildrenMask)); return(newNode); } newNode._children = node._children.ToArray(); newNode.ChildrenMask = node.ChildrenMask; newNode._children[pos] = value; newHashes = childrenHashes.ToList(); newHashes[pos] = valueHash ?? throw new ArgumentNullException(nameof(valueHash)); newNode.UpdateHash(newHashes, GetChildrenLabels(newNode.ChildrenMask)); return(newNode); }