github.com/mitranim/gg@v0.1.17/set.go (about)

     1  package gg
     2  
     3  import "encoding/json"
     4  
     5  /*
     6  Syntactic shortcut for making a set from a slice, with element type inference
     7  and capacity preallocation. Always returns non-nil, even if the input is
     8  empty.
     9  */
    10  func SetOf[A comparable](val ...A) Set[A] {
    11  	return make(Set[A], len(val)).Add(val...)
    12  }
    13  
    14  /*
    15  Syntactic shortcut for making a set from multiple slices, with element type
    16  inference and capacity preallocation. Always returns non-nil, even if the input
    17  is empty.
    18  */
    19  func SetFrom[Slice ~[]Elem, Elem comparable](val ...Slice) Set[Elem] {
    20  	buf := make(Set[Elem], Lens(val...))
    21  	for _, val := range val {
    22  		buf.Add(val...)
    23  	}
    24  	return buf
    25  }
    26  
    27  /*
    28  Creates a set by "mapping" the elements of a given slice via the provided
    29  function. Always returns non-nil, even if the input is empty.
    30  */
    31  func SetMapped[Elem any, Val comparable](src []Elem, fun func(Elem) Val) Set[Val] {
    32  	buf := make(Set[Val], len(src))
    33  	if fun != nil {
    34  		for _, val := range src {
    35  			buf[fun(val)] = struct{}{}
    36  		}
    37  	}
    38  	return buf
    39  }
    40  
    41  // Generic unordered set backed by a map.
    42  type Set[A comparable] map[A]struct{}
    43  
    44  /*
    45  Idempotently inits the map via `make`, making it writable. The output pointer
    46  must be non-nil.
    47  */
    48  func (self *Set[A]) Init() Set[A] {
    49  	if *self == nil {
    50  		*self = make(Set[A])
    51  	}
    52  	return *self
    53  }
    54  
    55  // Same as `len(set)`. Nil-safe.
    56  func (self Set[_]) Len() int { return len(self) }
    57  
    58  // True if the set includes the given value. Nil-safe.
    59  func (self Set[A]) Has(val A) bool { return MapHas(self, val) }
    60  
    61  // Idempotently adds the given values to the receiver, which must be non-nil.
    62  func (self Set[A]) Add(val ...A) Set[A] {
    63  	for _, val := range val {
    64  		self[val] = struct{}{}
    65  	}
    66  	return self
    67  }
    68  
    69  /*
    70  Set union. Idempotently adds all values from the given source sets to the
    71  receiver, which must be non-nil.
    72  */
    73  func (self Set[A]) AddFrom(val ...Set[A]) Set[A] {
    74  	for _, val := range val {
    75  		for val := range val {
    76  			self[val] = struct{}{}
    77  		}
    78  	}
    79  	return self
    80  }
    81  
    82  // Deletes the given values from the receiver, which may be nil.
    83  func (self Set[A]) Del(val ...A) Set[A] {
    84  	for _, val := range val {
    85  		delete(self, val)
    86  	}
    87  	return self
    88  }
    89  
    90  /*
    91  Deletes all values present in the given source sets from the receiver, which may
    92  be nil.
    93  */
    94  func (self Set[A]) DelFrom(val ...Set[A]) Set[A] {
    95  	for _, val := range val {
    96  		for val := range val {
    97  			delete(self, val)
    98  		}
    99  	}
   100  	return self
   101  }
   102  
   103  /*
   104  Clears and returns the receiver, which may be nil. Note that this type is
   105  implemented as a map, and this method involves iterating the map, which is
   106  inefficient in Go. In many cases, it's more efficient to make a new set.
   107  */
   108  func (self Set[A]) Clear() Set[A] {
   109  	for val := range self {
   110  		delete(self, val)
   111  	}
   112  	return self
   113  }
   114  
   115  // Combination of `Set.Clear` and `Set.Add`.
   116  func (self Set[A]) Reset(val ...A) Set[A] {
   117  	self.Clear()
   118  	self.Add(val...)
   119  	return self
   120  }
   121  
   122  // Converts the map to a slice of its values. Order is random.
   123  func (self Set[A]) Slice() []A { return MapKeys(self) }
   124  
   125  /*
   126  Returns the subset of values for which the given function returns true.
   127  Order is random. If function is nil, output is nil.
   128  */
   129  func (self Set[A]) Filter(fun func(A) bool) []A {
   130  	var out []A
   131  	if fun != nil {
   132  		for val := range self {
   133  			if fun(val) {
   134  				out = append(out, val)
   135  			}
   136  		}
   137  	}
   138  	return out
   139  }
   140  
   141  // JSON-encodes as a list. Order is random.
   142  func (self Set[A]) MarshalJSON() ([]byte, error) {
   143  	return json.Marshal(self.Slice())
   144  }
   145  
   146  /*
   147  JSON-decodes the input, which must either represent JSON "null" or a JSON list
   148  of values compatible with the value type.
   149  */
   150  func (self *Set[A]) UnmarshalJSON(src []byte) error {
   151  	var buf []A
   152  	err := json.Unmarshal(src, &buf)
   153  	if err != nil {
   154  		return err
   155  	}
   156  
   157  	self.Init().Reset(buf...)
   158  	return nil
   159  }
   160  
   161  // Implement `fmt.GoStringer`, returning valid Go code that constructs the set.
   162  func (self Set[A]) GoString() string {
   163  	typ := TypeOf(self).String()
   164  
   165  	if self == nil {
   166  		return typ + `(nil)`
   167  	}
   168  
   169  	if len(self) <= 0 {
   170  		return typ + `{}`
   171  	}
   172  
   173  	var buf Buf
   174  	buf.AppendString(typ)
   175  	buf.AppendString(`{}.Add(`)
   176  
   177  	var found bool
   178  	for val := range self {
   179  		if found {
   180  			buf.AppendString(`, `)
   181  		}
   182  		found = true
   183  		buf.AppendGoString(val)
   184  	}
   185  
   186  	buf.AppendString(`)`)
   187  	return buf.String()
   188  }