Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

node.gno

3.37 Kb · 138 lines
  1package trie
  2
  3// node is a single position in the trie tree
  4type node struct {
  5	char     byte    // node's char, unused in the root node
  6	value    any     // node's value, stored when isKey is true
  7	isKey    bool    // whether a key terminates at this node
  8	children []*node // child nodes, kept sorted ascending by char
  9}
 10
 11// childIndex returns the index of the child reached by byte c and whether such
 12// a child exists. When it does not exist, the returned index is the position at
 13// which a child with byte c must be inserted to keep children sorted.
 14func (n *node) childIndex(c byte) (int, bool) {
 15	lo := 0
 16	hi := len(n.children)
 17	for lo < hi {
 18		mid := (lo + hi) / 2
 19
 20		switch {
 21		case n.children[mid].char < c:
 22			lo = mid + 1
 23		case n.children[mid].char > c:
 24			hi = mid
 25		default:
 26			return mid, true
 27		}
 28	}
 29	return lo, false
 30}
 31
 32// get retrieves the value stored under key in the subtree rooted at n.
 33func (n *node) get(key string) (value any, exists bool) {
 34	cur := n
 35	for i := 0; i < len(key); i++ {
 36		idx, ok := cur.childIndex(key[i])
 37		if !ok {
 38			return nil, false
 39		}
 40
 41		cur = cur.children[idx]
 42	}
 43
 44	if !cur.isKey {
 45		return nil, false
 46	}
 47	return cur.value, true
 48}
 49
 50// set inserts or updates key with value. It returns true when the key already
 51// existed and its value updated, and false when it was newly inserted.
 52func (n *node) set(key string, value any) (updated bool) {
 53	cur := n
 54	for i := 0; i < len(key); i++ {
 55		c := key[i]
 56		idx, ok := cur.childIndex(c)
 57		if ok {
 58			cur = cur.children[idx]
 59			continue
 60		}
 61
 62		child := &node{char: c}
 63		cur.children = append(cur.children, nil)
 64		copy(cur.children[idx+1:], cur.children[idx:])
 65		cur.children[idx] = child
 66		cur = child
 67	}
 68
 69	if cur.isKey {
 70		cur.value = value
 71		return true
 72	}
 73
 74	cur.isKey = true
 75	cur.value = value
 76	return false
 77}
 78
 79// remove deletes key from the subtree rooted at n, pruning any nodes that no
 80// longer terminate a key and have no children. It returns the removed value and
 81// whether the key was found.
 82func (n *node) remove(key string) (value any, removed bool) {
 83	if key == "" {
 84		if !n.isKey {
 85			return nil, false
 86		}
 87
 88		value = n.value
 89		n.isKey = false
 90		n.value = nil
 91		return value, true
 92	}
 93
 94	idx, ok := n.childIndex(key[0])
 95	if !ok {
 96		return nil, false
 97	}
 98
 99	child := n.children[idx]
100	value, removed = child.remove(key[1:])
101	if removed && !child.isKey && len(child.children) == 0 {
102		n.children = append(n.children[:idx], n.children[idx+1:]...)
103	}
104	return value, removed
105}
106
107// inorder visits this node (when it terminates a key) and its whole subtree.
108// key is the full key spelled from the root to this node. When ascending is
109// true keys are produced in lexicographic order, otherwise in reverse. Because
110// a key always sorts before any key that extends it, the terminal value is
111// emitted before the children when ascending and after them when descending.
112// It returns true as soon as cb requests the walk to stop.
113func (n *node) inorder(key string, ascending bool, cb func(key string, value any) bool) (stop bool) {
114	if ascending {
115		if n.isKey && cb(key, n.value) {
116			return true
117		}
118
119		for _, c := range n.children {
120			if c.inorder(key+string([]byte{c.char}), ascending, cb) {
121				return true
122			}
123		}
124		return false
125	}
126
127	for i := len(n.children) - 1; i >= 0; i-- {
128		c := n.children[i]
129		if c.inorder(key+string([]byte{c.char}), ascending, cb) {
130			return true
131		}
132	}
133
134	if n.isKey && cb(key, n.value) {
135		return true
136	}
137	return false
138}