ATLAS Offline Software
Loading...
Searching...
No Matches
MeasurementContainerWithDimension.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4#ifndef MEASUREMENTCONTAINERWITHDIMENSION_H
5#define MEASUREMENTCONTAINERWITHDIMENSION_H
6#include <variant>
7#include <vector>
8#include <sstream>
9#include <algorithm>
10
11// Helper type to associate the measurement dimension to the pointer to a measurement container
12template <typename container_t, std::size_t DIM>
14public:
15 using container_type = container_t;
18 static constexpr std::size_t s_dimension = DIM;
19 // the dimension of the measurements stored in this container
20 static constexpr std::size_t dimension() { return s_dimension; }
21
22 // pointer to the container
23 const container_t *containerPtr() const {return m_container; }
24 const container_t &container() const {return *m_container; }
25private:
26 const container_t *m_container;
27};
28
29#ifdef ENABLE_DEBUG_TRACE
30#define DEBUG_TRACE(a) do { a; } while (0)
31#else
32#define DEBUG_TRACE(a) do { } while (0)
33#endif
34
35// Variant which allows to store pointer to different measurement containers with associated dimension
36// T_Container should be of type ContainerRefWithDim< ContainerType, N>
37// T_Container should:
38// - implement the static constexpr T_Container::dimension()
39// - define the alias T_Container::container_type
40template <typename derived_t, typename ...T_Container>
42public:
43 using measurement_container_variant_t = std::variant< T_Container...>;
44
45protected:
46
47 const derived_t &derived() const { return *static_cast<const derived_t *>(this); }
48
49 template <typename T>
50 static constexpr T lvalue(T &&a) { return a;}
51
52 template <std::size_t N=std::variant_size_v< measurement_container_variant_t > >
53 static constexpr std::size_t dimMax(std::size_t max_dim=0ul) {
54 if constexpr(N>0) {
55 using this_variant_type = decltype( lvalue(std::get<N-1>(measurement_container_variant_t{}) ) );
56 return dimMax<N-1>(std::max( this_variant_type::dimension(), max_dim ) );
57 }
58 return max_dim;
59 }
60
61 template <typename container_t, std::size_t N>
62 static constexpr bool isSameContainer() {
63 using this_variant_type = decltype( lvalue(std::get<N>(measurement_container_variant_t{}) ) );
64 return std::is_same<container_t, typename this_variant_type::container_type>::value;
65 }
66
67 // helper to check whether the measurement variant contains a certain container
68 template <typename container_t, std::size_t N= std::variant_size_v< measurement_container_variant_t > >
69 static constexpr unsigned int countVariants() {
70 if constexpr(N==0) {
71 return 0;
72 }
73 else {
74 return countVariants<container_t, N-1>()+ isSameContainer<container_t, N-1>();
75 }
76 }
77 template <typename container_t, std::size_t N= std::variant_size_v< measurement_container_variant_t > >
78 static unsigned int countDerivedVariants(const container_t &a) {
79 if constexpr(N==0) {
80 return 0;
81 }
82 else {
83 if constexpr(isSameContainer<container_t, N-1>()) {
84 return countDerivedVariants<container_t, N-1>(a)+1;
85 }
86 else {
87 using this_variant_type = decltype( lvalue(std::get<N-1>(measurement_container_variant_t{}) ) );
88 using this_container_type = typename this_variant_type::container_type;
89 if constexpr(std::is_base_of_v<container_t, this_container_type>
90 && std::has_virtual_destructor_v<this_container_type> && std::has_virtual_destructor_v<container_t>) {
91 return countDerivedVariants<container_t, N-1>(a)+ ( dynamic_cast<const this_container_type *>(&a) != nullptr );
92 }
93 else {
94 return countDerivedVariants<container_t, N-1>(a);
95 }
96 }
97 }
98 }
99public:
100 template <std::size_t N= std::variant_size_v< measurement_container_variant_t > >
101 static void dumpVariantTypes(std::ostream &out) {
102 if constexpr(N>0) {
103 using a_type = decltype( lvalue(std::get<N-1>(measurement_container_variant_t{}) ) );
104 out << N-1 << ": " << typeid(a_type).name() << std::endl;
105 dumpVariantTypes<N-1>(out);
106 }
107 }
108protected:
109 static void throwContainerNotInVariant(const char *a) {
110 std::stringstream msg;
111 msg << "Container " << a << " not in variant:" << std::endl;
113 throw std::runtime_error(msg.str());
114 }
115
116 template <typename container_t, bool check_dimension, std::size_t N >
117 static measurement_container_variant_t getContainerWithDimensionNoAmbiguities(const container_t &a, unsigned int dimension=0) {
118 if constexpr(N==0) {
119 // this measns that the container_t has not been found in the list of possible options of the variant
120 // reasons: the type is not in the list, a derived type was provided and compaibility was not understood
121 throwContainerNotInVariant(typeid(a).name());
122 using this_variant_type = decltype( lvalue(std::get<0>(measurement_container_variant_t{}) ) );
123 return this_variant_type();
124 }
125 else {
126 using this_variant_type = decltype( lvalue(std::get<N-1>(measurement_container_variant_t{}) ) );
127 using this_container_type = typename this_variant_type::container_type ;
128 DEBUG_TRACE( std::cout << "DEBUG search option for " << typeid(container_t).name() << " (aka " << typeid(a).name() << ")"
129 << " option: " << N << " " << typeid(this_container_type).name() << " dim " << this_variant_type::dimension()
130 << " check dimension ? " << check_dimension << " desired dimension " << dimension
131 << std:: endl );
132 if constexpr(std::is_same_v<this_container_type, container_t>) {
133 // this option of the variant has perfect type match.
134 if constexpr(!check_dimension && countVariants<container_t>()==1) {
135 // if dimensions are not to be checked there must not be other options which also match the type
136 // the caller should have ensureed that this branch is impossible,
137 // but this can only be excluded at runtime, so a static_assert
138 // is impossible here
140 DEBUG_TRACE( std::cout << "DEBUG --> for " << typeid(container_t).name() << " (aka " << typeid(a).name() << ")"
141 << " foumd unambiguous option: " << N << " " << typeid(this_container_type).name() << " dim " << this_variant_type::dimension()
142 << std:: endl );
144 }
145 else {
146 // otherwise check if the dimension of this option is identical to the
147 // expected dimension
148 if (this_variant_type::dimension() == dimension) {
149 DEBUG_TRACE( std::cout << "DEBUG --> for " << typeid(container_t).name() << " (aka " << typeid(a).name() << ")"
150 << " foumd dimension option: " << N << " " << typeid(this_container_type).name() << " dim " << this_variant_type::dimension()
151 << std:: endl );
153 }
154 }
155 }
156 else if constexpr(std::is_base_of_v<container_t, this_container_type>) {
157 // it is also possible that the container is a base of an option of the variant.
158 if constexpr(std::has_virtual_destructor_v<this_container_type> && std::has_virtual_destructor_v<container_t>) {
159 // casting can only be done safely if dynamic casts are possible, which requires
160 // a virtuaal destructor
161 const this_container_type *derived_container = dynamic_cast<const this_container_type *>(&a);
162 if (derived_container) {
163 // if the provided container can be casted to the type of this variant option
164 // then check the dimensions
165 if constexpr(!check_dimension) {
166 // Branch may be incorrectly chose and/or assert may fail
167 // if A is base of B and B is Base of C and both B and C are options of the variant
168 // the auto-detection will treat B
169 if constexpr(countVariants<container_t,N-1>() != 0) {
170 return getContainerWithDimensionNoAmbiguities<container_t, check_dimension, N-1>(a, dimension);
171 }
172 else {
173 DEBUG_TRACE( std::cout << "DEBUG --> for " << typeid(this_container_type).name() << " (aka " << typeid(a).name() << ")"
174 << " foumd derived option: " << N << " " << typeid(this_container_type).name() << " dim " << this_variant_type::dimension()
175 << std:: endl );
177 }
178 }
179 else {
180 if (this_variant_type::dimension() == dimension) {
181 DEBUG_TRACE( std::cout << "DEBUG --> for " << typeid(this_container_type).name() << " (aka " << typeid(a).name() << ")"
182 << " derived with dimension option: " << N << " " << typeid(this_container_type).name()
183 << " dim " << this_variant_type::dimension()
184 << std:: endl );
186 }
187 }
188 }
189 }
190 }
191 return getContainerWithDimensionNoAmbiguities<container_t, check_dimension, N-1>(a, dimension);
192 }
193 }
194
195 template <typename container_t, std::size_t N>
196 static unsigned int getDimensionOfDerivedVariantOption(const container_t &a) {
197 if constexpr(N==0) {
198 // failure
199 return 0;
200 }
201 else {
202 using this_variant_type = decltype( lvalue(std::get<N-1>(measurement_container_variant_t{}) ) );
203 using this_container_type = typename this_variant_type::container_type;
204
205 DEBUG_TRACE( std::cout << "DEBUG determin dimension for " << typeid(container_t).name() << " (aka " << typeid(a).name() << ")"
206 << " option: " << N << " " << typeid(this_container_type).name() << " dim " << this_variant_type::dimension()
207 << std:: endl );
208
209 if constexpr(std::is_same<container_t, this_container_type>::value) {
210 DEBUG_TRACE( std::cout << "DEBUG get dimension for " << typeid(container_t).name() << " (aka " << typeid(a).name() << ")"
211 << " option: " << N << " " << typeid(this_container_type).name() << " dim " << this_variant_type::dimension()
212 << std:: endl );
213 return derived_t::getDimension(a);
214 }
215 else if constexpr(std::is_base_of_v<container_t, this_container_type>) {
216 DEBUG_TRACE( std::cout << "DEBUG try get dimension for derived " << typeid(container_t).name() << " (aka " << typeid(a).name() << ")"
217 << " option: " << N << " " << typeid(this_container_type).name() << " dim " << this_variant_type::dimension()
218 << std:: endl );
219 // it is also possible that the container is a base of an option of the variant.
220 if constexpr(std::has_virtual_destructor_v<this_container_type> && std::has_virtual_destructor_v<container_t>) {
221 // if there is no ambiguity there is no point in determining the dimension
222 // @TODO but this does not guarantee that this option matches if the provided container
223 // can have multiple dimensions.
224 if constexpr(countVariants<this_container_type>() > 1) {
225 // casting can only be done safely if dynamic casts are possible, which requires
226 // a virtual destructor
227 const this_container_type *derived_container = dynamic_cast<const this_container_type *>(&a);
228 if (derived_container) {
229 return derived_t::getDimension(*derived_container);
230 }
231 }
232 }
233 }
234 return getDimensionOfDerivedVariantOption<container_t, N-1>(a);
235 }
236 }
237
238 template <typename container_t, std::size_t = std::variant_size_v< measurement_container_variant_t > >
240 constexpr unsigned int variant_multiplicity = countVariants<container_t>();
241 // the container must by among the options of the measurement_container_variant_t
242 static constexpr std::size_t NVariants = std::variant_size_v< measurement_container_variant_t >;
243 if constexpr( variant_multiplicity == 1) {
245 }
246 else {
247 if (variant_multiplicity==0) {
250 }
251 }
252 DEBUG_TRACE( std::cout << "DEBUG need to search with dimension check for " << typeid(container_t).name() << " (aka " << typeid(a).name() << ")"
253 << " multiplicity : " << variant_multiplicity << " derived " << countDerivedVariants<container_t>(a)
254 << std:: endl );
256 }
257 }
258};
259
260template <typename derived_t, typename... T_Container>
262public:
263 using Base = MeasurementContainerWithDimension<derived_t,T_Container...>;
265private:
266 std::vector< measurement_container_variant_t > m_containerList;
267
268public:
269 static constexpr std::size_t getMeasurementDimMax() {
270 return Base::dimMax();
271 }
272 static void dumpVariantTypes() {
274 }
275
276 std::size_t size() const {
277 return m_containerList.size();
278 }
279
280 const measurement_container_variant_t &at(std::size_t container_index) const {
281 return m_containerList.at(container_index);
282 }
283 const std::vector< measurement_container_variant_t > &containerList() const { return m_containerList;}
284
285 template <typename container_t>
286 void setContainer(std::size_t container_index, const container_t &container) {
287 if (container_index>=m_containerList.size()) {
288 m_containerList.resize(container_index+1);
289 }
290 m_containerList[container_index] = this->getContainerWithDimension(container);
291 if ( std::holds_alternative< decltype(this->lvalue(get<0>(measurement_container_variant_t{}))) >( m_containerList[container_index])
292 && std::get<0>(m_containerList[container_index]).containerPtr() == nullptr) {
293 // @TODO should never happen
294 std::runtime_error("Unhandled measurement type");
295 }
296
297 }
298
299};
300#endif
static Double_t a
#define DEBUG_TRACE(a)
Base::measurement_container_variant_t measurement_container_variant_t
const measurement_container_variant_t & at(std::size_t container_index) const
void setContainer(std::size_t container_index, const container_t &container)
const std::vector< measurement_container_variant_t > & containerList() const
std::vector< measurement_container_variant_t > m_containerList
MeasurementContainerWithDimension< derived_t, T_Container... > Base
static unsigned int countDerivedVariants(const container_t &a)
static unsigned int getDimensionOfDerivedVariantOption(const container_t &a)
static measurement_container_variant_t getContainerWithDimensionNoAmbiguities(const container_t &a, unsigned int dimension=0)
std::variant< T_Container... > measurement_container_variant_t
static measurement_container_variant_t getContainerWithDimension(const container_t &a)
static constexpr std::size_t dimMax(std::size_t max_dim=0ul)
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
ContainerRefWithDim(const container_t &container)
const container_t & container() const
const container_t * containerPtr() const
static constexpr std::size_t s_dimension
static constexpr std::size_t dimension()
MsgStream & msg
Definition testRead.cxx:32