util/set: add ContainsSet and ContainsAll

These are trivial methods, but useful and generally applicable operations
for a set type.

Updates #cleanup

Change-Id: I94610b901cd10fe66dd15c38b8601f29ead71811
Signed-off-by: Tom Proctor <tomhjp@users.noreply.github.com>
This commit is contained in:
Tom Proctor 2026-04-23 14:19:44 +01:00
parent a7d8aeb8ae
commit 5de7033a82
No known key found for this signature in database
2 changed files with 86 additions and 0 deletions

View File

@ -6,6 +6,7 @@ package set
import (
"encoding/json"
"iter"
"maps"
"reflect"
"sort"
@ -111,6 +112,23 @@ func (s Set[T]) Contains(e T) bool {
return ok
}
// ContainsSet reports whether s is a superset of e. Returns true if e is nil,
// empty, or equal to s.
func (s Set[T]) ContainsSet(e Set[T]) bool {
return s.ContainsAll(maps.Keys(e))
}
// ContainsAll reports whether s contains all elements of e. Returns true if e
// has 0 elements.
func (s Set[T]) ContainsAll(e iter.Seq[T]) bool {
for k := range e {
if !s.Contains(k) {
return false
}
}
return true
}
// Len reports the number of items in s.
func (s Set[T]) Len() int { return len(s) }

View File

@ -5,6 +5,8 @@ package set
import (
"encoding/json"
"iter"
"maps"
"slices"
"testing"
)
@ -200,3 +202,69 @@ func TestMake(t *testing.T) {
t.Error("missing 1")
}
}
func TestContainsCollection(t *testing.T) {
s := Of(1, 2, 3)
for name, tc := range map[string]struct {
e []int
expected bool
}{
"equal": {
e: []int{1, 2, 3},
expected: true,
},
"superset": {
e: []int{2, 3},
expected: true,
},
"disjoint": {
e: []int{4, 5},
expected: false,
},
"partial": {
e: []int{2, 4},
expected: false,
},
} {
t.Run(name, func(t *testing.T) {
if s.ContainsSet(Of(tc.e...)) != tc.expected {
t.Errorf("ContainsSet(%v) = %v; want %v", tc.e, !tc.expected, tc.expected)
}
if s.ContainsAll(slices.Values(tc.e)) != tc.expected {
t.Errorf("ContainsSet(%v) = %v; want %v", tc.e, !tc.expected, tc.expected)
}
})
}
}
// Test ContainsSet always return true for empty collections.
func TestContainsSetEmpty(t *testing.T) {
var emptySets = []Set[int]{
nil,
make(Set[int]),
Of[int](),
}
for _, s := range []Set[int]{nil, make(Set[int]), Of[int](), Of(1, 2, 3)} {
for _, empty := range emptySets {
if !s.ContainsSet(empty) {
t.Errorf("set %v should contain empty set %v", s, empty)
}
}
}
}
// Test ContainsAll always return true for empty collections.
func TestContainsAllEmpty(t *testing.T) {
var emptyIters = []iter.Seq[int]{
func(yield func(int) bool) {},
slices.Values([]int{}),
maps.Keys(map[int]struct{}{}),
}
for _, s := range []Set[int]{nil, make(Set[int]), Of[int](), Of(1, 2, 3)} {
for _, empty := range emptyIters {
if !s.ContainsAll(empty) {
t.Errorf("set %v should contain empty iterator %v", s, empty)
}
}
}
}