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