github.com/kazu/loncha@v0.6.3/filter2.go (about) 1 package loncha 2 3 import "reflect" 4 5 type CondFunc2[T any] func(t *T) bool 6 7 type CondFunc3[T any] func(t T) bool 8 9 type CondFuncWithPtr[T any] interface { 10 CondFunc2[T] | CondFunc3[T] 11 } 12 13 type CondFuncWithIndex[T any] func(i int, t *T) bool 14 15 // FilterOpt ... functional option for FIlter2() 16 type FilterOpt[T any] struct { 17 isDestructive bool 18 condFns []CondFunc 19 condFns2 []CondFunc2[T] 20 fVersion int 21 equalObject T 22 } 23 24 func (fopt *FilterOpt[T]) condFn(fns ...CondFunc) (prev []CondFunc) { 25 26 prev = fopt.condFns 27 fopt.condFns = fns 28 return prev 29 30 } 31 32 func (fopt *FilterOpt[T]) condFn2(fns ...CondFunc2[T]) (prev []CondFunc2[T]) { 33 34 prev = fopt.condFns2 35 fopt.condFns2 = fns 36 return prev 37 } 38 39 func (fopt *FilterOpt[T]) filterVersion(v int) (prev int) { 40 prev = fopt.fVersion 41 fopt.fVersion = v 42 return prev 43 } 44 45 func (fopt *FilterOpt[T]) equal(v T) (prev T) { 46 prev = fopt.equalObject 47 fopt.equalObject = v 48 return prev 49 } 50 51 type eqaulSetter[T any, S any] interface { 52 equal(S) S 53 *T 54 } 55 56 type fVersionSetter[T any] interface { 57 filterVersion(int) int 58 *T 59 } 60 61 type condFuncSetter[T any] interface { 62 condFn(fns ...CondFunc) (prevs []CondFunc) 63 *T 64 } 65 66 type condFuncSetter2[T any, S any] interface { 67 condFn(fns ...CondFunc) (prevs []CondFunc) 68 condFn2(fns ...CondFunc2[S]) (prevs []CondFunc2[S]) 69 *T 70 } 71 72 func FilterVersion[T any, PT fVersionSetter[T]](v int) Opt[T] { 73 74 return func(p *opParam[T]) Opt[T] { 75 prevs := PT(&p.Param).filterVersion(v) 76 return FilterVersion[T, PT](prevs) 77 } 78 79 } 80 81 // Cond ... set conditional function for FIlter2() 82 func Cond[T any, PT condFuncSetter[T]](fns ...CondFunc) Opt[T] { 83 return func(p *opParam[T]) Opt[T] { 84 prevs := PT(&p.Param).condFn(fns...) 85 return Cond[T, PT](prevs...) 86 } 87 } 88 89 // Cond2 ... no index variant of Cond 90 func Cond2[OptT any, S comparable, OptPT condFuncSetter2[OptT, S]](fns ...CondFunc2[S]) Opt[OptT] { 91 return func(p *opParam[OptT]) Opt[OptT] { 92 prevs := OptPT(&p.Param).condFn2(fns...) 93 return Cond2[OptT, S, OptPT](prevs...) 94 } 95 } 96 97 func Equal[T any, S any, PT eqaulSetter[T, S]](v S) Opt[T] { 98 return func(p *opParam[T]) Opt[T] { 99 prevs := PT(&p.Param).equal(v) 100 return Equal[T, S, PT](prevs) 101 } 102 } 103 104 // Filter ... FIlter implementation with type parameters 105 func Filter[T comparable](slice []T, condFn CondFunc2[T], opts ...Opt[FilterOpt[T]]) ([]T, error) { 106 107 opt, prev := MergeOpts(opts...) 108 defer prev(opt) 109 110 eq := new(T) 111 if opt.Param.equalObject != *eq { 112 innerFilter2(&slice, true, 113 func(t *T) bool { 114 return *t == opt.Param.equalObject 115 }) 116 } 117 if condFn != nil { 118 innerFilter2(&slice, true, condFn) 119 return slice, nil 120 } 121 122 if len(opt.Param.condFns) > 0 { 123 err := OldFilter(&slice, opt.Param.condFns...) 124 return slice, err 125 } 126 if len(opt.Param.condFns2) > 0 { 127 switch opt.Param.fVersion { 128 case 3: 129 innerFilter3(&slice, true, opt.Param.condFns2...) 130 case 4: 131 innerFilter4(&slice, true, opt.Param.condFns2...) 132 default: 133 innerFilter2(&slice, true, opt.Param.condFns2...) 134 } 135 return slice, nil 136 } 137 138 return slice, nil 139 } 140 141 func innerFilter2[T any](pslice *[]T, keep bool, funcs ...CondFunc2[T]) { 142 143 length := len(*pslice) 144 145 if length == 0 { 146 return 147 } 148 149 movelist := make([]int, length) 150 newIdx := 0 151 152 for i := 0; i < length; i++ { 153 allok := (true == keep) 154 for _, f := range funcs { 155 if !f(&(*pslice)[i]) { 156 allok = (false == keep) 157 } 158 } 159 160 if allok { 161 movelist[i] = newIdx 162 newIdx++ 163 } else { 164 movelist[i] = -1 165 } 166 } 167 168 if newIdx == length { 169 return 170 } 171 172 swap := reflect.Swapper(*pslice) 173 174 for i, v := range movelist { 175 if v != -1 { 176 swap(i, v) 177 } 178 } 179 180 (*pslice) = (*pslice)[:newIdx] 181 182 } 183 184 type filterRange struct { 185 Start int 186 End int 187 } 188 189 func innerFilter4[T comparable](pslice *[]T, keep bool, funcs ...CondFunc2[T]) { 190 191 slice := *pslice 192 length := len(*pslice) 193 194 if length == 0 { 195 return 196 } 197 198 skiplist := make([]filterRange, 0, length) 199 200 for i := 0; i < length; i++ { 201 allok := (true == keep) 202 for _, f := range funcs { 203 if !f(&(*pslice)[i]) { 204 allok = (false == keep) 205 } 206 } 207 if allok { 208 continue 209 } 210 211 if len(skiplist) == 0 { // add first 212 skiplist = append(skiplist, filterRange{i, i}) 213 continue 214 } 215 216 if skiplist[len(skiplist)-1].End+1 == i { 217 skiplist[len(skiplist)-1].End++ 218 continue 219 } 220 221 skiplist = append(skiplist, filterRange{i, i}) 222 } 223 224 // not perged 225 if len(skiplist) == length { 226 return 227 } 228 229 slices := make([][]T, 0) 230 for i, _ := range skiplist { 231 v := skiplist[i] 232 be := 0 233 if i > 0 { 234 be = skiplist[i-1].End + 1 235 } 236 if v.End == len(slice)-1 { 237 pv := skiplist[i-1] 238 slices = append(slices, slice[pv.End+1:v.Start:v.Start]) 239 240 continue 241 } 242 if be == 0 && v.Start == 0 { 243 continue 244 } 245 if len(slices) == 0 { 246 slices = append(slices, slice[be:v.Start]) 247 continue 248 } 249 slices = append(slices, slice[be:v.Start:v.Start]) 250 251 } 252 slice = Inject(slices, 253 func(old []T, e []T) (neo []T) { 254 if len(old) == 0 { 255 return e 256 } 257 neo = old 258 neo = neo[:len(neo)+len(e)] 259 copy(neo[len(old):], e) 260 return neo 261 }) 262 slices = nil 263 *pslice = slice 264 265 } 266 267 func innerFilter3[T comparable](pslice *[]T, keep bool, funcs ...CondFunc2[T]) { 268 269 slice := *pslice 270 length := len(*pslice) 271 272 if length == 0 { 273 return 274 } 275 276 skiplist := make([]filterRange, 0, length) 277 278 for i := 0; i < length; i++ { 279 allok := (true == keep) 280 for _, f := range funcs { 281 if !f(&(*pslice)[i]) { 282 allok = (false == keep) 283 } 284 } 285 if allok { 286 continue 287 } 288 289 if len(skiplist) == 0 { // add first 290 skiplist = append(skiplist, filterRange{i, i}) 291 continue 292 } 293 294 if skiplist[len(skiplist)-1].End+1 == i { 295 skiplist[len(skiplist)-1].End++ 296 continue 297 } 298 299 skiplist = append(skiplist, filterRange{i, i}) 300 } 301 302 // not perged 303 if len(skiplist) == length { 304 return 305 } 306 307 purgeCnt := 0 308 for i, _ := range skiplist { 309 v := skiplist[i] 310 end := v.End - purgeCnt + 1 311 if end == len(slice) { 312 slice = slice[0 : v.Start-purgeCnt] 313 break 314 } 315 316 slice = append(slice[0:v.Start-purgeCnt], slice[end:]...) 317 318 purgeCnt += v.End - v.Start + 1 319 } 320 321 *pslice = slice 322 323 }