diff --git a/util/set/set.go b/util/set/set.go index 38bf676f8..c6db4f3f2 100644 --- a/util/set/set.go +++ b/util/set/set.go @@ -10,6 +10,8 @@ "maps" "reflect" "sort" + + "tailscale.com/types/views" ) // Set is a set of T. @@ -27,6 +29,13 @@ func Of[T comparable](slice ...T) Set[T] { return s } +// OfSliceView returns a new set constructed from the elements in v. +func OfSliceView[T comparable](v views.Slice[T]) Set[T] { + s := make(Set[T], v.Len()) + s.AddSliceView(v) + return s +} + // Clone returns a new set cloned from the elements in s. func (s Set[T]) Clone() Set[T] { return maps.Clone(s) @@ -56,6 +65,13 @@ func (s Set[T]) AddSlice(es []T) { } } +// AddSliceView adds each element of v to s. +func (s Set[T]) AddSliceView(v views.Slice[T]) { + for _, e := range v.All() { + s.Add(e) + } +} + // AddSet adds each element of es to s. func (s Set[T]) AddSet(es Set[T]) { for e := range es { diff --git a/util/set/set_test.go b/util/set/set_test.go index d3d118bee..1c7dee287 100644 --- a/util/set/set_test.go +++ b/util/set/set_test.go @@ -7,6 +7,8 @@ "encoding/json" "slices" "testing" + + "tailscale.com/types/views" ) func TestSet(t *testing.T) { @@ -98,6 +100,18 @@ func TestSetOf(t *testing.T) { } } +func TestOfSliceView(t *testing.T) { + s := OfSliceView(views.SliceOf([]int{1, 2, 3, 4, 4, 1})) + if s.Len() != 4 { + t.Errorf("wrong len %d; want 4", s.Len()) + } + for _, n := range []int{1, 2, 3, 4} { + if !s.Contains(n) { + t.Errorf("should contain %d", n) + } + } +} + func TestEqual(t *testing.T) { type test struct { name string