package merkletrie // Iter is a radix tree iterator that will traverse the trie in // depth-first pre-order. Entries are traversed in (case-sensitive) // alphabetical order for each level. // // This is the kind of traversal you will expect when listing // ordinary files and directories recursively, for example: // // Trie Traversal order // ---- --------------- // . // / | \ a // / | \ b // b a z ===> b/a // / \ b/c // c a z // // // The Step method will return the next item, the Next method will do // the same but without descending deeper into the tree (i.e. skipping // the contents of "directories"). // // The name of the type and its methods are based on the well known "next" // and "step" operations, quite common in debuggers, like gdb. type Iter struct { // tells if the iteration has started. hasStarted bool // Each level of the tree is represented as a frame, this stack // keeps track of the frames wrapping the current iterator position. // The iterator will "step" into a node by adding its frame to the // stack, or go to the next element at the same level by poping the // current frame. frameStack []*frame } // NewIter returns a new iterator for the trie with its root at n. func NewIter(n Noder) *Iter { ret := &Iter{} ret.push(newFrame("", n)) return ret } func (iter *Iter) top() (*frame, bool) { if len(iter.frameStack) == 0 { return nil, false } top := len(iter.frameStack) - 1 return iter.frameStack[top], true } func (iter *Iter) pop() (*frame, bool) { if len(iter.frameStack) == 0 { return nil, false } top := len(iter.frameStack) - 1 ret := iter.frameStack[top] iter.frameStack[top] = nil iter.frameStack = iter.frameStack[:top] return ret, true } func (iter *Iter) push(f *frame) { iter.frameStack = append(iter.frameStack, f) } const ( descend = true dontDescend = false ) // Next returns the next node without descending deeper into the tree // and true. If there are no more entries it returns nil and false. func (iter *Iter) Next() (Noder, bool) { return iter.advance(dontDescend) } // Step returns the next node in the tree, descending deeper into it if // needed. If there are no more nodes in the tree, it returns nil and // false. func (iter *Iter) Step() (Noder, bool) { return iter.advance(descend) } // advances the iterator in whatever direction you want: descend or // dontDescend. func (iter *Iter) advance(mustDescend bool) (Noder, bool) { node, ok := iter.current() if !ok { return nil, false } // The first time we just return the current node. if !iter.hasStarted { iter.hasStarted = true return node, ok } // following advances will involve dropping already seen nodes // or getting into their children ignoreChildren := node.NumChildren() == 0 || !mustDescend if ignoreChildren { // if we must ignore the current node children, just drop // it and find the next one in the existing frames. _ = iter.drop() node, ok = iter.current() return node, ok } // if we must descend into the current's node children, drop the // parent and add a new frame with its children. _ = iter.drop() iter.push(newFrame(node.Key(), node)) node, _ = iter.current() return node, true } // returns the current frame and the current node (i.e. the ones at the // top of their respective stacks. func (iter *Iter) current() (Noder, bool) { f, ok := iter.top() if !ok { return nil, false } n, ok := f.top() if !ok { return nil, false } return n, true } // removes the current node and all the frames that become empty as a // consecuence of this action. It returns true if something was dropped, // and false if there were no more nodes in the iterator. func (iter *Iter) drop() bool { frame, ok := iter.top() if !ok { return false } _, ok = frame.pop() if !ok { return false } for { // remove empty frames if len(frame.stack) != 0 { break } _, _ = iter.pop() frame, ok = iter.top() if !ok { break } } return true }