コード例 #1
0
ファイル: Trie.cs プロジェクト: bryllite/web4b-cs
        // 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));
        }
コード例 #2
0
ファイル: Trie.cs プロジェクト: bryllite/web4b-cs
        // 루트 부터 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!");
        }