Skip to content

Commit 8d358d6

Browse files
committed
add a Set abstraction that canonically hashes objects before storing
this is helpful for storing and comparing otherwise non-comparable types, as in a kube object with an embedded array
1 parent a9287e5 commit 8d358d6

File tree

4 files changed

+524
-4
lines changed

4 files changed

+524
-4
lines changed

.golangci.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ linters:
77
enable:
88
- "bidichk"
99
- "bodyclose"
10-
- "deadcode"
1110
- "errcheck"
1211
- "errname"
1312
- "errorlint"
@@ -17,7 +16,6 @@ linters:
1716
- "gosec"
1817
- "gosimple"
1918
- "govet"
20-
- "ifshort"
2119
- "importas"
2220
- "ineffassign"
2321
- "makezero"
@@ -27,12 +25,10 @@ linters:
2725
- "revive"
2826
- "rowserrcheck"
2927
- "staticcheck"
30-
- "structcheck"
3128
- "stylecheck"
3229
- "tenv"
3330
- "typecheck"
3431
- "unconvert"
3532
- "unused"
36-
- "varcheck"
3733
- "wastedassign"
3834
- "whitespace"

hash/set.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package hash
2+
3+
// Set is a set that stores objects based on their Object hash
4+
type Set[T any] map[string]T
5+
6+
// NewSet creates a set from a list of objects
7+
func NewSet[T any](objects ...T) Set[T] {
8+
set := make(map[string]T, len(objects))
9+
for _, o := range objects {
10+
set[Object(o)] = o
11+
}
12+
return set
13+
}
14+
15+
// Has returns true if all objects are already in the set
16+
func (s Set[T]) Has(objects ...T) bool {
17+
for _, o := range objects {
18+
_, ok := s[Object(o)]
19+
if !ok {
20+
return false
21+
}
22+
}
23+
return true
24+
}
25+
26+
// Insert adds all objects to the set
27+
func (s Set[T]) Insert(objects ...T) Set[T] {
28+
for _, o := range objects {
29+
s[Object(o)] = o
30+
}
31+
return s
32+
}
33+
34+
// Delete removes all objects from the set
35+
func (s Set[T]) Delete(objects ...T) Set[T] {
36+
for _, o := range objects {
37+
delete(s, Object(o))
38+
}
39+
return s
40+
}
41+
42+
// Len returns the number of objects in the set
43+
func (s Set[T]) Len() int {
44+
return len(s)
45+
}
46+
47+
// Intersect returns a new set containing all the elements common to both.
48+
// The new set will contain the object values from the receiver, not from the
49+
// argument.
50+
func (s Set[T]) Intersect(other Set[T]) Set[T] {
51+
out := NewSet[T]()
52+
for h, o := range s {
53+
if _, ok := other[h]; ok {
54+
out[h] = o
55+
}
56+
}
57+
return out
58+
}
59+
60+
// SetDifference returns the set of objects in s that are not in other.
61+
func (s Set[T]) SetDifference(other Set[T]) Set[T] {
62+
result := NewSet[T]()
63+
for h, o := range s {
64+
if _, ok := other[h]; !ok {
65+
result[h] = o
66+
}
67+
}
68+
return result
69+
}
70+
71+
// Union returns the set of objects common to both sets.
72+
func (s Set[T]) Union(other Set[T]) Set[T] {
73+
result := NewSet[T]()
74+
for h, o := range other {
75+
result[h] = o
76+
}
77+
for h, o := range s {
78+
result[h] = o
79+
}
80+
return result
81+
}
82+
83+
// Contains returns true if all elements of other can be found in s.
84+
func (s Set[T]) Contains(other Set[T]) bool {
85+
for h := range other {
86+
if _, ok := s[h]; !ok {
87+
return false
88+
}
89+
}
90+
return true
91+
}
92+
93+
// EqualElements returns true if both sets have equal elements.
94+
func (s Set[T]) EqualElements(other Set[T]) bool {
95+
return s.Len() == other.Len() && s.Contains(other)
96+
}
97+
98+
// Pop removes and returns a single element from the set, and a bool indicating
99+
// whether an element was found to pop.
100+
func (s Set[T]) Pop() (T, bool) {
101+
for h, o := range s {
102+
delete(s, h)
103+
return o, true
104+
}
105+
var zero T
106+
return zero, false
107+
}

0 commit comments

Comments
 (0)