go-hep.org/x/hep@v0.38.1/groot/rdict/db.go (about) 1 // Copyright ©2018 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package rdict 6 7 import ( 8 "fmt" 9 "sort" 10 "sync" 11 12 "go-hep.org/x/hep/groot/rbytes" 13 ) 14 15 // StreamerInfos stores all the streamers available at runtime. 16 var StreamerInfos = &streamerDb{ 17 db: make(map[streamerDbKey]rbytes.StreamerInfo), 18 } 19 20 type streamerDbKey struct { 21 class string 22 version int 23 } 24 25 type streamerDb struct { 26 sync.RWMutex 27 db map[streamerDbKey]rbytes.StreamerInfo 28 } 29 30 func (db *streamerDb) StreamerInfo(name string, vers int) (rbytes.StreamerInfo, error) { 31 si, ok := db.Get(name, vers) 32 if !ok { 33 return nil, fmt.Errorf("rdict: no streamer for %q (version=%d)", name, vers) 34 } 35 return si, nil 36 } 37 38 func (db *streamerDb) Get(class string, vers int) (rbytes.StreamerInfo, bool) { 39 db.RLock() 40 defer db.RUnlock() 41 switch { 42 case vers < 0: 43 var slice []rbytes.StreamerInfo 44 for k, v := range db.db { 45 if k.class == class { 46 slice = append(slice, v) 47 continue 48 } 49 title := v.Title() 50 if title == "" { 51 continue 52 } 53 if name, ok := Typename(class, title); ok && name == class { 54 slice = append(slice, v) 55 } 56 } 57 if len(slice) == 0 { 58 return nil, false 59 } 60 sort.Slice(slice, func(i, j int) bool { 61 return slice[i].ClassVersion() < slice[j].ClassVersion() 62 }) 63 return slice[len(slice)-1], true 64 default: 65 key := streamerDbKey{ 66 class: class, 67 version: vers, 68 } 69 70 streamer, ok := db.db[key] 71 if !ok { 72 return nil, false 73 } 74 return streamer, true 75 } 76 } 77 78 // FIXME(sbinet): ROOT changed its checksum behaviour at some point. 79 // our reference ROOT files have been caught in the middle of this migration. 80 // disable the check for duplicate streamers with different checksums for now. 81 const checkdups = false 82 83 func (db *streamerDb) Add(streamer rbytes.StreamerInfo) { 84 db.Lock() 85 defer db.Unlock() 86 87 key := streamerDbKey{ 88 class: streamer.Name(), 89 version: streamer.ClassVersion(), 90 } 91 92 if checkdups { 93 old, dup := db.db[key] 94 if dup { 95 if old.CheckSum() != streamer.CheckSum() { 96 panic(fmt.Errorf("rdict: StreamerInfo class=%q version=%d with checksum=%d (got checksum=%d)", 97 streamer.Name(), streamer.ClassVersion(), streamer.CheckSum(), old.CheckSum(), 98 )) 99 } 100 return 101 } 102 } 103 104 db.db[key] = streamer 105 } 106 107 // Values returns all the known StreamerInfos. 108 func (db *streamerDb) Values() []rbytes.StreamerInfo { 109 db.RLock() 110 defer db.RUnlock() 111 112 var sinfos = make([]rbytes.StreamerInfo, 0, len(db.db)) 113 for _, si := range db.db { 114 sinfos = append(sinfos, si) 115 } 116 117 sort.Slice(sinfos, func(i, j int) bool { 118 si := sinfos[i] 119 sj := sinfos[j] 120 if si.Name() == sj.Name() { 121 return si.ClassVersion() < sj.ClassVersion() 122 } 123 return si.Name() < sj.Name() 124 }) 125 126 return sinfos 127 } 128 129 var ( 130 _ rbytes.StreamerInfoContext = (*streamerDb)(nil) 131 )