-
Notifications
You must be signed in to change notification settings - Fork 1
/
lazy_coll.go
177 lines (151 loc) · 4.87 KB
/
lazy_coll.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package gg
import "encoding/json"
/*
Same as `CollOf` but for `LazyColl`. Note that while the return type is a
non-pointer for easy assignment, callers must always access `LazyColl` by
pointer to avoid redundant reindexing.
*/
func LazyCollOf[Key comparable, Val Pker[Key]](src ...Val) LazyColl[Key, Val] {
var tar LazyColl[Key, Val]
tar.Reset(src...)
return tar
}
/*
Same as `CollFrom` but for `LazyColl`. Note that while the return type is a
non-pointer for easy assignment, callers must always access `LazyColl` by
pointer to avoid redundant reindexing.
*/
func LazyCollFrom[Key comparable, Val Pker[Key], Slice ~[]Val](src ...Slice) LazyColl[Key, Val] {
var tar LazyColl[Key, Val]
switch len(src) {
case 1:
tar.Reset(src[0]...)
default:
for _, src := range src {
tar.Add(src...)
}
}
return tar
}
/*
Short for "lazy collection". Variant of `Coll` where the index is built lazily
rather than immediately. This is not the default behavior in `Coll` because it
requires various access methods such as `.Has` and `.Get` to be defined on the
pointer type rather than value type, and more importantly, it's more error
prone: the caller is responsible for making sure that the collection is always
accessed by pointer, never by value, to avoid redundant reindexing.
*/
type LazyColl[Key comparable, Val Pker[Key]] Coll[Key, Val]
// Same as `Coll.Len`.
func (self LazyColl[_, _]) Len() int { return self.coll().Len() }
// Same as `Coll.IsEmpty`.
func (self LazyColl[_, _]) IsEmpty() bool { return self.coll().IsEmpty() }
// Same as `Coll.IsNotEmpty`.
func (self LazyColl[_, _]) IsNotEmpty() bool { return self.coll().IsNotEmpty() }
// Same as `Coll.Has`. Lazily rebuilds the index if necessary.
func (self *LazyColl[Key, _]) Has(key Key) bool {
self.ReindexOpt()
return self.coll().Has(key)
}
// Same as `Coll.Get`. Lazily rebuilds the index if necessary.
func (self *LazyColl[Key, Val]) Get(key Key) Val {
self.ReindexOpt()
return self.coll().Get(key)
}
// Same as `Coll.GetReq`. Lazily rebuilds the index if necessary.
func (self *LazyColl[Key, Val]) GetReq(key Key) Val {
self.ReindexOpt()
return self.coll().GetReq(key)
}
// Same as `Coll.Got`. Lazily rebuilds the index if necessary.
func (self *LazyColl[Key, Val]) Got(key Key) (Val, bool) {
self.ReindexOpt()
return self.coll().Got(key)
}
// Same as `Coll.Ptr`. Lazily rebuilds the index if necessary.
func (self *LazyColl[Key, Val]) Ptr(key Key) *Val {
self.ReindexOpt()
return self.coll().Ptr(key)
}
// Same as `Coll.PtrReq`. Lazily rebuilds the index if necessary.
func (self *LazyColl[Key, Val]) PtrReq(key Key) *Val {
self.ReindexOpt()
return self.coll().PtrReq(key)
}
// Similar to `Coll.Add`, but does not add new entries to the index.
func (self *LazyColl[Key, Val]) Add(src ...Val) *LazyColl[Key, Val] {
for _, val := range src {
key := ValidPk[Key](val)
ind, ok := self.Index[key]
if ok {
self.Slice[ind] = val
continue
}
Append(&self.Slice, val)
}
return self
}
// Same as `Coll.AddUniq`. Lazily rebuilds the index.
func (self *LazyColl[Key, Val]) AddUniq(src ...Val) *LazyColl[Key, Val] {
self.ReindexOpt()
self.coll().AddUniq(src...)
return self
}
// Same as `Coll.Reset` but deletes the index instead of rebuilding it.
func (self *LazyColl[Key, Val]) Reset(src ...Val) *LazyColl[Key, Val] {
self.Index = nil
self.Slice = src
return self
}
// Same as `Coll.Clear`.
func (self *LazyColl[Key, Val]) Clear() *LazyColl[Key, Val] {
self.coll().Clear()
return self
}
// Same as `Coll.Reindex`.
func (self *LazyColl[Key, Val]) Reindex() *LazyColl[Key, Val] {
self.coll().Reindex()
return self
}
/*
Rebuilds the index if the length of inner slice and index doesn't match.
This is used internally by all "read" methods on this type.
*/
func (self *LazyColl[Key, _]) ReindexOpt() {
if len(self.Slice) != len(self.Index) {
self.Reindex()
}
}
// Same as `Coll.Swap` but deletes the index instead of modifying it.
func (self *LazyColl[Key, _]) Swap(ind0, ind1 int) {
self.Index = nil
self.coll().Swap(ind0, ind1)
}
/*
Implement `json.Marshaler`. Same as `Coll.MarshalJSON`. Encodes the inner slice,
ignoring the index.
*/
func (self LazyColl[_, _]) MarshalJSON() ([]byte, error) {
return self.coll().MarshalJSON()
}
/*
Implement `json.Unmarshaler`. Similar to `Coll.UnmarshalJSON`, but after
decoding the input into the inner slice, deletes the index instead of
rebuilding it.
*/
func (self *LazyColl[_, _]) UnmarshalJSON(src []byte) error {
self.Index = nil
return json.Unmarshal(src, &self.Slice)
}
// Converts to equivalent `Coll`. Lazily rebuilds the index if necessary.
func (self *LazyColl[Key, Val]) Coll() *Coll[Key, Val] {
self.ReindexOpt()
return (*Coll[Key, Val])(self)
}
/*
Free cast to equivalent `Coll`. Private because careless use produces invalid
behavior. Incomplete index in `LazyColl` violates assumptions made by `Coll`.
*/
func (self *LazyColl[Key, Val]) coll() *Coll[Key, Val] {
return (*Coll[Key, Val])(self)
}