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 }