// keyRemainder는 Empty일 수 있다. // key는 Empty일 수 없다. // stack은 0보다 크다 protected TrieNode InsertNode(TrieKey key, byte[] value, TrieKey keyRemainder, Stack <TrieNode> stack) { Guard.Assert(!key.Empty); Guard.Assert(stack.Count > 0); // 스택의 최종 노드 TrieNode node = stack.Pop(); // 최종 노드가 브랜치 노드인 경우 if (node.Type == NodeType.FullNode) { stack.Push(node); // 브랜치 노드의 자식 노드로 새로운 리프 노드 추가 // keyRemainder is not empty always stack.Push(new TrieNode(this, keyRemainder.Skip(1), value)); } else { TrieKey nodeKey = node.Key; TrieNode fullNode = new TrieNode(this); int matchingLength = keyRemainder.Compare(nodeKey); if (matchingLength > 0) { // 공유키로 익스텐션 노드 생성 TrieKey sharedKey = new TrieKey(keyRemainder.Take(matchingLength).Path, false); stack.Push(new TrieNode(this, sharedKey, fullNode)); nodeKey = nodeKey.Skip(matchingLength); keyRemainder = keyRemainder.Skip(matchingLength); } // 스택에 브랜치 노드 추가 stack.Push(fullNode); // 기존 노드 if (!nodeKey.Empty) { Nibble branchKey = nodeKey.PopFront(); if (nodeKey.Empty && node.Type == NodeType.ShortNode) { // replace extension node to branch node var child = node.Next; fullNode.SetChild(branchKey, child.EncodeRLP()); } else { node.Key = nodeKey; fullNode.SetChild(branchKey, node.EncodeRLP()); } } else { Guard.Assert(node.Type == NodeType.ValueNode); // 브랜치 노드에 값 설정 fullNode.Value = node.Value; } // 스택에 새로운 리프 노드를 추가한다. // 만약, 잔여 키가 비어있으면 브랜치 노드에 값 설정한다. if (keyRemainder.Empty) { fullNode.Value = value; } else { stack.Push(new TrieNode(this, keyRemainder.Skip(1), value)); } } return(SaveStack(key, stack)); }
// 루트 부터 key에 해당하는 경로를 탐색하여 // 일치하는 노드, 잔여 경로, 노드 스택(경로에 해당하는) 을 구한다. protected (TrieNode found, TrieKey keyRemainder, Stack <TrieNode> stack) FindNode(TrieNode root, TrieKey key) { if (ReferenceEquals(root, null)) { throw new ArgumentNullException(nameof(root)); } if (ReferenceEquals(key, null) || key.Empty) { throw new ArgumentNullException(nameof(key)); } // 노드 경로 스택 Stack <TrieNode> stack = new Stack <TrieNode>(); // 노드와 검색 경로 TrieNode node = root; TrieKey keyRemainder = key.Clone(); while (node != null && node.Type != NodeType.EmptyNode) { // 노드 스택에 노드 추가 stack.Push(node); // 현재 노드가 브랜치 노드이면 if (node.Type == NodeType.FullNode) { // 브랜치 노드에서 경로가 종료되면 탐색 종료 if (keyRemainder.Empty) { return(node, TrieKey.EmptyKey, stack); } // 경로에 해당하는 자식 노드가 없으면 탐색 종료 Nibble radix = keyRemainder[0]; TrieNode child = node.GetChild(radix); if (child == null) { return(null, keyRemainder, stack); } // 자식 노드로 탐색 계속 진행 node = child; keyRemainder.PopFront(); continue; } // 현재 노드가 익스텐션 노드이면 if (node.Type == NodeType.ShortNode) { // 노드 키 ( 항상 키가 존재해야 한다 ) TrieKey k = node.Key; Guard.Assert(!k.Empty); // 익스텐션 키가 일치하지 않으면 탐색 종료 int matchingLength = keyRemainder.Compare(k); if (matchingLength != k.Length) { return(null, keyRemainder, stack); } // 익스텐션 노드의 자식 노드로 계속 탐색 진행 //keyRemainder.PopFront(k.Length); keyRemainder = keyRemainder.Skip(k.Length); node = node.Next; continue; } // 리프 노드 return(keyRemainder == node.Key ? (node, TrieKey.EmptyKey, stack) : (null, keyRemainder, stack)); } throw new Exception("wtf!"); }