GCC Code Coverage Report


Directory: ./
File: include/na64util/vctr.hh
Date: 2025-09-01 06:19:01
Exec Total Coverage
Lines: 28 29 96.6%
Functions: 7 11 63.6%
Branches: 17 20 85.0%

Line Branch Exec Source
1 #pragma once
2
3 #include <typeinfo>
4 #include <typeindex>
5 #include <stdexcept>
6 #include <map>
7 #include <memory>
8 #include <cassert>
9 #include <iostream>
10
11 namespace na64dp {
12
13 namespace errors {
14
15 /// Excpetion thrown by virtual constructor instance when requested name is not
16 /// found among registered entries of certain type.
17 class CtrNotFound : public std::runtime_error {
18 private:
19 char _name[128];
20 const std::type_info & _typeInfo;
21 public:
22 CtrNotFound( const std::string & name
23 , const std::type_info & typeInfo ) throw();
24 const char * name() const throw() { return _name; }
25 const std::type_info & type_info() throw() { return _typeInfo; }
26 };
27
28 /** Excpetion thrown by virtual constructor when there are
29 * no entries defined for requested type.
30 *
31 * \note This exception is thrown when the abstract type for the entities is
32 * defined together with its traits, but no entry was added until the
33 * construction was requested. Contrary, if VCtr is parameterized with
34 * incorrect type you got compiling error instead of this runtime exception as
35 * traits are not defined.
36 */
37 class NoCtrsOfType : public std::runtime_error {
38 private:
39 const std::type_info & _typeInfo;
40 public:
41 NoCtrsOfType( const std::type_info & typeInfo ) throw();
42 const std::type_info & type_info() throw() { return _typeInfo; }
43 };
44
45 };
46
47 /// Virtual constructor traits; shall define `Constructor` type
48 template<typename T> struct CtrTraits;
49
50 /**\brief Common virtual constructor dispatcher implementation
51 *
52 * The "virtual constructor" is a common idiom that implies instantiation of
53 * classes with some common base by runtime arguments. This class implements
54 * a generalized registry for virtual multiple constructors based on the C++
55 * type ID of the bases.
56 *
57 * \note Dynamically loaded modules uses this singleton before main logging
58 * is initialized.
59 */
60 class VCtr {
61 public:
62 /// Abstract base class for all virtual constructors
63 class iCtrRegistry {};
64
65 /// Virtual constructor registry -- indexes constructors of classes with
66 /// common ancestor by their string identifiers (names)
67 template<typename T>
68 class CtrRegistry : public iCtrRegistry
69 , public std::map< std::string
70 , std::pair<typename CtrTraits<T>::Constructor, std::string> > {
71 public:
72 /// Registers new constructor
73 2 bool register_class( const std::string & name
74 , typename CtrTraits<T>::Constructor ctr
75 , const std::string & description ) {
76
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 auto ir = this->emplace( name, std::make_pair(ctr, description) );
77 2 return ir.second;
78 }
79 /// Constructs typed entry
80 template<typename... ArgsT> T *
81 3 make( const std::string & name, ArgsT &... args) {
82
1/1
✓ Branch 1 taken 3 times.
3 auto it = this->find(name);
83
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
3 if( this->end() == it ) {
84 1 throw errors::CtrNotFound( name, typeid(T) );
85 }
86
1/1
✓ Branch 2 taken 2 times.
4 return it->second.first( args... );
87 }
88 };
89 private:
90 /// Pointer to global self instance of the registry
91 static VCtr * _self;
92 /// Index of all registries
93 std::map< std::type_index, std::unique_ptr<iCtrRegistry> > _regs;
94 public:
95 /**\brief Returns registry instance of certain base type (const)
96 *
97 * Raises `NoCtrsOfType` exception if type does not exist.
98 */
99 3 template<typename T> const CtrRegistry<T> & registry() const {
100
1/1
✓ Branch 2 taken 3 times.
3 auto it = _regs.find( typeid(T) );
101
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if( _regs.end() == it ) {
102 // In principle, this exception shall never be thrown
103 throw errors::NoCtrsOfType(typeid(T));
104 }
105 3 const CtrRegistry<T> * reg = static_cast<const CtrRegistry<T> *>(it->second.get());
106 3 return *reg;
107 }
108 /**\brief Returns registry instance of certain base type
109 *
110 * Raises `NoCtrsOfType` exception if type does not exist.
111 */
112 3 template<typename T> CtrRegistry<T> & registry() {
113 3 return const_cast<CtrRegistry<T> &>(const_cast<const VCtr*>(this)->registry<T>());
114 }
115
116 /// Registers new entry in the corresponding registry
117 template<typename T> bool
118 2 register_class( const std::string & name
119 , typename CtrTraits<T>::Constructor ctr
120 , const std::string & description ) {
121
1/1
✓ Branch 2 taken 2 times.
2 auto it = _regs.find( typeid(T) );
122
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2 if( _regs.end() == it ) {
123
2/3
✓ Branch 1 taken 1 times.
✓ Branch 5 taken 1 times.
✗ Branch 8 not taken.
1 auto ir = _regs.emplace( typeid(T), new CtrRegistry<T>() );
124
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert( ir.second );
125 1 it = ir.first;
126 }
127 2 CtrRegistry<T> * regPtr = static_cast<CtrRegistry<T>*>(it->second.get());
128
1/1
✓ Branch 1 taken 2 times.
4 return regPtr->register_class(name, ctr, description);
129 }
130
131 /// Constructs entity of type `T` with arguments provided by args list.
132 template<typename T, typename... ArgsT> T *
133 3 make( const std::string & name, ArgsT & ... args ) {
134 3 return registry<T>().make( name, args... );
135 }
136
137 /// Returns global instance of the virtual constructor object
138 5 static VCtr & self() {
139
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if( _self ) return *_self;
140 1 return *( _self = new VCtr() );
141 }
142 };
143
144 } // namespace na64dp
145
146 /* \defgroup vctr-defs Virtual constructor definitions
147 *
148 * This group contains C/C++ preprocessor macros that define a runtime
149 * extension of a certain type. They typically start with `REGISTER_` prefix
150 * and are used to shorten the definition of new "virtual constructor"
151 * function (see `VCtr`).
152 *
153 * Note that these macros not necessarily accomplish the type registration
154 * task -- one can still invoke the `VCtr<>::register_class()` directly. Though
155 * these macros significantly improve readability, they migt be avoided in
156 * favor of direct calls in case of, say, explicit template instantiation. */
157