github.com/m4gshm/gollections@v0.0.13-0.20240331203319-a34a86e58a24/loop/api.go (about)

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