Sfoglia il codice sorgente

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 <[email protected]>
Change-Id: Id863a87e674f3caa87945519be8e09650e9c1d76
Andrew Dunham 2 anni fa
parent
commit
2ac7c0161b
2 ha cambiato i file con 53 aggiunte e 0 eliminazioni
  1. 14 0
      util/slicesx/slicesx.go
  2. 39 0
      util/slicesx/slicesx_test.go

+ 14 - 0
util/slicesx/slicesx.go

@@ -77,3 +77,17 @@ func EqualSameNil[S ~[]E, E comparable](s1, s2 S) bool {
 	}
 	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
+}

+ 39 - 0
util/slicesx/slicesx_test.go

@@ -97,3 +97,42 @@ func TestEqualSameNil(t *testing.T) {
 	c.Check(EqualSameNil([]string{}, nil), qt.Equals, false)
 	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)
+	}
+}