go-hep.org/x/hep@v0.38.1/groot/rtypes/factory.go (about)

     1  // Copyright ©2017 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 rtypes
     6  
     7  import (
     8  	"errors"
     9  	"reflect"
    10  	"sync"
    11  )
    12  
    13  var (
    14  	errInvalidType = errors.New("rtypes: invalid classname")
    15  )
    16  
    17  // FactoryFct creates new values of a given type.
    18  type FactoryFct func() reflect.Value
    19  
    20  type factory struct {
    21  	mu sync.RWMutex
    22  	db map[string]FactoryFct // a registry of all factory functions by type name
    23  }
    24  
    25  func (f *factory) Len() int {
    26  	f.mu.RLock()
    27  	n := len(f.db)
    28  	f.mu.RUnlock()
    29  	return n
    30  }
    31  
    32  func (f *factory) Keys() []string {
    33  	f.mu.RLock()
    34  	keys := make([]string, 0, len(f.db))
    35  	for k := range f.db {
    36  		keys = append(keys, k)
    37  	}
    38  	f.mu.RUnlock()
    39  	return keys
    40  }
    41  
    42  func (f *factory) HasKey(n string) bool {
    43  	f.mu.RLock()
    44  	_, ok := f.db[n]
    45  	f.mu.RUnlock()
    46  	return ok
    47  }
    48  
    49  func (f *factory) Get(n string) FactoryFct {
    50  	if n == "" {
    51  		panic(errInvalidType)
    52  	}
    53  
    54  	f.mu.RLock()
    55  	fct, ok := f.db[n]
    56  	f.mu.RUnlock()
    57  	if ok {
    58  		return fct
    59  	}
    60  
    61  	// if we are here, nobody registered a streamer+factory for 'string'.
    62  	// try our streamer-less rbase.String version.
    63  	if n == "string" {
    64  		f.mu.RLock()
    65  		fct, ok := f.db["*rbase.String"]
    66  		f.mu.RUnlock()
    67  		if ok {
    68  			return fct
    69  		}
    70  	}
    71  
    72  	f.mu.RLock()
    73  	obj := f.db["*rdict.Object"]
    74  	f.mu.RUnlock()
    75  
    76  	fct = func() reflect.Value {
    77  		v := obj()
    78  		v.Interface().(setClasser).SetClass(n)
    79  		return v
    80  	}
    81  
    82  	return fct
    83  }
    84  
    85  func (f *factory) Add(n string, fct FactoryFct) {
    86  	f.mu.Lock()
    87  	f.db[n] = fct
    88  	f.mu.Unlock()
    89  }
    90  
    91  type setClasser interface {
    92  	SetClass(name string)
    93  }
    94  
    95  var Factory = &factory{
    96  	db: make(map[string]FactoryFct),
    97  }