// 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 import ( ) // 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 [ ~[], 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 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 [ ~[], 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+m rotateRight([:], ) // 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)]. func [ ~[], any]( , , int) { _ = [::len()] // bounds check if == { return } := len() = append([:], [:]...) clear([len():]) // zero/nil out the obsolete elements, for GC return } // 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. 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 GC return [:] } // 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. func [ ~[], any]( , , int, ...) { _ = [:] // bounds check if == { return Insert(, , ...) } if == len() { return append([:], ...) } := len([:]) + len() + len([:]) if > cap() { // Too big to fit, allocate and copy over. := append([:], make(, -)...) // See Insert copy([:], ) copy([+len():], [:]) return } := [:] if +len() <= { // Easy, as v fits in the deleted portion. copy([:], ) copy([+len():], [:]) clear([:]) // zero/nil out the obsolete elements, for GC return } // 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 into if !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 portion if !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. func [ ~[], any]( ) { // The s[:0:0] preserves nil in case it matters. return append([:0:0], ...) } // 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. func [ ~[], comparable]( ) { if len() < 2 { return } := 1 for := 1; < len(); ++ { if [] != [-1] { if != { [] = [] } ++ } } clear([:]) // zero/nil out the obsolete elements, for GC 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. func [ ~[], any]( , func(, ) bool) { if len() < 2 { return } := 1 for := 1; < len(); ++ { if !([], [-1]) { if != { [] = [] } ++ } } clear([:]) // zero/nil out the obsolete elements, for GC 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. func [ ~[], any]( , int) { if < 0 { panic("cannot be negative") } if -= cap() - len(); > 0 { = append([:cap()], make([], )...)[:len()] } return } // Clip removes unused capacity from the slice, returning s[:len(s):len(s)]. func [ ~[], any]( ) { return [:len():len()] } // Rotation algorithm explanation: // // rotate left by 2 // start with // 0123456789 // split up like this // 01 234567 89 // swap first 2 and last 2 // 89 234567 01 // join first parts // 89234567 01 // recursively rotate first left part by 2 // 23456789 01 // join at the end // 2345678901 // // rotate left by 8 // start with // 0123456789 // split up like this // 01 234567 89 // swap first 2 and last 2 // 89 234567 01 // join last parts // 89 23456701 // recursively rotate second part left by 6 // 89 01234567 // join at the end // 8901234567 // TODO: There are other rotate algorithms. // This algorithm has the desirable property that it moves each element exactly twice. // The triple-reverse algorithm is simpler and more cache friendly, but takes more writes. // The follow-cycles algorithm can be 1-write but it is not very cache friendly. // rotateLeft rotates b left by n spaces. // s_final[i] = s_orig[i+r], wrapping around. func rotateLeft[ any]( [], int) { for != 0 && != len() { if *2 <= len() { swap([:], [len()-:]) = [:len()-] } else { swap([:len()-], [:]) , = [len()-:], *2-len() } } } func rotateRight[ any]( [], int) { rotateLeft(, len()-) } // swap swaps the contents of x and y. x and y must be equal length and disjoint. func swap[ any](, []) { for := 0; < len(); ++ { [], [] = [], [] } } // overlaps reports whether the memory ranges a[0:len(a)] and b[0: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/alias/alias.go:AnyOverlap return 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. func [ ~[], any]( ...) { := 0 for , := range { += len() if < 0 { panic("len out of range") } } := Grow[](nil, ) for , := range { = append(, ...) } return }