github.com/cilium/statedb@v0.3.2/part/iterator.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package part 5 6 import ( 7 "bytes" 8 "slices" 9 "sort" 10 ) 11 12 // Iterator for key and value pairs where value is of type T 13 type Iterator[T any] struct { 14 next [][]*header[T] // sets of edges to explore 15 } 16 17 // Clone returns a copy of the iterator, allowing restarting 18 // the iterator from scratch. 19 func (it *Iterator[T]) Clone() *Iterator[T] { 20 // Since the iterator does not mutate the edge array elements themselves ([]*header[T]) 21 // it is enough to do a shallow clone here. 22 return &Iterator[T]{slices.Clone(it.next)} 23 } 24 25 // Next returns the next key, value and true if the value exists, 26 // otherwise it returns false. 27 func (it *Iterator[T]) Next() (key []byte, value T, ok bool) { 28 for len(it.next) > 0 { 29 // Pop the next set of edges to explore 30 edges := it.next[len(it.next)-1] 31 for len(edges) > 0 && edges[0] == nil { 32 // Node256 may have nil children, so jump over them. 33 edges = edges[1:] 34 } 35 it.next = it.next[:len(it.next)-1] 36 37 if len(edges) == 0 { 38 continue 39 } else if len(edges) > 1 { 40 // More edges remain to be explored, add them back. 41 it.next = append(it.next, edges[1:]) 42 } 43 44 // Follow the smallest edge and add its children to the queue. 45 node := edges[0] 46 47 if node.size() > 0 { 48 it.next = append(it.next, node.children()) 49 } 50 if leaf := node.getLeaf(); leaf != nil { 51 key = leaf.key 52 value = leaf.value 53 ok = true 54 return 55 } 56 } 57 return 58 } 59 60 func newIterator[T any](start *header[T]) *Iterator[T] { 61 if start == nil { 62 return &Iterator[T]{nil} 63 } 64 return &Iterator[T]{[][]*header[T]{{start}}} 65 } 66 67 func prefixSearch[T any](root *header[T], key []byte) (*Iterator[T], <-chan struct{}) { 68 this := root 69 var watch <-chan struct{} 70 for { 71 if !this.isLeaf() && this.watch != nil { 72 // Leaf watch channels only close when the leaf is manipulated, 73 // thus we only return non-leaf watch channels. 74 watch = this.watch 75 } 76 77 switch { 78 case bytes.Equal(key, this.prefix[:min(len(key), len(this.prefix))]): 79 return newIterator(this), watch 80 81 case bytes.HasPrefix(key, this.prefix): 82 key = key[len(this.prefix):] 83 if len(key) == 0 { 84 return newIterator(this), this.watch 85 } 86 87 default: 88 return newIterator[T](nil), root.watch 89 } 90 91 this = this.find(key[0]) 92 if this == nil { 93 return newIterator[T](nil), root.watch 94 } 95 } 96 } 97 98 func traverseToMin[T any](n *header[T], edges [][]*header[T]) [][]*header[T] { 99 if leaf := n.getLeaf(); leaf != nil { 100 return append(edges, []*header[T]{n}) 101 } 102 children := n.children() 103 104 // Find the first non-nil child 105 for len(children) > 0 && children[0] == nil { 106 children = children[1:] 107 } 108 109 if len(children) > 0 { 110 // Add the larger children. 111 if len(children) > 1 { 112 edges = append(edges, children[1:]) 113 } 114 // Recurse into the smallest child 115 return traverseToMin(children[0], edges) 116 } 117 return edges 118 } 119 120 func lowerbound[T any](start *header[T], key []byte) *Iterator[T] { 121 // The starting edges to explore. This contains all larger nodes encountered 122 // on the path to the node larger or equal to the key. 123 edges := [][]*header[T]{} 124 this := start 125 loop: 126 for { 127 switch bytes.Compare(this.prefix, key[:min(len(key), len(this.prefix))]) { 128 case -1: 129 // Prefix is smaller, stop here and return an iterator for 130 // the larger nodes in the parent's. 131 break loop 132 133 case 0: 134 if len(this.prefix) == len(key) { 135 // Exact match. 136 edges = append(edges, []*header[T]{this}) 137 break loop 138 } 139 140 // Prefix matches the beginning of the key, but more 141 // remains of the key. Drop the matching part and keep 142 // going further. 143 key = key[len(this.prefix):] 144 145 if this.kind() == nodeKind256 { 146 children := this.node256().children[:] 147 idx := int(key[0]) 148 this = children[idx] 149 150 // Add all larger children and recurse further. 151 children = children[idx+1:] 152 for len(children) > 0 && children[0] == nil { 153 children = children[1:] 154 } 155 edges = append(edges, children) 156 157 if this == nil { 158 break loop 159 } 160 } else { 161 children := this.children() 162 163 // Find the smallest child that is equal or larger than the lower bound 164 idx := sort.Search(len(children), func(i int) bool { 165 return children[i].prefix[0] >= key[0] 166 }) 167 if idx >= this.size() { 168 break loop 169 } 170 // Add all larger children and recurse further. 171 if len(children) > idx+1 { 172 edges = append(edges, children[idx+1:]) 173 } 174 this = children[idx] 175 } 176 177 case 1: 178 // Prefix bigger than lowerbound, go to smallest node and stop. 179 edges = traverseToMin(this, edges) 180 break loop 181 } 182 } 183 184 if len(edges) > 0 { 185 return &Iterator[T]{edges} 186 } 187 return &Iterator[T]{nil} 188 }