github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/genutil/mapz/set.go (about)

     1  package mapz
     2  
     3  import (
     4  	"maps"
     5  
     6  	"github.com/rs/zerolog"
     7  
     8  	expmaps "golang.org/x/exp/maps"
     9  )
    10  
    11  // Set implements a very basic generic set.
    12  type Set[T comparable] struct {
    13  	values map[T]struct{}
    14  }
    15  
    16  // NewSet returns a new set.
    17  func NewSet[T comparable](items ...T) *Set[T] {
    18  	s := &Set[T]{
    19  		values: map[T]struct{}{},
    20  	}
    21  	for _, item := range items {
    22  		s.values[item] = struct{}{}
    23  	}
    24  	return s
    25  }
    26  
    27  // Has returns true if the set contains the given value.
    28  func (s *Set[T]) Has(value T) bool {
    29  	_, exists := s.values[value]
    30  	return exists
    31  }
    32  
    33  // Add adds the given value to the set and returns true. If
    34  // the value is already present, returns false.
    35  func (s *Set[T]) Add(value T) bool {
    36  	if s.Has(value) {
    37  		return false
    38  	}
    39  
    40  	s.values[value] = struct{}{}
    41  	return true
    42  }
    43  
    44  // Insert adds the given value to the set.
    45  func (s *Set[T]) Insert(value T) {
    46  	s.values[value] = struct{}{}
    47  }
    48  
    49  // Delete removes the value from the set, returning nothing.
    50  func (s *Set[T]) Delete(value T) {
    51  	delete(s.values, value)
    52  }
    53  
    54  // Extend adds all the values to the set.
    55  func (s *Set[T]) Extend(values []T) {
    56  	for _, value := range values {
    57  		s.values[value] = struct{}{}
    58  	}
    59  }
    60  
    61  // Merge adds all the values from the other set to this set.
    62  func (s *Set[T]) Merge(other *Set[T]) {
    63  	for value := range other.values {
    64  		s.values[value] = struct{}{}
    65  	}
    66  }
    67  
    68  // Union adds all the values from the other set to this set,
    69  // returning a new set.
    70  func (s *Set[T]) Union(other *Set[T]) *Set[T] {
    71  	cpy := s.Copy()
    72  	for value := range other.values {
    73  		cpy.values[value] = struct{}{}
    74  	}
    75  	return cpy
    76  }
    77  
    78  // IntersectionDifference removes any values from this set that
    79  // are not shared with the other set. Returns the same set.
    80  func (s *Set[T]) IntersectionDifference(other *Set[T]) *Set[T] {
    81  	for value := range s.values {
    82  		if !other.Has(value) {
    83  			delete(s.values, value)
    84  		}
    85  	}
    86  	return s
    87  }
    88  
    89  // RemoveAll removes all values from this set found in the other set.
    90  func (s *Set[T]) RemoveAll(other *Set[T]) {
    91  	for value := range other.values {
    92  		delete(s.values, value)
    93  	}
    94  }
    95  
    96  // Subtract subtracts the other set from this set, returning a new set.
    97  func (s *Set[T]) Subtract(other *Set[T]) *Set[T] {
    98  	cpy := s.Copy()
    99  	cpy.RemoveAll(other)
   100  	return cpy
   101  }
   102  
   103  // Copy returns a copy of this set.
   104  func (s *Set[T]) Copy() *Set[T] {
   105  	return &Set[T]{
   106  		values: maps.Clone(s.values),
   107  	}
   108  }
   109  
   110  // Intersect removes any values from this set that
   111  // are not shared with the other set, returning a new set.
   112  func (s *Set[T]) Intersect(other *Set[T]) *Set[T] {
   113  	cpy := s.Copy()
   114  	for value := range cpy.values {
   115  		if !other.Has(value) {
   116  			delete(cpy.values, value)
   117  		}
   118  	}
   119  	return cpy
   120  }
   121  
   122  // Equal returns true if both sets have the same elements
   123  func (s *Set[T]) Equal(other *Set[T]) bool {
   124  	return maps.Equal(s.values, other.values)
   125  }
   126  
   127  // IsEmpty returns true if the set is empty.
   128  func (s *Set[T]) IsEmpty() bool {
   129  	return len(s.values) == 0
   130  }
   131  
   132  // AsSlice returns the set as a slice of values.
   133  func (s *Set[T]) AsSlice() []T {
   134  	if len(s.values) == 0 {
   135  		return nil
   136  	}
   137  
   138  	return expmaps.Keys(s.values)
   139  }
   140  
   141  // Len returns the length of the set.
   142  func (s *Set[T]) Len() int {
   143  	return len(s.values)
   144  }
   145  
   146  // ForEach executes the callback for each item in the set until an error is encountered.
   147  func (s *Set[T]) ForEach(callback func(value T) error) error {
   148  	for value := range s.values {
   149  		if err := callback(value); err != nil {
   150  			return err
   151  		}
   152  	}
   153  
   154  	return nil
   155  }
   156  
   157  func (s *Set[T]) MarshalZerologObject(e *zerolog.Event) {
   158  	xs := zerolog.Arr()
   159  	for _, value := range s.values {
   160  		xs.Interface(value)
   161  	}
   162  	e.Array("values", xs)
   163  }