-
Notifications
You must be signed in to change notification settings - Fork 4
/
fields.go
63 lines (56 loc) · 1.34 KB
/
fields.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
package ubjson
import (
"reflect"
"sync"
"sync/atomic"
)
// Based on 'encoding/json/encode.go'.
var fieldCache struct {
value atomic.Value // map[reflect.Type]fields
mu sync.Mutex // used only by writers
}
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
// Based on 'encoding/json/encode.go'.
func cachedTypeFields(t reflect.Type) fields {
m, _ := fieldCache.value.Load().(map[reflect.Type]fields)
f, ok := m[t]
if ok {
return f
}
// Compute names without lock.
// Might duplicate effort but won't hold other computations back.
f = typeFields(t)
fieldCache.mu.Lock()
m, _ = fieldCache.value.Load().(map[reflect.Type]fields)
newM := make(map[reflect.Type]fields, len(m)+1)
for k, v := range m {
newM[k] = v
}
newM[t] = f
fieldCache.value.Store(newM)
fieldCache.mu.Unlock()
return f
}
// Indexes fields by 'ubjson' struct tag if present, otherwise name.
func typeFields(t reflect.Type) fields {
fs := fields{
indexByName: make(map[string]int),
}
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if f.PkgPath == "" {
name := f.Name
// Check for 'ubjson' struct tag.
if v, ok := f.Tag.Lookup("ubjson"); ok {
name = v
}
fs.names = append(fs.names, name)
fs.indexByName[name] = i
}
}
return fs
}
type fields struct {
names []string
indexByName map[string]int
}