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 }