144 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package trie
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 
 | |
| 	"github.com/ethereum/go-ethereum/ethutil"
 | |
| )
 | |
| 
 | |
| type NodeType byte
 | |
| 
 | |
| const (
 | |
| 	EmptyNode NodeType = iota
 | |
| 	BranchNode
 | |
| 	LeafNode
 | |
| 	ExtNode
 | |
| )
 | |
| 
 | |
| func getType(node *ethutil.Value) NodeType {
 | |
| 	if node.Len() == 0 {
 | |
| 		return EmptyNode
 | |
| 	}
 | |
| 
 | |
| 	if node.Len() == 2 {
 | |
| 		k := CompactDecode(node.Get(0).Str())
 | |
| 		if HasTerm(k) {
 | |
| 			return LeafNode
 | |
| 		}
 | |
| 
 | |
| 		return ExtNode
 | |
| 	}
 | |
| 
 | |
| 	return BranchNode
 | |
| }
 | |
| 
 | |
| type Iterator struct {
 | |
| 	Path [][]byte
 | |
| 	trie *Trie
 | |
| 
 | |
| 	Key   []byte
 | |
| 	Value *ethutil.Value
 | |
| }
 | |
| 
 | |
| func NewIterator(trie *Trie) *Iterator {
 | |
| 	return &Iterator{trie: trie}
 | |
| }
 | |
| 
 | |
| func (self *Iterator) key(node *ethutil.Value, path [][]byte) []byte {
 | |
| 	switch getType(node) {
 | |
| 	case LeafNode:
 | |
| 		k := RemTerm(CompactDecode(node.Get(0).Str()))
 | |
| 
 | |
| 		self.Path = append(path, k)
 | |
| 		self.Value = node.Get(1)
 | |
| 
 | |
| 		return k
 | |
| 	case BranchNode:
 | |
| 		if node.Get(16).Len() > 0 {
 | |
| 			return []byte{16}
 | |
| 		}
 | |
| 
 | |
| 		for i := byte(0); i < 16; i++ {
 | |
| 			o := self.key(self.trie.getNode(node.Get(int(i)).Raw()), append(path, []byte{i}))
 | |
| 			if o != nil {
 | |
| 				return append([]byte{i}, o...)
 | |
| 			}
 | |
| 		}
 | |
| 	case ExtNode:
 | |
| 		currKey := node.Get(0).Bytes()
 | |
| 
 | |
| 		return self.key(self.trie.getNode(node.Get(1).Raw()), append(path, currKey))
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (self *Iterator) next(node *ethutil.Value, key []byte, path [][]byte) []byte {
 | |
| 	switch typ := getType(node); typ {
 | |
| 	case EmptyNode:
 | |
| 		return nil
 | |
| 	case BranchNode:
 | |
| 		if len(key) > 0 {
 | |
| 			subNode := self.trie.getNode(node.Get(int(key[0])).Raw())
 | |
| 
 | |
| 			o := self.next(subNode, key[1:], append(path, key[:1]))
 | |
| 			if o != nil {
 | |
| 				return append([]byte{key[0]}, o...)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		var r byte = 0
 | |
| 		if len(key) > 0 {
 | |
| 			r = key[0] + 1
 | |
| 		}
 | |
| 
 | |
| 		for i := r; i < 16; i++ {
 | |
| 			subNode := self.trie.getNode(node.Get(int(i)).Raw())
 | |
| 			o := self.key(subNode, append(path, []byte{i}))
 | |
| 			if o != nil {
 | |
| 				return append([]byte{i}, o...)
 | |
| 			}
 | |
| 		}
 | |
| 	case LeafNode, ExtNode:
 | |
| 		k := RemTerm(CompactDecode(node.Get(0).Str()))
 | |
| 		if typ == LeafNode {
 | |
| 			if bytes.Compare([]byte(k), []byte(key)) > 0 {
 | |
| 				self.Value = node.Get(1)
 | |
| 				self.Path = append(path, k)
 | |
| 
 | |
| 				return k
 | |
| 			}
 | |
| 		} else {
 | |
| 			subNode := self.trie.getNode(node.Get(1).Raw())
 | |
| 			subKey := key[len(k):]
 | |
| 			var ret []byte
 | |
| 			if BeginsWith(key, k) {
 | |
| 				ret = self.next(subNode, subKey, append(path, k))
 | |
| 			} else if bytes.Compare(k, key[:len(k)]) > 0 {
 | |
| 				ret = self.key(node, append(path, k))
 | |
| 			} else {
 | |
| 				ret = nil
 | |
| 			}
 | |
| 
 | |
| 			if ret != nil {
 | |
| 				return append(k, ret...)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Get the next in keys
 | |
| func (self *Iterator) Next(key string) []byte {
 | |
| 	self.trie.mut.Lock()
 | |
| 	defer self.trie.mut.Unlock()
 | |
| 
 | |
| 	k := RemTerm(CompactHexDecode(key))
 | |
| 	n := self.next(self.trie.getNode(self.trie.Root), k, nil)
 | |
| 
 | |
| 	self.Key = []byte(DecodeCompact(n))
 | |
| 
 | |
| 	return self.Key
 | |
| }
 |