Source File
slices.go
Belonging Package
slices
// 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 slicesimport ()// 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.// Empty and nil slices are considered equal.// Floating point NaNs are not considered equal.func [ ~[], comparable](, ) bool {if len() != len() {return false}for := range {if [] != [] {return false}}return true}// EqualFunc reports whether two slices are equal using an equality// 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 [ ~[], ~[], , any]( , , func(, ) bool) bool {if len() != len() {return false}for , := range {:= []if !(, ) {return false}}return true}// Compare compares the elements of s1 and s2, using [cmp.Compare] on each pair// of elements. The elements are compared sequentially, starting at index 0,// until one element is not equal to the other.// The result of comparing the first non-matching elements is returned.// If both slices are equal until one of them ends, the shorter slice is// considered less than the longer one.// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2.func [ ~[], cmp.Ordered](, ) int {for , := range {if >= len() {return +1}:= []if := cmp.Compare(, ); != 0 {return}}if len() < len() {return -1}return 0}// CompareFunc is like [Compare] but uses a custom comparison function on each// pair of elements.// The result is the first non-zero result of cmp; if cmp always// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2),// and +1 if len(s1) > len(s2).func [ ~[], ~[], , any]( , , func(, ) int) int {for , := range {if >= len() {return +1}:= []if := (, ); != 0 {return}}if len() < len() {return -1}return 0}// Index returns the index of the first occurrence of v in s,// or -1 if not present.func [ ~[], comparable]( , ) int {for := range {if == [] {return}}return -1}// IndexFunc returns the first index i satisfying f(s[i]),// or -1 if none do.func [ ~[], any]( , func() bool) int {for := range {if ([]) {return}}return -1}// Contains reports whether v is present in s.func [ ~[], comparable]( , ) bool {return Index(, ) >= 0}// ContainsFunc reports whether at least one// element e of s satisfies f(e).func [ ~[], any]( , func() bool) bool {return IndexFunc(, ) >= 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, if i < len(s), r[i+len(v)] == value originally at r[i].// Insert panics if i > len(s).// This function is O(len(s) + len(v)).// If the result is empty, it has the same nilness as s.func [ ~[], any]( , int, ...) {_ = [:] // bounds check:= len()if == 0 {return}:= len()if == {return append(, ...)}if + > cap() {// Use append rather than make so that we bump the size of// the slice up to the next storage class.// This is what Grow does but we don't call Grow because// that might copy the values twice.:= append([:], make(, +-)...)copy([:], )copy([+:], [:])return}= [:+]// before:// s: aaaaaaaabbbbccccccccdddd// ^ ^ ^ ^// i i+m n n+m// after:// s: aaaaaaaavvvvbbbbcccccccc// ^ ^ ^ ^// i i+m n n+m//// a are the values that don't move in s.// v are the values copied in from v.// b and c are the values from s that are shifted up in index.// d are the values that get overwritten, never to be seen again.if !overlaps(, [+:]) {// Easy case - v does not overlap either the c or d regions.// (It might be in some of a or b, or elsewhere entirely.)// The data we copy up doesn't write to v at all, so just do it.copy([+:], [:])// Now we have// s: aaaaaaaabbbbbbbbcccccccc// ^ ^ ^ ^// i i+m n n+m// Note the b values are duplicated.copy([:], )// Now we have// s: aaaaaaaavvvvbbbbcccccccc// ^ ^ ^ ^// i i+m n n+m// That's the result we want.return}// The hard case - v overlaps c or d. We can't just shift up// the data because we'd move or clobber the values we're trying// to insert.// So instead, write v on top of d, then rotate.copy([:], )// Now we have// s: aaaaaaaabbbbccccccccvvvv// ^ ^ ^ ^// i i+m n n+mrotateRight([:], )// Now we have// s: aaaaaaaavvvvbbbbcccccccc// ^ ^ ^ ^// i i+m n n+m// That's the result we want.return}// Delete removes the elements s[i:j] from s, returning the modified slice.// Delete panics if j > len(s) or s[i:j] is not a valid slice of s.// Delete is O(len(s)-i), 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 zeroes the elements s[len(s)-(j-i):len(s)].// If the result is empty, it has the same nilness as s.func [ ~[], any]( , , int) {_ = [::len()] // bounds checkif == {return}:= len()= append([:], [:]...)clear([len():]) // zero/nil out the obsolete elements, for GCreturn}// DeleteFunc removes any elements from s for which del returns true,// returning the modified slice.// DeleteFunc zeroes the elements between the new length and the original length.// If the result is empty, it has the same nilness as s.func [ ~[], any]( , func() bool) {:= IndexFunc(, )if == -1 {return}// Don't start copying elements until we find one to delete.for := + 1; < len(); ++ {if := []; !() {[] =++}}clear([:]) // zero/nil out the obsolete elements, for GCreturn [:]}// Replace replaces the elements s[i:j] by the given v, and returns the// modified slice.// Replace panics if j > len(s) or s[i:j] is not a valid slice of s.// When len(v) < (j-i), Replace zeroes the elements between the new length and the original length.// If the result is empty, it has the same nilness as s.func [ ~[], any]( , , int, ...) {_ = [:] // bounds checkif == {return Insert(, , ...)}if == len() {:= append([:], ...)if len() < len() {clear([len():]) // zero/nil out the obsolete elements, for GC}return}:= len([:]) + len() + len([:])if > cap() {// Too big to fit, allocate and copy over.:= append([:], make(, -)...) // See Insertcopy([:], )copy([+len():], [:])return}:= [:]if +len() <= {// Easy, as v fits in the deleted portion.copy([:], )copy([+len():], [:])clear([:]) // zero/nil out the obsolete elements, for GCreturn}// We are expanding (v is bigger than j-i).// The situation is something like this:// (example has i=4,j=8,len(s)=16,len(v)=6)// s: aaaaxxxxbbbbbbbbyy// ^ ^ ^ ^// i j len(s) tot// a: prefix of s// x: deleted range// b: more of s// y: area to expand intoif !overlaps([+len():], ) {// Easy, as v is not clobbered by the first copy.copy([+len():], [:])copy([:], )return}// This is a situation where we don't have a single place to which// we can copy v. Parts of it need to go to two different places.// We want to copy the prefix of v into y and the suffix into x, then// rotate |y| spots to the right.//// v[2:] v[:2]// | |// s: aaaavvvvbbbbbbbbvv// ^ ^ ^ ^// i j len(s) tot//// If either of those two destinations don't alias v, then we're good.:= len() - ( - ) // length of y portionif !overlaps([:], ) {copy([:], [:])copy([len():], [:])rotateRight([:], )return}if !overlaps([len():], ) {copy([len():], [:])copy([:], [:])rotateRight([:], )return}// Now we know that v overlaps both x and y.// That means that the entirety of b is *inside* v.// So we don't need to preserve b at all; instead we// can copy v first, then copy the b part of v out of// v to the right destination.:= startIdx(, [:])copy([:], )copy([+len():], [+:])return}// Clone returns a copy of the slice.// The elements are copied using assignment, so this is a shallow clone.// The result may have additional unused capacity.// The result preserves the nilness of s.func [ ~[], any]( ) {// Preserve nilness in case it matters.if == nil {return nil}// Avoid s[:0:0] as it leads to unwanted liveness when cloning a// zero-length slice of a large array; see https://go.dev/issue/68488.return append({}, ...)}// 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 and returns the modified slice,// which may have a smaller length.// Compact zeroes the elements between the new length and the original length.// The result preserves the nilness of s.func [ ~[], comparable]( ) {if len() < 2 {return}for := 1; < len(); ++ {if [] == [-1] {:= [:]for := 1; < len(); ++ {if [] != [-1] {[] = []++}}clear([:]) // zero/nil out the obsolete elements, for GCreturn [:]}}return}// CompactFunc is like [Compact] but uses an equality function to compare elements.// For runs of elements that compare equal, CompactFunc keeps the first one.// CompactFunc zeroes the elements between the new length and the original length.// The result preserves the nilness of s.func [ ~[], any]( , func(, ) bool) {if len() < 2 {return}for := 1; < len(); ++ {if ([], [-1]) {:= [:]for := 1; < len(); ++ {if !([], [-1]) {[] = []++}}clear([:]) // zero/nil out the obsolete elements, for GCreturn [:]}}return}// 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.// The result preserves the nilness of s.func [ ~[], any]( , int) {if < 0 {panic("cannot be negative")}if -= cap() - len(); > 0 {// This expression allocates only once (see test).= append([:cap()], make([], )...)[:len()]}return}// Clip removes unused capacity from the slice, returning s[:len(s):len(s)].// The result preserves the nilness of s.func [ ~[], any]( ) {return [:len():len()]}// TODO: There are other rotate algorithms.// This algorithm has the desirable property that it moves each element at most twice.// The follow-cycles algorithm can be 1-write but it is not very cache friendly.// rotateLeft rotates s left by r spaces.// s_final[i] = s_orig[i+r], wrapping around.func rotateLeft[ any]( [], int) {Reverse([:])Reverse([:])Reverse()}func rotateRight[ any]( [], int) {rotateLeft(, len()-)}// overlaps reports whether the memory ranges a[:len(a)] and b[:len(b)] overlap.func overlaps[ any](, []) bool {if len() == 0 || len() == 0 {return false}:= unsafe.Sizeof([0])if == 0 {return false}// TODO: use a runtime/unsafe facility once one becomes available. See issue 12445.// Also see crypto/internal/fips140/alias/alias.go:AnyOverlapreturn uintptr(unsafe.Pointer(&[0])) <= uintptr(unsafe.Pointer(&[len()-1]))+(-1) &&uintptr(unsafe.Pointer(&[0])) <= uintptr(unsafe.Pointer(&[len()-1]))+(-1)}// startIdx returns the index in haystack where the needle starts.// prerequisite: the needle must be aliased entirely inside the haystack.func startIdx[ any](, []) int {:= &[0]for := range {if == &[] {return}}// TODO: what if the overlap is by a non-integral number of Es?panic("needle not found")}// Reverse reverses the elements of the slice in place.func [ ~[], any]( ) {for , := 0, len()-1; < ; , = +1, -1 {[], [] = [], []}}// Concat returns a new slice concatenating the passed in slices.// If the concatenation is empty, the result is nil.func [ ~[], any]( ...) {:= 0for , := range {+= len()if < 0 {panic("len out of range")}}// Use Grow, not make, to round up to the size class:// the extra space is otherwise unused and helps// callers that append a few elements to the result.:= Grow[](nil, )for , := range {= append(, ...)}return}// Repeat returns a new slice that repeats the provided slice the given number of times.// The result has length and capacity (len(x) * count).// The result is never nil.// Repeat panics if count is negative or if the result of (len(x) * count)// overflows.func [ ~[], any]( , int) {if < 0 {panic("cannot be negative")}const = ^uint(0) >> 1, := bits.Mul(uint(len()), uint())if > 0 || > {panic("the result of (len(x) * count) overflows")}:= make(, int()) // lo = len(x) * count:= copy(, )for < len() {+= copy([:], [:])}return}
![]() |
The pages are generated with Golds v0.7.9-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |