Files
phishingclub/backend/vendor/github.com/enetx/g/slice.go
T

1035 lines
26 KiB
Go

package g
import (
"fmt"
"reflect"
"slices"
"strings"
"github.com/enetx/g/cmp"
"github.com/enetx/g/f"
)
// Slice is a generic alias for a slice.
type Slice[T any] []T
// NewSlice creates a new Slice of the given generic type T with the specified length and
// capacity.
// The size variadic parameter can have zero, one, or two integer values.
// If no values are provided, an empty Slice with a length and capacity of 0 is returned.
// If one value is provided, it sets both the length and capacity of the Slice.
// If two values are provided, the first value sets the length and the second value sets the
// capacity.
//
// Parameters:
//
// - size ...Int: A variadic parameter specifying the length and/or capacity of the Slice
//
// Returns:
//
// - Slice[T]: A new Slice of the specified generic type T with the given length and capacity
//
// Example usage:
//
// s1 := g.NewSlice[int]() // Creates an empty Slice of type int
// s2 := g.NewSlice[int](5) // Creates an Slice with length and capacity of 5
// s3 := g.NewSlice[int](3, 10) // Creates an Slice with length of 3 and capacity of 10
func NewSlice[T any](size ...Int) Slice[T] {
var (
length Int
capacity Int
)
switch {
case len(size) > 1:
length, capacity = size[0], size[1]
case len(size) == 1:
length, capacity = size[0], size[0]
}
return make(Slice[T], length, capacity)
}
// SliceOf creates a new generic slice containing the provided elements.
func SliceOf[T any](slice ...T) Slice[T] { return slice }
// TransformSlice maps a plain Go slice into a Slice through fn. It is the
// exported bridge between stdlib-shaped results and g containers, shared with
// the subpackages (rx uses it for its match groups).
func TransformSlice[T, U any](sl []T, fn func(T) U) Slice[U] {
if len(sl) == 0 {
return NewSlice[U]()
}
result := make(Slice[U], len(sl))
for i, v := range sl {
result[i] = fn(v)
}
return result
}
// Transform applies a transformation function to the Slice and returns the result.
func (sl Slice[T]) Transform[U any](fn func(Slice[T]) U) U { return fn(sl) }
// Iter returns an iterator (Seq[T]) for the Slice, allowing for sequential iteration
// over its elements. It is commonly used in combination with higher-order functions,
// such as 'ForEach', to perform operations on each element of the Slice.
//
// Returns:
//
// A Seq[T], which can be used for sequential iteration over the elements of the Slice.
//
// Example usage:
//
// slice := g.Slice[int]{1, 2, 3, 4, 5}
// iterator := slice.Iter()
// iterator.ForEach(func(element int) {
// // Perform some operation on each element
// fmt.Println(element)
// })
//
// The 'Iter' method provides a convenient way to traverse the elements of a Slice
// in a functional style, enabling operations like mapping or filtering.
func (sl Slice[T]) Iter() Seq[T] { return Seq[T](seqFromSlice(sl)) }
// IterReverse returns an iterator (Seq[T]) for the Slice that allows for sequential iteration
// over its elements in reverse order. This method is useful when you need to traverse the elements
// from the end to the beginning.
//
// Returns:
//
// A Seq[T], which can be used for sequential iteration over the elements of the Slice in reverse order.
//
// Example usage:
//
// slice := g.Slice[int]{1, 2, 3, 4, 5}
// iterator := slice.IterReverse()
// iterator.ForEach(func(element int) {
// // Perform some operation on each element in reverse order
// fmt.Println(element)
// })
//
// The 'IterReverse' method enhances the functionality of the Slice by providing an alternative
// way to iterate through its elements, enhancing flexibility in how data within a Slice is accessed and manipulated.
func (sl Slice[T]) IterReverse() Seq[T] {
return func(yield func(T) bool) {
for _, v := range slices.Backward(sl) {
if !yield(v) {
return
}
}
}
}
// Fill fills the slice with the specified value.
// This function is useful when you want to create an Slice with all elements having the same
// value.
// This method modifies the original slice in place.
//
// Parameters:
//
// - val T: The value to fill the Slice with.
//
// Example usage:
//
// slice := g.Slice[int]{0, 0, 0}
// slice.Fill(5)
//
// The modified slice will now contain: 5, 5, 5.
func (sl Slice[T]) Fill(val T) {
if len(sl) == 0 {
return
}
if len(sl) > 32 {
sl[0] = val
for i := 1; i < len(sl); i <<= 1 {
copy(sl[i:], sl[:i])
}
} else {
for i := range sl {
sl[i] = val
}
}
}
// Index returns the index of the first occurrence of the specified value in the slice, or -1 if
// not found.
func (sl Slice[T]) Index(val T) Int {
if f.IsComparable[T]() && reflect.TypeFor[T]().Kind() != reflect.Interface {
target := any(val)
for i, v := range sl {
if any(v) == target {
return Int(i)
}
}
return -1
}
return sl.IndexBy(f.Eqd(val))
}
// IndexBy returns the index of the first element in the slice
// satisfying the predicate function provided by the user.
// It iterates through the slice and applies the predicate to each element.
// If the predicate returns true for an element, it returns the index of that element.
// If no such element is found, it returns -1.
func (sl Slice[T]) IndexBy(fn func(t T) bool) Int { return Int(slices.IndexFunc(sl, fn)) }
// Insert inserts values at the specified index in the slice and modifies the original
// slice.
//
// Panics if the index is out of range. A negative index counts from the end of
// the slice; i == Len() appends at the end.
//
// Parameters:
//
// - i Int: The index at which to insert the new values.
//
// - values ...T: A variadic list of values to insert at the specified index.
//
// Example usage:
//
// slice := g.Slice[string]{"a", "b", "c", "d"}
// slice.Insert(2, "e", "f")
//
// The resulting slice will be: ["a", "b", "e", "f", "c", "d"].
func (sl *Slice[T]) Insert(i Int, values ...T) {
if sl.IsEmpty() {
if i != 0 {
boundpanic(i, 0)
}
sl.Push(values...)
return
}
sl.Replace(i, i, values...)
}
// Replace replaces the elements of sl[i:j] with the given values,
// and modifies the original slice in place. Replace panics if sl[i:j]
// is not a valid slice of sl.
//
// Parameters:
//
// - i Int: The starting index of the slice to be replaced.
//
// - j Int: The ending index of the slice to be replaced.
//
// - values ...T: A variadic list of values to replace the existing slice.
//
// Example usage:
//
// slice := g.Slice[string]{"a", "b", "c", "d"}
// slice.Replace(1, 3, "e", "f")
//
// After the Replace operation, the resulting slice will be: ["a", "e", "f", "d"].
func (sl *Slice[T]) Replace(i, j Int, values ...T) {
ii, ok := sl.boundReplace(i)
if !ok {
boundpanic(i, len(*sl))
}
jj, ok := sl.boundReplace(j)
if !ok {
boundpanic(j, len(*sl))
}
i, j = ii, jj
if i > j {
boundpanic(j, len(*sl))
}
oldLen := sl.Len()
removedCount := j - i
addedCount := Int(len(values))
newLen := oldLen - removedCount + addedCount
if i == j {
if addedCount == 0 {
return
}
if newLen > sl.Cap() {
newSlice := make(Slice[T], newLen)
copy(newSlice[:i], (*sl)[:i])
copy(newSlice[i:i+addedCount], values)
copy(newSlice[i+addedCount:], (*sl)[i:])
*sl = newSlice
} else {
*sl = (*sl)[:newLen]
copy((*sl)[i+addedCount:], (*sl)[i:oldLen])
copy((*sl)[i:], values)
}
return
}
if newLen > sl.Cap() {
newSlice := make(Slice[T], newLen)
copy(newSlice[:i], (*sl)[:i])
copy(newSlice[i:i+addedCount], values)
copy(newSlice[i+addedCount:], (*sl)[j:])
*sl = newSlice
} else {
if newLen != oldLen {
*sl = (*sl)[:newLen]
}
if addedCount != removedCount {
copy((*sl)[i+addedCount:], (*sl)[j:oldLen])
}
copy((*sl)[i:], values)
}
}
// Get returns the element at the given index, handling negative indices as counting from the end
// of the slice.
func (sl Slice[T]) Get(index Int) Option[T] {
i, ok := sl.bound(index)
if !ok {
return None[T]()
}
return Some(sl[i])
}
// Reverse reverses the order of the elements in the slice.
// This method modifies the original slice in place.
//
// Example usage:
//
// slice := g.Slice[int]{1, 2, 3, 4, 5}
// slice.Reverse()
// fmt.Println(slice)
//
// Output: [5 4 3 2 1].
func (sl Slice[T]) Reverse() { slices.Reverse(sl) }
// SortBy sorts the elements in the slice using the provided comparison function.
// It modifies the original slice in place.
//
// The comparison function should return:
// - cmp.Less if a should come before b
// - cmp.Greater if a should come after b
// - cmp.Equal if a and b are considered equal
//
// The sort is not guaranteed to be stable: the relative order of elements that
// compare equal may change.
//
// Parameters:
//
// - fn func(a, b T) cmp.Ordering: A comparison function reporting the ordering of a relative to b.
//
// Example usage:
//
// sl := NewSlice[int](1, 5, 3, 2, 4)
// sl.SortBy(func(a, b int) cmp.Ordering { return cmp.Cmp(a, b) }) // sorts in ascending order.
func (sl Slice[T]) SortBy(fn func(a, b T) cmp.Ordering) {
slices.SortFunc(sl, func(a, b T) int { return int(fn(a, b)) })
}
// IsSortedBy checks if the slice is sorted according to the provided comparison function.
//
// The function takes a custom comparison function as an argument and checks if the elements
// are sorted according to the provided logic.
//
// Parameters:
//
// - fn func(a, b T) cmp.Ordering: A comparison function that defines the sort order.
//
// Returns:
//
// - bool: true if the slice is sorted according to the comparison function, false otherwise.
//
// Example usage:
//
// sl := g.SliceOf(1, 2, 3, 4, 5)
// sorted := sl.IsSortedBy(func(a, b int) cmp.Ordering { return cmp.Cmp(a, b) }) // returns true
func (sl Slice[T]) IsSortedBy(fn func(a, b T) cmp.Ordering) bool {
if len(sl) <= 1 {
return true
}
for i := 1; i < len(sl); i++ {
if fn(sl[i-1], sl[i]).IsGt() {
return false
}
}
return true
}
// BinarySearch searches a sorted slice for value using the comparator fn and
// returns Some(index) if an equal element is found, or None otherwise. The slice
// must be sorted in ascending order according to fn (see IsSortedBy).
func (sl Slice[T]) BinarySearch(value T, fn func(a, b T) cmp.Ordering) Option[Int] {
if i, ok := slices.BinarySearchFunc(sl, value, func(a, b T) int { return int(fn(a, b)) }); ok {
return Some(Int(i))
}
return None[Int]()
}
// PartitionPoint returns the index of the first element for which pred returns
// false, assuming the slice is partitioned so that all elements satisfying pred
// come first. If pred is true for every element, it returns the slice length.
// Runs in O(log n).
func (sl Slice[T]) PartitionPoint(pred func(T) bool) Int {
lo, hi := Int(0), sl.Len()
for lo < hi {
mid := (lo + hi) / 2
if pred(sl[mid]) {
lo = mid + 1
} else {
hi = mid
}
}
return lo
}
// Retain keeps only the elements for which fn returns true, removing the rest
// in place while preserving order. It is the in-place counterpart of Deque.Retain.
func (sl *Slice[T]) Retain(fn func(T) bool) {
*sl = slices.DeleteFunc(*sl, func(v T) bool { return !fn(v) })
}
// DedupBy removes consecutive elements considered equal by eq, keeping the first
// of each run, in place. It is the eager, in-place counterpart of the lazy
// Seq.Dedup. Only adjacent duplicates are removed, so sort first for a
// global dedup.
func (sl *Slice[T]) DedupBy(eq func(a, b T) bool) {
*sl = slices.CompactFunc(*sl, eq)
}
// Join joins the elements in the slice into a single String, separated by the provided separator (if any).
func (sl Slice[T]) Join(sep ...T) String {
if sl.IsEmpty() {
return ""
}
if s, ok := any(sl).(Slice[Bytes]); ok {
if len(s) == 0 {
return ""
}
var separator Bytes
if len(sep) != 0 {
separator, _ = any(sep[0]).(Bytes)
}
total := len(separator) * (len(s) - 1)
for _, value := range s {
total += len(value)
}
var builder Builder
builder.Grow(Int(total))
for i, value := range s {
if i > 0 {
builder.Write(separator)
}
builder.Write(value)
}
return builder.String()
}
if s, ok := any(sl).(Slice[String]); ok {
var separator string
if len(sep) != 0 {
if sepStr, ok := any(sep[0]).(String); ok {
separator = sepStr.Std()
} else {
separator = fmt.Sprint(sep[0])
}
}
total := len(separator) * (len(s) - 1)
for _, str := range s {
total += len(str)
}
var b strings.Builder
b.Grow(total)
for i, str := range s {
if i > 0 {
b.WriteString(separator)
}
b.WriteString(str.Std())
}
return String(b.String())
}
var separator string
if len(sep) != 0 {
separator = fmt.Sprint(sep[0])
}
var b strings.Builder
for i, v := range sl {
if i > 0 {
b.WriteString(separator)
}
fmt.Fprint(&b, v)
}
return String(b.String())
}
// SubSlice returns a new slice containing elements from the current slice between the specified start
// and end indices, with an optional step parameter to define the increment between elements.
// Negative start or end indices count from the end of the slice.
//
// Panics if start or end is out of range after negative-index resolution.
//
// Parameters:
//
// - start (Int): The start index of the range.
//
// - end (Int): The end index of the range.
//
// - step (Int, optional): The increment between elements. Defaults to 1 if not provided.
// If negative, the slice is traversed in reverse order.
//
// Returns:
//
// - Slice[T]: A new slice containing elements from the current slice between the start and end
// indices, with the specified step.
//
// Example usage:
//
// slice := g.Slice[int]{1, 2, 3, 4, 5, 6, 7, 8, 9}
// subSlice := slice.SubSlice(1, 7, 2) // Extracts elements 2, 4, 6
// fmt.Println(subSlice)
//
// Output: [2 4 6].
func (sl Slice[T]) SubSlice(start, end Int, step ...Int) Slice[T] {
if sl.IsEmpty() {
return NewSlice[T]()
}
_step := Int(1)
if len(step) > 0 {
_step = Int(step[0])
}
ii, ok := sl.boundsub(start)
if !ok {
boundpanic(start, len(sl))
}
jj, ok := sl.boundsub(end)
if !ok {
boundpanic(end, len(sl))
}
start, end = ii, jj
// For a negative step the iteration starts AT start and moves down, so a
// start clamped to len(sl) must begin at the last element (s[100:0:-1]
// starts at the final index, not one past it).
if _step < 0 && start == sl.Len() {
start--
}
if _step == 1 {
if start >= end {
return NewSlice[T]()
}
return slices.Clone(sl[start:end])
}
if (start >= end && _step > 0) || (start <= end && _step < 0) || _step == 0 {
return NewSlice[T]()
}
var resultSize Int
if _step > 0 {
resultSize = (end - start + _step - 1) / _step
} else {
resultSize = (start - end + (-_step) - 1) / (-_step)
}
slice := make(Slice[T], 0, resultSize)
if _step > 0 {
for i := start; i < end; i += _step {
slice = append(slice, sl[i])
}
} else {
for i := start; i > end; i += _step {
slice = append(slice, sl[i])
}
}
return slice
}
// Clone returns a copy of the slice.
func (sl Slice[T]) Clone() Slice[T] {
if sl.IsEmpty() {
return NewSlice[T]()
}
return slices.Clone(sl)
}
// LastIndex returns the last index of the slice.
func (sl Slice[T]) LastIndex() Int {
if !sl.IsEmpty() {
return sl.Len() - 1
}
return 0
}
// Eq returns true if the slice is equal to the provided other slice.
func (sl Slice[T]) Eq(other Slice[T]) bool {
if len(sl) != len(other) {
return false
}
if f.IsComparable[T]() && reflect.TypeFor[T]().Kind() != reflect.Interface {
for i, v := range sl {
if any(v) != any(other[i]) {
return false
}
}
return true
}
return sl.EqBy(other, func(x, y T) bool { return reflect.DeepEqual(x, y) })
}
// EqBy reports whether two slices are equal using an equality
// function on each pair of elements. If the lengths are different,
// EqBy 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 (sl Slice[T]) EqBy(other Slice[T], fn func(x, y T) bool) bool {
return slices.EqualFunc(sl, other, fn)
}
// String returns a string representation of the slice.
func (sl Slice[T]) String() string {
if len(sl) == 0 {
return "Slice[]"
}
var b Builder
b.Grow(Int(len(sl)) * 8)
b.WriteString("Slice[")
for i, v := range sl {
if i > 0 {
b.WriteString(", ")
}
fmt.Fprint(&b, v)
}
b.WriteString("]")
return b.String().Std()
}
// Append appends the provided elements to the slice and returns the modified slice.
func (sl Slice[T]) Append(elems ...T) Slice[T] { return append(sl, elems...) }
// AppendUnique appends unique elements from the provided arguments to the current slice.
//
// The function iterates over the provided elements and checks if they are already present
// in the slice. If an element is not already present, it is appended to the slice. The
// resulting slice is returned, containing the unique elements from both the original
// slice and the provided elements.
//
// Parameters:
//
// - elems (...T): A variadic list of elements to be appended to the slice.
//
// Returns:
//
// - Slice[T]: A new slice containing the unique elements from both the original slice
// and the provided elements.
//
// Example usage:
//
// slice := g.Slice[int]{1, 2, 3, 4, 5}
// slice = slice.AppendUnique(3, 4, 5, 6, 7)
// fmt.Println(slice)
//
// Output: [1 2 3 4 5 6 7].
func (sl Slice[T]) AppendUnique(elems ...T) Slice[T] {
if f.IsComparable[T]() && reflect.TypeFor[T]().Kind() != reflect.Interface {
set := make(Set[any], len(sl)+len(elems))
for _, v := range sl {
set[v] = Unit{}
}
for _, elem := range elems {
if !set.Contains(elem) {
sl = append(sl, elem)
set.Insert(elem)
}
}
return sl
}
for _, elem := range elems {
if !sl.Contains(elem) {
sl = append(sl, elem)
}
}
return sl
}
// Push appends the provided elements to the slice and modifies the original slice.
func (sl *Slice[T]) Push(elems ...T) { *sl = append(*sl, elems...) }
// PushUnique appends unique elements from the provided arguments to the current slice.
//
// The function iterates over the provided elements and checks if they are already present
// in the slice. If an element is not already present, it is appended to the slice.
//
// Parameters:
//
// - elems (...T): A variadic list of elements to be appended to the slice.
//
// Example usage:
//
// slice := g.Slice[int]{1, 2, 3, 4, 5}
// slice.PushUnique(3, 4, 5, 6, 7)
// fmt.Println(slice)
//
// Output: [1 2 3 4 5 6 7].
func (sl *Slice[T]) PushUnique(elems ...T) {
if f.IsComparable[T]() && reflect.TypeFor[T]().Kind() != reflect.Interface {
set := make(Set[any], len(*sl)+len(elems))
for _, v := range *sl {
set[v] = Unit{}
}
for _, elem := range elems {
if !set.Contains(elem) {
sl.Push(elem)
set.Insert(elem)
}
}
return
}
for _, elem := range elems {
if !sl.Contains(elem) {
sl.Push(elem)
}
}
}
// Cap returns the capacity of the Slice.
func (sl Slice[T]) Cap() Int { return Int(cap(sl)) }
// Contains returns true if the slice contains the provided value.
func (sl Slice[T]) Contains(val T) bool { return sl.Index(val) >= 0 }
// ContainsBy returns true if the slice contains an element that satisfies the provided function fn, false otherwise.
func (sl Slice[T]) ContainsBy(fn func(t T) bool) bool { return sl.IndexBy(fn) >= 0 }
// ContainsAny checks if the Slice contains any element from another Slice.
func (sl Slice[T]) ContainsAny(values ...T) bool {
if sl.IsEmpty() || len(values) == 0 {
return false
}
if f.IsComparable[T]() && reflect.TypeFor[T]().Kind() != reflect.Interface {
set := make(Set[any], len(sl))
for _, v := range sl {
set[v] = Unit{}
}
for _, v := range values {
if set.Contains(v) {
return true
}
}
return false
}
return slices.ContainsFunc(values, sl.Contains)
}
// ContainsAll checks if the Slice contains all elements from another Slice.
func (sl Slice[T]) ContainsAll(values ...T) bool {
if sl.IsEmpty() || len(values) == 0 {
return len(values) == 0
}
if f.IsComparable[T]() && reflect.TypeFor[T]().Kind() != reflect.Interface {
set := make(Set[any], len(sl))
for _, v := range sl {
set[v] = Unit{}
}
for _, v := range values {
if !set.Contains(v) {
return false
}
}
return true
}
for _, v := range values {
if !sl.Contains(v) {
return false
}
}
return true
}
// Remove removes and returns the element at the specified index.
// Returns None if index is out of bounds.
// Negative indices are supported: -1 refers to the last element, etc.
func (sl *Slice[T]) Remove(index Int) Option[T] {
if sl.IsEmpty() {
return None[T]()
}
length := sl.Len()
if index < 0 {
index += length
}
if index < 0 || index >= length {
return None[T]()
}
value := (*sl)[index]
*sl = append((*sl)[:index], (*sl)[index+1:]...)
return Some(value)
}
// IsEmpty returns true if the slice is empty.
func (sl Slice[T]) IsEmpty() bool { return len(sl) == 0 }
// First returns the first element of the slice.
func (sl Slice[T]) First() Option[T] { return sl.Get(0) }
// Last returns the last element of the slice.
func (sl Slice[T]) Last() Option[T] { return sl.Get(-1) }
// Ne returns true if the slice is not equal to the provided other slice.
func (sl Slice[T]) Ne(other Slice[T]) bool { return !sl.Eq(other) }
// NeBy reports whether two slices are not equal using an inequality
// function on each pair of elements. If the lengths are different,
// NeBy returns true. Otherwise, the elements are compared in
// increasing index order, and the comparison stops at the first index
// for which fn returns true.
func (sl Slice[T]) NeBy(other Slice[T], fn func(x, y T) bool) bool { return !sl.EqBy(other, fn) }
// Pop removes and returns the last element of the slice.
// It mutates the original slice by removing the last element.
// It returns None if the slice is empty.
func (sl *Slice[T]) Pop() Option[T] {
if sl.Len() == 0 {
return None[T]()
}
last := (*sl)[sl.Len()-1]
*sl = (*sl)[:sl.Len()-1]
return Some(last)
}
// Set sets the value at the specified index in the slice and returns the previous
// value wrapped in Some. If the index is out of bounds, the slice is left unchanged
// and None is returned, mirroring Deque.Set.
// This method modifies the original slice in place. Negative indices count from the end.
//
// Parameters:
//
// - index (Int): The index at which to set the new value.
// - val (T): The new value to be set at the specified index.
//
// Returns:
//
// - Option[T]: The previous value at the index, or None if the index is out of bounds.
//
// Example usage:
//
// slice := g.Slice[int]{1, 2, 3, 4, 5}
// old := slice.Set(2, 99) // Some(3)
// fmt.Println(slice)
//
// Output: [1 2 99 4 5].
func (sl Slice[T]) Set(index Int, val T) Option[T] {
i, ok := sl.bound(index)
if !ok {
return None[T]()
}
old := sl[i]
sl[i] = val
return Some(old)
}
// Len returns the length of the slice.
func (sl Slice[T]) Len() Int { return Int(len(sl)) }
// Swap swaps the elements at the specified indices in the slice.
// This method modifies the original slice in place.
//
// Panics if either index is out of range. A negative index counts
// from the end of the slice.
//
// Parameters:
//
// - i (Int): The index of the first element to be swapped.
//
// - j (Int): The index of the second element to be swapped.
//
// Example usage:
//
// slice := g.Slice[int]{1, 2, 3, 4, 5}
// slice.Swap(1, 3)
// fmt.Println(slice)
//
// Output: [1 4 3 2 5].
func (sl Slice[T]) Swap(i, j Int) {
ii, ok := sl.bound(i)
if !ok {
boundpanic(i, len(sl))
}
jj, ok := sl.bound(j)
if !ok {
boundpanic(j, len(sl))
}
sl[ii], sl[jj] = sl[jj], sl[ii]
}
// 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 (sl Slice[T]) Grow(n Int) Slice[T] { return slices.Grow(sl, n.Std()) }
// Clip removes unused capacity from the slice.
func (sl Slice[T]) Clip() Slice[T] { return slices.Clip(sl) }
// Std returns a new slice with the same elements as the Slice[T].
func (sl Slice[T]) Std() []T { return sl }
// Print writes the elements of the Slice to the standard output (console)
// and returns the Slice unchanged.
func (sl Slice[T]) Print() Slice[T] { fmt.Print(sl); return sl }
// Println writes the elements of the Slice to the standard output (console) with a newline
// and returns the Slice unchanged.
func (sl Slice[T]) Println() Slice[T] { fmt.Println(sl); return sl }
// Unpack assigns values of the slice's elements to the variables passed as pointers.
// If the number of variables passed is greater than the length of the slice,
// the function ignores the extra variables.
//
// Parameters:
//
// - vars (...*T): Pointers to variables where the values of the slice's elements will be stored.
//
// Example:
//
// slice := g.Slice[int]{1, 2, 3, 4, 5}
// var a, b, c int
// slice.Unpack(&a, &b, &c)
// fmt.Println(a, b, c) // Output: 1 2 3
func (sl Slice[T]) Unpack(vars ...*T) {
n := min(len(sl), len(vars))
for i := range n {
if vars[i] != nil {
*vars[i] = sl[i]
}
}
}
func (sl Slice[T]) bound(i Int) (Int, bool) {
n := sl.Len()
if n == 0 {
return 0, false
}
if i < 0 {
i += n
}
if i >= n || i < 0 {
return 0, false
}
return i, true
}
// boundReplace resolves an index for Replace, which may legitimately target
// i == len(sl) to append at the end. Element accessors use bound (strict i < n).
func (sl Slice[T]) boundReplace(i Int) (Int, bool) {
n := sl.Len()
if n == 0 {
return 0, false
}
if i < 0 {
i += n
}
if i > n || i < 0 {
return 0, false
}
return i, true
}
func (sl Slice[T]) boundsub(i Int) (Int, bool) {
n := sl.Len()
if n == 0 {
return 0, false
}
if i < 0 {
i += n
}
if i > n || i < -1 {
return 0, false
}
return i, true
}
func boundpanic(index Int, length int) {
panic(fmt.Sprintf("runtime error: slice bounds out of range [%d] with length %d", index, length))
}