github.com/sridharv/stencil@v0.0.0-20170626103218-a81b4a7626a1/std/slice/slice.go (about)

     1  // Package slice implements operations on slices.
     2  //
     3  // All operations act on slices of T. Use stencil to specialise to a type.
     4  //
     5  // For example, in order to use a string version of this package, import it as
     6  //
     7  //	import (
     8  //		str_slice "github.com/sridharv/stencil/std/slice/T/string"
     9  //	)
    10  //
    11  // and run stencil on the importing package.
    12  package slice
    13  
    14  import (
    15  	"reflect"
    16  	"sort"
    17  )
    18  
    19  type T interface{}
    20  
    21  // Any returns true if fn is true for any elements of s
    22  func Any(s []T, fn func(T) bool) bool {
    23  	return IndexFunc(s, fn) != -1
    24  }
    25  
    26  // Any returns true if fn is true for all elements of s
    27  func All(s []T, fn func(T) bool) bool {
    28  	return IndexFunc(s, func(e T) bool { return !fn(e) }) == -1
    29  }
    30  
    31  // IndexFunc returns the index of the first element for which fn returns true.
    32  // If no such element exists it returns -1.
    33  func IndexFunc(s []T, fn func(T) bool) int {
    34  	for i, e := range s {
    35  		if fn(e) {
    36  			return i
    37  		}
    38  	}
    39  	return -1
    40  }
    41  
    42  // Index returns the first index of e in s
    43  func Index(s []T, e T) int {
    44  	return IndexFunc(s, func(el T) bool { return el == e })
    45  }
    46  
    47  var (
    48  	zero    T
    49  	needsGC = typeNeedsGC(reflect.TypeOf(zero))
    50  )
    51  
    52  func typeNeedsGC(t reflect.Type) bool {
    53  	switch t.Kind() {
    54  	case reflect.Map, reflect.Interface, reflect.Ptr, reflect.Chan, reflect.Slice:
    55  		return true
    56  	case reflect.Struct:
    57  		n := t.NumField()
    58  		for i := 0; i < n; i++ {
    59  			if typeNeedsGC(t.Field(i).Type) {
    60  				return true
    61  			}
    62  		}
    63  		return false
    64  	default:
    65  		return false
    66  	}
    67  }
    68  
    69  // The following are taken from https://github.com/golang/go/wiki/SliceTricks
    70  //
    71  // Cut, Delete, DeleteUnordered, Push, Pop, Reverse, Insert, InsertSlice
    72  
    73  // Cut removes all elements between i and j.
    74  func Cut(a []T, i, j int) []T {
    75  	if !needsGC {
    76  		return append(a[:i], a[j:]...)
    77  	}
    78  	copy(a[i:], a[j:])
    79  	for k, n := len(a)-j+i, len(a); k < n; k++ {
    80  		a[k] = zero
    81  	}
    82  	return a[:len(a)-j+i]
    83  }
    84  
    85  // Delete removes the ith element from a and returns the resulting slice.
    86  func Delete(a []T, i int) []T {
    87  	return Cut(a, i, i+1)
    88  }
    89  
    90  // DeleteUnordered removes the ith element in a, without preserving order. It can be faster that
    91  // Delete as it results in much fewer copies.
    92  func DeleteUnordered(a []T, i int) []T {
    93  	a[i] = a[len(a)-1]
    94  	a[len(a)-1] = zero
    95  	return a[:len(a)-1]
    96  }
    97  
    98  // Insert inserts v in a at index i and returns the new slice
    99  func Insert(a []T, v T, i int) []T {
   100  	a = append(a, zero)
   101  	copy(a[i+1:], a[i:])
   102  	a[i] = v
   103  	return a
   104  }
   105  
   106  // InsertSlice inserts v into a at index i and returns the new slice
   107  func InsertSlice(a []T, v []T, i int) []T {
   108  	return append(a[:i], append(v, a[i:]...)...)
   109  }
   110  
   111  // Push pushes v on to the end of a, returning an updated slice.
   112  func Push(a []T, v T) []T {
   113  	return append(a, v)
   114  }
   115  
   116  // Pop removes the last element from a, returning an updating slice
   117  func Pop(a []T) (T, []T) {
   118  	return a[len(a)-1], a[:len(a)-1]
   119  }
   120  
   121  // Reverse reverses a in place.
   122  func Reverse(a []T) {
   123  	for l, r := 0, len(a)-1; l < r; l, r = l+1, r-1 {
   124  		a[l], a[r] = a[r], a[l]
   125  	}
   126  }
   127  
   128  type sorter struct {
   129  	a    []T
   130  	less func(a, b T) bool
   131  }
   132  
   133  func (s *sorter) Len() int           { return len(s.a) }
   134  func (s *sorter) Less(i, j int) bool { return s.less(s.a[i], s.a[j]) }
   135  func (s *sorter) Swap(i, j int)      { s.a[i], s.a[j] = s.a[j], s.a[i] }
   136  
   137  // Sort sorts a using the comparison function less.
   138  func Sort(a []T, less func(a, b T) bool) {
   139  	sort.Sort(&sorter{a, less})
   140  }
   141  
   142  // SortStable sorts a stably using the comparison function less.
   143  func SortStable(a []T, less func(a, b T) bool) {
   144  	sort.Stable(&sorter{a, less})
   145  }
   146  
   147  // Flatten returns a slice created by adding each element of each slice in slices
   148  func Flatten(slices ...[]T) []T {
   149  	var a []T
   150  	for _, s := range slices {
   151  		a = append(a, s...)
   152  	}
   153  	return a
   154  }