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