/
value_rep.go
404 lines (368 loc) · 9.42 KB
/
value_rep.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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vdl
// This file contains the non-trivial "rep" types, which are the representation
// of values of certain types.
// repBytes represents []byte and [N]byte values. We special-case these kinds
// of types to easily support the Value.Bytes() and Value.CopyBytes() methods,
// which makes usage more convenient for the user. This is also a more
// efficient representation.
type repBytes []byte
// allZeroBytes is a buffer containing all 0 bytes. It's used for fast filling
// of 0 bytes after resizing.
var allZeroBytes = make(repBytes, 1024)
func zeroRepBytes(len int) *repBytes {
if len == 0 {
return new(repBytes)
}
rep := make(repBytes, len)
return &rep
}
func copyRepBytes(rep *repBytes) *repBytes {
if *rep == nil {
return new(repBytes)
}
cp := make(repBytes, len(*rep))
copy(cp, *rep)
return &cp
}
func (rep *repBytes) AllBytesZero() bool {
for _, b := range *rep {
if b != 0 {
return false
}
}
return true
}
// Resize resizes rep to size n, ignoring existing bytes.
func (rep *repBytes) Resize(n int) {
if n <= cap(*rep) {
*rep = (*rep)[:n]
} else {
*rep = make(repBytes, n)
}
}
// AssignLen resizes rep to size n, ensuring existing bytes are transferred, and
// all bytes beyond the original length are initialized to zero.
func (rep *repBytes) AssignLen(n int) {
if n <= cap(*rep) {
// Increase rep length, and fill rep[oldlen:n] with zero bytes.
oldlen := len(*rep)
*rep = (*rep)[:n]
for ix := oldlen; ix < n; {
ix += copy((*rep)[ix:], allZeroBytes)
}
} else {
oldrep := *rep
*rep = make(repBytes, n)
copy(*rep, oldrep)
}
}
// repMap represents set and map values. There are two underlying
// representations depending on the key type. We decide which one to use based
// on the type of the map key, and never change representations thereafter.
// fast: Use a real Go map to associate keys with a kvPair
// slow: Just a slice of kvPairs.
//
// Fast has the same O(1) amortized complexity as regular Go maps for insert and
// lookup, while slow is O(N). Since fast uses a real Go map, it only works for
// maps whose key type is allowed in a real Go map; e.g. structs are implemented
// as a slice of fields, but slices aren't allowed as Go map keys, so that must
// use slow.
//
// TODO(toddw): Slow is really slow; e.g. Equal is quadratic. Speed this up.
type repMap struct {
fastIndex map[interface{}]kvPair // maps with scalar keys use the fast rep
slowIndex []kvPair // everything else uses the slow rep
}
type kvPair struct {
key, val *Value
}
func copyKVPair(kv kvPair) kvPair {
return kvPair{CopyValue(kv.key), CopyValue(kv.val)}
}
func (kv kvPair) String() string {
s := stringRep(kv.key.t, kv.key.rep)
if kv.val != nil {
s += ": " + stringRep(kv.val.t, kv.val.rep)
}
return s
}
func useFastIndex(key *Type) bool {
// TODO(toddw): Structs with exactly 1 simple field may also use fast.
switch key.kind {
case Bool, Byte, Uint16, Uint32, Uint64, Int8, Int16, Int32, Int64, Float32, Float64, String, Enum:
return true
}
if key.IsBytes() {
return true
}
return false
}
// fastKeyRep returns a representation of key that may be used in a regular Go
// map. It's only called on keys where useFastIndex returns true.
func fastKeyRep(key *Value) interface{} {
switch {
case key.Kind() == Float32:
// Float32 is represented as float64 in vdl.Value, but we must convert to
// float32 to ensure map lookups work with the correct precision. Otherwise
// a single float32 may be reprsesented as different keys.
return float32(key.rep.(float64))
case key.t.IsBytes():
// Convert []byte into a string so that it can be used as a map key.
return string(key.Bytes())
}
return key.rep
}
func zeroRepMap(key *Type) *repMap {
rep := &repMap{}
if useFastIndex(key) {
rep.fastIndex = make(map[interface{}]kvPair)
}
return rep
}
func copyRepMap(rep *repMap) *repMap {
cp := &repMap{}
if rep.fastIndex != nil {
cp.fastIndex = make(map[interface{}]kvPair, len(rep.fastIndex))
for keyrep, kv := range rep.fastIndex {
cp.fastIndex[keyrep] = copyKVPair(kv)
}
} else {
if len(rep.slowIndex) > 0 {
cp.slowIndex = make([]kvPair, len(rep.slowIndex))
for index, kv := range rep.slowIndex {
cp.slowIndex[index] = copyKVPair(kv)
}
}
}
return cp
}
func equalRepMap(a, b *repMap) bool {
if a.Len() != b.Len() {
return false
}
if a.fastIndex != nil {
for _, akv := range a.fastIndex {
if !b.hasKV(akv) {
return false
}
}
} else {
for _, akv := range a.slowIndex {
if !b.hasKV(akv) {
return false
}
}
}
return true
}
func (rep *repMap) hasKV(kv kvPair) bool {
val, ok := rep.Index(kv.key)
if !ok {
return false
}
return EqualValue(kv.val, val)
}
func (rep *repMap) Len() int {
if rep.fastIndex != nil {
return len(rep.fastIndex)
} else {
return len(rep.slowIndex)
}
}
func (rep *repMap) String() string {
s := "{"
if rep.fastIndex != nil {
first := true
for _, kv := range rep.fastIndex {
if !first {
s += ", "
}
s += kv.String()
first = false
}
} else {
for index, kv := range rep.slowIndex {
if index > 0 {
s += ", "
}
s += kv.String()
}
}
return s + "}"
}
func (rep *repMap) Keys() []*Value {
len := rep.Len()
if len == 0 {
return nil
}
keys := make([]*Value, len)
if rep.fastIndex != nil {
index := 0
for _, kv := range rep.fastIndex {
keys[index] = CopyValue(kv.key)
index++
}
} else {
for index, kv := range rep.slowIndex {
keys[index] = CopyValue(kv.key)
}
}
return keys
}
func (rep *repMap) Index(key *Value) (*Value, bool) {
if rep.fastIndex != nil {
if kv, ok := rep.fastIndex[fastKeyRep(key)]; ok {
return kv.val, true
}
} else {
for _, kv := range rep.slowIndex {
if EqualValue(kv.key, key) {
return kv.val, true
}
}
}
return nil, false
}
func (rep *repMap) Assign(key, elem *Value) {
if rep.fastIndex != nil {
rep.fastIndex[fastKeyRep(key)] = kvPair{key, elem}
} else {
for ix := 0; ix < len(rep.slowIndex); ix++ {
if EqualValue(rep.slowIndex[ix].key, key) {
rep.slowIndex[ix].val = elem
return
}
}
// The key doesn't exist in the slow index; append it.
rep.slowIndex = append(rep.slowIndex, kvPair{key, elem})
}
}
func (rep *repMap) Delete(key *Value) {
if rep.fastIndex != nil {
delete(rep.fastIndex, fastKeyRep(key))
} else {
for ix := 0; ix < len(rep.slowIndex); ix++ {
if EqualValue(rep.slowIndex[ix].key, key) {
// Delete entry ix by moving last entry into ix and shrinking by 1.
last := len(rep.slowIndex) - 1
rep.slowIndex[ix] = rep.slowIndex[last]
rep.slowIndex = rep.slowIndex[:last]
return
}
}
}
}
// repSequence represents the elements of a list and array, and the fields of a
// struct. Each value is lazily initialized; the semantics dictate that nil is
// indistinguishable from zero values.
//
// Arrays and structs are initialized to their fixed-length, while lists are
// initialized to nil.
type repSequence []*Value
func zeroRepSequence(len int) *repSequence {
if len == 0 {
return new(repSequence)
}
rep := make(repSequence, len)
return &rep
}
func copyRepSequence(rep *repSequence) *repSequence {
if *rep == nil {
return new(repSequence)
}
cp := make(repSequence, len(*rep))
for index, val := range *rep {
cp[index] = CopyValue(val)
}
return &cp
}
func equalRepSequence(a, b *repSequence) bool {
if len(*a) != len(*b) {
return false
}
for index, aval := range *a {
// Handle cases where we're using nil to represent zero values.
switch bval := (*b)[index]; {
case aval == nil && bval != nil:
if !bval.IsZero() {
return false
}
case aval != nil && bval == nil:
if !aval.IsZero() {
return false
}
case !EqualValue(aval, bval):
return false
}
}
return true
}
func (rep *repSequence) AllValuesZero() bool {
for _, val := range *rep {
if val != nil && !val.IsZero() {
return false
}
}
return true
}
func (rep *repSequence) String(t *Type) string {
s := "{"
for index, val := range *rep {
if index > 0 {
s += ", "
}
valtype := t.elem
if t.Kind() == Struct {
valtype = t.fields[index].Type
s += t.fields[index].Name
s += ": "
}
if val == nil {
s += stringRep(valtype, zeroRep(valtype))
} else {
s += stringRep(val.t, val.rep)
}
}
return s + "}"
}
// AssignLen resizes rep to size n, ensuring existing values are transferred,
// and all values beyond the original length are initialized to nil.
func (rep *repSequence) AssignLen(n int) {
if n <= cap(*rep) {
// Increase rep length, and fill rep[oldlen:n] with nil values.
oldlen := len(*rep)
*rep = (*rep)[:n]
for ix := oldlen; ix < n; ix++ {
(*rep)[ix] = nil
}
} else {
oldrep := *rep
*rep = make(repSequence, n)
copy(*rep, oldrep)
}
}
func (rep *repSequence) Index(t *Type, index int) *Value {
if oldval := (*rep)[index]; oldval != nil {
return oldval
}
// Lazy initialization; create the new value upon first access.
newval := ZeroValue(t)
(*rep)[index] = newval
return newval
}
// repUnion represents a Union value, which includes the field index of its
// type, and the underlying elem.
type repUnion struct {
index int
value *Value
}
func equalRepUnion(a, b *repUnion) bool {
return a.index == b.index && EqualValue(a.value, b.value)
}
func (rep *repUnion) String(t *Type) string {
v := rep.value
return "{" + t.fields[rep.index].Name + ": " + stringRep(v.t, v.rep) + "}"
}