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  }