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 #include <vector>
8 #include <sstream>
9 #include <algorithm>
10 
11 // Helper type to associate the measurement dimension to the pointer to a measurement container
12 template <typename container_t, std::size_t DIM>
14 public:
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; }
25 private:
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
40 template <typename derived_t, typename ...T_Container>
42 public:
43  using measurement_container_variant_t = std::variant< T_Container...>;
44 
45 protected:
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{}) ) );
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  }
99 public:
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  }
108 protected:
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
139  assert( (countVariants<this_container_type,N-1>()) == 0 );
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 
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) {
244  return getContainerWithDimensionNoAmbiguities<container_t, false, NVariants>(a);
245  }
246  else {
247  if (variant_multiplicity==0) {
248  if (countDerivedVariants<container_t>(a) == 1) {
249  return getContainerWithDimensionNoAmbiguities<container_t, false, NVariants>(a);
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 );
255  return getContainerWithDimensionNoAmbiguities<container_t, true, NVariants>(a, getDimensionOfDerivedVariantOption<container_t,NVariants>(a));
256  }
257  }
258 };
259 
260 template <typename derived_t, typename... T_Container>
261 class MeasurementContainerListWithDimension : protected MeasurementContainerWithDimension<derived_t, T_Container...> {
262 public:
263  using Base = MeasurementContainerWithDimension<derived_t,T_Container...>;
265 private:
266  std::vector< measurement_container_variant_t > m_containerList;
267 
268 public:
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
MeasurementContainerListWithDimension::m_containerList
std::vector< measurement_container_variant_t > m_containerList
Definition: MeasurementContainerWithDimension.h:266
MeasurementContainerWithDimension::derived
const derived_t & derived() const
Definition: MeasurementContainerWithDimension.h:47
MeasurementContainerWithDimension::isSameContainer
static constexpr bool isSameContainer()
Definition: MeasurementContainerWithDimension.h:62
MeasurementContainerWithDimension::getDimensionOfDerivedVariantOption
static unsigned int getDimensionOfDerivedVariantOption(const container_t &a)
Definition: MeasurementContainerWithDimension.h:196
ContainerRefWithDim::s_dimension
static constexpr std::size_t s_dimension
Definition: MeasurementContainerWithDimension.h:18
MeasurementContainerWithDimension::dumpVariantTypes
static void dumpVariantTypes(std::ostream &out)
Definition: MeasurementContainerWithDimension.h:101
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
ContainerRefWithDim::container
const container_t & container() const
Definition: MeasurementContainerWithDimension.h:24
MeasurementContainerWithDimension< derived_t, T_Container... >::measurement_container_variant_t
std::variant< T_Container... > measurement_container_variant_t
Definition: MeasurementContainerWithDimension.h:43
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:70
athena.value
value
Definition: athena.py:124
MeasurementContainerWithDimension::getContainerWithDimensionNoAmbiguities
static measurement_container_variant_t getContainerWithDimensionNoAmbiguities(const container_t &a, unsigned int dimension=0)
Definition: MeasurementContainerWithDimension.h:117
JetTiledMap::N
@ N
Definition: TiledEtaPhiMap.h:44
ContainerRefWithDim::container_type
container_t container_type
Definition: MeasurementContainerWithDimension.h:15
MeasurementContainerWithDimension::countVariants
static constexpr unsigned int countVariants()
Definition: MeasurementContainerWithDimension.h:69
MeasurementContainerWithDimension::lvalue
static constexpr T lvalue(T &&a)
Definition: MeasurementContainerWithDimension.h:50
ContainerRefWithDim
Definition: MeasurementContainerWithDimension.h:13
ContainerRefWithDim::ContainerRefWithDim
ContainerRefWithDim(const container_t &container)
Definition: MeasurementContainerWithDimension.h:17
ContainerRefWithDim::m_container
const container_t * m_container
Definition: MeasurementContainerWithDimension.h:26
ContainerRefWithDim::dimension
static constexpr std::size_t dimension()
Definition: MeasurementContainerWithDimension.h:20
MeasurementContainerListWithDimension::setContainer
void setContainer(std::size_t container_index, const container_t &container)
Definition: MeasurementContainerWithDimension.h:286
detail::ul
unsigned long ul
Definition: PrimitiveHelpers.h:46
MeasurementContainerWithDimension::countDerivedVariants
static unsigned int countDerivedVariants(const container_t &a)
Definition: MeasurementContainerWithDimension.h:78
MeasurementContainerListWithDimension
Definition: MeasurementContainerWithDimension.h:261
MeasurementContainerListWithDimension::size
std::size_t size() const
Definition: MeasurementContainerWithDimension.h:276
ContainerRefWithDim::ContainerRefWithDim
ContainerRefWithDim()
Definition: MeasurementContainerWithDimension.h:16
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
a
TList * a
Definition: liststreamerinfos.cxx:10
ContainerRefWithDim::containerPtr
const container_t * containerPtr() const
Definition: MeasurementContainerWithDimension.h:23
DEBUG_TRACE
#define DEBUG_TRACE(a)
Definition: MeasurementContainerWithDimension.h:32
MeasurementContainerWithDimension
Definition: MeasurementContainerWithDimension.h:41
MeasurementContainerWithDimension::throwContainerNotInVariant
static void throwContainerNotInVariant(const char *a)
Definition: MeasurementContainerWithDimension.h:109
MeasurementContainerWithDimension::getContainerWithDimension
static measurement_container_variant_t getContainerWithDimension(const container_t &a)
Definition: MeasurementContainerWithDimension.h:239
MeasurementContainerListWithDimension::dumpVariantTypes
static void dumpVariantTypes()
Definition: MeasurementContainerWithDimension.h:272
MeasurementContainerListWithDimension::at
const measurement_container_variant_t & at(std::size_t container_index) const
Definition: MeasurementContainerWithDimension.h:280
MeasurementContainerListWithDimension::containerList
const std::vector< measurement_container_variant_t > & containerList() const
Definition: MeasurementContainerWithDimension.h:283
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:53
TSU::T
unsigned long long T
Definition: L1TopoDataTypes.h:35
MeasurementContainerListWithDimension::getMeasurementDimMax
static constexpr std::size_t getMeasurementDimMax()
Definition: MeasurementContainerWithDimension.h:269