github.com/m4gshm/gollections@v0.0.13-0.20240331203319-a34a86e58a24/map_/iter.go (about) 1 package map_ 2 3 import ( 4 "unsafe" 5 6 "github.com/m4gshm/gollections/c" 7 "github.com/m4gshm/gollections/kv/collection" 8 kvloop "github.com/m4gshm/gollections/kv/loop" 9 "github.com/m4gshm/gollections/loop" 10 "github.com/m4gshm/gollections/op" 11 ) 12 13 // NewIter returns the Iter based on map elements 14 func NewIter[K comparable, V any](elements map[K]V) Iter[K, V] { 15 hmap := *(*unsafe.Pointer)(unsafe.Pointer(&elements)) 16 i := any(elements) 17 maptype := *(*unsafe.Pointer)(unsafe.Pointer(&i)) 18 var iterator *hiter 19 if hmap != nil { 20 iterator = new(hiter) 21 } 22 return Iter[K, V]{maptype: maptype, hmap: hmap, size: len(elements), iterator: iterator} 23 } 24 25 // Iter is the embedded map based Iterator implementation 26 type Iter[K comparable, V any] struct { 27 iterator *hiter 28 maptype unsafe.Pointer 29 hmap unsafe.Pointer 30 size int 31 } 32 33 var _ collection.Iterator[int, any] = (*Iter[int, any])(nil) 34 35 // All is used to iterate through the iterator using `for ... range`. Supported since go 1.22 with GOEXPERIMENT=rangefunc enabled. 36 func (i *Iter[K, V]) All(consumer func(key K, value V) bool) { 37 kvloop.All(i.Next, consumer) 38 } 39 40 // Track takes key, value pairs retrieved by the iterator. Can be interrupt by returning Break 41 func (i *Iter[K, V]) Track(traker func(key K, value V) error) error { 42 return kvloop.Track(i.Next, traker) 43 } 44 45 // TrackEach takes all key, value pairs retrieved by the iterator 46 func (i *Iter[K, V]) TrackEach(traker func(key K, value V)) { 47 kvloop.TrackEach(i.Next, traker) 48 } 49 50 // Next returns the next element. 51 // The ok result indicates whether the element was returned by the iterator. 52 // If ok == false, then the iteration must be completed. 53 func (i *Iter[K, V]) Next() (key K, value V, ok bool) { 54 if i == nil { 55 return key, value, false 56 } 57 iterator := i.iterator 58 if iterator == nil { 59 return key, value, false 60 } 61 if !iterator.initialized() { 62 mapiterinit(i.maptype, i.hmap, iterator) 63 } else { 64 mapiternext(iterator) 65 } 66 iterkey := mapiterkey(iterator) 67 if iterkey == nil { 68 return key, value, false 69 } 70 iterelem := mapiterelem(iterator) 71 key = *(*K)(iterkey) 72 value = *(*V)(iterelem) 73 return key, value, true 74 } 75 76 // Size returns the size of the map 77 func (i *Iter[K, V]) Size() int { 78 if i == nil { 79 return 0 80 } 81 return i.size 82 } 83 84 //go:linkname mapiterinit reflect.mapiterinit 85 func mapiterinit(maptype, hmap unsafe.Pointer, it *hiter) 86 87 func mapiterkey(it *hiter) unsafe.Pointer { 88 return it.key 89 } 90 91 func mapiterelem(it *hiter) unsafe.Pointer { 92 return it.elem 93 } 94 95 //go:linkname mapiternext reflect.mapiternext 96 func mapiternext(it *hiter) 97 98 // hiter's structure matches runtime.hiter's structure 99 type hiter struct { 100 key unsafe.Pointer 101 elem unsafe.Pointer 102 t unsafe.Pointer 103 h unsafe.Pointer 104 buckets unsafe.Pointer 105 bptr unsafe.Pointer 106 overflow *[]unsafe.Pointer 107 oldoverflow *[]unsafe.Pointer 108 startBucket uintptr 109 offset uint8 110 wrapped bool 111 B uint8 112 i uint8 113 bucket uintptr 114 checkBucket uintptr 115 } 116 117 func (h *hiter) initialized() bool { 118 return h.t != nil 119 } 120 121 // NewKeyIter instantiates a map keys iterator 122 func NewKeyIter[K comparable, V any](uniques map[K]V) KeyIter[K, V] { 123 return KeyIter[K, V]{Iter: NewIter(uniques)} 124 } 125 126 // KeyIter is the Iterator implementation that provides iterating over keys of a key/value pairs iterator 127 type KeyIter[K comparable, V any] struct { 128 Iter[K, V] 129 } 130 131 var ( 132 _ c.Iterator[string] = (*KeyIter[string, any])(nil) 133 _ c.Iterator[string] = KeyIter[string, any]{} 134 ) 135 136 // All is used to iterate through the iterator using `for ... range`. Supported since go 1.22 with GOEXPERIMENT=rangefunc enabled. 137 func (i KeyIter[K, V]) All(consumer func(element K) bool) { 138 loop.All(i.Next, consumer) 139 } 140 141 // For takes elements retrieved by the iterator. Can be interrupt by returning Break 142 func (i KeyIter[K, V]) For(consumer func(element K) error) error { 143 return loop.For(i.Next, consumer) 144 } 145 146 // ForEach FlatIter all elements retrieved by the iterator 147 func (i KeyIter[K, V]) ForEach(consumer func(element K)) { 148 loop.ForEach(i.Next, consumer) 149 } 150 151 // Next returns the next element. 152 // The ok result indicates whether the element was returned by the iterator. 153 // If ok == false, then the iteration must be completed. 154 func (i KeyIter[K, V]) Next() (K, bool) { 155 key, _, ok := i.Iter.Next() 156 return key, ok 157 } 158 159 // Size returns the iterator capacity 160 func (i KeyIter[K, V]) Size() int { 161 return i.Iter.Size() 162 } 163 164 // NewValIter is the main values iterator constructor 165 func NewValIter[K comparable, V any](uniques map[K]V) ValIter[K, V] { 166 return ValIter[K, V]{Iter: NewIter(op.IfElse(uniques != nil, uniques, map[K]V{}))} 167 } 168 169 // ValIter is a map values iterator 170 type ValIter[K comparable, V any] struct { 171 Iter[K, V] 172 } 173 174 var ( 175 _ c.Iterator[any] = (*ValIter[int, any])(nil) 176 _ c.Iterator[any] = ValIter[int, any]{} 177 ) 178 179 // All is used to iterate through the iterator using `for ... range`. Supported since go 1.22 with GOEXPERIMENT=rangefunc enabled. 180 func (i ValIter[K, V]) All(consumer func(element V) bool) { 181 loop.All(i.Next, consumer) 182 } 183 184 // For takes elements retrieved by the iterator. Can be interrupt by returning Break 185 func (i ValIter[K, V]) For(consumer func(element V) error) error { 186 return loop.For(i.Next, consumer) 187 } 188 189 // ForEach FlatIter all elements retrieved by the iterator 190 func (i ValIter[K, V]) ForEach(consumer func(element V)) { 191 loop.ForEach(i.Next, consumer) 192 } 193 194 // Next returns the next element. 195 // The ok result indicates whether the element was returned by the iterator. 196 // If ok == false, then the iteration must be completed. 197 func (i ValIter[K, V]) Next() (V, bool) { 198 _, val, ok := i.Iter.Next() 199 return val, ok 200 } 201 202 // Size returns the size of the map 203 func (i ValIter[K, V]) Size() int { 204 return i.Iter.Size() 205 }