Skip to content

Commit 1e9925f

Browse files
ianlancetaylorgopherbot
authored andcommitted
slices: new package
This copies parts of x/exp/slices into the standard library. We omit all functions that depend on constraints.Ordered, and the Func variants of all such functions. In particular this omits the various Sort and Search functions. Fixes #57433 Change-Id: I3c28f4c2e6bd1e3c9ad70e120a0dd68065388f77 Reviewed-on: https://go-review.googlesource.com/c/go/+/467417 Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Eli Bendersky <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]>
1 parent 790f250 commit 1e9925f

File tree

5 files changed

+816
-1
lines changed

5 files changed

+816
-1
lines changed

api/next/57433.txt

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
pkg slices, func Clip[$0 interface{ ~[]$1 }, $1 interface{}]($0) $0 #57433
2+
pkg slices, func Clone[$0 interface{ ~[]$1 }, $1 interface{}]($0) $0 #57433
3+
pkg slices, func CompactFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1, $1) bool) $0 #57433
4+
pkg slices, func Compact[$0 interface{ ~[]$1 }, $1 comparable]($0) $0 #57433
5+
pkg slices, func ContainsFunc[$0 interface{}]([]$0, func($0) bool) bool #57433
6+
pkg slices, func Contains[$0 comparable]([]$0, $0) bool #57433
7+
pkg slices, func Delete[$0 interface{ ~[]$1 }, $1 interface{}]($0, int, int) $0 #57433
8+
pkg slices, func EqualFunc[$0 interface{}, $1 interface{}]([]$0, []$1, func($0, $1) bool) bool #57433
9+
pkg slices, func Equal[$0 comparable]([]$0, []$0) bool #57433
10+
pkg slices, func Grow[$0 interface{ ~[]$1 }, $1 interface{}]($0, int) $0 #57433
11+
pkg slices, func IndexFunc[$0 interface{}]([]$0, func($0) bool) int #57433
12+
pkg slices, func Index[$0 comparable]([]$0, $0) int #57433
13+
pkg slices, func Insert[$0 interface{ ~[]$1 }, $1 interface{}]($0, int, ...$1) $0 #57433
14+
pkg slices, func Replace[$0 interface{ ~[]$1 }, $1 interface{}]($0, int, int, ...$1) $0 #57433

src/go/build/deps_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ var depsRules = `
4545
internal/cpu, internal/goarch,
4646
internal/goexperiment, internal/goos,
4747
internal/goversion, internal/nettrace, internal/platform,
48-
maps, unicode/utf8, unicode/utf16, unicode,
48+
maps, slices, unicode/utf8, unicode/utf16, unicode,
4949
unsafe;
5050
5151
# These packages depend only on internal/goarch and unsafe.

src/go/doc/comment/std.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/slices/slices.go

+196
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
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

Comments
 (0)