util/set: add some more Set operations (#10022)

Updates #cleanup

Signed-off-by: Chris Palmer <cpalmer@tailscale.com>
pull/10044/head
Chris Palmer 1 year ago committed by GitHub
parent 7f3208592f
commit 00375f56ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -4,6 +4,10 @@
// Package set contains set types. // Package set contains set types.
package set package set
import (
"maps"
)
// Set is a set of T. // Set is a set of T.
type Set[T comparable] map[T]struct{} type Set[T comparable] map[T]struct{}
@ -14,16 +18,28 @@ func SetOf[T comparable](slice []T) Set[T] {
return s return s
} }
// Add adds e to the set. // Clone returns a new set cloned from the elements in s.
func Clone[T comparable](s Set[T]) Set[T] {
return maps.Clone(s)
}
// Add adds e to s.
func (s Set[T]) Add(e T) { s[e] = struct{}{} } func (s Set[T]) Add(e T) { s[e] = struct{}{} }
// AddSlice adds each element of es to the set. // AddSlice adds each element of es to s.
func (s Set[T]) AddSlice(es []T) { func (s Set[T]) AddSlice(es []T) {
for _, e := range es { for _, e := range es {
s.Add(e) s.Add(e)
} }
} }
// AddSet adds each element of es to s.
func (s Set[T]) AddSet(es Set[T]) {
for e := range es {
s.Add(e)
}
}
// Slice returns the elements of the set as a slice. The elements will not be // Slice returns the elements of the set as a slice. The elements will not be
// in any particular order. // in any particular order.
func (s Set[T]) Slice() []T { func (s Set[T]) Slice() []T {
@ -45,3 +61,8 @@ func (s Set[T]) Contains(e T) bool {
// Len reports the number of items in s. // Len reports the number of items in s.
func (s Set[T]) Len() int { return len(s) } func (s Set[T]) Len() int { return len(s) }
// Equal reports whether s is equal to other.
func (s Set[T]) Equal(other Set[T]) bool {
return maps.Equal(s, other)
}

@ -54,7 +54,7 @@ func TestSet(t *testing.T) {
func TestSetOf(t *testing.T) { func TestSetOf(t *testing.T) {
s := SetOf[int]([]int{1, 2, 3, 4, 4, 1}) s := SetOf[int]([]int{1, 2, 3, 4, 4, 1})
if s.Len() != 4 { if s.Len() != 4 {
t.Errorf("wrong len %d; want 2", s.Len()) t.Errorf("wrong len %d; want 4", s.Len())
} }
for _, n := range []int{1, 2, 3, 4} { for _, n := range []int{1, 2, 3, 4} {
if !s.Contains(n) { if !s.Contains(n) {
@ -62,3 +62,53 @@ func TestSetOf(t *testing.T) {
} }
} }
} }
func TestEqual(t *testing.T) {
type test struct {
name string
a Set[int]
b Set[int]
expected bool
}
tests := []test{
{
"equal",
SetOf([]int{1, 2, 3, 4}),
SetOf([]int{1, 2, 3, 4}),
true,
},
{
"not equal",
SetOf([]int{1, 2, 3, 4}),
SetOf([]int{1, 2, 3, 5}),
false,
},
{
"different lengths",
SetOf([]int{1, 2, 3, 4, 5}),
SetOf([]int{1, 2, 3, 5}),
false,
},
}
for _, tt := range tests {
if tt.a.Equal(tt.b) != tt.expected {
t.Errorf("%s: failed", tt.name)
}
}
}
func TestClone(t *testing.T) {
s := SetOf[int]([]int{1, 2, 3, 4, 4, 1})
if s.Len() != 4 {
t.Errorf("wrong len %d; want 4", s.Len())
}
s2 := Clone(s)
if !s.Equal(s2) {
t.Error("clone not equal to original")
}
s.Add(100)
if s.Equal(s2) {
t.Error("clone is not distinct from original")
}
}

Loading…
Cancel
Save