/
db.go
131 lines (112 loc) · 2.8 KB
/
db.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
// Copyright ©2018 The go-hep 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 rdict
import (
"fmt"
"sort"
"sync"
"go-hep.org/x/hep/groot/rbytes"
)
// StreamerInfos stores all the streamers available at runtime.
var StreamerInfos = &streamerDb{
db: make(map[streamerDbKey]rbytes.StreamerInfo),
}
type streamerDbKey struct {
class string
version int
}
type streamerDb struct {
sync.RWMutex
db map[streamerDbKey]rbytes.StreamerInfo
}
func (db *streamerDb) StreamerInfo(name string, vers int) (rbytes.StreamerInfo, error) {
si, ok := db.Get(name, vers)
if !ok {
return nil, fmt.Errorf("rdict: no streamer for %q (version=%d)", name, vers)
}
return si, nil
}
func (db *streamerDb) Get(class string, vers int) (rbytes.StreamerInfo, bool) {
db.RLock()
defer db.RUnlock()
switch {
case vers < 0:
var slice []rbytes.StreamerInfo
for k, v := range db.db {
if k.class == class {
slice = append(slice, v)
continue
}
title := v.Title()
if title == "" {
continue
}
if name, ok := Typename(class, title); ok && name == class {
slice = append(slice, v)
}
}
if len(slice) == 0 {
return nil, false
}
sort.Slice(slice, func(i, j int) bool {
return slice[i].ClassVersion() < slice[j].ClassVersion()
})
return slice[len(slice)-1], true
default:
key := streamerDbKey{
class: class,
version: vers,
}
streamer, ok := db.db[key]
if !ok {
return nil, false
}
return streamer, true
}
}
// FIXME(sbinet): ROOT changed its checksum behaviour at some point.
// our reference ROOT files have been caught in the middle of this migration.
// disable the check for duplicate streamers with different checksums for now.
const checkdups = false
func (db *streamerDb) Add(streamer rbytes.StreamerInfo) {
db.Lock()
defer db.Unlock()
key := streamerDbKey{
class: streamer.Name(),
version: streamer.ClassVersion(),
}
if checkdups {
old, dup := db.db[key]
if dup {
if old.CheckSum() != streamer.CheckSum() {
panic(fmt.Errorf("rdict: StreamerInfo class=%q version=%d with checksum=%d (got checksum=%d)",
streamer.Name(), streamer.ClassVersion(), streamer.CheckSum(), old.CheckSum(),
))
}
return
}
}
db.db[key] = streamer
}
// Values returns all the known StreamerInfos.
func (db *streamerDb) Values() []rbytes.StreamerInfo {
db.RLock()
defer db.RUnlock()
var sinfos = make([]rbytes.StreamerInfo, 0, len(db.db))
for _, si := range db.db {
sinfos = append(sinfos, si)
}
sort.Slice(sinfos, func(i, j int) bool {
si := sinfos[i]
sj := sinfos[j]
if si.Name() == sj.Name() {
return si.ClassVersion() < sj.ClassVersion()
}
return si.Name() < sj.Name()
})
return sinfos
}
var (
_ rbytes.StreamerInfoContext = (*streamerDb)(nil)
)