| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | // 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. | 
					
						
							|  |  |  | // Unless otherwise specified, these functions all apply to the elements | 
					
						
							|  |  |  | // of a slice at index 0 <= i < len(s). | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Note that the less function in IsSortedFunc, SortFunc, SortStableFunc requires a | 
					
						
							|  |  |  | // strict weak ordering (https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings), | 
					
						
							|  |  |  | // or the sorting may fail to sort correctly. A common case is when sorting slices of | 
					
						
							|  |  |  | // floating-point numbers containing NaN values. | 
					
						
							|  |  |  | package slices | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import "golang.org/x/exp/constraints" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Compare compares the elements of s1 and s2. | 
					
						
							|  |  |  | // 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. | 
					
						
							|  |  |  | // Comparisons involving floating point NaNs are ignored. | 
					
						
							|  |  |  | func Compare[E constraints.Ordered](s1, s2 []E) int { | 
					
						
							|  |  |  | 	s2len := len(s2) | 
					
						
							|  |  |  | 	for i, v1 := range s1 { | 
					
						
							|  |  |  | 		if i >= s2len { | 
					
						
							|  |  |  | 			return +1 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		v2 := s2[i] | 
					
						
							|  |  |  | 		switch { | 
					
						
							|  |  |  | 		case v1 < v2: | 
					
						
							|  |  |  | 			return -1 | 
					
						
							|  |  |  | 		case v1 > v2: | 
					
						
							|  |  |  | 			return +1 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(s1) < s2len { | 
					
						
							|  |  |  | 		return -1 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // CompareFunc is like Compare but uses a comparison function | 
					
						
							|  |  |  | // on each pair of elements. The elements are compared in increasing | 
					
						
							|  |  |  | // index order, and the comparisons stop after the first time cmp | 
					
						
							|  |  |  | // returns non-zero. | 
					
						
							|  |  |  | // 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 CompareFunc[E1, E2 any](s1 []E1, s2 []E2, cmp func(E1, E2) int) int { | 
					
						
							|  |  |  | 	s2len := len(s2) | 
					
						
							|  |  |  | 	for i, v1 := range s1 { | 
					
						
							|  |  |  | 		if i >= s2len { | 
					
						
							|  |  |  | 			return +1 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		v2 := s2[i] | 
					
						
							|  |  |  | 		if c := cmp(v1, v2); c != 0 { | 
					
						
							|  |  |  | 			return c | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(s1) < s2len { | 
					
						
							|  |  |  | 		return -1 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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 { | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | 	for i := range s { | 
					
						
							|  |  |  | 		if v == s[i] { | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | 			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 { | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | 	for i := range s { | 
					
						
							|  |  |  | 		if f(s[i]) { | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | 			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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | // 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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | // Insert inserts the values v... into s at index i, | 
					
						
							|  |  |  | // returning the modified slice. | 
					
						
							|  |  |  | // In the returned slice r, r[i] == v[0]. | 
					
						
							|  |  |  | // 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. | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | // Delete is O(len(s)-j), so if many items must be deleted, it is better to | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | // make a single call deleting them all together than to delete one at a time. | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | // 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. | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | func Delete[S ~[]E, E any](s S, i, j int) S { | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | 	_ = s[i:j] // bounds check | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | 	return append(s[:i], s[j:]...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | // 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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | // 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. | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | // 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. | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | func Compact[S ~[]E, E comparable](s S) S { | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | 	if len(s) < 2 { | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | 		return s | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	i := 1 | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | 	for k := 1; k < len(s); k++ { | 
					
						
							|  |  |  | 		if s[k] != s[k-1] { | 
					
						
							|  |  |  | 			if i != k { | 
					
						
							|  |  |  | 				s[i] = s[k] | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | 			i++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	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 { | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | 	if len(s) < 2 { | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | 		return s | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	i := 1 | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | 	for k := 1; k < len(s); k++ { | 
					
						
							|  |  |  | 		if !eq(s[k], s[k-1]) { | 
					
						
							|  |  |  | 			if i != k { | 
					
						
							|  |  |  | 				s[i] = s[k] | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | 			i++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	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 | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | // to the slice without another allocation. If n is negative or too large to | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | // allocate the memory, Grow panics. | 
					
						
							|  |  |  | func Grow[S ~[]E, E any](s S, n int) S { | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | 	if n < 0 { | 
					
						
							|  |  |  | 		panic("cannot be negative") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n -= cap(s) - len(s); n > 0 { | 
					
						
							|  |  |  | 		// TODO(https://go.dev/issue/53888): Make using []E instead of S | 
					
						
							|  |  |  | 		// to workaround a compiler bug where the runtime.growslice optimization | 
					
						
							|  |  |  | 		// does not take effect. Revert when the compiler is fixed. | 
					
						
							|  |  |  | 		s = append([]E(s)[:cap(s)], make([]E, n)...)[:len(s)] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return s | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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)] | 
					
						
							|  |  |  | } |