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  }