github.com/m4gshm/gollections@v0.0.10/loop/api.go (about)

     1  // Package loop provides helpers for loop operation and iterator implementations
     2  package loop
     3  
     4  import (
     5  	"golang.org/x/exp/constraints"
     6  
     7  	"github.com/m4gshm/gollections/break/loop"
     8  	breakAlways "github.com/m4gshm/gollections/break/predicate/always"
     9  	"github.com/m4gshm/gollections/c"
    10  	"github.com/m4gshm/gollections/convert"
    11  	"github.com/m4gshm/gollections/convert/as"
    12  	"github.com/m4gshm/gollections/map_/resolv"
    13  	"github.com/m4gshm/gollections/notsafe"
    14  	"github.com/m4gshm/gollections/op"
    15  	"github.com/m4gshm/gollections/op/check/not"
    16  	"github.com/m4gshm/gollections/predicate/always"
    17  )
    18  
    19  // ErrBreak is the 'break' statement of the For, Track methods
    20  var ErrBreak = c.ErrBreak
    21  
    22  // Looper provides an iterable loop function
    23  type Looper[T any, I interface{ Next() (T, bool) }] interface {
    24  	Loop() I
    25  }
    26  
    27  // Of wrap the elements by loop function
    28  func Of[T any](elements ...T) func() (e T, ok bool) {
    29  	l := len(elements)
    30  	i := 0
    31  	if l == 0 || i < 0 || i >= l {
    32  		return func() (e T, ok bool) { return e, false }
    33  	}
    34  	return func() (e T, ok bool) {
    35  		if i < l {
    36  			e, ok = elements[i], true
    37  			i++
    38  		}
    39  		return e, ok
    40  	}
    41  }
    42  
    43  // For applies the 'walker' function for the elements retrieved by the 'next' function. Return the c.ErrBreak to stop
    44  func For[T any](next func() (T, bool), walker func(T) error) error {
    45  	for v, ok := next(); ok; v, ok = next() {
    46  		if err := walker(v); err == ErrBreak {
    47  			return nil
    48  		} else if err != nil {
    49  			return err
    50  		}
    51  	}
    52  	return nil
    53  }
    54  
    55  // ForEach applies the 'walker' function to the elements retrieved by the 'next' function
    56  func ForEach[T any](next func() (T, bool), walker func(T)) {
    57  	for v, ok := next(); ok; v, ok = next() {
    58  		walker(v)
    59  	}
    60  }
    61  
    62  // ForEachFiltered applies the 'walker' function to the elements retrieved by the 'next' function that satisfy the 'predicate' function condition
    63  func ForEachFiltered[T any](next func() (T, bool), predicate func(T) bool, walker func(T)) {
    64  	for v, ok := next(); ok; v, ok = next() {
    65  		if predicate(v) {
    66  			walker(v)
    67  		}
    68  	}
    69  }
    70  
    71  // First returns the first element that satisfies the condition of the 'predicate' function
    72  func First[T any](next func() (T, bool), predicate func(T) bool) (v T, ok bool) {
    73  	for one, ok := next(); ok; one, ok = next() {
    74  		if predicate(one) {
    75  			return one, true
    76  		}
    77  	}
    78  	return v, ok
    79  }
    80  
    81  // Track applies the 'tracker' function to position/element pairs retrieved by the 'next' function. Return the c.ErrBreak to stop tracking..
    82  func Track[I, T any](next func() (I, T, bool), tracker func(I, T) error) error {
    83  	for p, v, ok := next(); ok; p, v, ok = next() {
    84  		if err := tracker(p, v); err == ErrBreak {
    85  			return nil
    86  		} else if err != nil {
    87  			return err
    88  		}
    89  	}
    90  	return nil
    91  }
    92  
    93  // TrackEach applies the 'tracker' function to position/element pairs retrieved by the 'next' function
    94  func TrackEach[I, T any](next func() (I, T, bool), tracker func(I, T)) {
    95  	for p, v, ok := next(); ok; p, v, ok = next() {
    96  		tracker(p, v)
    97  	}
    98  }
    99  
   100  // Slice collects the elements retrieved by the 'next' function into a new slice
   101  func Slice[T any](next func() (T, bool)) []T {
   102  	return SliceCap(next, 0)
   103  }
   104  
   105  // SliceCap collects the elements retrieved by the 'next' function into a new slice with predefined capacity
   106  func SliceCap[T any](next func() (T, bool), cap int) (out []T) {
   107  	if cap > 0 {
   108  		out = make([]T, 0, cap)
   109  	}
   110  	return Append(next, out)
   111  }
   112  
   113  // Append collects the elements retrieved by the 'next' function into the specified 'out' slice
   114  func Append[T any, TS ~[]T](next func() (T, bool), out TS) TS {
   115  	for v, ok := next(); ok; v, ok = next() {
   116  		out = append(out, v)
   117  	}
   118  	return out
   119  }
   120  
   121  // Reduce reduces the elements retrieved by the 'next' function into an one using the 'merger' function
   122  func Reduce[T any](next func() (T, bool), merger func(T, T) T) (result T) {
   123  	if v, ok := next(); ok {
   124  		result = v
   125  	} else {
   126  		return result
   127  	}
   128  	for v, ok := next(); ok; v, ok = next() {
   129  		result = merger(result, v)
   130  	}
   131  	return result
   132  }
   133  
   134  // Sum returns the sum of all elements
   135  func Sum[T c.Summable](next func() (T, bool)) T {
   136  	return Reduce(next, op.Sum[T])
   137  }
   138  
   139  // HasAny finds the first element that satisfies the 'predicate' function condition and returns true if successful
   140  func HasAny[T any](next func() (T, bool), predicate func(T) bool) bool {
   141  	_, ok := First(next, predicate)
   142  	return ok
   143  }
   144  
   145  // Contains  finds the first element that equal to the example and returns true
   146  func Contains[T comparable](next func() (T, bool), example T) bool {
   147  	for one, ok := next(); ok; one, ok = next() {
   148  		if one == example {
   149  			return true
   150  		}
   151  	}
   152  	return false
   153  }
   154  
   155  // Conv instantiates an iterator that converts elements with a converter and returns them.
   156  func Conv[From, To any](next func() (From, bool), converter func(From) (To, error)) loop.ConvertIter[From, To] {
   157  	return loop.Conv(loop.From(next), converter)
   158  }
   159  
   160  // Convert instantiates an iterator that converts elements with a converter and returns them.
   161  func Convert[From, To any](next func() (From, bool), converter func(From) To) ConvertIter[From, To] {
   162  	return ConvertIter[From, To]{next: next, converter: converter}
   163  }
   164  
   165  // ConvCheck is similar to ConvertFilt, but it checks and transforms elements together
   166  func ConvCheck[From, To any](next func() (From, bool), converter func(from From) (To, bool, error)) loop.ConvertCheckIter[From, To] {
   167  	return loop.ConvCheck(loop.From(next), converter)
   168  }
   169  
   170  // ConvertCheck is similar to ConvertFilt, but it checks and transforms elements together
   171  func ConvertCheck[From, To any](next func() (From, bool), converter func(from From) (To, bool)) ConvertCheckIter[From, To] {
   172  	return ConvertCheckIter[From, To]{next: next, converter: converter}
   173  }
   174  
   175  // FiltAndConv returns a stream that filters source elements and converts them
   176  func FiltAndConv[From, To any](next func() (From, bool), filter func(From) (bool, error), converter func(From) (To, error)) loop.ConvFiltIter[From, To] {
   177  	return loop.FiltAndConv(loop.From(next), filter, converter)
   178  }
   179  
   180  // FilterAndConvert returns a stream that filters source elements and converts them
   181  func FilterAndConvert[From, To any](next func() (From, bool), filter func(From) bool, converter func(From) To) ConvertFiltIter[From, To] {
   182  	return FilterConvertFilter(next, filter, converter, always.True[To])
   183  }
   184  
   185  // FilterConvertFilter filters source, converts, and filters converted elements
   186  func FilterConvertFilter[From, To any](next func() (From, bool), filter func(From) bool, converter func(From) To, filterTo func(To) bool) ConvertFiltIter[From, To] {
   187  	return ConvertFiltIter[From, To]{next: next, converter: converter, filterFrom: filter, filterTo: filterTo}
   188  }
   189  
   190  // ConvertAndFilter additionally filters 'To' elements
   191  func ConvertAndFilter[From, To any](next func() (From, bool), converter func(From) To, filter func(To) bool) ConvertFiltIter[From, To] {
   192  	return FilterConvertFilter(next, always.True[From], converter, filter)
   193  }
   194  
   195  // Flatt instantiates an iterator that extracts slices of 'To' by a flattener from elements of 'From' and flattens as one iterable collection of 'To' elements.
   196  func Flatt[From, To any](next func() (From, bool), flattener func(From) ([]To, error)) *loop.FlatIter[From, To] {
   197  	return loop.Flatt(loop.From(next), flattener)
   198  }
   199  
   200  // Flat instantiates an iterator that extracts slices of 'To' by a flattener from elements of 'From' and flattens as one iterable collection of 'To' elements.
   201  func Flat[From, To any](next func() (From, bool), flattener func(From) []To) *FlatIter[From, To] {
   202  	return &FlatIter[From, To]{next: next, flattener: flattener, elemSizeTo: notsafe.GetTypeSize[To]()}
   203  }
   204  
   205  // FiltAndFlat filters source elements and extracts slices of 'To' by the 'flattener' function
   206  func FiltAndFlat[From, To any](next func() (From, bool), filter func(From) (bool, error), flattener func(From) ([]To, error)) *loop.FlattFiltIter[From, To] {
   207  	return loop.FiltFlattFilt(loop.From(next), filter, flattener, breakAlways.True[To])
   208  }
   209  
   210  // FilterAndFlat filters source elements and extracts slices of 'To' by the 'flattener' function
   211  func FilterAndFlat[From, To any](next func() (From, bool), filter func(From) bool, flattener func(From) []To) *FlatFilterIter[From, To] {
   212  	return FilterFlatFilter(next, filter, flattener, always.True[To])
   213  }
   214  
   215  // FlatAndFilt extracts slices of 'To' by the 'flattener' function and filters extracted elements
   216  func FlatAndFilt[From, To any](next func() (From, bool, error), flattener func(From) ([]To, error), filterTo func(To) (bool, error)) *loop.FlattFiltIter[From, To] {
   217  	return loop.FiltFlattFilt(next, breakAlways.True[From], flattener, filterTo)
   218  }
   219  
   220  // FlattAndFilter extracts slices of 'To' by the 'flattener' function and filters extracted elements
   221  func FlattAndFilter[From, To any](next func() (From, bool), flattener func(From) []To, filterTo func(To) bool) *FlatFilterIter[From, To] {
   222  	return FilterFlatFilter(next, always.True[From], flattener, filterTo)
   223  }
   224  
   225  // FiltFlattFilt filters source elements, extracts slices of 'To' by the 'flattener' function and filters extracted elements
   226  func FiltFlattFilt[From, To any](next func() (From, bool), filterFrom func(From) (bool, error), flattener func(From) ([]To, error), filterTo func(To) (bool, error)) *loop.FlattFiltIter[From, To] {
   227  	return loop.FiltFlattFilt(loop.From(next), filterFrom, flattener, filterTo)
   228  }
   229  
   230  // FilterFlatFilter filters source elements, extracts slices of 'To' by the 'flattener' function and filters extracted elements
   231  func FilterFlatFilter[From, To any](next func() (From, bool), filterFrom func(From) bool, flattener func(From) []To, filterTo func(To) bool) *FlatFilterIter[From, To] {
   232  	return &FlatFilterIter[From, To]{next: next, filterFrom: filterFrom, flattener: flattener, filterTo: filterTo, elemSizeTo: notsafe.GetTypeSize[To]()}
   233  }
   234  
   235  // Filt creates an iterator that checks elements by the 'filter' function and returns successful ones.
   236  func Filt[T any](next func() (T, bool), filter func(T) (bool, error)) loop.FiltIter[T] {
   237  	return loop.Filt(loop.From(next), filter)
   238  }
   239  
   240  // Filter creates an iterator that checks elements by the 'filter' function and returns successful ones.
   241  func Filter[T any](next func() (T, bool), filter func(T) bool) FiltIter[T] {
   242  	return FiltIter[T]{next: next, by: filter}
   243  }
   244  
   245  // NotNil creates an iterator that filters nullable elements
   246  func NotNil[T any](next func() (*T, bool)) FiltIter[*T] {
   247  	return Filter(next, not.Nil[T])
   248  }
   249  
   250  // PtrVal creates an iterator that transform pointers to the values referenced by those pointers.
   251  // Nil pointers are transformet to zero values.
   252  func PtrVal[T any](next func() (*T, bool)) ConvertIter[*T, T] {
   253  	return Convert(next, convert.PtrVal[T])
   254  }
   255  
   256  // NoNilPtrVal creates an iterator that transform only not nil pointers to the values referenced referenced by those pointers.
   257  // Nil pointers are ignored.
   258  func NoNilPtrVal[T any](next func() (*T, bool)) ConvertCheckIter[*T, T] {
   259  	return ConvertCheck(next, convert.NoNilPtrVal[T])
   260  }
   261  
   262  // KeyValue transforms iterable elements to key/value iterator based on applying key, value extractors to the elements
   263  func KeyValue[T any, K, V any](next func() (T, bool), keyExtractor func(T) K, valExtractor func(T) V) KeyValuer[T, K, V] {
   264  	return NewKeyValuer(next, keyExtractor, valExtractor)
   265  }
   266  
   267  // KeyValuee transforms iterable elements to key/value iterator based on applying key, value extractors to the elements
   268  func KeyValuee[T any, K, V any](next func() (T, bool), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) loop.KeyValuer[T, K, V] {
   269  	return loop.KeyValuee(loop.From(next), keyExtractor, valExtractor)
   270  }
   271  
   272  // KeysValues transforms iterable elements to key/value iterator based on applying multiple keys, values extractor to the elements
   273  func KeysValues[T, K, V any](next func() (T, bool), keysExtractor func(T) []K, valsExtractor func(T) []V) *MultipleKeyValuer[T, K, V] {
   274  	return NewMultipleKeyValuer(next, keysExtractor, valsExtractor)
   275  }
   276  
   277  // KeysValue transforms iterable elements to key/value iterator based on applying keys, value extractor to the elements
   278  func KeysValue[T, K, V any](next func() (T, bool), keysExtractor func(T) []K, valExtractor func(T) V) *MultipleKeyValuer[T, K, V] {
   279  	return KeysValues(next, keysExtractor, func(t T) []V { return convert.AsSlice(valExtractor(t)) })
   280  }
   281  
   282  // KeysValuee transforms iterable elements to key/value iterator based on applying keys, value extractor to the elements
   283  func KeysValuee[T, K, V any](next func() (T, bool), keysExtractor func(T) ([]K, error), valExtractor func(T) (V, error)) *loop.MultipleKeyValuer[T, K, V] {
   284  	return loop.KeysValuee(loop.From(next), keysExtractor, valExtractor)
   285  }
   286  
   287  // KeyValues transforms iterable elements to key/value iterator based on applying key, values extractor to the elements
   288  func KeyValues[T, K, V any](next func() (T, bool), keyExtractor func(T) K, valsExtractor func(T) []V) *MultipleKeyValuer[T, K, V] {
   289  	return KeysValues(next, func(t T) []K { return convert.AsSlice(keyExtractor(t)) }, valsExtractor)
   290  }
   291  
   292  // KeyValuess transforms iterable elements to key/value iterator based on applying key, values extractor to the elements
   293  func KeyValuess[T, K, V any](next func() (T, bool), keyExtractor func(T) (K, error), valsExtractor func(T) ([]V, error)) *loop.MultipleKeyValuer[T, K, V] {
   294  	return loop.KeyValuess(loop.From(next), keyExtractor, valsExtractor)
   295  }
   296  
   297  // ExtraVals transforms iterable elements to key/value iterator based on applying values extractor to the elements
   298  func ExtraVals[T, V any](next func() (T, bool), valsExtractor func(T) []V) *MultipleKeyValuer[T, T, V] {
   299  	return KeyValues(next, as.Is[T], valsExtractor)
   300  }
   301  
   302  // ExtraValss transforms iterable elements to key/value iterator based on applying values extractor to the elements
   303  func ExtraValss[T, V any](next func() (T, bool), valsExtractor func(T) ([]V, error)) *loop.MultipleKeyValuer[T, T, V] {
   304  	return KeyValuess(next, as.ErrTail(as.Is[T]), valsExtractor)
   305  }
   306  
   307  // ExtraKeys transforms iterable elements to key/value iterator based on applying key extractor to the elements
   308  func ExtraKeys[T, K any](next func() (T, bool), keysExtractor func(T) []K) *MultipleKeyValuer[T, K, T] {
   309  	return KeysValue(next, keysExtractor, as.Is[T])
   310  }
   311  
   312  // ExtraKeyss transforms iterable elements to key/value iterator based on applying key extractor to the elements
   313  func ExtraKeyss[T, K any](next func() (T, bool), keyExtractor func(T) (K, error)) *loop.MultipleKeyValuer[T, K, T] {
   314  	return KeyValuess(next, keyExtractor, as.ErrTail(convert.AsSlice[T]))
   315  }
   316  
   317  // ExtraKey transforms iterable elements to key/value iterator based on applying key extractor to the elements
   318  func ExtraKey[T, K any](next func() (T, bool), keysExtractor func(T) K) KeyValuer[T, K, T] {
   319  	return KeyValue(next, keysExtractor, as.Is[T])
   320  }
   321  
   322  // ExtraKeyy transforms iterable elements to key/value iterator based on applying key extractor to the elements
   323  func ExtraKeyy[T, K any](next func() (T, bool), keyExtractor func(T) (K, error)) loop.KeyValuer[T, K, T] {
   324  	return loop.KeyValuee[T, K](loop.From(next), keyExtractor, as.ErrTail(as.Is[T]))
   325  }
   326  
   327  // ExtraValue transforms iterable elements to key/value iterator based on applying value extractor to the elements
   328  func ExtraValue[T, V any](next func() (T, bool), valueExtractor func(T) V) KeyValuer[T, T, V] {
   329  	return KeyValue(next, as.Is[T], valueExtractor)
   330  }
   331  
   332  // ExtraValuee transforms iterable elements to key/value iterator based on applying value extractor to the elements
   333  func ExtraValuee[T, V any](next func() (T, bool), valExtractor func(T) (V, error)) loop.KeyValuer[T, T, V] {
   334  	return loop.KeyValuee[T, T, V](loop.From(next), as.ErrTail(as.Is[T]), valExtractor)
   335  }
   336  
   337  // Group converts elements retrieved by the 'next' function into a map, extracting a key for each element applying the converter 'keyExtractor'.
   338  // The keyExtractor converts an element to a key.
   339  // The valExtractor converts an element to an value.
   340  func Group[T any, K comparable, V any](next func() (T, bool), keyExtractor func(T) K, valExtractor func(T) V) map[K][]V {
   341  	return ToMapResolv(next, keyExtractor, valExtractor, resolv.Append[K, V])
   342  }
   343  
   344  // Groupp converts elements retrieved by the 'next' function into a map, extracting a key for each element applying the converter 'keyExtractor'.
   345  // The keyExtractor converts an element to a key.
   346  // The valExtractor converts an element to an value.
   347  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) {
   348  	return loop.Groupp(loop.From(next), keyExtractor, valExtractor)
   349  }
   350  
   351  // GroupByMultiple converts elements retrieved by the 'next' function into a map, extracting multiple keys, values per each element applying the 'keysExtractor' and 'valsExtractor' functions.
   352  // The keysExtractor retrieves one or more keys per element.
   353  // The valsExtractor retrieves one or more values per element.
   354  func GroupByMultiple[T any, K comparable, V any](next func() (T, bool), keysExtractor func(T) []K, valsExtractor func(T) []V) map[K][]V {
   355  	groups := map[K][]V{}
   356  	for e, ok := next(); ok; e, ok = next() {
   357  		if keys, vals := keysExtractor(e), valsExtractor(e); len(keys) == 0 {
   358  			var key K
   359  			for _, v := range vals {
   360  				initGroup(key, v, groups)
   361  			}
   362  		} else {
   363  			for _, key := range keys {
   364  				if len(vals) == 0 {
   365  					var v V
   366  					initGroup(key, v, groups)
   367  				} else {
   368  					for _, v := range vals {
   369  						initGroup(key, v, groups)
   370  					}
   371  				}
   372  			}
   373  		}
   374  	}
   375  	return groups
   376  }
   377  
   378  // 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.
   379  // The keysExtractor retrieves one or more keys per element.
   380  // The valExtractor converts an element to a value.
   381  func GroupByMultipleKeys[T any, K comparable, V any](next func() (T, bool), keysExtractor func(T) []K, valExtractor func(T) V) map[K][]V {
   382  	groups := map[K][]V{}
   383  	for e, ok := next(); ok; e, ok = next() {
   384  		if keys, v := keysExtractor(e), valExtractor(e); len(keys) == 0 {
   385  			var key K
   386  			initGroup(key, v, groups)
   387  		} else {
   388  			for _, key := range keys {
   389  				initGroup(key, v, groups)
   390  			}
   391  		}
   392  	}
   393  	return groups
   394  }
   395  
   396  // 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.
   397  // The keyExtractor converts an element to a key.
   398  // The valsExtractor retrieves one or more values per element.
   399  func GroupByMultipleValues[T any, K comparable, V any](next func() (T, bool), keyExtractor func(T) K, valsExtractor func(T) []V) map[K][]V {
   400  	groups := map[K][]V{}
   401  	for e, ok := next(); ok; e, ok = next() {
   402  		if key, vals := keyExtractor(e), valsExtractor(e); len(vals) == 0 {
   403  			var v V
   404  			initGroup(key, v, groups)
   405  		} else {
   406  			for _, v := range vals {
   407  				initGroup(key, v, groups)
   408  			}
   409  		}
   410  	}
   411  	return groups
   412  }
   413  
   414  func initGroup[T any, K comparable, TS ~[]T](key K, e T, groups map[K]TS) {
   415  	groups[key] = append(groups[key], e)
   416  }
   417  
   418  // ToMap collects key\value elements to a map by iterating over the elements
   419  func ToMap[T any, K comparable, V any](next func() (T, bool), keyExtractor func(T) K, valExtractor func(T) V) map[K]V {
   420  	return ToMapResolv(next, keyExtractor, valExtractor, resolv.First[K, V])
   421  }
   422  
   423  // ToMapp collects key\value elements to a map by iterating over the elements
   424  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) {
   425  	return loop.ToMapp(loop.From(next), keyExtractor, valExtractor)
   426  }
   427  
   428  // ToMapResolv collects key\value elements to a map by iterating over the elements with resolving of duplicated key values
   429  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 {
   430  	m := map[K]VR{}
   431  	for e, ok := next(); ok; e, ok = next() {
   432  		k, v := keyExtractor(e), valExtractor(e)
   433  		exists, ok := m[k]
   434  		m[k] = resolver(ok, k, exists, v)
   435  	}
   436  	return m
   437  }
   438  
   439  // New makes a loop from an abstract source
   440  func New[S, T any](source S, hasNext func(S) bool, getNext func(S) T) func() (T, bool) {
   441  	return func() (out T, ok bool) {
   442  		if hasNext(source) {
   443  			out, ok = getNext(source), true
   444  		}
   445  		return out, ok
   446  	}
   447  }
   448  
   449  // RangeClosed creates a loop that generates integers in the range defined by from and to inclusive
   450  func RangeClosed[T constraints.Integer](from T, toInclusive T) func() (T, bool) {
   451  	amount := toInclusive - from
   452  	delta := T(1)
   453  	if amount < 0 {
   454  		amount = -amount
   455  		delta = -delta
   456  	}
   457  	amount++
   458  	nextElement := from
   459  	i := T(0)
   460  	return func() (out T, ok bool) {
   461  		if ok = i < amount; ok {
   462  			out = nextElement
   463  			i++
   464  			nextElement = nextElement + delta
   465  		}
   466  		return out, ok
   467  	}
   468  }
   469  
   470  // Range creates a loop that generates integers in the range defined by from and to exclusive
   471  func Range[T constraints.Integer](from T, toExclusive T) func() (T, bool) {
   472  	amount := toExclusive - from
   473  	delta := T(1)
   474  	if amount < 0 {
   475  		amount = -amount
   476  		delta = -delta
   477  	}
   478  	nextElement := from
   479  	i := T(0)
   480  	return func() (out T, ok bool) {
   481  		if ok = i < amount; ok {
   482  			out = nextElement
   483  			i++
   484  			nextElement = nextElement + delta
   485  		}
   486  		return out, ok
   487  	}
   488  }
   489  
   490  // OfIndexed builds a loop by extracting elements from an indexed soruce.
   491  // the len is length ot the source.
   492  // the getAt retrieves an element by its index from the source.
   493  func OfIndexed[T any](len int, next func(int) T) func() (T, bool) {
   494  	i := 0
   495  	return func() (out T, ok bool) {
   496  		if ok = i < len; ok {
   497  			out = next(i)
   498  			i++
   499  		}
   500  		return out, ok
   501  	}
   502  }
   503  
   504  // ConvertAndReduce converts each elements and merges them into one
   505  func ConvertAndReduce[From, To any](next func() (From, bool), converter func(From) To, merger func(To, To) To) (out To) {
   506  	if v, ok := next(); ok {
   507  		out = converter(v)
   508  	} else {
   509  		return out
   510  	}
   511  	for v, ok := next(); ok; v, ok = next() {
   512  		out = merger(out, converter(v))
   513  	}
   514  	return out
   515  }
   516  
   517  // ConvAndReduce converts each elements and merges them into one
   518  func ConvAndReduce[From, To any](next func() (From, bool), converter func(From) (To, error), merger func(To, To) To) (out To, err error) {
   519  	if v, ok := next(); ok {
   520  		out, err = converter(v)
   521  		if err != nil {
   522  			return out, err
   523  		}
   524  	} else {
   525  		return out, nil
   526  	}
   527  	for v, ok := next(); ok; v, ok = next() {
   528  		c, err := converter(v)
   529  		if err != nil {
   530  			return out, err
   531  		}
   532  		out = merger(out, c)
   533  	}
   534  	return out, nil
   535  }
   536  
   537  // Start is used with for loop construct like 'for i, k, v, ok := i.Start(); ok; k, v, ok = i.Next() { }'
   538  func Start[T any](next func() (T, bool)) (func() (T, bool), T, bool) {
   539  	element, ok := next()
   540  	return next, element, ok
   541  }