mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 04:14:39 +03:00
Use slices package from the stdlib when possible (#5360)
* Use slices from the stdlib when possible * Add some unit tests * More small tweaks + add benchmark func
This commit is contained in:
@@ -1,26 +1,14 @@
|
||||
// Package sliceutil provides utilities for working with slices.
|
||||
package sliceutil
|
||||
|
||||
// Index returns the first index of the provided value in the provided
|
||||
// slice. It returns -1 if it is not found.
|
||||
func Index[T comparable](vs []T, t T) int {
|
||||
for i, v := range vs {
|
||||
if v == t {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Contains returns whether the vs slice contains t.
|
||||
func Contains[T comparable](vs []T, t T) bool {
|
||||
return Index(vs, t) >= 0
|
||||
}
|
||||
import (
|
||||
"slices"
|
||||
)
|
||||
|
||||
// AppendUnique appends toAdd to the vs slice if toAdd does not already
|
||||
// exist in the slice. It returns the new or unchanged slice.
|
||||
func AppendUnique[T comparable](vs []T, toAdd T) []T {
|
||||
if Contains(vs, toAdd) {
|
||||
if slices.Contains(vs, toAdd) {
|
||||
return vs
|
||||
}
|
||||
|
||||
@@ -31,6 +19,13 @@ func AppendUnique[T comparable](vs []T, toAdd T) []T {
|
||||
// appends values that do not already exist in the slice.
|
||||
// It returns the new or unchanged slice.
|
||||
func AppendUniques[T comparable](vs []T, toAdd []T) []T {
|
||||
if len(toAdd) == 0 {
|
||||
return vs
|
||||
}
|
||||
|
||||
// Extend the slice's capacity to avoid multiple re-allocations even in the worst case
|
||||
vs = slices.Grow(vs, len(toAdd))
|
||||
|
||||
for _, v := range toAdd {
|
||||
vs = AppendUnique(vs, v)
|
||||
}
|
||||
@@ -41,9 +36,9 @@ func AppendUniques[T comparable](vs []T, toAdd []T) []T {
|
||||
// Exclude returns a copy of the vs slice, excluding all values
|
||||
// that are also present in the toExclude slice.
|
||||
func Exclude[T comparable](vs []T, toExclude []T) []T {
|
||||
var ret []T
|
||||
ret := make([]T, 0, len(vs))
|
||||
for _, v := range vs {
|
||||
if !Contains(toExclude, v) {
|
||||
if !slices.Contains(toExclude, v) {
|
||||
ret = append(ret, v)
|
||||
}
|
||||
}
|
||||
@@ -53,8 +48,8 @@ func Exclude[T comparable](vs []T, toExclude []T) []T {
|
||||
|
||||
// Unique returns a copy of the vs slice, with non-unique values removed.
|
||||
func Unique[T comparable](vs []T) []T {
|
||||
distinctValues := make(map[T]struct{})
|
||||
var ret []T
|
||||
distinctValues := make(map[T]struct{}, len(vs))
|
||||
ret := make([]T, 0, len(vs))
|
||||
for _, v := range vs {
|
||||
if _, exists := distinctValues[v]; !exists {
|
||||
distinctValues[v] = struct{}{}
|
||||
@@ -66,7 +61,7 @@ func Unique[T comparable](vs []T) []T {
|
||||
|
||||
// Delete returns a copy of the vs slice with toDel values removed.
|
||||
func Delete[T comparable](vs []T, toDel T) []T {
|
||||
var ret []T
|
||||
ret := make([]T, 0, len(vs))
|
||||
for _, v := range vs {
|
||||
if v != toDel {
|
||||
ret = append(ret, v)
|
||||
@@ -79,7 +74,7 @@ func Delete[T comparable](vs []T, toDel T) []T {
|
||||
func Intersect[T comparable](a []T, b []T) []T {
|
||||
var ret []T
|
||||
for _, v := range a {
|
||||
if Contains(b, v) {
|
||||
if slices.Contains(b, v) {
|
||||
ret = append(ret, v)
|
||||
}
|
||||
}
|
||||
@@ -91,13 +86,13 @@ func Intersect[T comparable](a []T, b []T) []T {
|
||||
func NotIntersect[T comparable](a []T, b []T) []T {
|
||||
var ret []T
|
||||
for _, v := range a {
|
||||
if !Contains(b, v) {
|
||||
if !slices.Contains(b, v) {
|
||||
ret = append(ret, v)
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range b {
|
||||
if !Contains(a, v) {
|
||||
if !slices.Contains(a, v) {
|
||||
ret = append(ret, v)
|
||||
}
|
||||
}
|
||||
@@ -166,8 +161,9 @@ func PtrsToValues[T any](vs []*T) []T {
|
||||
func ValuesToPtrs[T any](vs []T) []*T {
|
||||
ret := make([]*T, len(vs))
|
||||
for i, v := range vs {
|
||||
vv := v
|
||||
ret[i] = &vv
|
||||
// We can do this safely because go.mod indicates Go 1.22
|
||||
// See: https://go.dev/blog/loopvar-preview
|
||||
ret[i] = &v
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package sliceutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -66,3 +67,85 @@ func TestSliceSame(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendUniques(t *testing.T) {
|
||||
type args struct {
|
||||
vs []int
|
||||
toAdd []int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []int
|
||||
}{
|
||||
{
|
||||
name: "append to empty slice",
|
||||
args: args{
|
||||
vs: []int{},
|
||||
toAdd: []int{1, 2, 3},
|
||||
},
|
||||
want: []int{1, 2, 3},
|
||||
},
|
||||
{
|
||||
name: "append all unique values",
|
||||
args: args{
|
||||
vs: []int{1, 2, 3},
|
||||
toAdd: []int{4, 5, 6},
|
||||
},
|
||||
want: []int{1, 2, 3, 4, 5, 6},
|
||||
},
|
||||
{
|
||||
name: "append with some duplicates",
|
||||
args: args{
|
||||
vs: []int{1, 2, 3},
|
||||
toAdd: []int{3, 4, 5},
|
||||
},
|
||||
want: []int{1, 2, 3, 4, 5},
|
||||
},
|
||||
{
|
||||
name: "append all duplicates",
|
||||
args: args{
|
||||
vs: []int{1, 2, 3},
|
||||
toAdd: []int{1, 2, 3},
|
||||
},
|
||||
want: []int{1, 2, 3},
|
||||
},
|
||||
{
|
||||
name: "append to nil slice",
|
||||
args: args{
|
||||
vs: nil,
|
||||
toAdd: []int{1, 2, 3},
|
||||
},
|
||||
want: []int{1, 2, 3},
|
||||
},
|
||||
{
|
||||
name: "append empty slice",
|
||||
args: args{
|
||||
vs: []int{1, 2, 3},
|
||||
toAdd: []int{},
|
||||
},
|
||||
want: []int{1, 2, 3},
|
||||
},
|
||||
{
|
||||
name: "append nil to slice",
|
||||
args: args{
|
||||
vs: []int{1, 2, 3},
|
||||
toAdd: nil,
|
||||
},
|
||||
want: []int{1, 2, 3},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := AppendUniques(tt.args.vs, tt.args.toAdd); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("AppendUniques() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAppendUniques(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
AppendUniques([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, []int{3, 4, 4, 11, 12, 13, 14, 15, 16, 17, 18})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ func FromString(s string, sep string) []string {
|
||||
// Unique returns a slice containing only unique values from the provided slice.
|
||||
// The comparison is case-insensitive.
|
||||
func UniqueFold(s []string) []string {
|
||||
seen := make(map[string]struct{})
|
||||
var ret []string
|
||||
seen := make(map[string]struct{}, len(s))
|
||||
ret := make([]string, 0, len(s))
|
||||
for _, v := range s {
|
||||
if _, exists := seen[strings.ToLower(v)]; exists {
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user