2 Copyright (C) 2002-2026 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.
22 * @brief Destruction functionals.
24 * Note that in the case of a forward declarations, it may be necessary
25 * to specialize this and separate the declaration and definition.
26 * See the DATAVECTOR_BASE_FWD macros.
31 static void destroy (void* p) { delete reinterpret_cast<T*> (p); }
34struct bi_destroy<void> {
36 static void destroy (void*) { }
40//===========================================================================
41// Internal implementation class for @a BaseInfo.
42// This is used as a singleton, and should be accessed using the @a BaseInfo
47 * @brief Internal implementation class for @a BaseInfo.
61 * @brief Add information about base class @a B (for @a T).
62 * @param is_virtual True if the derivation from @a B to @a T
63 * is via virtual derivation.
65#if defined(__REFLEX__) || defined(__COVERITY__)
67 void add_base (bool is_virtual);
70 void add_base (bool is_virtual)
72 // Make sure the bib for the base class exists.
73 if (!std::is_same<T, B>::value) {
74 // Don't call it if the types are the same.
75 // Otherwise, we can get recursive calls to instance(), triggering
77 BaseInfo<B>::maybeInit();
80 // Add the information for this base.
81 this->add_info (typeid(B),
82 converter<B>, converterTo<B>, is_virtual);
88 * @brief Converter function.
89 * @param p Pointer to convert. A @a T* converted to a @a void*.
91 * Converts a @a T* to a @a B* (where @a T derives from @a B).
92 * The pointers are given and returned as @a void*.
95 static void* converter (void* p)
97 typedef typename std::remove_const<B>::type B_nc;
98 typedef typename std::remove_const<T>::type T_nc;
99 B_nc* b = reinterpret_cast<T_nc*> (p);
105 * @brief Converter function.
106 * @param p Pointer to convert. A @a B* converted to a @a void*.
108 * Converts a @a B* to a @a T* (where @a T derives from @a B).
109 * The pointers are given and returned as @a void*.
110 * Returns 0 if the conversion fails.
112 * Implementation note: to @c dynamic_cast @a B to @a T, @a B needs to have
113 * a vtable. If B doesn't have a vtable, then we don't attempt the
114 * conversion. (In principle, we could use is_virtual_base_of, and fall
115 * back to a static_cast if it's false. However, using is_virtual_base_of
116 * generates some nasty compilation warnings, so i'll avoid it for now.)
119 static void* converterTo (void* p)
121 return converterToHelper<B> (p, std::is_polymorphic<B>());
125 // B has a vtable. Use dynamic_cast.
127 static void* converterToHelper (void* p, std::true_type)
129 typedef typename std::remove_const<B>::type B_nc;
130 typedef typename std::remove_const<T>::type T_nc;
131 T_nc* b = dynamic_cast<T_nc*> (reinterpret_cast<B_nc*> (p));
136 // B doesn't have a vtable. Don't try to convert.
138 static void* converterToHelper (void* /*p*/, std::false_type)
145//===========================================================================
147// Here we walk the class hierarchy, calling @a add_base for each base.
151 * @brief Initializer for base @a B.
157 static void init (BaseInfoImpl<T>& c, bool is_virtual)
159 // Here, we initialize the @a BaseInfo for @a T for base class @a B.
160 // First, we add the information for this base to the instance.
161 c.template add_base<B>(is_virtual);
163 // Then we recurse on each possible base.
164 auto add = [&] (auto* p, bool base_is_virtual)
166 using base_t = std::remove_pointer_t<decltype(p)>;
167 c.template add_base<base_t> (is_virtual || base_is_virtual);
170 Bases<B>::bases::foreach_ (add);
176 * @brief Constructor.
179BaseInfoImpl<T>::BaseInfoImpl ()
180 : BaseInfoBase (typeid(T), bi_destroy<T>::destroy)
182 // This starts the walk over the bases.
183 // We start with @a T itself.
184 // The virtual flag is initially false.
185 BaseInfo_init<T>::init (*this, false);
189//===========================================================================
190// The @a BaseInfo wrapper class.
191// This will statically hold a singleton instance of @a BaseInfoImpl
192// (in the instance function).
196 * @brief Cast to a base pointer.
197 * @param p The pointer to cast.
198 * @param clid ID of the class to which to cast.
199 * @return The pointer cast to the requested type, returned
200 * as a @a void*. @a clid must be known to be a base
201 * of @a T; otherwise, 0 will be returned.
204void* BaseInfo<T>::cast (T* p, CLID clid)
206 typedef typename std::remove_const<T>::type T_nc;
207 return instance().cast (const_cast<T_nc*>(p), clid);
212 * @brief Cast to a base pointer.
213 * @param p The pointer to cast.
214 * @param clid @a type_info of the class to which to cast.
215 * @return The pointer cast to the requested type, returned
216 * as a @a void*. @a tinfo must be known to be a base
217 * of @a T; otherwise, 0 will be returned.
220void* BaseInfo<T>::cast (T* p, const std::type_info& tinfo)
222 typedef typename std::remove_const<T>::type T_nc;
223 return instance().cast (const_cast<T_nc*>(p), tinfo);
228 * @brief Cast to a derived pointer.
229 * @param p The pointer to cast.
230 * @param clid ID of the class @a B from which to cast.
231 * @return The pointer cast to a @a T*.
232 * @a B must be known to be a base
233 * of @a T; otherwise, 0 will be returned.
234 * 0 will also be returned if the @a dynamic_cast fails.
237T* BaseInfo<T>::castTo (void* p, CLID clid)
239 return reinterpret_cast<T*> (instance().castTo (p, clid));
244 * @brief Cast to a derived pointer.
245 * @param p The pointer to cast.
246 * @param clid @a type_info of the class @a B from which to cast.
247 * @return The pointer cast to a @a T*.
248 * @a B must be known to be a base
249 * of @a T; otherwise, 0 will be returned.
250 * 0 will also be returned if the @a dynamic_cast fails.
253T* BaseInfo<T>::castTo (void* p, const std::type_info& tinfo)
255 return reinterpret_cast<T*> (instance().castTo (p, tinfo));
259#if !defined(__REFLEX__) && !defined(__COVERITY__)
261 * @brief Return a function for casting to a base pointer.
262 * @param clid ID of the class to which to cast.
263 * @return A function to convert a pointer to a @c T to a pointer
264 * to the type identified by @a clid.
265 * @a clid must be known to be a base
266 * of @a T; otherwise, 0 will be returned.
269BaseInfoBase::castfn_t* BaseInfo<T>::castfn (CLID clid)
271 return instance().castfn (clid);
276 * @brief Return a function for casting to a base pointer.
277 * @param clid @a type_info of the class to which to cast.
278 * @return A function to convert a pointer to a @c T to a pointer
279 * to the type identified by @a tinfo.
280 * @a tinfo must be known to be a base
281 * of @a T; otherwise, 0 will be returned.
284BaseInfoBase::castfn_t*
285BaseInfo<T>::castfn (const std::type_info& tinfo)
287 return instance().castfn (tinfo);
292 * @brief Return a function for casting to a derived pointer.
293 * @param clid ID of the class @a B from which to cast.
294 * @return A function to convert a pointer to a @c T to a pointer
295 * to a @a T. @a clid must be known to be a base
296 * of @a T; otherwise, 0 will be returned.
297 * 0 will also be returned if the @a dynamic_cast fails.
300BaseInfoBase::castfn_t* BaseInfo<T>::castfnTo (CLID clid)
302 return instance().castfnTo (clid);
307 * @brief Return a function for casting to a derived pointer.
308 * @param clid @a type_info of the class @a B from which to cast.
309 * @return A function to convert a pointer to a @c B to a pointer
310 * to a @T. @a tinfo must be known to be a base
311 * of @a T; otherwise, 0 will be returned.
312 * 0 will also be returned if the @a dynamic_cast fails.
315BaseInfoBase::castfn_t*
316BaseInfo<T>::castfnTo (const std::type_info& tinfo)
318 return instance().castfnTo (tinfo);
324 * @brief Return the class IDs of all known bases of @a T (that
325 * have class IDs). The list will include @a T itself.
328const std::vector<CLID>& BaseInfo<T>::get_bases ()
330 return instance().get_bases();
335 * @brief Return the @c type_info's of all known bases of @a T.
336 * The list will include @a T itself.
339std::vector<const std::type_info*>
340BaseInfo<T>::get_ti_bases ()
342 return instance().get_ti_bases();
347 * @brief Return true if @a clid is the ID of a class that
348 * is known to be a base of @a T. @a T is considered
349 * to be its own base for this purpose.
350 * @param clid The ID of the class to test.
353bool BaseInfo<T>::is_base (CLID clid)
355 return instance().is_base (clid);
360 * @brief Return true if @a tinfo is the @a std::type_info of a class that
361 * is known to be a base of @a T. @a T is considered
362 * to be its own base for this purpose.
363 * @param tinfo The @a std::type_info of the class to test.
366bool BaseInfo<T>::is_base (const std::type_info& tinfo)
368 return instance().is_base (tinfo);
373 * @brief Return true if @a clid is the ID of a class that
374 * is known to be a virtual base of @a T. (This will always
375 * be false for @a T itself.)
376 * @param clid The ID of the class to test.
379bool BaseInfo<T>::is_virtual (CLID clid)
381 return instance().is_virtual (clid);
386 * @brief Delete an instance of the described type.
387 * @param p Pointer to the instance to delete.
390void BaseInfo<T>::destroy (T* p)
392 return instance().destroy (p);
397 * @brief Return true if @a tinfo is the @a std::type_info of a class that
398 * is known to be a virtual base of @a T. (This will always
399 * be false for @a T itself.)
400 * @param tinfo The @a std::type_info of the class to test.
403bool BaseInfo<T>::is_virtual (const std::type_info& tinfo)
405 return instance().is_virtual (tinfo);
410 * @brief Return the non-templated @c BaseInfoBase object for this type.
413const BaseInfoBase& BaseInfo<T>::baseinfo()
420void BaseInfo<T>::maybeInit()
427 * @brief Return a reference to the (singleton) implementation object
431BaseInfoImpl<T>& BaseInfo<T>::instance()
433 s_instance.maybeInit();
437//coverity[GLOBAL_INIT_ORDER]
439BaseInfoImpl<T> BaseInfo<T>::s_instance;
443 * @brief Helper to get @c BaseInfo initialized.
446struct RegisterBaseInit
450 // Force this function to appear as a symbol in the output file,
451 // even in an optimized build where it's always inlined.
452 // Otherwise, we get complaints from cling that it can't find the symbol
453 // (as of root 6.04).
454 __attribute__ ((used))
460#if !defined(__REFLEX__) && !defined(__COVERITY__)
462RegisterBaseInit<T>::RegisterBaseInit()
464 BaseInfoBase::addInit(&typeid(T),
465 [] (BaseInfoBase*) { BaseInfo<T>::baseinfo(); });
471 * @brief Helper to get @c BaseInfo initialized.
473template <class T> struct BaseInit {
474 static const RegisterBaseInit<T> s_regbase;
477template <class T> const RegisterBaseInit<T> BaseInit<T>::s_regbase;
481//**********************************************************
482// SG_ADD_BASE and SG_ADD_COPY_CONVERSION implementation.
486 * @brief Helper to get @c AddBaseInfo initialized.
488template <class D, class B>
489struct RegisterAddBaseInit
491 /// Add ourself to the init list.
492 RegisterAddBaseInit();
494 /// Init callback: add the new base to the BIB.
495 static void doinit (BaseInfoBase* bib);
499#if !defined(__REFLEX__) && !defined(__COVERITY__)
501 * @brief Init callback: add the new base to the BIB.
503template <class D, class B>
504void RegisterAddBaseInit<D, B>::doinit (BaseInfoBase* bib)
506 // B may either be the actual base class we want,
507 // or Virtual<BB>. Unwrap a surrounding Virtual<> if needed.
508 typedef typename BaseType<B>::type base_type;
509 bool is_virtual = BaseType<B>::is_virtual::value;
513 bib = &BaseInfo<D>::instance();
515 // Add the new base to it.
516 SG::BaseInfoImpl<D>& impl = *static_cast<SG::BaseInfoImpl<D>*> (bib);
517 impl.template add_base<base_type> (is_virtual);
523 * @brief Add ourself to the init list.
525template <class D, class B>
526RegisterAddBaseInit<D, B>::RegisterAddBaseInit()
528 BaseInfoBase::addInit(&typeid(D), doinit);
534 * @brief Helper to get @c AddBaseInfo initialized.
536template <class D, class B> struct AddBaseInit {
537 static const RegisterAddBaseInit<D, B> s_regbase;
540template <class D, class B>
541const RegisterAddBaseInit<D,B> AddBaseInit<D,B>::s_regbase;
547 * @brief Helper to get the copy conversion initialized.
549template <class D, class B>
550struct RegisterAddCopyConversionInit
552 /// Add ourself to the init list.
553 RegisterAddCopyConversionInit();
555 /// Init callback: xxx
556 static void doinit (BaseInfoBase* bib);
560#if !defined(__REFLEX__) && !defined(__COVERITY__)
562 * @brief Init callback: add the new conversion to the BIB.
564template <class T, class C>
565void RegisterAddCopyConversionInit<T, C>::doinit (BaseInfoBase* bib)
569 bib = &BaseInfo<T>::instance();
571 typedef typename C::target_type target_type;
572 bib->add_copy_conversion (typeid(target_type),
579 * @brief Add ourself to the init list.
581template <class T, class C>
582RegisterAddCopyConversionInit<T, C>::RegisterAddCopyConversionInit()
584 BaseInfoBase::addInit(&typeid(T), doinit);
590 * @brief Helper to get @c AddBaseInfo initialized.
592template <class T, class C> struct AddCopyConversionInit {
593 static const RegisterAddCopyConversionInit<T, C> s_regbase;
596template <class T, class C>
597const RegisterAddCopyConversionInit<T,C> AddCopyConversionInit<T,C>::s_regbase;