blob: 1ecaf831c785b3e94fe6d59dc844fc152c5af86d [file] [log] [blame]
William Kurkianea869482019-04-09 15:16:11 -04001package iradix
2
Abhilash S.L3b494632019-07-16 15:51:09 +05303import (
4 "bytes"
5)
William Kurkianea869482019-04-09 15:16:11 -04006
7// Iterator is used to iterate over a set of nodes
8// in pre-order
9type Iterator struct {
10 node *Node
11 stack []edges
12}
13
14// SeekPrefixWatch is used to seek the iterator to a given prefix
15// and returns the watch channel of the finest granularity
16func (i *Iterator) SeekPrefixWatch(prefix []byte) (watch <-chan struct{}) {
17 // Wipe the stack
18 i.stack = nil
19 n := i.node
20 watch = n.mutateCh
21 search := prefix
22 for {
23 // Check for key exhaution
24 if len(search) == 0 {
25 i.node = n
26 return
27 }
28
29 // Look for an edge
30 _, n = n.getEdge(search[0])
31 if n == nil {
32 i.node = nil
33 return
34 }
35
36 // Update to the finest granularity as the search makes progress
37 watch = n.mutateCh
38
39 // Consume the search prefix
40 if bytes.HasPrefix(search, n.prefix) {
41 search = search[len(n.prefix):]
42
43 } else if bytes.HasPrefix(n.prefix, search) {
44 i.node = n
45 return
46 } else {
47 i.node = nil
48 return
49 }
50 }
51}
52
53// SeekPrefix is used to seek the iterator to a given prefix
54func (i *Iterator) SeekPrefix(prefix []byte) {
55 i.SeekPrefixWatch(prefix)
56}
57
Abhilash S.L3b494632019-07-16 15:51:09 +053058func (i *Iterator) recurseMin(n *Node) *Node {
59 // Traverse to the minimum child
60 if n.leaf != nil {
61 return n
62 }
63 if len(n.edges) > 0 {
64 // Add all the other edges to the stack (the min node will be added as
65 // we recurse)
66 i.stack = append(i.stack, n.edges[1:])
67 return i.recurseMin(n.edges[0].node)
68 }
69 // Shouldn't be possible
70 return nil
71}
72
73// SeekLowerBound is used to seek the iterator to the smallest key that is
74// greater or equal to the given key. There is no watch variant as it's hard to
75// predict based on the radix structure which node(s) changes might affect the
76// result.
77func (i *Iterator) SeekLowerBound(key []byte) {
78 // Wipe the stack. Unlike Prefix iteration, we need to build the stack as we
79 // go because we need only a subset of edges of many nodes in the path to the
80 // leaf with the lower bound.
81 i.stack = []edges{}
82 n := i.node
83 search := key
84
85 found := func(n *Node) {
86 i.node = n
87 i.stack = append(i.stack, edges{edge{node: n}})
88 }
89
90 for {
91 // Compare current prefix with the search key's same-length prefix.
92 var prefixCmp int
93 if len(n.prefix) < len(search) {
94 prefixCmp = bytes.Compare(n.prefix, search[0:len(n.prefix)])
95 } else {
96 prefixCmp = bytes.Compare(n.prefix, search)
97 }
98
99 if prefixCmp > 0 {
100 // Prefix is larger, that means the lower bound is greater than the search
101 // and from now on we need to follow the minimum path to the smallest
102 // leaf under this subtree.
103 n = i.recurseMin(n)
104 if n != nil {
105 found(n)
106 }
107 return
108 }
109
110 if prefixCmp < 0 {
111 // Prefix is smaller than search prefix, that means there is no lower
112 // bound
113 i.node = nil
114 return
115 }
116
117 // Prefix is equal, we are still heading for an exact match. If this is a
118 // leaf we're done.
119 if n.leaf != nil {
120 if bytes.Compare(n.leaf.key, key) < 0 {
121 i.node = nil
122 return
123 }
124 found(n)
125 return
126 }
127
128 // Consume the search prefix
129 if len(n.prefix) > len(search) {
130 search = []byte{}
131 } else {
132 search = search[len(n.prefix):]
133 }
134
135 // Otherwise, take the lower bound next edge.
136 idx, lbNode := n.getLowerBoundEdge(search[0])
137 if lbNode == nil {
138 i.node = nil
139 return
140 }
141
142 // Create stack edges for the all strictly higher edges in this node.
143 if idx+1 < len(n.edges) {
144 i.stack = append(i.stack, n.edges[idx+1:])
145 }
146
147 i.node = lbNode
148 // Recurse
149 n = lbNode
150 }
151}
152
William Kurkianea869482019-04-09 15:16:11 -0400153// Next returns the next node in order
154func (i *Iterator) Next() ([]byte, interface{}, bool) {
155 // Initialize our stack if needed
156 if i.stack == nil && i.node != nil {
157 i.stack = []edges{
158 edges{
159 edge{node: i.node},
160 },
161 }
162 }
163
164 for len(i.stack) > 0 {
165 // Inspect the last element of the stack
166 n := len(i.stack)
167 last := i.stack[n-1]
168 elem := last[0].node
169
170 // Update the stack
171 if len(last) > 1 {
172 i.stack[n-1] = last[1:]
173 } else {
174 i.stack = i.stack[:n-1]
175 }
176
177 // Push the edges onto the frontier
178 if len(elem.edges) > 0 {
179 i.stack = append(i.stack, elem.edges)
180 }
181
182 // Return the leaf values if any
183 if elem.leaf != nil {
184 return elem.leaf.key, elem.leaf.val, true
185 }
186 }
187 return nil, nil, false
188}