// 일치하는 키와 남은 키를 구한다. public TrieKey GetMatchKey(TrieKey key, out TrieKey keyRemain) { int count = Compare(key); keyRemain = Skip(count); return(Take(count)); }
protected void ToList(TrieNode node, TrieKey key, List <KeyValuePair <byte[], byte[]> > array) { if (node.Type == NodeType.ValueNode) { byte[] value = node.Value; if (!value.IsNullOrEmpty()) { array.Add(new KeyValuePair <byte[], byte[]>((key + node.Key).Path.ToByteArray(), value)); } } else if (node.Type == NodeType.ShortNode) { ToList(node.Next, key + node.Key, array); } else if (node.Type == NodeType.FullNode) { byte[] value = node.Value; if (!value.IsNullOrEmpty()) { array.Add(new KeyValuePair <byte[], byte[]>(key.Path.ToByteArray(), value)); } for (byte i = 0; i < 16; i++) { var n = node.GetChild(i); if (!ReferenceEquals(n, null)) { ToList(n, key + new TrieKey(new Nibble[] { i }, true), array); } } } }
public int Compare(TrieKey key, out TrieKey keyRemain) { int count = Compare(key); keyRemain = Skip(count); return(count); }
public void Dispose() { rlp = null; key = null; next = null; chidrens = null; value = null; }
public static TrieKey operator +(TrieKey left, TrieKey right) { var key = new TrieKey(); key.Push(left); key.Push(right); return(key); }
// new extension node public TrieNode(ITrie trie, TrieKey key, TrieNode next) { this.trie = trie; rlp = new RlpEncoder(key, next.Hash).Encode(); Type = NodeType.ShortNode; Dirty = true; DecodeRLP(); }
// new leaf node public TrieNode(ITrie trie, TrieKey key, byte[] value) { this.trie = trie; rlp = new RlpEncoder(key, value).Encode(); Type = NodeType.ValueNode; Dirty = true; DecodeRLP(); }
// GET public byte[] Get(byte[] key) { if (!HasRoot) { return(null); } TrieKey k = GetTrieKey(key); TrieNode node = FindNode(RootNode, k).found; return(node != null ? node.Value : null); }
public static NodeType GetNodeType(RlpDecoder rlp) { if (rlp.Count == 17) { return(NodeType.FullNode); } if (rlp.Count == 2) { return(TrieKey.Decode(rlp[0].Value).HasTerm ? NodeType.ValueNode : NodeType.ShortNode); } return(NodeType.EmptyNode); }
// DELETE public void Del(byte[] key) { TrieKey k = GetTrieKey(key); if (HasRoot) { // 탐색 진행 (TrieNode found, TrieKey keyRemainder, Stack <TrieNode> stack) = FindNode(RootNode, k); if (found != null) { // 노드를 찾았으면 값을 삭제하고 // 스택을 저장한다. found.Value = null; RootNode = SaveStack(k, stack); return; } } }
// PUT public void Put(byte[] key, byte[] value) { TrieKey k = GetTrieKey(key); if (!HasRoot) { RootNode = new TrieNode(this, k, value); return; } // 탐색 진행 (TrieNode found, TrieKey keyRemainder, Stack <TrieNode> stack) = FindNode(RootNode, k); if (found != null) { // 노드를 찾았으면 값을 설정하고 // 스택을 저장한다. found.Value = value; RootNode = SaveStack(k, stack); return; } // 노드를 추가한다. RootNode = InsertNode(k, value, keyRemainder, stack); }
// 스택을 정리한다. protected TrieNode SaveStack(TrieKey key, Stack <TrieNode> stack) { TrieNode root = null; TrieKey k = key.Clone(); while (stack.Count > 0) { TrieNode node = stack.Pop(); if (node.Type == NodeType.ValueNode) { k.Pop(node.Key.Length); } else if (node.Type == NodeType.ShortNode) { k.Pop(node.Key.Length); if (null != root) { node.Next = root; } } else if (node.Type == NodeType.FullNode) { if (null != root) { Guard.Assert(!k.Empty); node.SetChild(k.Pop(), root); } } // 노드 RLP 인코딩 root = node.EncodeRLP(); } return(root); }
public void Push(TrieKey key) { Path = Path.Append(key?.Path); }
// 일치하는 키를 구한다. public TrieKey GetMatchKey(TrieKey key) { int count = Compare(key); return(Take(count)); }
public TrieKey(TrieKey other) { Path = other.Path.ToArray(); HasTerm = other.HasTerm; }
// 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!"); }
// RLP를 디코딩하여 노드 상태를 완전하게 만든다. internal TrieNode DecodeRLP() { if (ReferenceEquals(rlp, null)) { throw new Exception("can't decode empty rlp"); } if (!Parsed) { var rlp = new RlpDecoder(this.rlp); if (Type == NodeType.FullNode) { if (rlp.Count != 17) { throw new Exception("can't decode rlp for full node"); } // child node chidrens = new TrieNode[16]; for (int i = 0; i < 16; i++) { byte[] node = trie.Read(rlp[i].Value); chidrens[i] = node != null ? new TrieNode(trie, node) : null; } // value value = rlp[16].Value; } else if (Type == NodeType.ShortNode) { if (rlp.Count != 2) { throw new Exception("can't decode rlp for short node"); } // key key = TrieKey.Decode(rlp[0].Value); // next node byte[] node = trie.Read(rlp[1].Value); next = node != null ? new TrieNode(trie, node) : null; } else if (Type == NodeType.ValueNode) { if (rlp.Count != 2) { throw new Exception("can't decode rlp for value node"); } // key key = TrieKey.Decode(rlp[0].Value); // value value = rlp[1].Value; } else { throw new Exception("can't decoded rlp for unknown node type"); } Parsed = true; } return(this); }
public int Compare(TrieKey key) { return(!ReferenceEquals(key, null) ? CountMatchingNibbleLength(Path, key.Path) : 0); }