Skip to content

Commit 9f67429

Browse files
authored
Merge pull request #243 from logicalhan/generics
add generic sets to utils
2 parents d93618c + 10cedcc commit 9f67429

File tree

4 files changed

+655
-0
lines changed

4 files changed

+655
-0
lines changed

set/OWNERS

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# See the OWNERS docs at https://go.k8s.io/owners
2+
3+
reviewers:
4+
- logicalhan
5+
- thockin
6+
approvers:
7+
- logicalhan
8+
- thockin

set/ordered.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package set
18+
19+
// ordered is a constraint that permits any ordered type: any type
20+
// that supports the operators < <= >= >.
21+
// If future releases of Go add new ordered types,
22+
// this constraint will be modified to include them.
23+
type ordered interface {
24+
integer | float | ~string
25+
}
26+
27+
// integer is a constraint that permits any integer type.
28+
// If future releases of Go add new predeclared integer types,
29+
// this constraint will be modified to include them.
30+
type integer interface {
31+
signed | unsigned
32+
}
33+
34+
// float is a constraint that permits any floating-point type.
35+
// If future releases of Go add new predeclared floating-point types,
36+
// this constraint will be modified to include them.
37+
type float interface {
38+
~float32 | ~float64
39+
}
40+
41+
// signed is a constraint that permits any signed integer type.
42+
// If future releases of Go add new predeclared signed integer types,
43+
// this constraint will be modified to include them.
44+
type signed interface {
45+
~int | ~int8 | ~int16 | ~int32 | ~int64
46+
}
47+
48+
// unsigned is a constraint that permits any unsigned integer type.
49+
// If future releases of Go add new predeclared unsigned integer types,
50+
// this constraint will be modified to include them.
51+
type unsigned interface {
52+
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
53+
}

set/set.go

+229
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package set
18+
19+
import (
20+
"sort"
21+
)
22+
23+
// Empty is public since it is used by some internal API objects for conversions between external
24+
// string arrays and internal sets, and conversion logic requires public types today.
25+
type Empty struct{}
26+
27+
// Set is a set of the same type elements, implemented via map[ordered]struct{} for minimal memory consumption.
28+
type Set[E ordered] map[E]Empty
29+
30+
// New creates a new set.
31+
func New[E ordered](items ...E) Set[E] {
32+
ss := Set[E]{}
33+
ss.Insert(items...)
34+
return ss
35+
}
36+
37+
// KeySet creates a Set[E] from a keys of a map[E](? extends interface{}).
38+
func KeySet[E ordered, A any](theMap map[E]A) Set[E] {
39+
ret := Set[E]{}
40+
for key := range theMap {
41+
ret.Insert(key)
42+
}
43+
return ret
44+
}
45+
46+
// Insert adds items to the set.
47+
func (s Set[E]) Insert(items ...E) Set[E] {
48+
for _, item := range items {
49+
s[item] = Empty{}
50+
}
51+
return s
52+
}
53+
54+
// Delete removes all items from the set.
55+
func (s Set[E]) Delete(items ...E) Set[E] {
56+
for _, item := range items {
57+
delete(s, item)
58+
}
59+
return s
60+
}
61+
62+
// Has returns true if and only if item is contained in the set.
63+
func (s Set[E]) Has(item E) bool {
64+
_, contained := s[item]
65+
return contained
66+
}
67+
68+
// HasAll returns true if and only if all items are contained in the set.
69+
func (s Set[E]) HasAll(items ...E) bool {
70+
for _, item := range items {
71+
if !s.Has(item) {
72+
return false
73+
}
74+
}
75+
return true
76+
}
77+
78+
// HasAny returns true if any items are contained in the set.
79+
func (s Set[E]) HasAny(items ...E) bool {
80+
for _, item := range items {
81+
if s.Has(item) {
82+
return true
83+
}
84+
}
85+
return false
86+
}
87+
88+
// Union returns a new set which includes items in either s1 or s2.
89+
// For example:
90+
// s1 = {a1, a2}
91+
// s2 = {a3, a4}
92+
// s1.Union(s2) = {a1, a2, a3, a4}
93+
// s2.Union(s1) = {a1, a2, a3, a4}
94+
func (s Set[E]) Union(s2 Set[E]) Set[E] {
95+
result := Set[E]{}
96+
result.Insert(s.UnsortedList()...)
97+
result.Insert(s2.UnsortedList()...)
98+
return result
99+
}
100+
101+
// Len returns the number of elements in the set.
102+
func (s Set[E]) Len() int {
103+
return len(s)
104+
}
105+
106+
// Intersection returns a new set which includes the item in BOTH s1 and s2
107+
// For example:
108+
// s1 = {a1, a2}
109+
// s2 = {a2, a3}
110+
// s1.Intersection(s2) = {a2}
111+
func (s Set[E]) Intersection(s2 Set[E]) Set[E] {
112+
var walk, other Set[E]
113+
result := Set[E]{}
114+
if s.Len() < s2.Len() {
115+
walk = s
116+
other = s2
117+
} else {
118+
walk = s2
119+
other = s
120+
}
121+
for key := range walk {
122+
if other.Has(key) {
123+
result.Insert(key)
124+
}
125+
}
126+
return result
127+
}
128+
129+
// IsSuperset returns true if and only if s1 is a superset of s2.
130+
func (s Set[E]) IsSuperset(s2 Set[E]) bool {
131+
for item := range s2 {
132+
if !s.Has(item) {
133+
return false
134+
}
135+
}
136+
return true
137+
}
138+
139+
// Difference returns a set of objects that are not in s2
140+
// For example:
141+
// s1 = {a1, a2, a3}
142+
// s2 = {a1, a2, a4, a5}
143+
// s1.Difference(s2) = {a3}
144+
// s2.Difference(s1) = {a4, a5}
145+
func (s Set[E]) Difference(s2 Set[E]) Set[E] {
146+
result := Set[E]{}
147+
for key := range s {
148+
if !s2.Has(key) {
149+
result.Insert(key)
150+
}
151+
}
152+
return result
153+
}
154+
155+
// Equal returns true if and only if s1 is equal (as a set) to s2.
156+
// Two sets are equal if their membership is identical.
157+
func (s Set[E]) Equal(s2 Set[E]) bool {
158+
return s.Len() == s.Len() && s.IsSuperset(s2)
159+
}
160+
161+
type sortableSlice[E ordered] []E
162+
163+
func (s sortableSlice[E]) Len() int {
164+
return len(s)
165+
}
166+
func (s sortableSlice[E]) Less(i, j int) bool { return s[i] < s[j] }
167+
func (s sortableSlice[E]) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
168+
169+
// SortedList returns the contents as a sorted slice.
170+
func (s Set[E]) SortedList() []E {
171+
res := make(sortableSlice[E], 0, s.Len())
172+
for key := range s {
173+
res = append(res, key)
174+
}
175+
sort.Sort(res)
176+
return res
177+
}
178+
179+
// UnsortedList returns the slice with contents in random order.
180+
func (s Set[E]) UnsortedList() []E {
181+
res := make([]E, 0, len(s))
182+
for key := range s {
183+
res = append(res, key)
184+
}
185+
return res
186+
}
187+
188+
// PopAny returns a single element from the set.
189+
func (s Set[E]) PopAny() (E, bool) {
190+
for key := range s {
191+
s.Delete(key)
192+
return key, true
193+
}
194+
var zeroValue E
195+
return zeroValue, false
196+
}
197+
198+
// Clone returns a new set which is a copy of the current set.
199+
func (s Set[T]) Clone() Set[T] {
200+
result := make(Set[T], len(s))
201+
for key := range s {
202+
result.Insert(key)
203+
}
204+
return result
205+
}
206+
207+
// SymmetricDifference returns a set of elements which are in either of the sets, but not in their intersection.
208+
// For example:
209+
// s1 = {a1, a2, a3}
210+
// s2 = {a1, a2, a4, a5}
211+
// s1.SymmetricDifference(s2) = {a3, a4, a5}
212+
// s2.SymmetricDifference(s1) = {a3, a4, a5}
213+
func (s Set[T]) SymmetricDifference(s2 Set[T]) Set[T] {
214+
return s.Difference(s2).Union(s2.Difference(s))
215+
}
216+
217+
// Clear empties the set.
218+
// It is preferable to replace the set with a newly constructed set,
219+
// but not all callers can do that (when there are other references to the map).
220+
// In some cases the set *won't* be fully cleared, e.g. a Set[float32] containing NaN
221+
// can't be cleared because NaN can't be removed.
222+
// For sets containing items of a type that is reflexive for ==,
223+
// this is optimized to a single call to runtime.mapclear().
224+
func (s Set[T]) Clear() Set[T] {
225+
for key := range s {
226+
delete(s, key)
227+
}
228+
return s
229+
}

0 commit comments

Comments
 (0)