2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
5 * @file AthenaKernel/BaseInfo.icc
8 * @brief Provide an interface for finding inheritance information
10 * Implementation file.
14 #include <type_traits>
20 //===========================================================================
21 // Internal implementation class for @a BaseInfo.
22 // This is used as a singleton, and should be accessed using the @a BaseInfo
27 * @brief Internal implementation class for @a BaseInfo.
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.
45 #if defined(__REFLEX__) || defined(__COVERITY__)
47 void add_base (bool is_virtual);
50 void add_base (bool is_virtual)
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
57 BaseInfo<B>::maybeInit();
60 // Add the information for this base.
61 this->add_info (typeid(B),
62 converter<B>, converterTo<B>, is_virtual);
68 * @brief Converter function.
69 * @param p Pointer to convert. A @a T* converted to a @a void*.
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*.
75 static void* converter (void* p)
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);
85 * @brief Converter function.
86 * @param p Pointer to convert. A @a B* converted to a @a void*.
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.
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.)
99 static void* converterTo (void* p)
101 return converterToHelper<B> (p, std::is_polymorphic<B>());
105 // B has a vtable. Use dynamic_cast.
107 static void* converterToHelper (void* p, std::true_type)
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));
116 // B doesn't have a vtable. Don't try to convert.
118 static void* converterToHelper (void* /*p*/, std::false_type)
125 //===========================================================================
127 // Here we walk the class hierarchy, calling @a add_base for each base.
131 * @brief Initializer for base @a B.
137 static void init (BaseInfoImpl<T>& c, bool is_virtual)
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);
143 // Then we recurse on each possible base.
144 auto add = [&] (auto* p, bool base_is_virtual)
146 using base_t = std::remove_pointer_t<decltype(p)>;
147 c.template add_base<base_t> (is_virtual || base_is_virtual);
150 Bases<B>::bases::foreach_ (add);
156 * @brief Constructor.
159 BaseInfoImpl<T>::BaseInfoImpl ()
160 : BaseInfoBase (typeid(T))
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);
169 //===========================================================================
170 // The @a BaseInfo wrapper class.
171 // This will statically hold a singleton instance of @a BaseInfoImpl
172 // (in the instance function).
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.
184 void* BaseInfo<T>::cast (T* p, CLID clid)
186 typedef typename std::remove_const<T>::type T_nc;
187 return instance().cast (const_cast<T_nc*>(p), clid);
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.
200 void* BaseInfo<T>::cast (T* p, const std::type_info& tinfo)
202 typedef typename std::remove_const<T>::type T_nc;
203 return instance().cast (const_cast<T_nc*>(p), tinfo);
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.
217 T* BaseInfo<T>::castTo (void* p, CLID clid)
219 return reinterpret_cast<T*> (instance().castTo (p, clid));
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.
233 T* BaseInfo<T>::castTo (void* p, const std::type_info& tinfo)
235 return reinterpret_cast<T*> (instance().castTo (p, tinfo));
239 #if !defined(__REFLEX__) && !defined(__COVERITY__)
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.
249 BaseInfoBase::castfn_t* BaseInfo<T>::castfn (CLID clid)
251 return instance().castfn (clid);
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.
264 BaseInfoBase::castfn_t*
265 BaseInfo<T>::castfn (const std::type_info& tinfo)
267 return instance().castfn (tinfo);
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.
280 BaseInfoBase::castfn_t* BaseInfo<T>::castfnTo (CLID clid)
282 return instance().castfnTo (clid);
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.
295 BaseInfoBase::castfn_t*
296 BaseInfo<T>::castfnTo (const std::type_info& tinfo)
298 return instance().castfnTo (tinfo);
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.
308 const std::vector<CLID>& BaseInfo<T>::get_bases ()
310 return instance().get_bases();
315 * @brief Return the @c type_info's of all known bases of @a T.
316 * The list will include @a T itself.
319 std::vector<const std::type_info*>
320 BaseInfo<T>::get_ti_bases ()
322 return instance().get_ti_bases();
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.
333 bool BaseInfo<T>::is_base (CLID clid)
335 return instance().is_base (clid);
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.
346 bool BaseInfo<T>::is_base (const std::type_info& tinfo)
348 return instance().is_base (tinfo);
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.
359 bool BaseInfo<T>::is_virtual (CLID clid)
361 return instance().is_virtual (clid);
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.
372 bool BaseInfo<T>::is_virtual (const std::type_info& tinfo)
374 return instance().is_virtual (tinfo);
379 * @brief Return the non-templated @c BaseInfoBase object for this type.
382 const BaseInfoBase& BaseInfo<T>::baseinfo()
389 void BaseInfo<T>::maybeInit()
396 * @brief Return a reference to the (singleton) implementation object
400 BaseInfoImpl<T>& BaseInfo<T>::instance()
402 s_instance.maybeInit();
407 BaseInfoImpl<T> BaseInfo<T>::s_instance;
411 * @brief Helper to get @c BaseInfo initialized.
414 struct RegisterBaseInit
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))
428 #if !defined(__REFLEX__) && !defined(__COVERITY__)
430 RegisterBaseInit<T>::RegisterBaseInit()
432 BaseInfoBase::addInit(&typeid(T),
433 [] (BaseInfoBase*) { BaseInfo<T>::baseinfo(); });
439 * @brief Helper to get @c BaseInfo initialized.
441 template <class T> struct BaseInit {
442 static const RegisterBaseInit<T> s_regbase;
445 template <class T> const RegisterBaseInit<T> BaseInit<T>::s_regbase;
449 //**********************************************************
450 // SG_ADD_BASE and SG_ADD_COPY_CONVERSION implementation.
454 * @brief Helper to get @c AddBaseInfo initialized.
456 template <class D, class B>
457 struct RegisterAddBaseInit
459 /// Add ourself to the init list.
460 RegisterAddBaseInit();
462 /// Init callback: add the new base to the BIB.
463 static void doinit (BaseInfoBase* bib);
467 #if !defined(__REFLEX__) && !defined(__COVERITY__)
469 * @brief Init callback: add the new base to the BIB.
471 template <class D, class B>
472 void RegisterAddBaseInit<D, B>::doinit (BaseInfoBase* bib)
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;
481 bib = &BaseInfo<D>::instance();
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);
491 * @brief Add ourself to the init list.
493 template <class D, class B>
494 RegisterAddBaseInit<D, B>::RegisterAddBaseInit()
496 BaseInfoBase::addInit(&typeid(D), doinit);
502 * @brief Helper to get @c AddBaseInfo initialized.
504 template <class D, class B> struct AddBaseInit {
505 static const RegisterAddBaseInit<D, B> s_regbase;
508 template <class D, class B>
509 const RegisterAddBaseInit<D,B> AddBaseInit<D,B>::s_regbase;
515 * @brief Helper to get the copy conversion initialized.
517 template <class D, class B>
518 struct RegisterAddCopyConversionInit
520 /// Add ourself to the init list.
521 RegisterAddCopyConversionInit();
523 /// Init callback: xxx
524 static void doinit (BaseInfoBase* bib);
528 #if !defined(__REFLEX__) && !defined(__COVERITY__)
530 * @brief Init callback: add the new conversion to the BIB.
532 template <class T, class C>
533 void RegisterAddCopyConversionInit<T, C>::doinit (BaseInfoBase* bib)
537 bib = &BaseInfo<T>::instance();
539 typedef typename C::target_type target_type;
540 bib->add_copy_conversion (typeid(target_type),
547 * @brief Add ourself to the init list.
549 template <class T, class C>
550 RegisterAddCopyConversionInit<T, C>::RegisterAddCopyConversionInit()
552 BaseInfoBase::addInit(&typeid(T), doinit);
558 * @brief Helper to get @c AddBaseInfo initialized.
560 template <class T, class C> struct AddCopyConversionInit {
561 static const RegisterAddCopyConversionInit<T, C> s_regbase;
564 template <class T, class C>
565 const RegisterAddCopyConversionInit<T,C> AddCopyConversionInit<T,C>::s_regbase;