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

     1  package loop
     2  
     3  import (
     4  	"github.com/m4gshm/gollections/break/kv"
     5  )
     6  
     7  // NewKeyValuer creates instance of the KeyValuer
     8  func NewKeyValuer[T any, K, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valsExtractor func(T) (V, error)) KeyValuer[T, K, V] {
     9  	return KeyValuer[T, K, V]{next: next, keyExtractor: keyExtractor, valExtractor: valsExtractor}
    10  }
    11  
    12  // NewMultipleKeyValuer creates instance of the MultipleKeyValuer
    13  func NewMultipleKeyValuer[T any, K, V any](next func() (T, bool, error), keysExtractor func(T) ([]K, error), valsExtractor func(T) ([]V, error)) *MultipleKeyValuer[T, K, V] {
    14  	return &MultipleKeyValuer[T, K, V]{next: next, keysExtractor: keysExtractor, valsExtractor: valsExtractor}
    15  }
    16  
    17  // KeyValuer is the Iterator wrapper that converts an element to a key\value pair and iterates over these pairs
    18  type KeyValuer[T, K, V any] struct {
    19  	next         func() (T, bool, error)
    20  	keyExtractor func(T) (K, error)
    21  	valExtractor func(T) (V, error)
    22  }
    23  
    24  var _ kv.Iterator[int, string] = (*KeyValuer[any, int, string])(nil)
    25  var _ kv.Iterator[int, string] = KeyValuer[any, int, string]{}
    26  var _ kv.IterFor[int, string, KeyValuer[any, int, string]] = KeyValuer[any, int, string]{}
    27  
    28  // Track takes key, value pairs retrieved by the iterator. Can be interrupt by returning ErrBreak
    29  func (kv KeyValuer[T, K, V]) Track(traker func(key K, value V) error) error {
    30  	return Track(kv.Next, traker)
    31  }
    32  
    33  // Next returns the next element.
    34  // The ok result indicates whether the element was returned by the iterator.
    35  // If ok == false, then the iteration must be completed.
    36  func (kv KeyValuer[T, K, V]) Next() (key K, value V, ok bool, err error) {
    37  	if next := kv.next; next != nil {
    38  		if elem, nextOk, err := next(); err != nil || !nextOk {
    39  			return key, value, false, err
    40  		} else if key, err = kv.keyExtractor(elem); err == nil {
    41  			value, err = kv.valExtractor(elem)
    42  		}
    43  	}
    44  	return key, value, true, err
    45  }
    46  
    47  // Start is used with for loop construct like 'for i, k, v, ok, err := i.Start(); ok || err != nil ; k, v, ok, err = i.Next() { if err != nil { return err }}'
    48  func (kv KeyValuer[T, K, V]) Start() (KeyValuer[T, K, V], K, V, bool, error) {
    49  	return startKvIt[K, V](kv)
    50  }
    51  
    52  // MultipleKeyValuer is the Iterator wrapper that converts an element to a key\value pair and iterates over these pairs
    53  type MultipleKeyValuer[T, K, V any] struct {
    54  	next          func() (T, bool, error)
    55  	keysExtractor func(T) ([]K, error)
    56  	valsExtractor func(T) ([]V, error)
    57  	keys          []K
    58  	values        []V
    59  	ki, vi        int
    60  }
    61  
    62  var _ kv.Iterator[int, string] = (*MultipleKeyValuer[any, int, string])(nil)
    63  var _ kv.IterFor[int, string, *MultipleKeyValuer[any, int, string]] = (*MultipleKeyValuer[any, int, string])(nil)
    64  
    65  // Track takes key, value pairs retrieved by the iterator. Can be interrupt by returning ErrBreak
    66  func (kv *MultipleKeyValuer[T, K, V]) Track(traker func(key K, value V) error) error {
    67  	return Track(kv.Next, traker)
    68  }
    69  
    70  // Next returns the next element.
    71  // The ok result indicates whether the element was returned by the iterator.
    72  // If ok == false, then the iteration must be completed.
    73  func (kv *MultipleKeyValuer[T, K, V]) Next() (key K, value V, ok bool, err error) {
    74  	if kv != nil {
    75  		if next := kv.next; next != nil {
    76  			for !ok {
    77  				var (
    78  					keys, values               = kv.keys, kv.values
    79  					keysLen, valuesLen         = len(keys), len(values)
    80  					lastKeyIndex, lastValIndex = keysLen - 1, valuesLen - 1
    81  				)
    82  				if keysLen > 0 && kv.ki >= 0 && kv.ki <= lastKeyIndex {
    83  					key = keys[kv.ki]
    84  					ok = true
    85  				}
    86  				if valuesLen > 0 && kv.vi >= 0 && kv.vi <= lastValIndex {
    87  					value = values[kv.vi]
    88  					ok = true
    89  				}
    90  				if ok {
    91  					if kv.ki < lastKeyIndex {
    92  						kv.ki++
    93  					} else if kv.vi < lastValIndex {
    94  						kv.ki = 0
    95  						kv.vi++
    96  					} else {
    97  						kv.keys, kv.values = nil, nil
    98  					}
    99  				} else if elem, nextOk, err := next(); err != nil {
   100  					return key, value, ok, err
   101  				} else if nextOk {
   102  					kv.keys, err = kv.keysExtractor(elem)
   103  					if err == nil {
   104  						kv.values, err = kv.valsExtractor(elem)
   105  					}
   106  					if err != nil {
   107  						break
   108  					}
   109  					kv.ki, kv.vi = 0, 0
   110  				} else {
   111  					kv.keys, kv.values = nil, nil
   112  					break
   113  				}
   114  			}
   115  		}
   116  	}
   117  	return key, value, ok, nil
   118  }
   119  
   120  // Start is used with for loop construct like 'for i, k, v, ok, err := i.Start(); ok || err != nil ; k, v, ok, err = i.Next() { if err != nil { return err }}'
   121  func (kv *MultipleKeyValuer[T, K, V]) Start() (*MultipleKeyValuer[T, K, V], K, V, bool, error) {
   122  	return startKvIt[K, V](kv)
   123  }