istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/util/sets/set.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package sets 16 17 import ( 18 "fmt" 19 20 "golang.org/x/exp/constraints" 21 22 "istio.io/istio/pkg/slices" 23 ) 24 25 type Set[T comparable] map[T]struct{} 26 27 type String = Set[string] 28 29 // NewWithLength returns an empty Set with the given capacity. 30 // It's only a hint, not a limitation. 31 func NewWithLength[T comparable](l int) Set[T] { 32 return make(Set[T], l) 33 } 34 35 // New creates a new Set with the given items. 36 func New[T comparable](items ...T) Set[T] { 37 s := NewWithLength[T](len(items)) 38 return s.InsertAll(items...) 39 } 40 41 // Insert a single item to this Set. 42 func (s Set[T]) Insert(item T) Set[T] { 43 s[item] = struct{}{} 44 return s 45 } 46 47 // InsertAll adds the items to this Set. 48 func (s Set[T]) InsertAll(items ...T) Set[T] { 49 for _, item := range items { 50 s[item] = struct{}{} 51 } 52 return s 53 } 54 55 // Delete removes an item from the set. 56 func (s Set[T]) Delete(item T) Set[T] { 57 delete(s, item) 58 return s 59 } 60 61 // DeleteAll removes items from the set. 62 func (s Set[T]) DeleteAll(items ...T) Set[T] { 63 for _, item := range items { 64 delete(s, item) 65 } 66 return s 67 } 68 69 // Merge a set of objects that are in s2 into s 70 // For example: 71 // s = {a1, a2, a3} 72 // s2 = {a3, a4, a5} 73 // s.Merge(s2) = {a1, a2, a3, a4, a5} 74 func (s Set[T]) Merge(s2 Set[T]) Set[T] { 75 for item := range s2 { 76 s[item] = struct{}{} 77 } 78 79 return s 80 } 81 82 // Copy this set. 83 func (s Set[T]) Copy() Set[T] { 84 result := NewWithLength[T](s.Len()) 85 for key := range s { 86 result.Insert(key) 87 } 88 return result 89 } 90 91 // Union returns a set of objects that are in s or s2 92 // For example: 93 // s = {a1, a2, a3} 94 // s2 = {a1, a2, a4, a5} 95 // s.Union(s2) = s2.Union(s) = {a1, a2, a3, a4, a5} 96 func (s Set[T]) Union(s2 Set[T]) Set[T] { 97 result := s.Copy() 98 for key := range s2 { 99 result.Insert(key) 100 } 101 return result 102 } 103 104 // Difference returns a set of objects that are not in s2 105 // For example: 106 // s = {a1, a2, a3} 107 // s2 = {a1, a2, a4, a5} 108 // s.Difference(s2) = {a3} 109 // s2.Difference(s) = {a4, a5} 110 func (s Set[T]) Difference(s2 Set[T]) Set[T] { 111 result := New[T]() 112 for key := range s { 113 if !s2.Contains(key) { 114 result.Insert(key) 115 } 116 } 117 return result 118 } 119 120 // DifferenceInPlace similar to Difference, but has better performance. 121 // Note: This function modifies s in place. 122 func (s Set[T]) DifferenceInPlace(s2 Set[T]) Set[T] { 123 for key := range s { 124 if s2.Contains(key) { 125 delete(s, key) 126 } 127 } 128 return s 129 } 130 131 // Diff takes a pair of Sets, and returns the elements that occur only on the left and right set. 132 func (s Set[T]) Diff(other Set[T]) (left []T, right []T) { 133 for k := range s { 134 if _, f := other[k]; !f { 135 left = append(left, k) 136 } 137 } 138 for k := range other { 139 if _, f := s[k]; !f { 140 right = append(right, k) 141 } 142 } 143 return 144 } 145 146 // Intersection returns a set of objects that are common between s and s2 147 // For example: 148 // s = {a1, a2, a3} 149 // s2 = {a1, a2, a4, a5} 150 // s.Intersection(s2) = {a1, a2} 151 func (s Set[T]) Intersection(s2 Set[T]) Set[T] { 152 result := New[T]() 153 for key := range s { 154 if s2.Contains(key) { 155 result.Insert(key) 156 } 157 } 158 return result 159 } 160 161 // IntersectInPlace similar to Intersection, but has better performance. 162 // Note: This function modifies s in place. 163 func (s Set[T]) IntersectInPlace(s2 Set[T]) Set[T] { 164 for key := range s { 165 if !s2.Contains(key) { 166 delete(s, key) 167 } 168 } 169 return s 170 } 171 172 // SupersetOf returns true if s contains all elements of s2 173 // For example: 174 // s = {a1, a2, a3} 175 // s2 = {a1, a2, a3, a4, a5} 176 // s.SupersetOf(s2) = false 177 // s2.SupersetOf(s) = true 178 func (s Set[T]) SupersetOf(s2 Set[T]) bool { 179 if s2 == nil { 180 return true 181 } 182 if len(s2) > len(s) { 183 return false 184 } 185 for key := range s2 { 186 if !s.Contains(key) { 187 return false 188 } 189 } 190 return true 191 } 192 193 // UnsortedList returns the slice with contents in random order. 194 func (s Set[T]) UnsortedList() []T { 195 res := make([]T, 0, s.Len()) 196 for key := range s { 197 res = append(res, key) 198 } 199 return res 200 } 201 202 // SortedList returns the slice with contents sorted. 203 func SortedList[T constraints.Ordered](s Set[T]) []T { 204 res := s.UnsortedList() 205 slices.Sort(res) 206 return res 207 } 208 209 // InsertContains inserts the item into the set and returns if it was already present. 210 // Example: 211 // 212 // if !set.InsertContains(item) { 213 // fmt.Println("Added item for the first time", item) 214 // } 215 func (s Set[T]) InsertContains(item T) bool { 216 if s.Contains(item) { 217 return true 218 } 219 s[item] = struct{}{} 220 return false 221 } 222 223 // Contains returns whether the given item is in the set. 224 func (s Set[T]) Contains(item T) bool { 225 _, ok := s[item] 226 return ok 227 } 228 229 // ContainsAll is alias of SupersetOf 230 // returns true if s contains all elements of s2 231 func (s Set[T]) ContainsAll(s2 Set[T]) bool { 232 return s.SupersetOf(s2) 233 } 234 235 // Equals checks whether the given set is equal to the current set. 236 func (s Set[T]) Equals(other Set[T]) bool { 237 if s.Len() != other.Len() { 238 return false 239 } 240 241 for key := range s { 242 if !other.Contains(key) { 243 return false 244 } 245 } 246 247 return true 248 } 249 250 // Len returns the number of elements in this Set. 251 func (s Set[T]) Len() int { 252 return len(s) 253 } 254 255 // IsEmpty indicates whether the set is the empty set. 256 func (s Set[T]) IsEmpty() bool { 257 return len(s) == 0 258 } 259 260 // String returns a string representation of the set. 261 // Be aware that the order of elements is random so the string representation may vary. 262 // Use it only for debugging and logging. 263 func (s Set[T]) String() string { 264 return fmt.Sprintf("%v", s.UnsortedList()) 265 } 266 267 // InsertOrNew inserts t into the set if the set exists, or returns a new set with t if not. 268 // Works well with DeleteCleanupLast. 269 // Example: 270 // 271 // InsertOrNew(m, key, value) 272 func InsertOrNew[K comparable, T comparable](m map[K]Set[T], k K, v T) { 273 s, f := m[k] 274 if !f { 275 m[k] = New(v) 276 } else { 277 s.Insert(v) 278 } 279 } 280 281 // DeleteCleanupLast removes an element from a set in a map of sets, deleting the key from the map if there are no keys left. 282 // Works well with InsertOrNew. 283 // Example: 284 // 285 // sets.DeleteCleanupLast(m, key, value) 286 func DeleteCleanupLast[K comparable, T comparable](m map[K]Set[T], k K, v T) { 287 if m[k].Delete(v).IsEmpty() { 288 delete(m, k) 289 } 290 }