|
| 1 | +// Copyright 2021 The Go Authors. All rights reserved. |
| 2 | +// Use of this source code is governed by a BSD-style |
| 3 | +// license that can be found in the LICENSE file. |
| 4 | + |
| 5 | +// Package slices defines various functions useful with slices of any type. |
| 6 | +package slices |
| 7 | + |
| 8 | +// Equal reports whether two slices are equal: the same length and all |
| 9 | +// elements equal. If the lengths are different, Equal returns false. |
| 10 | +// Otherwise, the elements are compared in increasing index order, and the |
| 11 | +// comparison stops at the first unequal pair. |
| 12 | +// Floating point NaNs are not considered equal. |
| 13 | +func Equal[E comparable](s1, s2 []E) bool { |
| 14 | + if len(s1) != len(s2) { |
| 15 | + return false |
| 16 | + } |
| 17 | + for i := range s1 { |
| 18 | + if s1[i] != s2[i] { |
| 19 | + return false |
| 20 | + } |
| 21 | + } |
| 22 | + return true |
| 23 | +} |
| 24 | + |
| 25 | +// EqualFunc reports whether two slices are equal using a comparison |
| 26 | +// function on each pair of elements. If the lengths are different, |
| 27 | +// EqualFunc returns false. Otherwise, the elements are compared in |
| 28 | +// increasing index order, and the comparison stops at the first index |
| 29 | +// for which eq returns false. |
| 30 | +func EqualFunc[E1, E2 any](s1 []E1, s2 []E2, eq func(E1, E2) bool) bool { |
| 31 | + if len(s1) != len(s2) { |
| 32 | + return false |
| 33 | + } |
| 34 | + for i, v1 := range s1 { |
| 35 | + v2 := s2[i] |
| 36 | + if !eq(v1, v2) { |
| 37 | + return false |
| 38 | + } |
| 39 | + } |
| 40 | + return true |
| 41 | +} |
| 42 | + |
| 43 | +// Index returns the index of the first occurrence of v in s, |
| 44 | +// or -1 if not present. |
| 45 | +func Index[E comparable](s []E, v E) int { |
| 46 | + for i, vs := range s { |
| 47 | + if v == vs { |
| 48 | + return i |
| 49 | + } |
| 50 | + } |
| 51 | + return -1 |
| 52 | +} |
| 53 | + |
| 54 | +// IndexFunc returns the first index i satisfying f(s[i]), |
| 55 | +// or -1 if none do. |
| 56 | +func IndexFunc[E any](s []E, f func(E) bool) int { |
| 57 | + for i, v := range s { |
| 58 | + if f(v) { |
| 59 | + return i |
| 60 | + } |
| 61 | + } |
| 62 | + return -1 |
| 63 | +} |
| 64 | + |
| 65 | +// Contains reports whether v is present in s. |
| 66 | +func Contains[E comparable](s []E, v E) bool { |
| 67 | + return Index(s, v) >= 0 |
| 68 | +} |
| 69 | + |
| 70 | +// ContainsFunc reports whether at least one |
| 71 | +// element e of s satisfies f(e). |
| 72 | +func ContainsFunc[E any](s []E, f func(E) bool) bool { |
| 73 | + return IndexFunc(s, f) >= 0 |
| 74 | +} |
| 75 | + |
| 76 | +// Insert inserts the values v... into s at index i, |
| 77 | +// returning the modified slice. |
| 78 | +// The elements at s[i:] are shifted up to make room. |
| 79 | +// In the returned slice r, r[i] == v[0], |
| 80 | +// and r[i+len(v)] == value originally at r[i]. |
| 81 | +// Insert panics if i is out of range. |
| 82 | +// This function is O(len(s) + len(v)). |
| 83 | +func Insert[S ~[]E, E any](s S, i int, v ...E) S { |
| 84 | + tot := len(s) + len(v) |
| 85 | + if tot <= cap(s) { |
| 86 | + s2 := s[:tot] |
| 87 | + copy(s2[i+len(v):], s[i:]) |
| 88 | + copy(s2[i:], v) |
| 89 | + return s2 |
| 90 | + } |
| 91 | + s2 := make(S, tot) |
| 92 | + copy(s2, s[:i]) |
| 93 | + copy(s2[i:], v) |
| 94 | + copy(s2[i+len(v):], s[i:]) |
| 95 | + return s2 |
| 96 | +} |
| 97 | + |
| 98 | +// Delete removes the elements s[i:j] from s, returning the modified slice. |
| 99 | +// Delete panics if s[i:j] is not a valid slice of s. |
| 100 | +// Delete modifies the contents of the slice s; it does not create a new slice. |
| 101 | +// Delete is O(len(s)-j), so if many items must be deleted, it is better to |
| 102 | +// make a single call deleting them all together than to delete one at a time. |
| 103 | +// Delete might not modify the elements s[len(s)-(j-i):len(s)]. If those |
| 104 | +// elements contain pointers you might consider zeroing those elements so that |
| 105 | +// objects they reference can be garbage collected. |
| 106 | +func Delete[S ~[]E, E any](s S, i, j int) S { |
| 107 | + _ = s[i:j] // bounds check |
| 108 | + |
| 109 | + return append(s[:i], s[j:]...) |
| 110 | +} |
| 111 | + |
| 112 | +// Replace replaces the elements s[i:j] by the given v, and returns the |
| 113 | +// modified slice. Replace panics if s[i:j] is not a valid slice of s. |
| 114 | +func Replace[S ~[]E, E any](s S, i, j int, v ...E) S { |
| 115 | + _ = s[i:j] // verify that i:j is a valid subslice |
| 116 | + tot := len(s[:i]) + len(v) + len(s[j:]) |
| 117 | + if tot <= cap(s) { |
| 118 | + s2 := s[:tot] |
| 119 | + copy(s2[i+len(v):], s[j:]) |
| 120 | + copy(s2[i:], v) |
| 121 | + return s2 |
| 122 | + } |
| 123 | + s2 := make(S, tot) |
| 124 | + copy(s2, s[:i]) |
| 125 | + copy(s2[i:], v) |
| 126 | + copy(s2[i+len(v):], s[j:]) |
| 127 | + return s2 |
| 128 | +} |
| 129 | + |
| 130 | +// Clone returns a copy of the slice. |
| 131 | +// The elements are copied using assignment, so this is a shallow clone. |
| 132 | +func Clone[S ~[]E, E any](s S) S { |
| 133 | + // Preserve nil in case it matters. |
| 134 | + if s == nil { |
| 135 | + return nil |
| 136 | + } |
| 137 | + return append(S([]E{}), s...) |
| 138 | +} |
| 139 | + |
| 140 | +// Compact replaces consecutive runs of equal elements with a single copy. |
| 141 | +// This is like the uniq command found on Unix. |
| 142 | +// Compact modifies the contents of the slice s; it does not create a new slice. |
| 143 | +// When Compact discards m elements in total, it might not modify the elements |
| 144 | +// s[len(s)-m:len(s)]. If those elements contain pointers you might consider |
| 145 | +// zeroing those elements so that objects they reference can be garbage collected. |
| 146 | +func Compact[S ~[]E, E comparable](s S) S { |
| 147 | + if len(s) < 2 { |
| 148 | + return s |
| 149 | + } |
| 150 | + i := 1 |
| 151 | + last := s[0] |
| 152 | + for _, v := range s[1:] { |
| 153 | + if v != last { |
| 154 | + s[i] = v |
| 155 | + i++ |
| 156 | + last = v |
| 157 | + } |
| 158 | + } |
| 159 | + return s[:i] |
| 160 | +} |
| 161 | + |
| 162 | +// CompactFunc is like Compact but uses a comparison function. |
| 163 | +func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { |
| 164 | + if len(s) < 2 { |
| 165 | + return s |
| 166 | + } |
| 167 | + i := 1 |
| 168 | + last := s[0] |
| 169 | + for _, v := range s[1:] { |
| 170 | + if !eq(v, last) { |
| 171 | + s[i] = v |
| 172 | + i++ |
| 173 | + last = v |
| 174 | + } |
| 175 | + } |
| 176 | + return s[:i] |
| 177 | +} |
| 178 | + |
| 179 | +// Grow increases the slice's capacity, if necessary, to guarantee space for |
| 180 | +// another n elements. After Grow(n), at least n elements can be appended |
| 181 | +// to the slice without another allocation. If n is negative or too large to |
| 182 | +// allocate the memory, Grow panics. |
| 183 | +func Grow[S ~[]E, E any](s S, n int) S { |
| 184 | + if n < 0 { |
| 185 | + panic("cannot be negative") |
| 186 | + } |
| 187 | + if n -= cap(s) - len(s); n > 0 { |
| 188 | + s = append(s[:cap(s)], make([]E, n)...)[:len(s)] |
| 189 | + } |
| 190 | + return s |
| 191 | +} |
| 192 | + |
| 193 | +// Clip removes unused capacity from the slice, returning s[:len(s):len(s)]. |
| 194 | +func Clip[S ~[]E, E any](s S) S { |
| 195 | + return s[:len(s):len(s)] |
| 196 | +} |
0 commit comments