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

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