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

     1  package gg
     2  
     3  import "encoding/json"
     4  
     5  /*
     6  Syntactic shortcut for making an `OrdSet` of the given arguments, with type
     7  inference.
     8  */
     9  func OrdSetOf[Val comparable](src ...Val) OrdSet[Val] {
    10  	var tar OrdSet[Val]
    11  	tar.Add(src...)
    12  	return tar
    13  }
    14  
    15  /*
    16  Syntactic shortcut for making an `OrdSet` from any number of source slices, with
    17  type inference.
    18  */
    19  func OrdSetFrom[Slice ~[]Val, Val comparable](src ...Slice) OrdSet[Val] {
    20  	var tar OrdSet[Val]
    21  	for _, src := range src {
    22  		tar.Add(src...)
    23  	}
    24  	return tar
    25  }
    26  
    27  /*
    28  Represents an ordered set. Similar to the `Coll` type, but behaves like a set
    29  rather than like a map. This implementation is specialized for easy and
    30  efficient appending, iteration, and membership testing, but as a tradeoff, it
    31  does not support deletion. For "proper" ordered sets that support deletion, see
    32  the library https://github.com/mitranim/gord.
    33  */
    34  type OrdSet[Val comparable] struct {
    35  	Slice []Val `role:"ref"`
    36  	Index Set[Val]
    37  }
    38  
    39  // Same as `len(self.Slice)`.
    40  func (self OrdSet[_]) Len() int { return len(self.Slice) }
    41  
    42  // True if `.Len` <= 0. Inverse of `.IsNotEmpty`.
    43  func (self OrdSet[_]) IsEmpty() bool { return self.Len() <= 0 }
    44  
    45  // True if `.Len` > 0. Inverse of `.IsEmpty`.
    46  func (self OrdSet[_]) IsNotEmpty() bool { return self.Len() > 0 }
    47  
    48  // True if the index has the given value. Ignores the inner slice.
    49  func (self OrdSet[Val]) Has(val Val) bool { return self.Index.Has(val) }
    50  
    51  /*
    52  Idempotently adds each given value to both the inner slice and the inner
    53  index, skipping duplicates.
    54  */
    55  func (self *OrdSet[Val]) Add(src ...Val) *OrdSet[Val] {
    56  	for _, val := range src {
    57  		if !self.Has(val) {
    58  			Append(&self.Slice, val)
    59  			self.Index.Init().Add(val)
    60  		}
    61  	}
    62  	return self
    63  }
    64  
    65  // Nullifies both the slice and the index. Does not preserve their capacity.
    66  func (self *OrdSet[Val]) Clear() *OrdSet[Val] {
    67  	if self != nil {
    68  		self.Slice = nil
    69  		self.Index = nil
    70  	}
    71  	return self
    72  }
    73  
    74  /*
    75  Rebuilds the inner index from the inner slice, without checking the validity of
    76  the existing index. Can be useful for external code that directly modifies the
    77  inner `.Slice`, for example by sorting it. This is NOT used when adding items
    78  via `.Add`, which modifies the index incrementally rather than all-at-once.
    79  */
    80  func (self *OrdSet[Val]) Reindex() {
    81  	self.Index = SetOf(self.Slice...)
    82  }
    83  
    84  // Implement `json.Marshaler`. Encodes the inner slice, ignoring the index.
    85  func (self OrdSet[_]) MarshalJSON() ([]byte, error) {
    86  	return json.Marshal(self.Slice)
    87  }
    88  
    89  // Unmarshals the input into the inner slice and rebuilds the index.
    90  func (self *OrdSet[_]) UnmarshalJSON(src []byte) error {
    91  	err := json.Unmarshal(src, &self.Slice)
    92  	self.Reindex()
    93  	return err
    94  }