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 }