ATLAS Offline Software
BaseInfo.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 /**
5  * @file AthenaKernel/BaseInfo.icc
6  * @author scott snyder
7  * @date Nov 2005
8  * @brief Provide an interface for finding inheritance information
9  * at run time.
10  * Implementation file.
11  */
12 
13 
14 #include <type_traits>
15 
16 
17 namespace SG {
18 
19 
20 //===========================================================================
21 // Internal implementation class for @a BaseInfo.
22 // This is used as a singleton, and should be accessed using the @a BaseInfo
23 // wrapper class.
24 //
25 
26 /**
27  * @brief Internal implementation class for @a BaseInfo.
28  */
29 template <class T>
30 class BaseInfoImpl
31  : public BaseInfoBase
32 {
33 public:
34  /**
35  * @brief Constructor.
36  */
37  BaseInfoImpl();
38 
39 
40  /**
41  * @brief Add information about base class @a B (for @a T).
42  * @param is_virtual True if the derivation from @a B to @a T
43  * is via virtual derivation.
44  */
45 #if defined(__REFLEX__) || defined(__COVERITY__)
46  template <class B>
47  void add_base (bool is_virtual);
48 #else
49  template <class B>
50  void add_base (bool is_virtual)
51  {
52  // Make sure the bib for the base class exists.
53  if (!std::is_same<T, B>::value) {
54  // Don't call it if the types are the same.
55  // Otherwise, we can get recursive calls to instance(), triggering
56  // a deadlock.
57  BaseInfo<B>::maybeInit();
58  }
59 
60  // Add the information for this base.
61  this->add_info (typeid(B),
62  converter<B>, converterTo<B>, is_virtual);
63  }
64 #endif
65 
66 private:
67  /**
68  * @brief Converter function.
69  * @param p Pointer to convert. A @a T* converted to a @a void*.
70  *
71  * Converts a @a T* to a @a B* (where @a T derives from @a B).
72  * The pointers are given and returned as @a void*.
73  */
74  template <class B>
75  static void* converter (void* p)
76  {
77  typedef typename std::remove_const<B>::type B_nc;
78  typedef typename std::remove_const<T>::type T_nc;
79  B_nc* b = reinterpret_cast<T_nc*> (p);
80  return b;
81  }
82 
83 
84  /**
85  * @brief Converter function.
86  * @param p Pointer to convert. A @a B* converted to a @a void*.
87  *
88  * Converts a @a B* to a @a T* (where @a T derives from @a B).
89  * The pointers are given and returned as @a void*.
90  * Returns 0 if the conversion fails.
91  *
92  * Implementation note: to @c dynamic_cast @a B to @a T, @a B needs to have
93  * a vtable. If B doesn't have a vtable, then we don't attempt the
94  * conversion. (In principle, we could use is_virtual_base_of, and fall
95  * back to a static_cast if it's false. However, using is_virtual_base_of
96  * generates some nasty compilation warnings, so i'll avoid it for now.)
97  */
98  template <class B>
99  static void* converterTo (void* p)
100  {
101  return converterToHelper<B> (p, std::is_polymorphic<B>());
102  }
103 
104 
105  // B has a vtable. Use dynamic_cast.
106  template <class B>
107  static void* converterToHelper (void* p, std::true_type)
108  {
109  typedef typename std::remove_const<B>::type B_nc;
110  typedef typename std::remove_const<T>::type T_nc;
111  T_nc* b = dynamic_cast<T_nc*> (reinterpret_cast<B_nc*> (p));
112  return b;
113  }
114 
115 
116  // B doesn't have a vtable. Don't try to convert.
117  template <class B>
118  static void* converterToHelper (void* /*p*/, std::false_type)
119  {
120  return 0;
121  }
122 };
123 
124 
125 //===========================================================================
126 // Initialization.
127 // Here we walk the class hierarchy, calling @a add_base for each base.
128 
129 
130 /**
131  * @brief Initializer for base @a B.
132  */
133 template <class B>
134 struct BaseInfo_init
135 {
136  template <class T>
137  static void init (BaseInfoImpl<T>& c, bool is_virtual)
138  {
139  // Here, we initialize the @a BaseInfo for @a T for base class @a B.
140  // First, we add the information for this base to the instance.
141  c.template add_base<B>(is_virtual);
142 
143  // Then we recurse on each possible base.
144  auto add = [&] (auto* p, bool base_is_virtual)
145  {
146  using base_t = std::remove_pointer_t<decltype(p)>;
147  c.template add_base<base_t> (is_virtual || base_is_virtual);
148  return false;
149  };
150  Bases<B>::bases::foreach_ (add);
151  }
152 };
153 
154 
155 /**
156  * @brief Constructor.
157  */
158 template <class T>
159 BaseInfoImpl<T>::BaseInfoImpl ()
160  : BaseInfoBase (typeid(T))
161 {
162  // This starts the walk over the bases.
163  // We start with @a T itself.
164  // The virtual flag is initially false.
165  BaseInfo_init<T>::init (*this, false);
166 }
167 
168 
169 //===========================================================================
170 // The @a BaseInfo wrapper class.
171 // This will statically hold a singleton instance of @a BaseInfoImpl
172 // (in the instance function).
173 
174 
175 /**
176  * @brief Cast to a base pointer.
177  * @param p The pointer to cast.
178  * @param clid ID of the class to which to cast.
179  * @return The pointer cast to the requested type, returned
180  * as a @a void*. @a clid must be known to be a base
181  * of @a T; otherwise, 0 will be returned.
182  */
183 template <class T>
184 void* BaseInfo<T>::cast (T* p, CLID clid)
185 {
186  typedef typename std::remove_const<T>::type T_nc;
187  return instance().cast (const_cast<T_nc*>(p), clid);
188 }
189 
190 
191 /**
192  * @brief Cast to a base pointer.
193  * @param p The pointer to cast.
194  * @param clid @a type_info of the class to which to cast.
195  * @return The pointer cast to the requested type, returned
196  * as a @a void*. @a tinfo must be known to be a base
197  * of @a T; otherwise, 0 will be returned.
198  */
199 template <class T>
200 void* BaseInfo<T>::cast (T* p, const std::type_info& tinfo)
201 {
202  typedef typename std::remove_const<T>::type T_nc;
203  return instance().cast (const_cast<T_nc*>(p), tinfo);
204 }
205 
206 
207 /**
208  * @brief Cast to a derived pointer.
209  * @param p The pointer to cast.
210  * @param clid ID of the class @a B from which to cast.
211  * @return The pointer cast to a @a T*.
212  * @a B must be known to be a base
213  * of @a T; otherwise, 0 will be returned.
214  * 0 will also be returned if the @a dynamic_cast fails.
215  */
216 template <class T>
217 T* BaseInfo<T>::castTo (void* p, CLID clid)
218 {
219  return reinterpret_cast<T*> (instance().castTo (p, clid));
220 }
221 
222 
223 /**
224  * @brief Cast to a derived pointer.
225  * @param p The pointer to cast.
226  * @param clid @a type_info of the class @a B from which to cast.
227  * @return The pointer cast to a @a T*.
228  * @a B must be known to be a base
229  * of @a T; otherwise, 0 will be returned.
230  * 0 will also be returned if the @a dynamic_cast fails.
231  */
232 template <class T>
233 T* BaseInfo<T>::castTo (void* p, const std::type_info& tinfo)
234 {
235  return reinterpret_cast<T*> (instance().castTo (p, tinfo));
236 }
237 
238 
239 #if !defined(__REFLEX__) && !defined(__COVERITY__)
240 /**
241  * @brief Return a function for casting to a base pointer.
242  * @param clid ID of the class to which to cast.
243  * @return A function to convert a pointer to a @c T to a pointer
244  * to the type identified by @a clid.
245  * @a clid must be known to be a base
246  * of @a T; otherwise, 0 will be returned.
247  */
248 template <class T>
249 BaseInfoBase::castfn_t* BaseInfo<T>::castfn (CLID clid)
250 {
251  return instance().castfn (clid);
252 }
253 
254 
255 /**
256  * @brief Return a function for casting to a base pointer.
257  * @param clid @a type_info of the class to which to cast.
258  * @return A function to convert a pointer to a @c T to a pointer
259  * to the type identified by @a tinfo.
260  * @a tinfo must be known to be a base
261  * of @a T; otherwise, 0 will be returned.
262  */
263 template <class T>
264 BaseInfoBase::castfn_t*
265 BaseInfo<T>::castfn (const std::type_info& tinfo)
266 {
267  return instance().castfn (tinfo);
268 }
269 
270 
271 /**
272  * @brief Return a function for casting to a derived pointer.
273  * @param clid ID of the class @a B from which to cast.
274  * @return A function to convert a pointer to a @c T to a pointer
275  * to a @a T. @a clid must be known to be a base
276  * of @a T; otherwise, 0 will be returned.
277  * 0 will also be returned if the @a dynamic_cast fails.
278  */
279 template <class T>
280 BaseInfoBase::castfn_t* BaseInfo<T>::castfnTo (CLID clid)
281 {
282  return instance().castfnTo (clid);
283 }
284 
285 
286 /**
287  * @brief Return a function for casting to a derived pointer.
288  * @param clid @a type_info of the class @a B from which to cast.
289  * @return A function to convert a pointer to a @c B to a pointer
290  * to a @T. @a tinfo must be known to be a base
291  * of @a T; otherwise, 0 will be returned.
292  * 0 will also be returned if the @a dynamic_cast fails.
293  */
294 template <class T>
295 BaseInfoBase::castfn_t*
296 BaseInfo<T>::castfnTo (const std::type_info& tinfo)
297 {
298  return instance().castfnTo (tinfo);
299 }
300 #endif
301 
302 
303 /**
304  * @brief Return the class IDs of all known bases of @a T (that
305  * have class IDs). The list will include @a T itself.
306  */
307 template <class T>
308 const std::vector<CLID>& BaseInfo<T>::get_bases ()
309 {
310  return instance().get_bases();
311 }
312 
313 
314 /**
315  * @brief Return the @c type_info's of all known bases of @a T.
316  * The list will include @a T itself.
317  */
318 template <class T>
319 std::vector<const std::type_info*>
320 BaseInfo<T>::get_ti_bases ()
321 {
322  return instance().get_ti_bases();
323 }
324 
325 
326 /**
327  * @brief Return true if @a clid is the ID of a class that
328  * is known to be a base of @a T. @a T is considered
329  * to be its own base for this purpose.
330  * @param clid The ID of the class to test.
331  */
332 template <class T>
333 bool BaseInfo<T>::is_base (CLID clid)
334 {
335  return instance().is_base (clid);
336 }
337 
338 
339 /**
340  * @brief Return true if @a tinfo is the @a std::type_info of a class that
341  * is known to be a base of @a T. @a T is considered
342  * to be its own base for this purpose.
343  * @param tinfo The @a std::type_info of the class to test.
344  */
345 template <class T>
346 bool BaseInfo<T>::is_base (const std::type_info& tinfo)
347 {
348  return instance().is_base (tinfo);
349 }
350 
351 
352 /**
353  * @brief Return true if @a clid is the ID of a class that
354  * is known to be a virtual base of @a T. (This will always
355  * be false for @a T itself.)
356  * @param clid The ID of the class to test.
357  */
358 template <class T>
359 bool BaseInfo<T>::is_virtual (CLID clid)
360 {
361  return instance().is_virtual (clid);
362 }
363 
364 
365 /**
366  * @brief Return true if @a tinfo is the @a std::type_info of a class that
367  * is known to be a virtual base of @a T. (This will always
368  * be false for @a T itself.)
369  * @param tinfo The @a std::type_info of the class to test.
370  */
371 template <class T>
372 bool BaseInfo<T>::is_virtual (const std::type_info& tinfo)
373 {
374  return instance().is_virtual (tinfo);
375 }
376 
377 
378 /**
379  * @brief Return the non-templated @c BaseInfoBase object for this type.
380  */
381 template <class T>
382 const BaseInfoBase& BaseInfo<T>::baseinfo()
383 {
384  return instance();
385 }
386 
387 
388 template <class T>
389 void BaseInfo<T>::maybeInit()
390 {
391  instance();
392 }
393 
394 
395 /**
396  * @brief Return a reference to the (singleton) implementation object
397  * for this class.
398  */
399 template <class T>
400 BaseInfoImpl<T>& BaseInfo<T>::instance()
401 {
402  s_instance.maybeInit();
403  return s_instance;
404 }
405 
406 template <class T>
407 BaseInfoImpl<T> BaseInfo<T>::s_instance;
408 
409 
410 /**
411  * @brief Helper to get @c BaseInfo initialized.
412  */
413 template <class T>
414 struct RegisterBaseInit
415 {
416  RegisterBaseInit()
417 #ifdef __GNUC__
418  // Force this function to appear as a symbol in the output file,
419  // even in an optimized build where it's always inlined.
420  // Otherwise, we get complaints from cling that it can't find the symbol
421  // (as of root 6.04).
422  __attribute__ ((used))
423 #endif
424  ;
425 };
426 
427 
428 #if !defined(__REFLEX__) && !defined(__COVERITY__)
429 template <class T>
430 RegisterBaseInit<T>::RegisterBaseInit()
431 {
432  BaseInfoBase::addInit(&typeid(T),
433  [] (BaseInfoBase*) { BaseInfo<T>::baseinfo(); });
434 }
435 #endif
436 
437 
438 /**
439  * @brief Helper to get @c BaseInfo initialized.
440  */
441 template <class T> struct BaseInit {
442  static const RegisterBaseInit<T> s_regbase;
443 };
444 #ifndef __APPLE__
445 template <class T> const RegisterBaseInit<T> BaseInit<T>::s_regbase;
446 #endif
447 
448 
449 //**********************************************************
450 // SG_ADD_BASE and SG_ADD_COPY_CONVERSION implementation.
451 
452 
453 /**
454  * @brief Helper to get @c AddBaseInfo initialized.
455  */
456 template <class D, class B>
457 struct RegisterAddBaseInit
458 {
459  /// Add ourself to the init list.
460  RegisterAddBaseInit();
461 
462  /// Init callback: add the new base to the BIB.
463  static void doinit (BaseInfoBase* bib);
464 };
465 
466 
467 #if !defined(__REFLEX__) && !defined(__COVERITY__)
468 /**
469  * @brief Init callback: add the new base to the BIB.
470  */
471 template <class D, class B>
472 void RegisterAddBaseInit<D, B>::doinit (BaseInfoBase* bib)
473 {
474  // B may either be the actual base class we want,
475  // or Virtual<BB>. Unwrap a surrounding Virtual<> if needed.
476  typedef typename BaseType<B>::type base_type;
477  bool is_virtual = BaseType<B>::is_virtual::value;
478 
479  // Look up the BIB.
480  if (!bib)
481  bib = &BaseInfo<D>::instance();
482  if (bib) {
483  // Add the new base to it.
484  SG::BaseInfoImpl<D>& impl = *static_cast<SG::BaseInfoImpl<D>*> (bib);
485  impl.template add_base<base_type> (is_virtual);
486  }
487 }
488 
489 
490 /**
491  * @brief Add ourself to the init list.
492  */
493 template <class D, class B>
494 RegisterAddBaseInit<D, B>::RegisterAddBaseInit()
495 {
496  BaseInfoBase::addInit(&typeid(D), doinit);
497 }
498 #endif
499 
500 
501 /**
502  * @brief Helper to get @c AddBaseInfo initialized.
503  */
504 template <class D, class B> struct AddBaseInit {
505  static const RegisterAddBaseInit<D, B> s_regbase;
506 };
507 #ifndef __APPLE__
508 template <class D, class B>
509 const RegisterAddBaseInit<D,B> AddBaseInit<D,B>::s_regbase;
510 #endif
511 
512 
513 
514 /**
515  * @brief Helper to get the copy conversion initialized.
516  */
517 template <class D, class B>
518 struct RegisterAddCopyConversionInit
519 {
520  /// Add ourself to the init list.
521  RegisterAddCopyConversionInit();
522 
523  /// Init callback: xxx
524  static void doinit (BaseInfoBase* bib);
525 };
526 
527 
528 #if !defined(__REFLEX__) && !defined(__COVERITY__)
529 /**
530  * @brief Init callback: add the new conversion to the BIB.
531  */
532 template <class T, class C>
533 void RegisterAddCopyConversionInit<T, C>::doinit (BaseInfoBase* bib)
534 {
535  // Look up the BIB.
536  if (!bib)
537  bib = &BaseInfo<T>::instance();
538  if (bib) {
539  typedef typename C::target_type target_type;
540  bib->add_copy_conversion (typeid(target_type),
541  new C);
542  }
543 }
544 
545 
546 /**
547  * @brief Add ourself to the init list.
548  */
549 template <class T, class C>
550 RegisterAddCopyConversionInit<T, C>::RegisterAddCopyConversionInit()
551 {
552  BaseInfoBase::addInit(&typeid(T), doinit);
553 }
554 #endif
555 
556 
557 /**
558  * @brief Helper to get @c AddBaseInfo initialized.
559  */
560 template <class T, class C> struct AddCopyConversionInit {
561  static const RegisterAddCopyConversionInit<T, C> s_regbase;
562 };
563 #ifndef __APPLE__
564 template <class T, class C>
565 const RegisterAddCopyConversionInit<T,C> AddCopyConversionInit<T,C>::s_regbase;
566 #endif
567 
568 
569 } // namespace SG
570