trie: Make iterator postorder instead of preorder

This commit is contained in:
Nick Johnson 2017-01-16 16:21:31 +00:00
parent 26d385c18b
commit 71a442ffbc
2 changed files with 40 additions and 45 deletions

View file

@ -132,70 +132,63 @@ func (it *NodeIterator) step() error {
state.hash = root state.hash = root
} }
it.stack = append(it.stack, state) it.stack = append(it.stack, state)
} else { return nil
// Continue iterating at the previous node otherwise.
it.stack = it.stack[:len(it.stack)-1]
if len(it.stack) == 0 {
it.trie = nil
return nil
}
} }
// Continue iteration to the next child // Continue iteration to the next child
for { for {
if len(it.stack) == 0 {
it.trie = nil
return nil
}
parent := it.stack[len(it.stack)-1] parent := it.stack[len(it.stack)-1]
ancestor := parent.hash ancestor := parent.hash
if (ancestor == common.Hash{}) { if (ancestor == common.Hash{}) {
ancestor = parent.parent ancestor = parent.parent
} }
if node, ok := parent.node.(*fullNode); ok { if node, ok := parent.node.(*fullNode); ok {
// Full node, traverse all children, then the node itself // Full node, iterate over children
if parent.child >= len(node.Children) { parent.child++
if parent.child < len(node.Children) {
it.stack = append(it.stack, &nodeIteratorState{
hash: common.BytesToHash(node.flags.hash),
node: node.Children[parent.child],
parent: ancestor,
child: -1,
})
break break
} }
for parent.child++; parent.child < len(node.Children); parent.child++ {
if current := node.Children[parent.child]; current != nil {
it.stack = append(it.stack, &nodeIteratorState{
hash: common.BytesToHash(node.flags.hash),
node: current,
parent: ancestor,
child: -1,
})
break
}
}
} else if node, ok := parent.node.(*shortNode); ok { } else if node, ok := parent.node.(*shortNode); ok {
// Short node, traverse the pointer singleton child, then the node itself // Short node, return the pointer singleton child
if parent.child >= 0 { if parent.child < 0 {
parent.child++
it.stack = append(it.stack, &nodeIteratorState{
hash: common.BytesToHash(node.flags.hash),
node: node.Val,
parent: ancestor,
child: -1,
})
break break
} }
parent.child++
it.stack = append(it.stack, &nodeIteratorState{
hash: common.BytesToHash(node.flags.hash),
node: node.Val,
parent: ancestor,
child: -1,
})
} else if hash, ok := parent.node.(hashNode); ok { } else if hash, ok := parent.node.(hashNode); ok {
// Hash node, resolve the hash child from the database, then the node itself // Hash node, resolve the hash child from the database
if parent.child >= 0 { if parent.child < 0 {
parent.child++
node, err := it.trie.resolveHash(hash, nil, nil)
if err != nil {
return err
}
it.stack = append(it.stack, &nodeIteratorState{
hash: common.BytesToHash(hash),
node: node,
parent: ancestor,
child: -1,
})
break break
} }
parent.child++
node, err := it.trie.resolveHash(hash, nil, nil)
if err != nil {
return err
}
it.stack = append(it.stack, &nodeIteratorState{
hash: common.BytesToHash(hash),
node: node,
parent: ancestor,
child: -1,
})
} else {
break
} }
it.stack = it.stack[:len(it.stack)-1]
} }
return nil return nil
} }

View file

@ -17,6 +17,7 @@
package trie package trie
import ( import (
"fmt"
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -44,6 +45,7 @@ func TestIterator(t *testing.T) {
found := make(map[string]string) found := make(map[string]string)
it := NewIterator(trie) it := NewIterator(trie)
for it.Next() { for it.Next() {
fmt.Printf("%s=%s\n", it.Key, it.Value)
found[string(it.Key)] = string(it.Value) found[string(it.Key)] = string(it.Value)
} }