Skip to content

Commit 0a48e5c

Browse files
ianlancetaylorgopherbot
authored andcommitted
slices: consistently use S ~[]E
Make all functions use a constraint S ~[]E even if they don't return the slice type. This makes explicitly instantiating the functions more consistent: you don't have to remember which take ~[]E and which do not. It also permits inferring the type when passing one of these functions to some other function that is using a named slice type. Fixes #60546 Change-Id: Ib3435255d0177fdbf03455ae527d08599b1ce012 Reviewed-on: https://go-review.googlesource.com/c/go/+/502955 Reviewed-by: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Axel Wagner <[email protected]> Reviewed-by: Eli Bendersky <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]>
1 parent 01b649b commit 0a48e5c

File tree

4 files changed

+66
-46
lines changed

4 files changed

+66
-46
lines changed

api/go1.21.txt

+20-20
Original file line numberDiff line numberDiff line change
@@ -365,35 +365,35 @@ pkg runtime, method (*Pinner) Pin(interface{}) #46787
365365
pkg runtime, method (*Pinner) Unpin() #46787
366366
pkg runtime, type PanicNilError struct #25448
367367
pkg runtime, type Pinner struct #46787
368-
pkg slices, func BinarySearch[$0 cmp.Ordered]([]$0, $0) (int, bool) #60091
369-
pkg slices, func BinarySearchFunc[$0 interface{}, $1 interface{}]([]$0, $1, func($0, $1) int) (int, bool) #60091
368+
pkg slices, func BinarySearch[$0 interface{ ~[]$1 }, $1 cmp.Ordered]($0, $1) (int, bool) #60091
369+
pkg slices, func BinarySearchFunc[$0 interface{ ~[]$1 }, $1 interface{}, $2 interface{}]($0, $2, func($1, $2) int) (int, bool) #60091
370370
pkg slices, func Clip[$0 interface{ ~[]$1 }, $1 interface{}]($0) $0 #57433
371371
pkg slices, func Clone[$0 interface{ ~[]$1 }, $1 interface{}]($0) $0 #57433
372372
pkg slices, func Compact[$0 interface{ ~[]$1 }, $1 comparable]($0) $0 #57433
373373
pkg slices, func CompactFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1, $1) bool) $0 #57433
374-
pkg slices, func Compare[$0 cmp.Ordered]([]$0, []$0) int #60091
375-
pkg slices, func CompareFunc[$0 interface{}, $1 interface{}]([]$0, []$1, func($0, $1) int) int #60091
376-
pkg slices, func Contains[$0 comparable]([]$0, $0) bool #57433
377-
pkg slices, func ContainsFunc[$0 interface{}]([]$0, func($0) bool) bool #57433
374+
pkg slices, func Compare[$0 interface{ ~[]$1 }, $1 cmp.Ordered]($0, $0) int #60091
375+
pkg slices, func CompareFunc[$0 interface{ ~[]$2 }, $1 interface{ ~[]$3 }, $2 interface{}, $3 interface{}]($0, $1, func($2, $3) int) int #60091
376+
pkg slices, func Contains[$0 interface{ ~[]$1 }, $1 comparable]($0, $1) bool #57433
377+
pkg slices, func ContainsFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1) bool) bool #57433
378378
pkg slices, func Delete[$0 interface{ ~[]$1 }, $1 interface{}]($0, int, int) $0 #57433
379379
pkg slices, func DeleteFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1) bool) $0 #54768
380-
pkg slices, func Equal[$0 comparable]([]$0, []$0) bool #57433
381-
pkg slices, func EqualFunc[$0 interface{}, $1 interface{}]([]$0, []$1, func($0, $1) bool) bool #57433
380+
pkg slices, func Equal[$0 interface{ ~[]$1 }, $1 comparable]($0, $0) bool #57433
381+
pkg slices, func EqualFunc[$0 interface{ ~[]$2 }, $1 interface{ ~[]$3 }, $2 interface{}, $3 interface{}]($0, $1, func($2, $3) bool) bool #57433
382382
pkg slices, func Grow[$0 interface{ ~[]$1 }, $1 interface{}]($0, int) $0 #57433
383-
pkg slices, func Index[$0 comparable]([]$0, $0) int #57433
384-
pkg slices, func IndexFunc[$0 interface{}]([]$0, func($0) bool) int #57433
383+
pkg slices, func Index[$0 interface{ ~[]$1 }, $1 comparable]($0, $1) int #57433
384+
pkg slices, func IndexFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1) bool) int #57433
385385
pkg slices, func Insert[$0 interface{ ~[]$1 }, $1 interface{}]($0, int, ...$1) $0 #57433
386-
pkg slices, func IsSorted[$0 cmp.Ordered]([]$0) bool #60091
387-
pkg slices, func IsSortedFunc[$0 interface{}]([]$0, func($0, $0) int) bool #60091
388-
pkg slices, func Max[$0 cmp.Ordered]([]$0) $0 #60091
389-
pkg slices, func MaxFunc[$0 interface{}]([]$0, func($0, $0) int) $0 #60091
390-
pkg slices, func Min[$0 cmp.Ordered]([]$0) $0 #60091
391-
pkg slices, func MinFunc[$0 interface{}]([]$0, func($0, $0) int) $0 #60091
386+
pkg slices, func IsSorted[$0 interface{ ~[]$1 }, $1 cmp.Ordered]($0) bool #60091
387+
pkg slices, func IsSortedFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1, $1) int) bool #60091
388+
pkg slices, func Max[$0 interface{ ~[]$1 }, $1 cmp.Ordered]($0) $1 #60091
389+
pkg slices, func MaxFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1, $1) int) $1 #60091
390+
pkg slices, func Min[$0 interface{ ~[]$1 }, $1 cmp.Ordered]($0) $1 #60091
391+
pkg slices, func MinFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1, $1) int) $1 #60091
392392
pkg slices, func Replace[$0 interface{ ~[]$1 }, $1 interface{}]($0, int, int, ...$1) $0 #57433
393-
pkg slices, func Reverse[$0 interface{}]([]$0) #58565
394-
pkg slices, func Sort[$0 cmp.Ordered]([]$0) #60091
395-
pkg slices, func SortFunc[$0 interface{}]([]$0, func($0, $0) int) #60091
396-
pkg slices, func SortStableFunc[$0 interface{}]([]$0, func($0, $0) int) #60091
393+
pkg slices, func Reverse[$0 interface{ ~[]$1 }, $1 interface{}]($0) #58565
394+
pkg slices, func Sort[$0 interface{ ~[]$1 }, $1 cmp.Ordered]($0) #60091
395+
pkg slices, func SortFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1, $1) int) #60091
396+
pkg slices, func SortStableFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1, $1) int) #60091
397397
pkg strings, func ContainsFunc(string, func(int32) bool) bool #54386
398398
pkg sync, func OnceFunc(func()) func() #56102
399399
pkg sync, func OnceValue[$0 interface{}](func() $0) func() $0 #56102

src/slices/slices.go

+14-14
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
// Otherwise, the elements are compared in increasing index order, and the
1616
// comparison stops at the first unequal pair.
1717
// Floating point NaNs are not considered equal.
18-
func Equal[E comparable](s1, s2 []E) bool {
18+
func Equal[S ~[]E, E comparable](s1, s2 S) bool {
1919
if len(s1) != len(s2) {
2020
return false
2121
}
@@ -32,7 +32,7 @@ func Equal[E comparable](s1, s2 []E) bool {
3232
// EqualFunc returns false. Otherwise, the elements are compared in
3333
// increasing index order, and the comparison stops at the first index
3434
// for which eq returns false.
35-
func EqualFunc[E1, E2 any](s1 []E1, s2 []E2, eq func(E1, E2) bool) bool {
35+
func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool {
3636
if len(s1) != len(s2) {
3737
return false
3838
}
@@ -52,7 +52,7 @@ func EqualFunc[E1, E2 any](s1 []E1, s2 []E2, eq func(E1, E2) bool) bool {
5252
// If both slices are equal until one of them ends, the shorter slice is
5353
// considered less than the longer one.
5454
// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2.
55-
func Compare[E cmp.Ordered](s1, s2 []E) int {
55+
func Compare[S ~[]E, E cmp.Ordered](s1, s2 S) int {
5656
for i, v1 := range s1 {
5757
if i >= len(s2) {
5858
return +1
@@ -73,7 +73,7 @@ func Compare[E cmp.Ordered](s1, s2 []E) int {
7373
// The result is the first non-zero result of cmp; if cmp always
7474
// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2),
7575
// and +1 if len(s1) > len(s2).
76-
func CompareFunc[E1, E2 any](s1 []E1, s2 []E2, cmp func(E1, E2) int) int {
76+
func CompareFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, cmp func(E1, E2) int) int {
7777
for i, v1 := range s1 {
7878
if i >= len(s2) {
7979
return +1
@@ -91,7 +91,7 @@ func CompareFunc[E1, E2 any](s1 []E1, s2 []E2, cmp func(E1, E2) int) int {
9191

9292
// Index returns the index of the first occurrence of v in s,
9393
// or -1 if not present.
94-
func Index[E comparable](s []E, v E) int {
94+
func Index[S ~[]E, E comparable](s S, v E) int {
9595
for i := range s {
9696
if v == s[i] {
9797
return i
@@ -102,7 +102,7 @@ func Index[E comparable](s []E, v E) int {
102102

103103
// IndexFunc returns the first index i satisfying f(s[i]),
104104
// or -1 if none do.
105-
func IndexFunc[E any](s []E, f func(E) bool) int {
105+
func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
106106
for i := range s {
107107
if f(s[i]) {
108108
return i
@@ -112,13 +112,13 @@ func IndexFunc[E any](s []E, f func(E) bool) int {
112112
}
113113

114114
// Contains reports whether v is present in s.
115-
func Contains[E comparable](s []E, v E) bool {
115+
func Contains[S ~[]E, E comparable](s S, v E) bool {
116116
return Index(s, v) >= 0
117117
}
118118

119119
// ContainsFunc reports whether at least one
120120
// element e of s satisfies f(e).
121-
func ContainsFunc[E any](s []E, f func(E) bool) bool {
121+
func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
122122
return IndexFunc(s, f) >= 0
123123
}
124124

@@ -441,7 +441,7 @@ func Clip[S ~[]E, E any](s S) S {
441441

442442
// rotateLeft rotates b left by n spaces.
443443
// s_final[i] = s_orig[i+r], wrapping around.
444-
func rotateLeft[S ~[]E, E any](s S, r int) {
444+
func rotateLeft[E any](s []E, r int) {
445445
for r != 0 && r != len(s) {
446446
if r*2 <= len(s) {
447447
swap(s[:r], s[len(s)-r:])
@@ -452,19 +452,19 @@ func rotateLeft[S ~[]E, E any](s S, r int) {
452452
}
453453
}
454454
}
455-
func rotateRight[S ~[]E, E any](s S, r int) {
455+
func rotateRight[E any](s []E, r int) {
456456
rotateLeft(s, len(s)-r)
457457
}
458458

459459
// swap swaps the contents of x and y. x and y must be equal length and disjoint.
460-
func swap[S ~[]E, E any](x, y S) {
460+
func swap[E any](x, y []E) {
461461
for i := 0; i < len(x); i++ {
462462
x[i], y[i] = y[i], x[i]
463463
}
464464
}
465465

466466
// overlaps reports whether the memory ranges a[0:len(a)] and b[0:len(b)] overlap.
467-
func overlaps[S ~[]E, E any](a, b S) bool {
467+
func overlaps[E any](a, b []E) bool {
468468
if len(a) == 0 || len(b) == 0 {
469469
return false
470470
}
@@ -480,7 +480,7 @@ func overlaps[S ~[]E, E any](a, b S) bool {
480480

481481
// startIdx returns the index in haystack where the needle starts.
482482
// prerequisite: the needle must be aliased entirely inside the haystack.
483-
func startIdx[S ~[]E, E any](haystack, needle S) int {
483+
func startIdx[E any](haystack, needle []E) int {
484484
p := &needle[0]
485485
for i := range haystack {
486486
if p == &haystack[i] {
@@ -492,7 +492,7 @@ func startIdx[S ~[]E, E any](haystack, needle S) int {
492492
}
493493

494494
// Reverse reverses the elements of the slice in place.
495-
func Reverse[E any](s []E) {
495+
func Reverse[S ~[]E, E any](s S) {
496496
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
497497
s[i], s[j] = s[j], s[i]
498498
}

src/slices/slices_test.go

+21-1
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@ func TestReverse(t *testing.T) {
856856
t.Errorf("Reverse(singeleton) = %v, want %v", singleton, want)
857857
}
858858

859-
Reverse[string](nil)
859+
Reverse[[]string](nil)
860860
}
861861

862862
// naiveReplace is a baseline implementation to the Replace function.
@@ -1053,3 +1053,23 @@ func TestReplaceGrowthRate(t *testing.T) {
10531053
t.Errorf("too many grows. got:%d want:%d", nGrow, want)
10541054
}
10551055
}
1056+
1057+
func apply[T any](v T, f func(T)) {
1058+
f(v)
1059+
}
1060+
1061+
// Test type inference with a named slice type.
1062+
func TestInference(t *testing.T) {
1063+
s1 := []int{1, 2, 3}
1064+
apply(s1, Reverse)
1065+
if want := []int{3, 2, 1}; !Equal(s1, want) {
1066+
t.Errorf("Reverse(%v) = %v, want %v", []int{1, 2, 3}, s1, want)
1067+
}
1068+
1069+
type S []int
1070+
s2 := S{4, 5, 6}
1071+
apply(s2, Reverse)
1072+
if want := (S{6, 5, 4}); !Equal(s2, want) {
1073+
t.Errorf("Reverse(%v) = %v, want %v", S{4, 5, 6}, s2, want)
1074+
}
1075+
}

src/slices/sort.go

+11-11
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111

1212
// Sort sorts a slice of any ordered type in ascending order.
1313
// When sorting floating-point numbers, NaNs are ordered before other values.
14-
func Sort[E cmp.Ordered](x []E) {
14+
func Sort[S ~[]E, E cmp.Ordered](x S) {
1515
n := len(x)
1616
pdqsortOrdered(x, 0, n, bits.Len(uint(n)))
1717
}
@@ -23,19 +23,19 @@ func Sort[E cmp.Ordered](x []E) {
2323
//
2424
// SortFunc requires that cmp is a strict weak ordering.
2525
// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.
26-
func SortFunc[E any](x []E, cmp func(a, b E) int) {
26+
func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
2727
n := len(x)
2828
pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp)
2929
}
3030

3131
// SortStableFunc sorts the slice x while keeping the original order of equal
3232
// elements, using cmp to compare elements.
33-
func SortStableFunc[E any](x []E, cmp func(a, b E) int) {
33+
func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
3434
stableCmpFunc(x, len(x), cmp)
3535
}
3636

3737
// IsSorted reports whether x is sorted in ascending order.
38-
func IsSorted[E cmp.Ordered](x []E) bool {
38+
func IsSorted[S ~[]E, E cmp.Ordered](x S) bool {
3939
for i := len(x) - 1; i > 0; i-- {
4040
if cmp.Less(x[i], x[i-1]) {
4141
return false
@@ -46,7 +46,7 @@ func IsSorted[E cmp.Ordered](x []E) bool {
4646

4747
// IsSortedFunc reports whether x is sorted in ascending order, with cmp as the
4848
// comparison function.
49-
func IsSortedFunc[E any](x []E, cmp func(a, b E) int) bool {
49+
func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
5050
for i := len(x) - 1; i > 0; i-- {
5151
if cmp(x[i], x[i-1]) < 0 {
5252
return false
@@ -58,7 +58,7 @@ func IsSortedFunc[E any](x []E, cmp func(a, b E) int) bool {
5858
// Min returns the minimal value in x. It panics if x is empty.
5959
// For floating-point numbers, Min propagates NaNs (any NaN value in x
6060
// forces the output to be NaN).
61-
func Min[E cmp.Ordered](x []E) E {
61+
func Min[S ~[]E, E cmp.Ordered](x S) E {
6262
if len(x) < 1 {
6363
panic("slices.Min: empty list")
6464
}
@@ -71,7 +71,7 @@ func Min[E cmp.Ordered](x []E) E {
7171

7272
// MinFunc returns the minimal value in x, using cmp to compare elements.
7373
// It panics if x is empty.
74-
func MinFunc[E any](x []E, cmp func(a, b E) int) E {
74+
func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
7575
if len(x) < 1 {
7676
panic("slices.MinFunc: empty list")
7777
}
@@ -87,7 +87,7 @@ func MinFunc[E any](x []E, cmp func(a, b E) int) E {
8787
// Max returns the maximal value in x. It panics if x is empty.
8888
// For floating-point E, Max propagates NaNs (any NaN value in x
8989
// forces the output to be NaN).
90-
func Max[E cmp.Ordered](x []E) E {
90+
func Max[S ~[]E, E cmp.Ordered](x S) E {
9191
if len(x) < 1 {
9292
panic("slices.Max: empty list")
9393
}
@@ -100,7 +100,7 @@ func Max[E cmp.Ordered](x []E) E {
100100

101101
// MaxFunc returns the maximal value in x, using cmp to compare elements.
102102
// It panics if x is empty.
103-
func MaxFunc[E any](x []E, cmp func(a, b E) int) E {
103+
func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
104104
if len(x) < 1 {
105105
panic("slices.MaxFunc: empty list")
106106
}
@@ -117,7 +117,7 @@ func MaxFunc[E any](x []E, cmp func(a, b E) int) E {
117117
// where target is found, or the position where target would appear in the
118118
// sort order; it also returns a bool saying whether the target is really found
119119
// in the slice. The slice must be sorted in increasing order.
120-
func BinarySearch[E cmp.Ordered](x []E, target E) (int, bool) {
120+
func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) {
121121
// Inlining is faster than calling BinarySearchFunc with a lambda.
122122
n := len(x)
123123
// Define x[-1] < target and x[n] >= target.
@@ -143,7 +143,7 @@ func BinarySearch[E cmp.Ordered](x []E, target E) (int, bool) {
143143
// or a positive number if the slice element follows the target.
144144
// cmp must implement the same ordering as the slice, such that if
145145
// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice.
146-
func BinarySearchFunc[E, T any](x []E, target T, cmp func(E, T) int) (int, bool) {
146+
func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) {
147147
n := len(x)
148148
// Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 .
149149
// Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0.

0 commit comments

Comments
 (0)