slices: add ContainsFunc function

Since we have Index, IndexFunc, and Contains functions, it's logical to have ContainsFunc function as well.

Fixes #53983

Change-Id: I1237d43bd93927d38b51e3e9ce5386b9098049f7
GitHub-Last-Rev: b7f6091ee3a33d1234a5cbe8a49e522d1932d580
GitHub-Pull-Request: golang/exp#39
Reviewed-on: https://go-review.googlesource.com/c/exp/+/417374
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Auto-Submit: Ian Lance Taylor <iant@google.com>
diff --git a/slices/slices.go b/slices/slices.go
index 6b7928e..01bed6c 100644
--- a/slices/slices.go
+++ b/slices/slices.go
@@ -128,6 +128,12 @@
 	return Index(s, v) >= 0
 }
 
+// ContainsFunc reports whether at least one
+// element e of s satisfies f(e).
+func ContainsFunc[E any](s []E, f func(E) bool) bool {
+	return IndexFunc(s, f) >= 0
+}
+
 // Insert inserts the values v... into s at index i,
 // returning the modified slice.
 // In the returned slice r, r[i] == v[0].
diff --git a/slices/slices_test.go b/slices/slices_test.go
index 7473886..1d9ffd2 100644
--- a/slices/slices_test.go
+++ b/slices/slices_test.go
@@ -358,6 +358,25 @@
 	}
 }
 
+func TestContainsFunc(t *testing.T) {
+	for _, test := range indexTests {
+		if got := ContainsFunc(test.s, equalToIndex(equal[int], test.v)); got != (test.want != -1) {
+			t.Errorf("ContainsFunc(%v, equalToIndex(equal[int], %v)) = %t, want %t", test.s, test.v, got, test.want != -1)
+		}
+	}
+
+	s1 := []string{"hi", "HI"}
+	if got := ContainsFunc(s1, equalToIndex(equal[string], "HI")); got != true {
+		t.Errorf("ContainsFunc(%v, equalToContains(equal[string], %q)) = %t, want %t", s1, "HI", got, true)
+	}
+	if got := ContainsFunc(s1, equalToIndex(equal[string], "hI")); got != false {
+		t.Errorf("ContainsFunc(%v, equalToContains(strings.EqualFold, %q)) = %t, want %t", s1, "hI", got, false)
+	}
+	if got := ContainsFunc(s1, equalToIndex(strings.EqualFold, "hI")); got != true {
+		t.Errorf("ContainsFunc(%v, equalToContains(strings.EqualFold, %q)) = %t, want %t", s1, "hI", got, true)
+	}
+}
+
 var insertTests = []struct {
 	s    []int
 	i    int