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  }