-
Notifications
You must be signed in to change notification settings - Fork 17.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <iant@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Eli Bendersky <eliben@google.com> Run-TryBot: Ian Lance Taylor <iant@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com>
- Loading branch information
1 parent
790f250
commit 1e9925f
Showing
5 changed files
with
816 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
pkg slices, func Clip[$0 interface{ ~[]$1 }, $1 interface{}]($0) $0 #57433 | ||
pkg slices, func Clone[$0 interface{ ~[]$1 }, $1 interface{}]($0) $0 #57433 | ||
pkg slices, func CompactFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1, $1) bool) $0 #57433 | ||
pkg slices, func Compact[$0 interface{ ~[]$1 }, $1 comparable]($0) $0 #57433 | ||
pkg slices, func ContainsFunc[$0 interface{}]([]$0, func($0) bool) bool #57433 | ||
pkg slices, func Contains[$0 comparable]([]$0, $0) bool #57433 | ||
pkg slices, func Delete[$0 interface{ ~[]$1 }, $1 interface{}]($0, int, int) $0 #57433 | ||
pkg slices, func EqualFunc[$0 interface{}, $1 interface{}]([]$0, []$1, func($0, $1) bool) bool #57433 | ||
pkg slices, func Equal[$0 comparable]([]$0, []$0) bool #57433 | ||
pkg slices, func Grow[$0 interface{ ~[]$1 }, $1 interface{}]($0, int) $0 #57433 | ||
pkg slices, func IndexFunc[$0 interface{}]([]$0, func($0) bool) int #57433 | ||
pkg slices, func Index[$0 comparable]([]$0, $0) int #57433 | ||
pkg slices, func Insert[$0 interface{ ~[]$1 }, $1 interface{}]($0, int, ...$1) $0 #57433 | ||
pkg slices, func Replace[$0 interface{ ~[]$1 }, $1 interface{}]($0, int, int, ...$1) $0 #57433 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
// Copyright 2021 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
// Package slices defines various functions useful with slices of any type. | ||
package slices | ||
|
||
// Equal reports whether two slices are equal: the same length and all | ||
// elements equal. If the lengths are different, Equal returns false. | ||
// Otherwise, the elements are compared in increasing index order, and the | ||
// comparison stops at the first unequal pair. | ||
// Floating point NaNs are not considered equal. | ||
func Equal[E comparable](s1, s2 []E) bool { | ||
if len(s1) != len(s2) { | ||
return false | ||
} | ||
for i := range s1 { | ||
if s1[i] != s2[i] { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// EqualFunc reports whether two slices are equal using a comparison | ||
// function on each pair of elements. If the lengths are different, | ||
// EqualFunc returns false. Otherwise, the elements are compared in | ||
// increasing index order, and the comparison stops at the first index | ||
// for which eq returns false. | ||
func EqualFunc[E1, E2 any](s1 []E1, s2 []E2, eq func(E1, E2) bool) bool { | ||
if len(s1) != len(s2) { | ||
return false | ||
} | ||
for i, v1 := range s1 { | ||
v2 := s2[i] | ||
if !eq(v1, v2) { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// Index returns the index of the first occurrence of v in s, | ||
// or -1 if not present. | ||
func Index[E comparable](s []E, v E) int { | ||
for i, vs := range s { | ||
if v == vs { | ||
return i | ||
} | ||
} | ||
return -1 | ||
} | ||
|
||
// IndexFunc returns the first index i satisfying f(s[i]), | ||
// or -1 if none do. | ||
func IndexFunc[E any](s []E, f func(E) bool) int { | ||
for i, v := range s { | ||
if f(v) { | ||
return i | ||
} | ||
} | ||
return -1 | ||
} | ||
|
||
// Contains reports whether v is present in s. | ||
func Contains[E comparable](s []E, v E) bool { | ||
return Index(s, v) >= 0 | ||
} | ||
|
||
// ContainsFunc reports whether at least one | ||
// element e of s satisfies f(e). | ||
func ContainsFunc[E any](s []E, f func(E) bool) bool { | ||
return IndexFunc(s, f) >= 0 | ||
} | ||
|
||
// Insert inserts the values v... into s at index i, | ||
// returning the modified slice. | ||
// The elements at s[i:] are shifted up to make room. | ||
// In the returned slice r, r[i] == v[0], | ||
// and r[i+len(v)] == value originally at r[i]. | ||
// Insert panics if i is out of range. | ||
// This function is O(len(s) + len(v)). | ||
func Insert[S ~[]E, E any](s S, i int, v ...E) S { | ||
tot := len(s) + len(v) | ||
if tot <= cap(s) { | ||
s2 := s[:tot] | ||
copy(s2[i+len(v):], s[i:]) | ||
copy(s2[i:], v) | ||
return s2 | ||
} | ||
s2 := make(S, tot) | ||
copy(s2, s[:i]) | ||
copy(s2[i:], v) | ||
copy(s2[i+len(v):], s[i:]) | ||
return s2 | ||
} | ||
|
||
// Delete removes the elements s[i:j] from s, returning the modified slice. | ||
// Delete panics if s[i:j] is not a valid slice of s. | ||
// Delete modifies the contents of the slice s; it does not create a new slice. | ||
// Delete is O(len(s)-j), so if many items must be deleted, it is better to | ||
// make a single call deleting them all together than to delete one at a time. | ||
// Delete might not modify the elements s[len(s)-(j-i):len(s)]. If those | ||
// elements contain pointers you might consider zeroing those elements so that | ||
// objects they reference can be garbage collected. | ||
func Delete[S ~[]E, E any](s S, i, j int) S { | ||
_ = s[i:j] // bounds check | ||
|
||
return append(s[:i], s[j:]...) | ||
} | ||
|
||
// Replace replaces the elements s[i:j] by the given v, and returns the | ||
// modified slice. Replace panics if s[i:j] is not a valid slice of s. | ||
func Replace[S ~[]E, E any](s S, i, j int, v ...E) S { | ||
_ = s[i:j] // verify that i:j is a valid subslice | ||
tot := len(s[:i]) + len(v) + len(s[j:]) | ||
if tot <= cap(s) { | ||
s2 := s[:tot] | ||
copy(s2[i+len(v):], s[j:]) | ||
copy(s2[i:], v) | ||
return s2 | ||
} | ||
s2 := make(S, tot) | ||
copy(s2, s[:i]) | ||
copy(s2[i:], v) | ||
copy(s2[i+len(v):], s[j:]) | ||
return s2 | ||
} | ||
|
||
// Clone returns a copy of the slice. | ||
// The elements are copied using assignment, so this is a shallow clone. | ||
func Clone[S ~[]E, E any](s S) S { | ||
// Preserve nil in case it matters. | ||
if s == nil { | ||
return nil | ||
} | ||
return append(S([]E{}), s...) | ||
} | ||
|
||
// Compact replaces consecutive runs of equal elements with a single copy. | ||
// This is like the uniq command found on Unix. | ||
// Compact modifies the contents of the slice s; it does not create a new slice. | ||
// When Compact discards m elements in total, it might not modify the elements | ||
// s[len(s)-m:len(s)]. If those elements contain pointers you might consider | ||
// zeroing those elements so that objects they reference can be garbage collected. | ||
func Compact[S ~[]E, E comparable](s S) S { | ||
if len(s) < 2 { | ||
return s | ||
} | ||
i := 1 | ||
last := s[0] | ||
for _, v := range s[1:] { | ||
if v != last { | ||
s[i] = v | ||
i++ | ||
last = v | ||
} | ||
} | ||
return s[:i] | ||
} | ||
|
||
// CompactFunc is like Compact but uses a comparison function. | ||
func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { | ||
if len(s) < 2 { | ||
return s | ||
} | ||
i := 1 | ||
last := s[0] | ||
for _, v := range s[1:] { | ||
if !eq(v, last) { | ||
s[i] = v | ||
i++ | ||
last = v | ||
} | ||
} | ||
return s[:i] | ||
} | ||
|
||
// Grow increases the slice's capacity, if necessary, to guarantee space for | ||
// another n elements. After Grow(n), at least n elements can be appended | ||
// to the slice without another allocation. If n is negative or too large to | ||
// allocate the memory, Grow panics. | ||
func Grow[S ~[]E, E any](s S, n int) S { | ||
if n < 0 { | ||
panic("cannot be negative") | ||
} | ||
if n -= cap(s) - len(s); n > 0 { | ||
s = append(s[:cap(s)], make([]E, n)...)[:len(s)] | ||
} | ||
return s | ||
} | ||
|
||
// Clip removes unused capacity from the slice, returning s[:len(s):len(s)]. | ||
func Clip[S ~[]E, E any](s S) S { | ||
return s[:len(s):len(s)] | ||
} |
Oops, something went wrong.