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  )