github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/base/bslice/bslice.go (about)

     1  package bslice
     2  
     3  import (
     4  	"github.com/songzhibin97/go-baseutils/base/btype"
     5  )
     6  
     7  // copied github.com/golang/exp/tree/master/slices
     8  
     9  // Equal reports whether two slices are equal: the same length and all
    10  // elements equal. If the lengths are different, Equal returns false.
    11  // Otherwise, the elements are compared in increasing index order, and the
    12  // comparison stops at the first unequal pair.
    13  // Floating point NaNs are not considered equal.
    14  func Equal[E comparable](s1, s2 []E) bool {
    15  	if len(s1) != len(s2) {
    16  		return false
    17  	}
    18  	for i := range s1 {
    19  		if s1[i] != s2[i] {
    20  			return false
    21  		}
    22  	}
    23  	return true
    24  }
    25  
    26  // EqualFunc reports whether two slices are equal using a comparison
    27  // function on each pair of elements. If the lengths are different,
    28  // EqualFunc returns false. Otherwise, the elements are compared in
    29  // increasing index order, and the comparison stops at the first index
    30  // for which eq returns false.
    31  func EqualFunc[E1, E2 any](s1 []E1, s2 []E2, eq func(E1, E2) bool) bool {
    32  	if len(s1) != len(s2) {
    33  		return false
    34  	}
    35  	for i, v1 := range s1 {
    36  		v2 := s2[i]
    37  		if !eq(v1, v2) {
    38  			return false
    39  		}
    40  	}
    41  	return true
    42  }
    43  
    44  // Compare compares the elements of s1 and s2.
    45  // The elements are compared sequentially, starting at index 0,
    46  // until one element is not equal to the other.
    47  // The result of comparing the first non-matching elements is returned.
    48  // If both slices are equal until one of them ends, the shorter slice is
    49  // considered less than the longer one.
    50  // The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2.
    51  // Comparisons involving floating point NaNs are ignored.
    52  func Compare[E btype.Ordered](s1, s2 []E) int {
    53  	s2len := len(s2)
    54  	for i, v1 := range s1 {
    55  		if i >= s2len {
    56  			return +1
    57  		}
    58  		v2 := s2[i]
    59  		switch {
    60  		case v1 < v2:
    61  			return -1
    62  		case v1 > v2:
    63  			return +1
    64  		}
    65  	}
    66  	if len(s1) < s2len {
    67  		return -1
    68  	}
    69  	return 0
    70  }
    71  
    72  // CompareFunc is like Compare but uses a comparison function
    73  // on each pair of elements. The elements are compared in increasing
    74  // index order, and the comparisons stop after the first time cmp
    75  // returns non-zero.
    76  // The result is the first non-zero result of cmp; if cmp always
    77  // returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2),
    78  // and +1 if len(s1) > len(s2).
    79  func CompareFunc[E1, E2 any](s1 []E1, s2 []E2, cmp func(E1, E2) int) int {
    80  	s2len := len(s2)
    81  	for i, v1 := range s1 {
    82  		if i >= s2len {
    83  			return +1
    84  		}
    85  		v2 := s2[i]
    86  		if c := cmp(v1, v2); c != 0 {
    87  			return c
    88  		}
    89  	}
    90  	if len(s1) < s2len {
    91  		return -1
    92  	}
    93  	return 0
    94  }
    95  
    96  // Index returns the index of the first occurrence of v in s,
    97  // or -1 if not present.
    98  func Index[E comparable](s []E, v E) int {
    99  	for i := range s {
   100  		if v == s[i] {
   101  			return i
   102  		}
   103  	}
   104  	return -1
   105  }
   106  
   107  // IndexFunc returns the first index i satisfying f(s[i]),
   108  // or -1 if none do.
   109  func IndexFunc[E any](s []E, f func(E) bool) int {
   110  	for i := range s {
   111  		if f(s[i]) {
   112  			return i
   113  		}
   114  	}
   115  	return -1
   116  }
   117  
   118  // Contains reports whether v is present in s.
   119  func Contains[E comparable](s []E, v E) bool {
   120  	return Index(s, v) >= 0
   121  }
   122  
   123  // ContainsFunc reports whether at least one
   124  // element e of s satisfies f(e).
   125  func ContainsFunc[E any](s []E, f func(E) bool) bool {
   126  	return IndexFunc(s, f) >= 0
   127  }
   128  
   129  // Insert inserts the values v... into s at index i,
   130  // returning the modified slice.
   131  // In the returned slice r, r[i] == v[0].
   132  // Insert panics if i is out of range.
   133  // This function is O(len(s) + len(v)).
   134  func Insert[S ~[]E, E any](s S, i int, v ...E) S {
   135  	tot := len(s) + len(v)
   136  	if tot <= cap(s) {
   137  		s2 := s[:tot]
   138  		copy(s2[i+len(v):], s[i:])
   139  		copy(s2[i:], v)
   140  		return s2
   141  	}
   142  	s2 := make(S, tot)
   143  	copy(s2, s[:i])
   144  	copy(s2[i:], v)
   145  	copy(s2[i+len(v):], s[i:])
   146  	return s2
   147  }
   148  
   149  // Delete removes the elements s[i:j] from s, returning the modified slice.
   150  // Delete panics if s[i:j] is not a valid slice of s.
   151  // Delete modifies the contents of the slice s; it does not create a new slice.
   152  // Delete is O(len(s)-j), so if many items must be deleted, it is better to
   153  // make a single call deleting them all together than to delete one at a time.
   154  // Delete might not modify the elements s[len(s)-(j-i):len(s)]. If those
   155  // elements contain pointers you might consider zeroing those elements so that
   156  // objects they reference can be garbage collected.
   157  func Delete[S ~[]E, E any](s S, i, j int) S {
   158  	_ = s[i:j] // bounds check
   159  
   160  	return append(s[:i], s[j:]...)
   161  }
   162  
   163  // Replace replaces the elements s[i:j] by the given v, and returns the
   164  // modified slice. Replace panics if s[i:j] is not a valid slice of s.
   165  func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
   166  	_ = s[i:j] // verify that i:j is a valid subslice
   167  	tot := len(s[:i]) + len(v) + len(s[j:])
   168  	if tot <= cap(s) {
   169  		s2 := s[:tot]
   170  		copy(s2[i+len(v):], s[j:])
   171  		copy(s2[i:], v)
   172  		return s2
   173  	}
   174  	s2 := make(S, tot)
   175  	copy(s2, s[:i])
   176  	copy(s2[i:], v)
   177  	copy(s2[i+len(v):], s[j:])
   178  	return s2
   179  }
   180  
   181  // Clone returns a copy of the slice.
   182  // The elements are copied using assignment, so this is a shallow clone.
   183  func Clone[S ~[]E, E any](s S) S {
   184  	// Preserve nil in case it matters.
   185  	if s == nil {
   186  		return nil
   187  	}
   188  	return append(S([]E{}), s...)
   189  }
   190  
   191  // Compact replaces consecutive runs of equal elements with a single copy.
   192  // This is like the uniq command found on Unix.
   193  // Compact modifies the contents of the slice s; it does not create a new slice.
   194  // When Compact discards m elements in total, it might not modify the elements
   195  // s[len(s)-m:len(s)]. If those elements contain pointers you might consider
   196  // zeroing those elements so that objects they reference can be garbage collected.
   197  func Compact[S ~[]E, E comparable](s S) S {
   198  	if len(s) < 2 {
   199  		return s
   200  	}
   201  	i := 1
   202  	for k := 1; k < len(s); k++ {
   203  		if s[k] != s[k-1] {
   204  			if i != k {
   205  				s[i] = s[k]
   206  			}
   207  			i++
   208  		}
   209  	}
   210  	return s[:i]
   211  }
   212  
   213  // CompactFunc is like Compact but uses a comparison function.
   214  func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
   215  	if len(s) < 2 {
   216  		return s
   217  	}
   218  	i := 1
   219  	for k := 1; k < len(s); k++ {
   220  		if !eq(s[k], s[k-1]) {
   221  			if i != k {
   222  				s[i] = s[k]
   223  			}
   224  			i++
   225  		}
   226  	}
   227  	return s[:i]
   228  }
   229  
   230  // Grow increases the slice's capacity, if necessary, to guarantee space for
   231  // another n elements. After Grow(n), at least n elements can be appended
   232  // to the slice without another allocation. If n is negative or too large to
   233  // allocate the memory, Grow panics.
   234  func Grow[S ~[]E, E any](s S, n int) S {
   235  	if n < 0 {
   236  		panic("cannot be negative")
   237  	}
   238  	if n -= cap(s) - len(s); n > 0 {
   239  		// TODO(https://go.dev/issue/53888): Make using []E instead of S
   240  		// to workaround a compiler bug where the runtime.growslice optimization
   241  		// does not take effect. Revert when the compiler is fixed.
   242  		s = append([]E(s)[:cap(s)], make([]E, n)...)[:len(s)]
   243  	}
   244  	return s
   245  }
   246  
   247  // Clip removes unused capacity from the slice, returning s[:len(s):len(s)].
   248  func Clip[S ~[]E, E any](s S) S {
   249  	return s[:len(s):len(s)]
   250  }