ATLAS Offline Software
Loading...
Searching...
No Matches
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
17namespace 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 */
29template <class T>
30class BaseInfoImpl
31 : public BaseInfoBase
32{
33public:
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
66private:
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 */
133template <class B>
134struct 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 */
158template <class T>
159BaseInfoImpl<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 */
183template <class T>
184void* 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 */
199template <class T>
200void* 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 */
216template <class T>
217T* 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 */
232template <class T>
233T* 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 */
248template <class T>
249BaseInfoBase::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 */
263template <class T>
264BaseInfoBase::castfn_t*
265BaseInfo<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 */
279template <class T>
280BaseInfoBase::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 */
294template <class T>
295BaseInfoBase::castfn_t*
296BaseInfo<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 */
307template <class T>
308const 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 */
318template <class T>
319std::vector<const std::type_info*>
320BaseInfo<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 */
332template <class T>
333bool 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 */
345template <class T>
346bool 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 */
358template <class T>
359bool 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 */
371template <class T>
372bool 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 */
381template <class T>
382const BaseInfoBase& BaseInfo<T>::baseinfo()
383{
384 return instance();
385}
386
387
388template <class T>
389void 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 */
399template <class T>
400BaseInfoImpl<T>& BaseInfo<T>::instance()
401{
402 s_instance.maybeInit();
403 return s_instance;
404}
405
406template <class T>
407BaseInfoImpl<T> BaseInfo<T>::s_instance;
408
409
410/**
411 * @brief Helper to get @c BaseInfo initialized.
412 */
413template <class T>
414struct 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__)
429template <class T>
430RegisterBaseInit<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 */
441template <class T> struct BaseInit {
442 static const RegisterBaseInit<T> s_regbase;
443};
444#ifndef __APPLE__
445template <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 */
456template <class D, class B>
457struct 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 */
471template <class D, class B>
472void 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 */
493template <class D, class B>
494RegisterAddBaseInit<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 */
504template <class D, class B> struct AddBaseInit {
505 static const RegisterAddBaseInit<D, B> s_regbase;
506};
507#ifndef __APPLE__
508template <class D, class B>
509const RegisterAddBaseInit<D,B> AddBaseInit<D,B>::s_regbase;
510#endif
511
512
513
514/**
515 * @brief Helper to get the copy conversion initialized.
516 */
517template <class D, class B>
518struct 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 */
532template <class T, class C>
533void 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 */
549template <class T, class C>
550RegisterAddCopyConversionInit<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 */
560template <class T, class C> struct AddCopyConversionInit {
561 static const RegisterAddCopyConversionInit<T, C> s_regbase;
562};
563#ifndef __APPLE__
564template <class T, class C>
565const RegisterAddCopyConversionInit<T,C> AddCopyConversionInit<T,C>::s_regbase;
566#endif
567
568
569} // namespace SG
570