util/slicesx: add Filter function

For use in corp, where we appear to have re-implemented this in a few
places with varying signatures.

Signed-off-by: Andrew Dunham <andrew@du.nham.ca>
Change-Id: Id863a87e674f3caa87945519be8e09650e9c1d76
pull/10899/head
Andrew Dunham 10 months ago
parent 2aec4f2c43
commit 2ac7c0161b

@ -77,3 +77,17 @@ func EqualSameNil[S ~[]E, E comparable](s1, s2 S) bool {
} }
return true return true
} }
// Filter calls fn with each element of the provided src slice, and appends the
// element to dst if fn returns true.
//
// dst can be nil to allocate a new slice, or set to src[:0] to filter in-place
// without allocating.
func Filter[S ~[]T, T any](dst, src S, fn func(T) bool) S {
for _, x := range src {
if fn(x) {
dst = append(dst, x)
}
}
return dst
}

@ -97,3 +97,42 @@ func TestEqualSameNil(t *testing.T) {
c.Check(EqualSameNil([]string{}, nil), qt.Equals, false) c.Check(EqualSameNil([]string{}, nil), qt.Equals, false)
c.Check(EqualSameNil[[]string](nil, nil), qt.Equals, true) c.Check(EqualSameNil[[]string](nil, nil), qt.Equals, true)
} }
func TestFilter(t *testing.T) {
var sl []int
for i := 1; i <= 10; i++ {
sl = append(sl, i)
}
evens := Filter(nil, sl, func(elem int) bool {
return elem%2 == 0
})
want := []int{2, 4, 6, 8, 10}
if !reflect.DeepEqual(evens, want) {
t.Errorf("evens: got %v, want %v", evens, want)
}
}
func TestFilterNoAllocations(t *testing.T) {
var sl []int
for i := 1; i <= 10; i++ {
sl = append(sl, i)
}
want := []int{2, 4, 6, 8, 10}
allocs := testing.AllocsPerRun(1000, func() {
src := slices.Clone(sl)
evens := Filter(src[:0], src, func(elem int) bool {
return elem%2 == 0
})
if !slices.Equal(evens, want) {
t.Errorf("evens: got %v, want %v", evens, want)
}
})
// 1 alloc for 'src', nothing else
if allocs != 1 {
t.Fatalf("got %.4f allocs, want 1", allocs)
}
}

Loading…
Cancel
Save