| 1 | package collect |
| 2 | |
| 3 | import ( |
| 4 | "reflect" |
| 5 | "slices" |
| 6 | ) |
| 7 | |
| 8 | // MapGenerator produces key-value pairs one at a time. It returns (key, value, true) |
| 9 | // for each pair and (zeroK, zeroV, false) when the sequence is exhausted. |
| 10 | type MapGenerator[K comparable, V any] func() (K, V, bool) |
| 11 | |
| 12 | // MapIterator is a lazy, pull-based iterator over key-value pairs. |
| 13 | // All intermediate operations (MapValues, MapEntries, Filter, Skip, Limit, etc.) return |
| 14 | // a new iterator; terminal operations (Apply, Collect) consume it. |
| 15 | type MapIterator[K comparable, V any] interface { |
| 16 | // MapValues returns an iterator that transforms values by applying f, keeping keys unchanged. |
| 17 | MapValues(f func(K, V) V) MapIterator[K, V] |
| 18 | // MapEntries returns an iterator that transforms both keys and values by applying f. |
| 19 | MapEntries(f func(K, V) (K, V)) MapIterator[K, V] |
| 20 | // Filter returns an iterator that yields only pairs satisfying pred. |
| 21 | Filter(pred func(K, V) bool) MapIterator[K, V] |
| 22 | // Unique returns an iterator that deduplicates pairs by the string key returned by fn. |
| 23 | Unique(fn func(K, V) string) MapIterator[K, V] |
| 24 | // MapValuesIndex returns an iterator that transforms values by applying f with a 0-based index. |
| 25 | MapValuesIndex(f func(int, K, V) V) MapIterator[K, V] |
| 26 | // MapEntriesIndex returns an iterator that transforms both keys and values by applying f with a 0-based index. |
| 27 | MapEntriesIndex(f func(int, K, V) (K, V)) MapIterator[K, V] |
| 28 | // FilterIndex returns an iterator that yields only pairs satisfying pred, which receives a 0-based index. |
| 29 | FilterIndex(pred func(int, K, V) bool) MapIterator[K, V] |
| 30 | // Apply exhausts the iterator, calling f for each key-value pair. |
| 31 | Apply(f func(K, V)) |
| 32 | // Collect collects all remaining pairs into a map. |
| 33 | Collect() map[K]V |
| 34 | // Materialize materializes all pairs into a map and returns a new iterator over it. |
| 35 | // If less is non-nil the keys are visited in sorted order; otherwise the order is unspecified. |
| 36 | Materialize(less func(K, K) bool) MapIterator[K, V] |
| 37 | // Skip returns an iterator that discards the first count pairs. |
| 38 | // Panics if count is negative. |
| 39 | Skip(count int) MapIterator[K, V] |
| 40 | // Limit returns an iterator that yields at most count elements. |
| 41 | // Panics if count is negative. |
| 42 | Limit(count int) MapIterator[K, V] |
| 43 | // Keys returns a ListIterator that yields the keys. |
| 44 | Keys() ListIterator[K] |
| 45 | // Values returns a ListIterator that yields the values. |
| 46 | Values() ListIterator[V] |
| 47 | } |
| 48 | |
| 49 | var _ MapIterator[int, any] = &mapIterator[int, any]{} |
| 50 | |
| 51 | type mapIterator[K comparable, V any] struct { |
| 52 | generator MapGenerator[K, V] |
| 53 | maxElements int |
| 54 | } |
| 55 | |
| 56 | // NewMapIterator creates a [MapIterator] backed by gen. maxElements is a hint |
| 57 | // for the expected upper bound of pairs (used for pre-allocation); pass -1 if unknown. |
| 58 | func NewMapIterator[K comparable, V any](gen MapGenerator[K, V], maxElements int) MapIterator[K, V] { |
| 59 | return &mapIterator[K, V]{generator: gen, maxElements: maxElements} |
| 60 | } |
| 61 | |
| 62 | // FromMap creates a [MapIterator] that yields the entries of inp. |
| 63 | // If less is non-nil the keys are visited in sorted order; otherwise the |
| 64 | // iteration order is unspecified (uses reflect.MapRange). |
| 65 | func FromMap[K comparable, V any](inp map[K]V, less func(K, K) bool) MapIterator[K, V] { |
| 66 | if less != nil { |
| 67 | keys := make([]K, 0, len(inp)) |
| 68 | for k := range inp { |
| 69 | keys = append(keys, k) |
| 70 | } |
| 71 | slices.SortFunc(keys, func(a, b K) int { |
| 72 | switch { |
| 73 | case less(a, b): |
| 74 | return -1 |
| 75 | case less(b, a): |
| 76 | return 1 |
| 77 | default: |
| 78 | return 0 |
| 79 | } |
| 80 | }) |
| 81 | pos := 0 |
| 82 | gen := func() (K, V, bool) { |
| 83 | if pos >= len(keys) { |
| 84 | var zeroK K |
| 85 | var zeroV V |
| 86 | return zeroK, zeroV, false |
| 87 | } |
| 88 | k := keys[pos] |
| 89 | pos++ |
| 90 | return k, inp[k], true |
| 91 | } |
| 92 | return &mapIterator[K, V]{generator: gen, maxElements: len(inp)} |
| 93 | } |
| 94 | |
| 95 | iter := reflect.ValueOf(inp).MapRange() |
| 96 | gen := func() (K, V, bool) { |
| 97 | if !iter.Next() { |
| 98 | var zeroK K |
| 99 | var zeroV V |
| 100 | return zeroK, zeroV, false |
| 101 | } |
| 102 | return iter.Key().Interface().(K), iter.Value().Interface().(V), true |
| 103 | } |
| 104 | return &mapIterator[K, V]{generator: gen, maxElements: len(inp)} |
| 105 | } |
| 106 | |
| 107 | func (m *mapIterator[K, V]) MapValues(f func(K, V) V) MapIterator[K, V] { |
| 108 | gen := m.generator |
| 109 | return &mapIterator[K, V]{ |
| 110 | generator: func() (K, V, bool) { |
| 111 | k, v, ok := gen() |
| 112 | if !ok { |
| 113 | return k, v, false |
| 114 | } |
| 115 | return k, f(k, v), true |
| 116 | }, |
| 117 | maxElements: m.maxElements, |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | func (m *mapIterator[K, V]) MapEntries(f func(K, V) (K, V)) MapIterator[K, V] { |
| 122 | gen := m.generator |
| 123 | return &mapIterator[K, V]{ |
| 124 | generator: func() (K, V, bool) { |
| 125 | k, v, ok := gen() |
| 126 | if !ok { |
| 127 | return k, v, false |
| 128 | } |
| 129 | nk, nv := f(k, v) |
| 130 | return nk, nv, true |
| 131 | }, |
| 132 | maxElements: m.maxElements, |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | func (m *mapIterator[K, V]) Filter(pred func(K, V) bool) MapIterator[K, V] { |
| 137 | gen := m.generator |
| 138 | return &mapIterator[K, V]{ |
| 139 | generator: func() (K, V, bool) { |
| 140 | for { |
| 141 | k, v, ok := gen() |
| 142 | if !ok { |
| 143 | return k, v, false |
| 144 | } |
| 145 | if pred(k, v) { |
| 146 | return k, v, true |
| 147 | } |
| 148 | } |
| 149 | }, |
| 150 | maxElements: m.maxElements, |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | func (m *mapIterator[K, V]) Unique(fn func(K, V) string) MapIterator[K, V] { |
| 155 | gen := m.generator |
| 156 | sz := max(m.maxElements, 0) |
| 157 | seen := make(map[string]struct{}, sz) |
| 158 | return &mapIterator[K, V]{ |
| 159 | generator: func() (K, V, bool) { |
| 160 | for { |
| 161 | k, v, ok := gen() |
| 162 | if !ok { |
| 163 | return k, v, false |
| 164 | } |
| 165 | key := fn(k, v) |
| 166 | if _, exists := seen[key]; exists { |
| 167 | continue |
| 168 | } |
| 169 | seen[key] = struct{}{} |
| 170 | return k, v, true |
| 171 | } |
| 172 | }, |
| 173 | maxElements: m.maxElements, |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | func (m *mapIterator[K, V]) MapValuesIndex(f func(int, K, V) V) MapIterator[K, V] { |
| 178 | gen := m.generator |
| 179 | pos := 0 |
| 180 | return &mapIterator[K, V]{ |
| 181 | generator: func() (K, V, bool) { |
| 182 | k, v, ok := gen() |
| 183 | if !ok { |
| 184 | return k, v, false |
| 185 | } |
| 186 | nv := f(pos, k, v) |
| 187 | pos++ |
| 188 | return k, nv, true |
| 189 | }, |
| 190 | maxElements: m.maxElements, |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | func (m *mapIterator[K, V]) MapEntriesIndex(f func(int, K, V) (K, V)) MapIterator[K, V] { |
| 195 | gen := m.generator |
| 196 | pos := 0 |
| 197 | return &mapIterator[K, V]{ |
| 198 | generator: func() (K, V, bool) { |
| 199 | k, v, ok := gen() |
| 200 | if !ok { |
| 201 | return k, v, false |
| 202 | } |
| 203 | nk, nv := f(pos, k, v) |
| 204 | pos++ |
| 205 | return nk, nv, true |
| 206 | }, |
| 207 | maxElements: m.maxElements, |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | func (m *mapIterator[K, V]) FilterIndex(pred func(int, K, V) bool) MapIterator[K, V] { |
| 212 | gen := m.generator |
| 213 | pos := 0 |
| 214 | return &mapIterator[K, V]{ |
| 215 | generator: func() (K, V, bool) { |
| 216 | for { |
| 217 | k, v, ok := gen() |
| 218 | if !ok { |
| 219 | return k, v, false |
| 220 | } |
| 221 | idx := pos |
| 222 | pos++ |
| 223 | if pred(idx, k, v) { |
| 224 | return k, v, true |
| 225 | } |
| 226 | } |
| 227 | }, |
| 228 | maxElements: m.maxElements, |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | func (m *mapIterator[K, V]) Apply(f func(K, V)) { |
| 233 | for { |
| 234 | k, v, ok := m.generator() |
| 235 | if !ok { |
| 236 | return |
| 237 | } |
| 238 | f(k, v) |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | func (m *mapIterator[K, V]) Collect() map[K]V { |
| 243 | sz := max(m.maxElements, 0) |
| 244 | rv := make(map[K]V, sz) |
| 245 | for { |
| 246 | k, v, ok := m.generator() |
| 247 | if !ok { |
| 248 | break |
| 249 | } |
| 250 | rv[k] = v |
| 251 | } |
| 252 | return rv |
| 253 | } |
| 254 | |
| 255 | func (m *mapIterator[K, V]) Materialize(less func(K, K) bool) MapIterator[K, V] { |
| 256 | return FromMap(m.Collect(), less) |
| 257 | } |
| 258 | |
| 259 | func (m *mapIterator[K, V]) Skip(count int) MapIterator[K, V] { |
| 260 | if count < 0 { |
| 261 | panic("collect: Skip count must be non-negative") |
| 262 | } |
| 263 | gen := m.generator |
| 264 | skipped := false |
| 265 | return &mapIterator[K, V]{ |
| 266 | generator: func() (K, V, bool) { |
| 267 | if !skipped { |
| 268 | skipped = true |
| 269 | for range count { |
| 270 | if _, _, ok := gen(); !ok { |
| 271 | var zeroK K |
| 272 | var zeroV V |
| 273 | return zeroK, zeroV, false |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | return gen() |
| 278 | }, |
| 279 | maxElements: max(m.maxElements-count, 0), |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | func (m *mapIterator[K, V]) Limit(count int) MapIterator[K, V] { |
| 284 | if count < 0 { |
| 285 | panic("collect: Limit count must be non-negative") |
| 286 | } |
| 287 | gen := m.generator |
| 288 | remaining := count |
| 289 | return &mapIterator[K, V]{ |
| 290 | generator: func() (K, V, bool) { |
| 291 | if remaining <= 0 { |
| 292 | var zeroK K |
| 293 | var zeroV V |
| 294 | return zeroK, zeroV, false |
| 295 | } |
| 296 | remaining-- |
| 297 | return gen() |
| 298 | }, |
| 299 | maxElements: min(m.maxElements, count), |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | func (m *mapIterator[K, V]) Keys() ListIterator[K] { |
| 304 | gen := m.generator |
| 305 | return &listIterator[K]{ |
| 306 | generator: func() (K, bool) { |
| 307 | k, _, ok := gen() |
| 308 | return k, ok |
| 309 | }, |
| 310 | maxElements: m.maxElements, |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | func (m *mapIterator[K, V]) Values() ListIterator[V] { |
| 315 | gen := m.generator |
| 316 | return &listIterator[V]{ |
| 317 | generator: func() (V, bool) { |
| 318 | _, v, ok := gen() |
| 319 | return v, ok |
| 320 | }, |
| 321 | maxElements: m.maxElements, |
| 322 | } |
| 323 | } |
| 324 | |