github.com/m4gshm/gollections@v0.0.13-0.20240331203319-a34a86e58a24/break/loop/api.go (about) 1 // Package loop provides helpers for loop operation and iterator implementations 2 package loop 3 4 import ( 5 "errors" 6 "unsafe" 7 8 breakkvloop "github.com/m4gshm/gollections/break/kv/loop" 9 "github.com/m4gshm/gollections/break/predicate/always" 10 "github.com/m4gshm/gollections/c" 11 "github.com/m4gshm/gollections/convert" 12 "github.com/m4gshm/gollections/convert/as" 13 "github.com/m4gshm/gollections/map_/resolv" 14 "github.com/m4gshm/gollections/notsafe" 15 "github.com/m4gshm/gollections/op" 16 "github.com/m4gshm/gollections/op/check/not" 17 ) 18 19 // Break is the 'break' statement of the For, Track methods. 20 var Break = c.Break 21 22 // S wrap the elements by loop function. 23 func S[TS ~[]T, T any](elements TS) Loop[T] { 24 return Of(elements...) 25 } 26 27 // Of wrap the elements by loop function. 28 func Of[T any](elements ...T) func() (e T, ok bool, err error) { 29 l := len(elements) 30 i := 0 31 if l == 0 || i < 0 || i >= l { 32 return func() (e T, ok bool, err error) { return e, false, nil } 33 } 34 return func() (e T, ok bool, err error) { 35 if i < l { 36 e, ok = elements[i], true 37 i++ 38 } 39 return e, ok, nil 40 } 41 } 42 43 // New is the main breakable loop constructor 44 func New[S, T any](source S, hasNext func(S) bool, getNext func(S) (T, error)) Loop[T] { 45 return func() (out T, ok bool, err error) { 46 if ok := hasNext(source); !ok { 47 return out, false, nil 48 } 49 out, err = getNext(source) 50 return out, err == nil, err 51 } 52 } 53 54 // From wrap the next loop to a breakable loop 55 func From[T any](next func() (T, bool)) Loop[T] { 56 if next == nil { 57 return nil 58 } 59 return func() (T, bool, error) { 60 e, ok := next() 61 return e, ok, nil 62 } 63 } 64 65 // To transforms a breakable loop to a simple loop. 66 // The errConsumer is a function that is called when an error occurs. 67 func To[T any](next func() (T, bool, error), errConsumer func(error)) func() (T, bool) { 68 if next == nil { 69 return nil 70 } 71 return func() (T, bool) { 72 e, ok, err := next() 73 if err != nil { 74 errConsumer(err) 75 return e, false 76 } 77 return e, ok 78 } 79 } 80 81 // All is an adapter for the next function for iterating by `for ... range`. Supported since go 1.22 with GOEXPERIMENT=rangefunc enabled. 82 func All[T any](next func() (T, bool, error), consumer func(T, error) bool) { 83 if next == nil { 84 return 85 } 86 for { 87 v, ok, err := next() 88 if !ok { 89 if err != nil { 90 consumer(v, err) 91 } 92 break 93 } else { 94 consumer(v, err) 95 } 96 } 97 } 98 99 // For applies the 'consumer' function for the elements retrieved by the 'next' function until the consumer returns the c.Break to stop. 100 func For[T any](next func() (T, bool, error), consumer func(T) error) error { 101 if next == nil { 102 return nil 103 } 104 for { 105 if v, ok, err := next(); err != nil || !ok { 106 return err 107 } else if err := consumer(v); err != nil { 108 return brk(err) 109 } 110 } 111 } 112 113 // ForFiltered applies the 'consumer' function to the elements retrieved by the 'next' function that satisfy the 'predicate' function condition 114 func ForFiltered[T any](next func() (T, bool, error), consumer func(T) error, predicate func(T) bool) error { 115 if next == nil { 116 return nil 117 } 118 for { 119 if v, ok, err := next(); err != nil || !ok { 120 return err 121 } else if ok := predicate(v); ok { 122 if err := consumer(v); err != nil { 123 return brk(err) 124 } 125 } 126 } 127 } 128 129 // First returns the first element that satisfies the condition of the 'predicate' function 130 func First[T any](next func() (T, bool, error), predicate func(T) bool) (out T, ok bool, err error) { 131 if next == nil { 132 return out, false, nil 133 } 134 for { 135 if out, ok, err = next(); err != nil || !ok { 136 return out, false, err 137 } else if ok := predicate(out); ok { 138 return out, true, nil 139 } 140 } 141 } 142 143 // Firstt returns the first element that satisfies the condition of the 'predicate' function 144 func Firstt[T any](next func() (T, bool, error), predicate func(T) (bool, error)) (out T, ok bool, err error) { 145 if next == nil { 146 return out, false, nil 147 } 148 for { 149 if out, ok, err := next(); err != nil || !ok { 150 return out, false, err 151 } else if ok, err := predicate(out); err != nil || ok { 152 return out, ok, err 153 } 154 } 155 } 156 157 // Track applies the 'consumer' function to position/element pairs retrieved by the 'next' function until the consumer returns the c.Break to stop. 158 func Track[I, T any](next func() (I, T, bool, error), consumer func(I, T) error) error { 159 return breakkvloop.Track(next, consumer) 160 } 161 162 // Slice collects the elements retrieved by the 'next' function into a slice 163 func Slice[T any](next func() (T, bool, error)) (out []T, err error) { 164 if next == nil { 165 return nil, nil 166 } 167 for { 168 v, ok, err := next() 169 if ok { 170 out = append(out, v) 171 } 172 if !ok || err != nil { 173 return out, err 174 } 175 } 176 } 177 178 // SliceCap collects the elements retrieved by the 'next' function into a new slice with predefined capacity 179 func SliceCap[T any](next func() (T, bool, error), cap int) (out []T, err error) { 180 if next == nil { 181 return nil, nil 182 } 183 if cap > 0 { 184 out = make([]T, 0, cap) 185 } 186 return Append(next, out) 187 } 188 189 // Append collects the elements retrieved by the 'next' function into the specified 'out' slice 190 func Append[T any, TS ~[]T](next func() (T, bool, error), out TS) (TS, error) { 191 if next == nil { 192 return out, nil 193 } 194 for v, ok, err := next(); ok; v, ok, err = next() { 195 if err != nil { 196 return out, err 197 } 198 out = append(out, v) 199 } 200 return out, nil 201 } 202 203 // Reduce reduces the elements retrieved by the 'next' function into an one using the 'merge' function. 204 func Reduce[T any](next func() (T, bool, error), merger func(T, T) T) (out T, e error) { 205 if next == nil { 206 return out, nil 207 } 208 v, ok, err := next() 209 if err != nil || !ok { 210 return out, err 211 } 212 out = v 213 for { 214 v, ok, err := next() 215 if err != nil || !ok { 216 return out, err 217 } 218 out = merger(out, v) 219 } 220 } 221 222 // Reducee reduces the elements retrieved by the 'next' function into an one using the 'merge' function 223 func Reducee[T any](next func() (T, bool, error), merger func(T, T) (T, error)) (out T, e error) { 224 if next == nil { 225 return out, nil 226 } 227 v, ok, err := next() 228 if err != nil || !ok { 229 return out, err 230 } 231 out = v 232 for { 233 if v, ok, err := next(); err != nil || !ok { 234 return out, err 235 } else if out, err = merger(out, v); err != nil { 236 return out, err 237 } 238 } 239 } 240 241 // Sum returns the sum of all elements 242 func Sum[T c.Summable](next func() (T, bool, error)) (T, error) { 243 return Reduce(next, op.Sum[T]) 244 } 245 246 // HasAny finds the first element that satisfies the 'predicate' function condition and returns true if successful 247 func HasAny[T any](next func() (T, bool, error), predicate func(T) bool) (bool, error) { 248 _, ok, err := First(next, predicate) 249 return ok, err 250 } 251 252 // HasAnyy finds the first element that satisfies the 'predicate' function condition and returns true if successful 253 func HasAnyy[T any](next func() (T, bool, error), predicate func(T) (bool, error)) (bool, error) { 254 _, ok, err := Firstt(next, predicate) 255 return ok, err 256 } 257 258 // Contains finds the first element that equal to the example and returns true 259 func Contains[T comparable](next func() (T, bool, error), example T) (bool, error) { 260 if next == nil { 261 return false, nil 262 } 263 for { 264 if one, ok, err := next(); err != nil || !ok { 265 return false, err 266 } else if one == example { 267 return true, nil 268 } 269 } 270 } 271 272 // Conv creates a loop that applies the 'converter' function to iterable elements. 273 func Conv[From, To any](next func() (From, bool, error), converter func(From) (To, error)) Loop[To] { 274 if next == nil { 275 return nil 276 } 277 return func() (t To, ok bool, err error) { 278 v, ok, err := next() 279 if err != nil || !ok { 280 return t, ok, err 281 } 282 vc, err := converter(v) 283 return vc, err == nil, err 284 } 285 } 286 287 // Convert creates a loop that applies the 'converter' function to iterable elements. 288 func Convert[From, To any](next func() (From, bool, error), converter func(From) To) Loop[To] { 289 if next == nil { 290 return nil 291 } 292 return func() (t To, ok bool, err error) { 293 if v, ok, err := next(); err != nil || !ok { 294 return t, ok, err 295 } else { 296 return converter(v), true, nil 297 } 298 } 299 } 300 301 // ConvCheck is similar to ConvertFilt, but it checks and transforms elements together 302 func ConvCheck[From, To any](next func() (From, bool, error), converter func(from From) (To, bool, error)) Loop[To] { 303 if next == nil { 304 return nil 305 } 306 return func() (t To, ok bool, err error) { 307 for { 308 if v, ok, err := next(); err != nil || !ok { 309 return t, false, err 310 } else if vc, ok, err := converter(v); err != nil || ok { 311 return vc, ok, err 312 } 313 } 314 } 315 } 316 317 // ConvertCheck is similar to ConvFilt, but it checks and transforms elements together 318 func ConvertCheck[From, To any](next func() (From, bool, error), converter func(from From) (To, bool)) Loop[To] { 319 if next == nil { 320 return nil 321 } 322 return func() (t To, ok bool, err error) { 323 for { 324 if e, ok, err := next(); err != nil || !ok { 325 return t, false, err 326 } else if t, ok := converter(e); ok { 327 return t, ok, err 328 } 329 } 330 } 331 } 332 333 // FiltAndConv creates a loop that filters source elements and converts them 334 func FiltAndConv[From, To any](next func() (From, bool, error), filter func(From) (bool, error), converter func(From) (To, error)) Loop[To] { 335 return FilterConvertFilter(next, filter, converter, always.True[To]) 336 } 337 338 // FilterAndConvert creates a loop that filters source elements and converts them 339 func FilterAndConvert[From, To any](next func() (From, bool, error), filter func(From) bool, converter func(From) To) Loop[To] { 340 return FilterConvertFilter(next, func(f From) (bool, error) { return filter(f), nil }, func(f From) (To, error) { return converter(f), nil }, always.True[To]) 341 } 342 343 // FilterConvertFilter filters source, converts, and filters converted elements 344 func FilterConvertFilter[From, To any](next func() (From, bool, error), filter func(From) (bool, error), converter func(From) (To, error), filterTo func(To) (bool, error)) Loop[To] { 345 if next == nil { 346 return nil 347 } 348 return func() (t To, ok bool, err error) { 349 for { 350 if f, ok, err := Firstt(next, filter); err != nil || !ok { 351 return t, false, err 352 } else if cf, err := converter(f); err != nil { 353 return t, false, err 354 } else if ok, err := filterTo(cf); err != nil || !ok { 355 return t, false, err 356 } else { 357 return cf, true, nil 358 } 359 } 360 } 361 } 362 363 // ConvertAndFilter additionally filters 'To' elements 364 func ConvertAndFilter[From, To any](next func() (From, bool, error), converter func(From) (To, error), filter func(To) (bool, error)) Loop[To] { 365 return FilterConvertFilter(next, always.True[From], converter, filter) 366 } 367 368 // Flatt creates a loop that extracts slices of 'To' by the 'flattener' function from iterable elements of 'From' and flattens as one iterable collection of 'To' elements. 369 func Flatt[From, To any](next func() (From, bool, error), flattener func(From) ([]To, error)) Loop[To] { 370 if next == nil { 371 return nil 372 } 373 var ( 374 elemSizeTo uintptr = notsafe.GetTypeSize[To]() 375 arrayTo unsafe.Pointer 376 indexTo, sizeTo int 377 ) 378 return func() (t To, ok bool, err error) { 379 if sizeTo > 0 { 380 if indexTo < sizeTo { 381 indexTo++ 382 return *(*To)(notsafe.GetArrayElemRef(arrayTo, indexTo, elemSizeTo)), true, nil 383 } 384 indexTo = 0 385 arrayTo = nil 386 sizeTo = 0 387 } 388 for { 389 if v, ok, err := next(); err != nil || !ok { 390 return t, ok, err 391 } else if elementsTo, err := flattener(v); err != nil { 392 return t, false, err 393 } else if len(elementsTo) > 0 { 394 indexTo = 1 395 header := notsafe.GetSliceHeaderByRef(unsafe.Pointer(&elementsTo)) 396 arrayTo = unsafe.Pointer(header.Data) 397 sizeTo = header.Len 398 return *(*To)(notsafe.GetArrayElemRef(arrayTo, 0, elemSizeTo)), true, nil 399 } 400 } 401 } 402 } 403 404 // Flat creates a loop that extracts slices of 'To' by the 'flattener' function from iterable elements of 'From' and flattens as one iterable collection of 'To' elements. 405 func Flat[From, To any](next func() (From, bool, error), flattener func(From) []To) Loop[To] { 406 if next == nil { 407 return nil 408 } 409 var ( 410 elemSizeTo uintptr = notsafe.GetTypeSize[To]() 411 arrayTo unsafe.Pointer 412 indexTo, sizeTo int 413 ) 414 return func() (t To, ok bool, err error) { 415 if sizeTo > 0 { 416 if indexTo < sizeTo { 417 i := indexTo 418 indexTo++ 419 return *(*To)(notsafe.GetArrayElemRef(arrayTo, i, elemSizeTo)), true, nil 420 } 421 indexTo = 0 422 arrayTo = nil 423 sizeTo = 0 424 } 425 for { 426 if v, ok, err := next(); err != nil { 427 return t, false, err 428 } else if !ok { 429 return t, false, nil 430 } else if elementsTo := flattener(v); len(elementsTo) > 0 { 431 indexTo = 1 432 header := notsafe.GetSliceHeaderByRef(unsafe.Pointer(&elementsTo)) 433 arrayTo = unsafe.Pointer(header.Data) 434 sizeTo = header.Len 435 return *(*To)(notsafe.GetArrayElemRef(arrayTo, 0, elemSizeTo)), true, nil 436 } 437 } 438 } 439 } 440 441 // FiltAndFlat filters source elements and extracts slices of 'To' by the 'flattener' function 442 func FiltAndFlat[From, To any](next func() (From, bool, error), filter func(From) (bool, error), flattener func(From) ([]To, error)) Loop[To] { 443 return FiltFlattFilt(next, filter, flattener, always.True[To]) 444 } 445 446 // FilterAndFlat filters source elements and extracts slices of 'To' by the 'flattener' function 447 func FilterAndFlat[From, To any](next func() (From, bool, error), filter func(From) bool, flattener func(From) []To) Loop[To] { 448 return FiltFlattFilt(next, func(f From) (bool, error) { return filter(f), nil }, func(f From) ([]To, error) { return flattener(f), nil }, always.True[To]) 449 } 450 451 // FlatAndFilt extracts slices of 'To' by the 'flattener' function and filters extracted elements 452 func FlatAndFilt[From, To any](next func() (From, bool, error), flattener func(From) ([]To, error), filterTo func(To) (bool, error)) Loop[To] { 453 return FiltFlattFilt(next, always.True[From], flattener, filterTo) 454 } 455 456 // FlattAndFilter extracts slices of 'To' by the 'flattener' function and filters extracted elements 457 func FlattAndFilter[From, To any](next func() (From, bool, error), flattener func(From) []To, filterTo func(To) bool) Loop[To] { 458 return FiltFlattFilt(next, always.True[From], func(f From) ([]To, error) { return flattener(f), nil }, func(t To) (bool, error) { return filterTo(t), nil }) 459 } 460 461 // FiltFlattFilt filters source elements, extracts slices of 'To' by the 'flattener' function and filters extracted elements 462 func FiltFlattFilt[From, To any](next func() (From, bool, error), filterFrom func(From) (bool, error), flattener func(From) ([]To, error), filterTo func(To) (bool, error)) Loop[To] { 463 if next == nil { 464 return nil 465 } 466 var ( 467 elemSizeTo uintptr = notsafe.GetTypeSize[To]() 468 arrayTo unsafe.Pointer 469 indexTo, sizeTo int 470 ) 471 return func() (t To, ok bool, err error) { 472 for { 473 if sizeTo > 0 { 474 if indexTo < sizeTo { 475 i := indexTo 476 indexTo++ 477 t = *(*To)(notsafe.GetArrayElemRef(arrayTo, i, elemSizeTo)) 478 if ok, err := filterTo(t); err != nil { 479 return t, false, err 480 } else if ok { 481 return t, true, nil 482 } 483 } 484 indexTo = 0 485 arrayTo = nil 486 sizeTo = 0 487 } 488 489 if v, ok, err := next(); err != nil || !ok { 490 return t, false, err 491 } else if ok, err := filterFrom(v); err != nil { 492 return t, false, err 493 } else if ok { 494 if elementsTo, err := flattener(v); err != nil { 495 return t, false, err 496 } else if len(elementsTo) > 0 { 497 indexTo = 1 498 header := notsafe.GetSliceHeaderByRef(unsafe.Pointer(&elementsTo)) 499 arrayTo = unsafe.Pointer(header.Data) 500 sizeTo = header.Len 501 t = *(*To)(notsafe.GetArrayElemRef(arrayTo, 0, elemSizeTo)) 502 if ok, err := filterTo(t); err != nil || ok { 503 return t, ok, err 504 } 505 } 506 } 507 } 508 } 509 // return &FlattFiltIter[From, To]{next: next, filterFrom: filterFrom, flattener: flattener, filterTo: filterTo, elemSizeTo: notsafe.GetTypeSize[To]()} 510 } 511 512 // FilterFlatFilter filters source elements, extracts slices of 'To' by the 'flattener' function and filters extracted elements 513 func FilterFlatFilter[From, To any](next func() (From, bool, error), filterFrom func(From) bool, flattener func(From) []To, filterTo func(To) bool) Loop[To] { 514 if next == nil { 515 return nil 516 } 517 var ( 518 elemSizeTo uintptr = notsafe.GetTypeSize[To]() 519 arrayTo unsafe.Pointer 520 indexTo, sizeTo int 521 ) 522 return func() (t To, ok bool, err error) { 523 for { 524 if sizeTo > 0 { 525 if indexTo < sizeTo { 526 i := indexTo 527 indexTo++ 528 tv := *(*To)(notsafe.GetArrayElemRef(arrayTo, i, elemSizeTo)) 529 if ok := filterTo(tv); ok { 530 return tv, true, nil 531 } 532 } 533 indexTo = 0 534 arrayTo = nil 535 sizeTo = 0 536 } 537 538 if fv, ok, err := next(); err != nil || !ok { 539 return t, false, err 540 } else if ok := filterFrom(fv); ok { 541 if elementsTo := flattener(fv); len(elementsTo) > 0 { 542 indexTo = 1 543 header := notsafe.GetSliceHeaderByRef(unsafe.Pointer(&elementsTo)) 544 arrayTo = unsafe.Pointer(header.Data) 545 sizeTo = header.Len 546 tv := *(*To)(notsafe.GetArrayElemRef(arrayTo, 0, elemSizeTo)) 547 if ok := filterTo(tv); ok { 548 return tv, true, nil 549 } 550 } 551 } 552 } 553 } 554 } 555 556 // Filt creates a loop that checks elements by the 'filter' function and returns successful ones. 557 func Filt[T any](next func() (T, bool, error), filter func(T) (bool, error)) Loop[T] { 558 if next == nil { 559 return nil 560 } 561 return func() (T, bool, error) { 562 return Firstt(next, filter) 563 } 564 } 565 566 // Filter creates a loop that checks elements by the 'filter' function and returns successful ones. 567 func Filter[T any](next func() (T, bool, error), filter func(T) bool) Loop[T] { 568 if next == nil { 569 return nil 570 } 571 return func() (T, bool, error) { 572 return First(next, filter) 573 } 574 } 575 576 // NotNil creates a loop that filters nullable elements. 577 func NotNil[T any](next func() (*T, bool, error)) Loop[*T] { 578 return Filt(next, as.ErrTail(not.Nil[T])) 579 } 580 581 // PtrVal creates a loop that transform pointers to the values referenced by those pointers. 582 // Nil pointers are transformet to zero values. 583 func PtrVal[T any](next func() (*T, bool, error)) Loop[T] { 584 return Convert(next, convert.PtrVal[T]) 585 } 586 587 // NoNilPtrVal creates a loop that transform only not nil pointers to the values referenced referenced by those pointers. 588 // Nil pointers are ignored. 589 func NoNilPtrVal[T any](next func() (*T, bool, error)) Loop[T] { 590 return ConvertCheck(next, convert.NoNilPtrVal[T]) 591 } 592 593 // KeyValue transforms a loop to the key/value loop based on applying key, value extractors to the elements 594 func KeyValue[T any, K, V any](next func() (T, bool, error), keyExtractor func(T) K, valExtractor func(T) V) breakkvloop.Loop[K, V] { 595 return KeyValuee(next, as.ErrTail(keyExtractor), as.ErrTail(valExtractor)) 596 } 597 598 // KeyValuee transforms a loop to the key/value loop based on applying key, value extractors to the elements 599 func KeyValuee[T any, K, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) breakkvloop.Loop[K, V] { 600 if next == nil { 601 return nil 602 } 603 return func() (key K, value V, ok bool, err error) { 604 if elem, nextOk, err := next(); err != nil || !nextOk { 605 return key, value, false, err 606 } else if key, err = keyExtractor(elem); err == nil { 607 value, err = valExtractor(elem) 608 return key, value, err == nil, err 609 } 610 return key, value, false, nil 611 } 612 } 613 614 // KeysValues transforms a loop to the key/value loop based on applying multiple keys, values extractor to the elements 615 func KeysValues[T, K, V any](next func() (T, bool, error), keysExtractor func(T) ([]K, error), valsExtractor func(T) ([]V, error)) breakkvloop.Loop[K, V] { 616 if next == nil { 617 return nil 618 } 619 var ( 620 keys []K 621 values []V 622 ki, vi int 623 ) 624 return func() (key K, value V, ok bool, err error) { 625 for !ok { 626 var ( 627 keysLen, valuesLen = len(keys), len(values) 628 lastKeyIndex, lastValIndex = keysLen - 1, valuesLen - 1 629 ) 630 if keysLen > 0 && ki >= 0 && ki <= lastKeyIndex { 631 key = keys[ki] 632 ok = true 633 } 634 if valuesLen > 0 && vi >= 0 && vi <= lastValIndex { 635 value = values[vi] 636 ok = true 637 } 638 if ok { 639 if ki < lastKeyIndex { 640 ki++ 641 } else if vi < lastValIndex { 642 ki = 0 643 vi++ 644 } else { 645 keys, values = nil, nil 646 } 647 } else if elem, nextOk, err := next(); err != nil { 648 return key, value, ok, err 649 } else if nextOk { 650 keys, err = keysExtractor(elem) 651 if err == nil { 652 values, err = valsExtractor(elem) 653 } 654 if err != nil { 655 break 656 } 657 ki, vi = 0, 0 658 } else { 659 keys, values = nil, nil 660 break 661 } 662 } 663 return key, value, ok, nil 664 } 665 // return NewMultipleKeyValuer(next, keysExtractor, valsExtractor) 666 } 667 668 // KeysValue transforms a loop to the key/value loop based on applying key, value extractor to the elements 669 func KeysValue[T, K, V any](next func() (T, bool, error), keysExtractor func(T) []K, valExtractor func(T) V) breakkvloop.Loop[K, V] { 670 return KeysValues(next, as.ErrTail(keysExtractor), convSlice(as.ErrTail(valExtractor))) 671 } 672 673 // KeysValuee transforms a loop to the key/value loop based on applying key, value extractor to the elements 674 func KeysValuee[T, K, V any](next func() (T, bool, error), keysExtractor func(T) ([]K, error), valExtractor func(T) (V, error)) breakkvloop.Loop[K, V] { 675 return KeysValues(next, keysExtractor, convSlice(valExtractor)) 676 } 677 678 // KeyValues transforms a loop to the key/value loop based on applying key, value extractor to the elements 679 func KeyValues[T, K, V any](next func() (T, bool, error), keyExtractor func(T) K, valsExtractor func(T) []V) breakkvloop.Loop[K, V] { 680 return KeysValues(next, convSlice(as.ErrTail(keyExtractor)), as.ErrTail(valsExtractor)) 681 } 682 683 // KeyValuess transforms a loop to the key/value loop based on applying key, value extractor to the elements 684 func KeyValuess[T, K, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valsExtractor func(T) ([]V, error)) breakkvloop.Loop[K, V] { 685 return KeysValues(next, convSlice(keyExtractor), valsExtractor) 686 } 687 688 // ExtraVals transforms a loop to the key/value loop based on applying value extractor to the elements 689 func ExtraVals[T, V any](next func() (T, bool, error), valsExtractor func(T) []V) breakkvloop.Loop[T, V] { 690 return KeyValues(next, as.Is[T], valsExtractor) 691 } 692 693 // ExtraValss transforms a loop to the key/value loop based on applying values extractor to the elements 694 func ExtraValss[T, V any](next func() (T, bool, error), valsExtractor func(T) ([]V, error)) breakkvloop.Loop[T, V] { 695 return KeyValuess(next, as.ErrTail(as.Is[T]), valsExtractor) 696 } 697 698 // ExtraKeys transforms a loop to the key/value loop based on applying key extractor to the elements 699 func ExtraKeys[T, K any](next func() (T, bool, error), keysExtractor func(T) []K) breakkvloop.Loop[K, T] { 700 return KeysValue(next, keysExtractor, as.Is[T]) 701 } 702 703 // ExtraKeyss transforms a loop to the key/value loop based on applying key extractor to the elements 704 func ExtraKeyss[T, K any](next func() (T, bool, error), keyExtractor func(T) (K, error)) breakkvloop.Loop[K, T] { 705 return KeyValuess(next, keyExtractor, as.ErrTail(convert.AsSlice[T])) 706 } 707 708 // ExtraKey transforms a loop to the key/value loop based on applying key extractor to the elements 709 func ExtraKey[T, K any](next func() (T, bool, error), keysExtractor func(T) K) breakkvloop.Loop[K, T] { 710 return KeyValue(next, keysExtractor, as.Is[T]) 711 } 712 713 // ExtraKeyy transforms a loop to the key/value loop based on applying key extractor to the elements 714 func ExtraKeyy[T, K any](next func() (T, bool, error), keyExtractor func(T) (K, error)) breakkvloop.Loop[K, T] { 715 return KeyValuee[T, K](next, keyExtractor, as.ErrTail(as.Is[T])) 716 } 717 718 // ExtraValue transforms a loop to the key/value loop based on applying value extractor to the elements 719 func ExtraValue[T, V any](next func() (T, bool, error), valueExtractor func(T) V) breakkvloop.Loop[T, V] { 720 return KeyValue(next, as.Is[T], valueExtractor) 721 } 722 723 // ExtraValuee transforms a loop to the key/value loop based on applying value extractor to the elements 724 func ExtraValuee[T, V any](next func() (T, bool, error), valExtractor func(T) (V, error)) breakkvloop.Loop[T, V] { 725 return KeyValuee[T, T, V](next, as.ErrTail(as.Is[T]), valExtractor) 726 } 727 728 // Group converts elements retrieved by the 'next' function into a map, extracting a key for each element applying the converter 'keyExtractor'. 729 // The keyExtractor converts an element to a key. 730 // The valExtractor converts an element to an value. 731 func Group[T any, K comparable, V any](next func() (T, bool, error), keyExtractor func(T) K, valExtractor func(T) V) (map[K][]V, error) { 732 return Groupp(next, as.ErrTail(keyExtractor), as.ErrTail(valExtractor)) 733 } 734 735 // Groupp converts elements retrieved by the 'next' function into a map, extracting a key for each element applying the converter 'keyExtractor'. 736 // The keyExtractor converts an element to a key. 737 // The valExtractor converts an element to an value. 738 func Groupp[T any, K comparable, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) (map[K][]V, error) { 739 return ToMapResolvv(next, keyExtractor, valExtractor, func(ok bool, k K, rv []V, v V) ([]V, error) { 740 return resolv.Slice(ok, k, rv, v), nil 741 }) 742 } 743 744 // GroupByMultiple converts elements retrieved by the 'next' function into a map, extracting multiple keys, values per each element applying the 'keysExtractor' and 'valsExtractor' functions. 745 // The keysExtractor retrieves one or more keys per element. 746 // The valsExtractor retrieves one or more values per element. 747 func GroupByMultiple[T any, K comparable, V any](next func() (T, bool, error), keysExtractor func(T) []K, valsExtractor func(T) []V) (map[K][]V, error) { 748 groups := map[K][]V{} 749 for { 750 if e, ok, err := next(); err != nil || !ok { 751 return groups, err 752 } else if keys, vals := keysExtractor(e), valsExtractor(e); len(keys) == 0 { 753 var key K 754 for _, v := range vals { 755 initGroup(key, v, groups) 756 } 757 } else { 758 for _, key := range keys { 759 if len(vals) == 0 { 760 var v V 761 initGroup(key, v, groups) 762 } else { 763 for _, v := range vals { 764 initGroup(key, v, groups) 765 } 766 } 767 } 768 } 769 } 770 } 771 772 // GroupByMultipleKeys converts elements retrieved by the 'next' function into a map, extracting multiple keys, one value per each element applying the 'keysExtractor' and 'valExtractor' functions. 773 // The keysExtractor retrieves one or more keys per element. 774 // The valExtractor converts an element to a value. 775 func GroupByMultipleKeys[T any, K comparable, V any](next func() (T, bool, error), keysExtractor func(T) []K, valExtractor func(T) V) (map[K][]V, error) { 776 groups := map[K][]V{} 777 for { 778 if e, ok, err := next(); err != nil || !ok { 779 return groups, err 780 } else if keys, v := keysExtractor(e), valExtractor(e); len(keys) == 0 { 781 var key K 782 initGroup(key, v, groups) 783 } else { 784 for _, key := range keys { 785 initGroup(key, v, groups) 786 } 787 } 788 } 789 } 790 791 // GroupByMultipleValues converts elements retrieved by the 'next' function into a map, extracting one key, multiple values per each element applying the 'keyExtractor' and 'valsExtractor' functions. 792 // The keyExtractor converts an element to a key. 793 // The valsExtractor retrieves one or more values per element. 794 func GroupByMultipleValues[T any, K comparable, V any](next func() (T, bool, error), keyExtractor func(T) K, valsExtractor func(T) []V) (map[K][]V, error) { 795 groups := map[K][]V{} 796 for { 797 if e, ok, err := next(); err != nil || !ok { 798 return groups, err 799 } else if key, vals := keyExtractor(e), valsExtractor(e); len(vals) == 0 { 800 var v V 801 initGroup(key, v, groups) 802 } else { 803 for _, v := range vals { 804 initGroup(key, v, groups) 805 } 806 } 807 } 808 } 809 810 func initGroup[T any, K comparable, TS ~[]T](key K, e T, groups map[K]TS) { 811 groups[key] = append(groups[key], e) 812 } 813 814 // ToMap collects key\value elements to a map by iterating over the elements 815 func ToMap[T any, K comparable, V any](next func() (T, bool), keyExtractor func(T) K, valExtractor func(T) V) (map[K]V, error) { 816 return ToMapp(From(next), as.ErrTail(keyExtractor), as.ErrTail(valExtractor)) 817 } 818 819 // ToMapp collects key\value elements to a map by iterating over the elements 820 func ToMapp[T any, K comparable, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) (map[K]V, error) { 821 return ToMapResolvv(next, keyExtractor, valExtractor, func(ok bool, k K, rv V, v V) (V, error) { return resolv.First(ok, k, rv, v), nil }) 822 } 823 824 // ToMapResolvv collects key\value elements to a map by iterating over the elements with resolving of duplicated key values 825 func ToMapResolvv[T any, K comparable, V, VR any]( 826 next func() (T, bool, error), keyExtractor func(T) (K, error), valExtractor func(T) (V, error), 827 resolver func(bool, K, VR, V) (VR, error), 828 ) (m map[K]VR, err error) { 829 if next == nil { 830 return nil, nil 831 } 832 m = map[K]VR{} 833 for { 834 if e, ok, err := next(); err != nil || !ok { 835 return m, err 836 } else if k, err := keyExtractor(e); err != nil { 837 return m, err 838 } else if v, err := valExtractor(e); err != nil { 839 return m, err 840 } else { 841 exists, ok := m[k] 842 if m[k], err = resolver(ok, k, exists, v); err != nil { 843 return m, err 844 } 845 } 846 } 847 } 848 849 // ConvertAndReduce converts each elements and merges them into one 850 func ConvertAndReduce[From, To any](next func() (From, bool, error), converter func(From) To, merger func(To, To) To) (out To, err error) { 851 return Reduce(Convert(next, converter), merger) 852 } 853 854 // ConvAndReduce converts each elements and merges them into one 855 func ConvAndReduce[From, To any](next func() (From, bool, error), converter func(From) (To, error), merger func(To, To) To) (out To, err error) { 856 return Reduce(Conv(next, converter), merger) 857 } 858 859 // Crank rertieves a next element from the 'next' function, returns the function, element, successfully flag. 860 func Crank[T any](next func() (T, bool, error)) (n Loop[T], t T, ok bool, err error) { 861 if next != nil { 862 t, ok, err = next() 863 } 864 return next, t, ok, err 865 } 866 867 func brk(err error) error { 868 if errors.Is(err, c.Break) { 869 return nil 870 } 871 return err 872 } 873 874 func convSlice[T, V any](conv func(T) (V, error)) func(t T) ([]V, error) { 875 return func(t T) ([]V, error) { 876 v, err := conv(t) 877 if err != nil { 878 return nil, err 879 } 880 return convert.AsSlice(v), nil 881 } 882 }