github.com/kazu/loncha@v0.6.3/select.go (about)

     1  package loncha
     2  
     3  import (
     4  	"errors"
     5  	"reflect"
     6  	"sort"
     7  )
     8  
     9  var (
    10  	ERR_SLICE_TYPE           error = errors.New("parameter must be slice or pointer of slice")
    11  	ERR_POINTER_SLICE_TYPE   error = errors.New("parameter must be pointer of slice")
    12  	ERR_NOT_FOUND            error = errors.New("data is not found")
    13  	ERR_ELEMENT_INVALID_TYPE error = errors.New("slice element is invalid type")
    14  	ERR_INVALID_INDEX        error = errors.New("invalid index")
    15  )
    16  
    17  type CondFunc func(idx int) bool
    18  type CompareFunc func(i, j int) bool
    19  
    20  func slice2Reflect(slice interface{}) (reflect.Value, error) {
    21  	rv := reflect.ValueOf(slice)
    22  	if rv.Kind() != reflect.Ptr {
    23  		return reflect.ValueOf(nil), ERR_SLICE_TYPE
    24  	}
    25  
    26  	if rv.Elem().Kind() != reflect.Slice {
    27  		return reflect.ValueOf(nil), ERR_SLICE_TYPE
    28  	}
    29  	return rv, nil
    30  }
    31  
    32  func sliceElm2Reflect(slice interface{}) (reflect.Value, error) {
    33  	rv := reflect.ValueOf(slice)
    34  
    35  	if rv.Kind() == reflect.Slice {
    36  		return rv, nil
    37  	}
    38  
    39  	if rv.Kind() != reflect.Ptr {
    40  		return reflect.ValueOf(nil), ERR_POINTER_SLICE_TYPE
    41  	}
    42  
    43  	if rv.Elem().Kind() != reflect.Slice {
    44  		return reflect.ValueOf(nil), ERR_SLICE_TYPE
    45  	}
    46  	return rv.Elem(), nil
    47  }
    48  
    49  // Reverse ... Transforms an array such that the first element will become the last, the second element will become the second to last, etc.
    50  func Reverse(slice interface{}) {
    51  
    52  	sort.Slice(slice, func(i, j int) bool { return i > j })
    53  }
    54  
    55  // Select ... return all element on match of CondFunc
    56  func Select(slice interface{}, fn CondFunc) (interface{}, error) {
    57  
    58  	rv, err := sliceElm2Reflect(slice)
    59  
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	newSlice := reflect.MakeSlice(rv.Type(), rv.Len(), rv.Cap())
    64  
    65  	reflect.Copy(newSlice, rv)
    66  
    67  	ptr := reflect.New(newSlice.Type())
    68  	ptr.Elem().Set(newSlice)
    69  
    70  	filter(ptr, fn)
    71  
    72  	return ptr.Elem().Interface(), nil
    73  }
    74  
    75  // OldFilter ... OldFilter element with mached funcs
    76  // Deprecated:  should use FIlter
    77  func OldFilter(slice interface{}, funcs ...CondFunc) error {
    78  
    79  	rv, err := slice2Reflect(slice)
    80  	if err != nil {
    81  		return err
    82  	}
    83  
    84  	filter(rv, funcs...)
    85  	return nil
    86  }
    87  
    88  // Delete ... Delete element with mached funcs
    89  func Delete(slice interface{}, funcs ...CondFunc) error {
    90  	rv, err := slice2Reflect(slice)
    91  	if err != nil {
    92  		return err
    93  	}
    94  
    95  	innterFilter(rv, false, funcs...)
    96  	return nil
    97  }
    98  
    99  func filter(pRv reflect.Value, funcs ...CondFunc) {
   100  
   101  	innterFilter(pRv, true, funcs...)
   102  }
   103  
   104  func innterFilter(pRv reflect.Value, keep bool, funcs ...CondFunc) {
   105  
   106  	rv := pRv.Elem()
   107  
   108  	length := rv.Len()
   109  	if length == 0 {
   110  		return
   111  	}
   112  
   113  	movelist := make([]int, length)
   114  	newIdx := 0
   115  
   116  	for i := 0; i < length; i++ {
   117  		allok := (true == keep)
   118  		for _, f := range funcs {
   119  			if !f(i) {
   120  				allok = (false == keep)
   121  			}
   122  		}
   123  
   124  		if allok {
   125  			movelist[i] = newIdx
   126  			newIdx++
   127  		} else {
   128  			movelist[i] = -1
   129  		}
   130  	}
   131  
   132  	if newIdx == length {
   133  		return
   134  	}
   135  
   136  	swap := reflect.Swapper(pRv.Elem().Interface())
   137  
   138  	for i, v := range movelist {
   139  		if v != -1 {
   140  			swap(i, v)
   141  		}
   142  	}
   143  
   144  	pRv.Elem().SetLen(newIdx)
   145  
   146  }