public static MPTNode Decode(byte[] data) { if (data is null || data.Length == 0) { return(null); } MPTNode node; using (BinaryReader reader = new BinaryReader(new MemoryStream(data, false), Encoding.UTF8)) { var nodeType = (NodeType)reader.ReadByte(); switch (nodeType) { case NodeType.BranchNode: { node = new BranchNode(); break; } case NodeType.ExtensionNode: { node = new ExtensionNode(); break; } case NodeType.LeafNode: { node = new LeafNode(); break; } default: throw new System.InvalidOperationException(); } node.DecodeSpecific(reader); } return(node); }
private bool Put(ref MPTNode node, byte[] path, MPTNode val) { switch (node) { case LeafNode leafNode: { if (val is LeafNode v) { if (path.Length == 0) { node = v; db.Put(node); return(true); } var branch = new BranchNode(); branch.Children[BranchNode.ChildCount - 1] = leafNode; Put(ref branch.Children[path[0]], path.Skip(1), v); db.Put(branch); node = branch; return(true); } return(false); } case ExtensionNode extensionNode: { if (path.AsSpan().StartsWith(extensionNode.Key)) { var result = Put(ref extensionNode.Next, path.Skip(extensionNode.Key.Length), val); if (result) { extensionNode.SetDirty(); db.Put(extensionNode); } return(result); } var prefix = extensionNode.Key.CommonPrefix(path); var pathRemain = path.Skip(prefix.Length); var keyRemain = extensionNode.Key.Skip(prefix.Length); var son = new BranchNode(); MPTNode grandSon1 = HashNode.EmptyNode(); MPTNode grandSon2 = HashNode.EmptyNode(); Put(ref grandSon1, keyRemain.Skip(1), extensionNode.Next); son.Children[keyRemain[0]] = grandSon1; if (pathRemain.Length == 0) { Put(ref grandSon2, pathRemain, val); son.Children[BranchNode.ChildCount - 1] = grandSon2; } else { Put(ref grandSon2, pathRemain.Skip(1), val); son.Children[pathRemain[0]] = grandSon2; } db.Put(son); if (prefix.Length > 0) { var exNode = new ExtensionNode() { Key = prefix, Next = son, }; db.Put(exNode); node = exNode; } else { node = son; } return(true); } case BranchNode branchNode: { bool result; if (path.Length == 0) { result = Put(ref branchNode.Children[BranchNode.ChildCount - 1], path, val); } else { result = Put(ref branchNode.Children[path[0]], path.Skip(1), val); } if (result) { branchNode.SetDirty(); db.Put(branchNode); } return(result); } case HashNode hashNode: { MPTNode newNode; if (hashNode.IsEmptyNode) { if (path.Length == 0) { newNode = val; } else { newNode = new ExtensionNode() { Key = path, Next = val, }; db.Put(newNode); } node = newNode; if (val is LeafNode) { db.Put(val); } return(true); } newNode = Resolve(hashNode); if (newNode is null) { return(false); } node = newNode; return(Put(ref node, path, val)); } default: throw new System.InvalidOperationException("Invalid node type."); } }