diff options
Diffstat (limited to 'internal/util')
-rw-r--r-- | internal/util/xslices/slices.go (renamed from internal/util/slices.go) | 43 | ||||
-rw-r--r-- | internal/util/xslices/slices_test.go (renamed from internal/util/slices_test.go) | 86 |
2 files changed, 119 insertions, 10 deletions
diff --git a/internal/util/slices.go b/internal/util/xslices/slices.go index 955fe8830..1c1c159b2 100644 --- a/internal/util/slices.go +++ b/internal/util/xslices/slices.go @@ -15,12 +15,53 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. -package util +package xslices import ( "slices" ) +// GrowJust increases slice capacity to guarantee +// extra room 'size', where in the case that it does +// need to allocate more it ONLY allocates 'size' extra. +// This is different to typical slices.Grow behaviour, +// which simply guarantees extra through append() which +// may allocate more than necessary extra size. +func GrowJust[T any](in []T, size int) []T { + + if cap(in)-len(in) < size { + // Reallocate enough for in + size. + in2 := make([]T, len(in), len(in)+size) + _ = copy(in2, in) + in = in2 + } + + return in +} + +// AppendJust appends extra elements to slice, +// ONLY allocating at most len(extra) elements. This +// is different to the typical append behaviour which +// will append extra, in a manner to reduce the need +// for new allocations on every call to append. +func AppendJust[T any](in []T, extra ...T) []T { + l := len(in) + + if cap(in)-l < len(extra) { + // Reallocate enough for + extra. + in2 := make([]T, l+len(extra)) + _ = copy(in2, in) + in = in2 + } else { + // Reslice for + extra. + in = in[:l+len(extra)] + } + + // Copy extra into slice. + _ = copy(in[l:], extra) + return in +} + // Deduplicate deduplicates entries in the given slice. func Deduplicate[T comparable](in []T) []T { var ( diff --git a/internal/util/slices_test.go b/internal/util/xslices/slices_test.go index c93e489f5..7c62ac77f 100644 --- a/internal/util/slices_test.go +++ b/internal/util/xslices/slices_test.go @@ -15,22 +15,90 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. -package util_test +package xslices_test import ( + "math/rand" "net/url" "slices" "testing" - "github.com/superseriousbusiness/gotosocial/internal/util" + "github.com/stretchr/testify/assert" + "github.com/superseriousbusiness/gotosocial/internal/util/xslices" ) -var ( - testURLSlice = []*url.URL{} -) +func TestGrowJust(t *testing.T) { + for _, l := range []int{0, 2, 4, 8, 16, 32, 64} { + for _, x := range []int{0, 2, 4, 8, 16, 32, 64} { + s := make([]int, l, l+x) + for _, g := range []int{0, 2, 4, 8, 16, 32, 64} { + s2 := xslices.GrowJust(s, g) + + // Slice length should not be different. + assert.Equal(t, len(s), len(s2)) + + switch { + // If slice already has capacity for + // 'g' then it should not be changed. + case cap(s) >= len(s)+g: + assert.Equal(t, cap(s), cap(s2)) + + // Else, returned slice should only + // have capacity for original length + // plus extra elements, NOTHING MORE. + default: + assert.Equal(t, cap(s2), len(s)+g) + } + } + } + } +} + +func TestAppendJust(t *testing.T) { + for _, l := range []int{0, 2, 4, 8, 16, 32, 64} { + for _, x := range []int{0, 2, 4, 8, 16, 32, 64} { + s := make([]int, l, l+x) + + // Randomize slice. + for i := range s { + s[i] = rand.Int() + } + + for _, a := range []int{0, 2, 4, 8, 16, 32, 64} { + toAppend := make([]int, a) + + // Randomize appended vals. + for i := range toAppend { + toAppend[i] = rand.Int() + } + + s2 := xslices.AppendJust(s, toAppend...) + + // Slice length should be as expected. + assert.Equal(t, len(s)+a, len(s2)) + + // Slice contents should be as expected. + assert.Equal(t, append(s, toAppend...), s2) + + switch { + // If slice already has capacity for + // 'toAppend' then it should not change. + case cap(s) >= len(s)+a: + assert.Equal(t, cap(s), cap(s2)) + + // Else, returned slice should only + // have capacity for original length + // plus extra elements, NOTHING MORE. + default: + assert.Equal(t, len(s)+a, cap(s2)) + } + } + } + } +} func TestGather(t *testing.T) { - out := util.Gather(nil, []*url.URL{ + out := xslices.Gather(nil, []*url.URL{ {Scheme: "https", Host: "google.com", Path: "/some-search"}, {Scheme: "http", Host: "example.com", Path: "/robots.txt"}, }, (*url.URL).String) @@ -41,7 +109,7 @@ func TestGather(t *testing.T) { t.Fatal("unexpected gather output") } - out = util.Gather([]string{ + out = xslices.Gather([]string{ "starting input string", "another starting input", }, []*url.URL{ @@ -59,7 +127,7 @@ func TestGather(t *testing.T) { } func TestGatherIf(t *testing.T) { - out := util.GatherIf(nil, []string{ + out := xslices.GatherIf(nil, []string{ "hello world", "not hello world", "hello world", @@ -73,7 +141,7 @@ func TestGatherIf(t *testing.T) { t.Fatal("unexpected gatherif output") } - out = util.GatherIf([]string{ + out = xslices.GatherIf([]string{ "starting input string", "another starting input", }, []string{ |