github.com/primecitizens/pcz/std@v0.2.1/core/iter/utils.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 4 package iter 5 6 import ( 7 "github.com/primecitizens/pcz/std/core/assert" 8 ) 9 10 // Contains returns true if there is x in iter. 11 func Contains[T comparable, Iter Core[T]](iter Iter, x T) bool { 12 for i := 0; ; i++ { 13 item, ok := iter.Nth(i) 14 if !ok { 15 return false 16 } 17 18 if x == item { 19 return true 20 } 21 } 22 } 23 24 // Index returns the index in range [0, n) from i. 25 // 26 // assuming n > 0: 27 // 28 // - when i >= 0, validate it 29 // - when i < 0, index from the n 30 // 31 // NOTE: the returned index is only valid when valid is true. 32 func Index(i, n int) (index int, valid bool) { 33 if i >= 0 { 34 return i, i < n 35 } 36 37 if n > 0 { 38 i = n + i 39 return i, i >= 0 && i < n 40 } 41 42 return -1, false 43 } 44 45 // Bound returns value used for slice bounding. 46 // 47 // assuming n >= 0: 48 // 49 // - i >= 0 && i < n: Bound(i, n) = Index(i, n) 50 // - i == n: returns (i, true) 51 // - i < 0: Bound(i, n) = Index(i, n) + 1 52 // 53 // NOTE: the returned bound is only valid when valid is true. 54 func Bound(i, n int) (bound int, valid bool) { 55 if i >= 0 { 56 return i, i <= n 57 } 58 59 if n < 0 { 60 return -1, false 61 } 62 63 i = n + i + 1 64 return i, i >= 0 && i <= n 65 } 66 67 // Range returns the [start:end] in range [0, n] 68 func Range(start, end, n int) (int, int, bool) { 69 if start >= 0 && end >= 0 { 70 return start, end, start <= end && end <= n 71 } 72 73 if start < 0 { 74 start = n + start + 1 75 if start < 0 { 76 return -1, -1, false 77 } 78 } 79 80 if end < 0 { 81 end = n + end + 1 82 if end < 0 { 83 return -1, -1, false 84 } 85 } 86 87 return start, end, start <= end && end <= n 88 } 89 90 // Each calls fn on each element from the iter. 91 func Each[Iter Core[Elem], Elem any]( 92 iter Iter, fn func(i int, v Elem) bool, 93 ) int { 94 return EachEx(iter, fn, func(i int, v Elem, fn func(i int, v Elem) bool) bool { 95 return fn(i, v) 96 }) 97 } 98 99 // EachEx is like Each but calls fn with an extra arg. 100 func EachEx[Iter Core[Elem], Elem, Arg any]( 101 iter Iter, arg Arg, fn func(i int, v Elem, arg Arg) bool, 102 ) int { 103 var ( 104 val Elem 105 ok bool 106 ) 107 108 for i := 0; ; i++ { 109 if val, ok = iter.Nth(i); ok { 110 if fn(i, val, arg) { 111 continue 112 } 113 } 114 115 return i 116 } 117 } 118 119 // Step calls fn on every next step element from the iter. 120 func Step[Elem any]( 121 iter Core[Elem], from, step int, fn func(i int, v Elem) bool, 122 ) int { 123 var ( 124 val Elem 125 ok bool 126 ) 127 128 if step == 0 { 129 assert.Throw("invald", "zero", "step") 130 } 131 132 if step < 0 { 133 if _, ok = iter.(CanBackward); ok { 134 assert.Throw("no", "backward", "iteration", "support") 135 } 136 } 137 138 if _, ok = iter.(CanSkip); ok && (step > 1 || step < -1) { 139 if step < 0 { 140 for i := from; ; i-- { 141 if val, ok = iter.Nth(i); ok { 142 if i == from { 143 if fn(i, val) { 144 from += step 145 continue 146 } 147 } else { 148 continue 149 } 150 } 151 152 return i 153 } 154 } else { 155 for i := from; ; i++ { 156 if val, ok = iter.Nth(i); ok { 157 if i == from { 158 if fn(i, val) { 159 from += step 160 continue 161 } 162 } else { 163 continue 164 } 165 } 166 167 return from 168 } 169 } 170 171 assert.Unreachable() 172 } 173 174 for ; ; from += step { 175 if val, ok = iter.Nth(from); ok { 176 if fn(from, val) { 177 continue 178 } 179 } 180 181 return from 182 } 183 } 184 185 // StepEx is like Step but calls fn with an extra arg. 186 // 187 // It panics if from or step is invalid for the iter. 188 func StepEx[Elem, Arg any]( 189 iter Core[Elem], from, step int, arg Arg, fn func(i int, v Elem, arg Arg) bool, 190 ) { 191 var ( 192 val Elem 193 ok bool 194 ) 195 196 if step == 0 { 197 assert.Throw("invald", "zero", "step") 198 } 199 200 if step < 0 { 201 if _, ok = iter.(CanBackward); ok { 202 assert.Throw("no", "backward", "iteration", "support") 203 } 204 } 205 206 if _, ok = iter.(CanSkip); ok { 207 if step < 0 { 208 for i := from; ; i-- { 209 if val, ok = iter.Nth(i); ok { 210 if i == from { 211 if fn(i, val, arg) { 212 from += step 213 continue 214 } 215 } else { 216 continue 217 } 218 } 219 220 return 221 } 222 223 assert.Unreachable() 224 } 225 226 for i := from; ; i++ { 227 if val, ok = iter.Nth(i); ok { 228 if i == from { 229 if fn(i, val, arg) { 230 from += step 231 continue 232 } 233 } else { 234 continue 235 } 236 } 237 238 return 239 } 240 241 assert.Unreachable() 242 } 243 244 for ; ; from += step { 245 if val, ok = iter.Nth(from); ok { 246 if fn(from, val, arg) { 247 continue 248 } 249 } 250 251 return 252 } 253 }