diff --git a/Control/AthenaKernel/AthenaKernel/AthenaKernelDict.h b/Control/AthenaKernel/AthenaKernel/AthenaKernelDict.h index 931abac33f3704245ef7a2eb766ee2d2914a5c61..9755339bde2fe20471c535d495694146edea25a8 100644 --- a/Control/AthenaKernel/AthenaKernel/AthenaKernelDict.h +++ b/Control/AthenaKernel/AthenaKernel/AthenaKernelDict.h @@ -18,6 +18,7 @@ #include "AthenaKernel/ILockable.h" #include "AthenaKernel/errorcheck.h" #include "AthenaKernel/ICutFlowSvc.h" +#include "AthenaKernel/BaseInfo.h" #include "AthenaKernel/DsoDb.h" #include "AthenaKernel/AthDsoUtils.h" diff --git a/Control/AthenaKernel/AthenaKernel/BaseInfo.h b/Control/AthenaKernel/AthenaKernel/BaseInfo.h new file mode 100755 index 0000000000000000000000000000000000000000..f7bfbb93be524d5fe3eef7e086db7f1d2ac7829a --- /dev/null +++ b/Control/AthenaKernel/AthenaKernel/BaseInfo.h @@ -0,0 +1,901 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: BaseInfo.h,v 1.11 2008-12-15 16:22:45 ssnyder Exp $ + +/** + * @file AthenaKernel/BaseInfo.h + * @author scott snyder + * @date Nov 2005 + * @brief Provide an interface for finding inheritance information + * at run time. + * + * The @a SG::BaseInfo<T> class provides an interface for finding + * inheritance information about class @a T. In the absence of compiler + * support for reflection, the inheritance information must be + * explicitly declared. This is done with the @a SG_BASE macro + * and friends. To declare that class @a D derives from class @a B, use + * + *@code + * struct B {}; + * struct D : public B {}; + * SG_BASE (D, B); + @endcode + * + * You can also use multiple inheritance with the @a SG_BASES2 + * and @a SG_BASES3 macros: + * + *@code + * struct B1 {}; + * struct B2 {}; + * struct B3 {}; + * struct D : public B1, public B2, public B3 {}; + * SG_BASES3 (D, B1, B2, B3); + @endcode + * + * Supporting more than three base classes requires (straightforward) + * changes to the code here. + * + * If any of the derivations are virtual, the corresponding + * base class should be within a @a SG_VIRTUAL macro: + * + *@code + * struct B1 {}; + * struct B2 {}; + * struct D : public B1, virtual public B2 {}; + * SG_BASES2 (D, B1, SG_VIRTUAL (B2)); + @endcode + * + * Note that these macros will only work with non-templated types, + * or with specific instantiations of templated types. If you want + * a templated @a SG_BASE, you'll need to declare the specialization + * yourself. You should specialize @a SG::Bases<T>, defining types + * @a Base1, @a Base2, and @a Base3 (which should be @a SG::NoBase + * if not used). Example: + * + *@code + * template <class T> struct B {}; + * template <class T> struct D : public B<T> {}; + * namespace SG { + * template <class T> + * struct Bases<D<T> > { + * typedef B<T> Base1; + * typedef NoBase Base2; + * typedef NoBase Base3; + * }; + * } + @endcode + * + * Once these declarations are in place, what can you do with it? + * The interface is provided by the @a SG::BaseInfo<T> class. + * (This is a wrapper around a singleton, so it's not expensive + * to create instances of this class.) You can specify the base + * classes either by the Gaudi class ID or by the C++ @c std::type_info. + * Of course, you'll only be able to get information by class ID + * if the classes actually have IDs defined. + * + * Here are the available methods of @a SG::BaseInfo<T>: + * + *@code + * static bool is_base (CLID clid) + * static bool is_base (const std::type_info& tinfo) + @endcode + * Test to see if the type given by @a clid or @a tinfo + * is a base of @a T. Note that @a T counts as its own base. + * + *@code + * static bool is_virtual (CLID clid) + * static bool is_virtual (const std::type_info& tinfo) + @endcode + * Test to see if the type given by @a clid or @a tinfo + * is a virtual base of @a T. This should always be @a false + * for @a T itself. + * + *@code + * static void* cast (T* p, CLID clid) + * static void* cast (T* p, const std::type_info& tinfo) + @endcode + * Cast a pointer from @a T* to a pointer to the type given + * by @a clid or @a tinfo, which must be a base if @a T + * known to @a BaseInfo. The result is returned as a @a void*. + * If the conversion cannot be done (because the target is not + * known to be a base of @a T), then 0 is returned. + * + *@code + * static T* castTo (void* p, CLID clid) + * static T* castTo (void* p, const std::type_info& tinfo) + @endcode + * Similar, except converts from a pointer to the type given by + * @a clid or @a tinfo (which must be a base of @a T) to @a T*. + * This involves a @a dynamic_cast. Returns 0 if the cast fails. + * + *@code + * static std::vector<CLID> get_bases () + @endcode + * Return all the known bases of @a T (that have class IDs). + * @a T itself will be included in this list. + * + *@code + * static std::vector<const std::type_info*> get_ti_bases () + @endcode + * Return all the known bases of @a T. + * @a T itself will be included in this list. + * + * It is also possible to get a non-templated version of @c SG::BaseInfo<T>. + * This is called @c SG::BaseInfoBase. These objects can be found using + * @c SG::BaseInfoBase::find, by either class ID or @c std::type_info + * (in order for this to work, the corresponding @c SG::BaseInfo<T> class + * must have been used somewhere in the program). The interface + * of @c SG::BaseInfoBase is the same as @c SG::BaseInfo<T>, except + * that @c void* replaces @c T* in the @c cast methods. + * + * Initialization issues: We don't want to build the @c SG::BaseInfo<T> + * objects at static initialization time. But we do need to remember + * which ones are available. Thus, @c BaseInfoBase maintains a list + * of CLIDs and @c std::type_info's for which we may not have done + * initialization, along with a function to call to do the initialization. + * The initialization list is filled during static initialization. + * When we look for an instance, if we don't find one, we look in the + * initialization list; if there's a match there, we run the initialization + * and remove it from the list. + * + * Copy conversions: The conversion machinery above provides access to the + * standard C++ base<>derived conversions. However, sometimes you'd like + * to allow additional conversions as well, for example between a + * vector<ElementLink<T> > and DataVector<T>. For those cases, + * you can register a conversion function with the _source_ type + * that can initialize an instance of the _destination_ type + * from the _source_ type. Then, when you try to retrieve the object + * from StoreGate with the _destination_ type, your conversion function + * will be called. + * + * Your conversion function should be the method @a convert of + * a class deriving from the @a SG::CopyConversion template; + * for example, + * + *@code + * class MyCopyConversion + * : public SG::CopyConversion<std::vector<ElementLink<MyType> >, + * DataVector<MyType> > + * { + * public: + * virtual void convert (const std::vector<ElementLink<MyType> >& src, + * DataVector<MyType>& dst) const + * { + * size_t sz = src.size(); + * if (dst.size() != sz) { + * dst.clear (SG::VIEW_ELEMENTS); + * dst.reserve (sz); + * for (size_t i = 0; i < sz; i++) { + * const MyType* p = *(src[i]).cptr(); + * dst.push_back (const_cast<MyType*> (p)); + * } + * } + * } + * }; + @endcode + * + * You then declare this using the macro + * + @code + * SG_ADD_COPY_CONVERSION (std::vector<ElementLink<MyType> >, + * MyCopyConversion); + @endcode + * + * Copy conversions are enabled only for objects that have been marked as const. + */ + +#ifndef ATHENAKERNEL_BASEINFO_H +#define ATHENAKERNEL_BASEINFO_H + +#include "GaudiKernel/ClassID.h" +#include <vector> +#include <typeinfo> + + +//=========================================================================== +// Macros used to declare base class information. +// + +/** + * @brief Used to mark virtual derivation. + * When using the @a SG_BASE macros below, use this in the case + * of virtual derivation. Example: + * + *@code + * struct B1 {}; + * struct B2 {}; + * struct D : public B1, virtual public B2 {}; + * SG_BASES2 (D, B1, SG_VIRTUAL (B2)); + @endcode + */ +#define SG_VIRTUAL(T) Virtual<T> + + +/** + * @brief Declare that class @a D derives from class @a B. Example: + * + *@code + * struct B {}; + * struct D : public B {}; + * SG_BASE (D, B); + @endcode + */ +#define SG_BASE(D, B) SG_BASES1(D, B) + + +/** + * @brief Declare that class @a D derives from class @a B. + * This is the same as @a SG_BASE. Example: + * + *@code + * struct B {}; + * struct D : public B {}; + * SG_BASES1 (D, B); + @endcode + */ +#define SG_BASES1(D, B) \ + namespace SG { \ + template<> struct Bases<D >{ \ + typedef B Base1; \ + typedef NoBase Base2; \ + typedef NoBase Base3; \ + }; \ + template struct RegisterBaseInit<D >; \ + template struct BaseInit<D >; \ +} struct sg_dummy // to swallow semicolon + + +/** + * @brief Declare that class @a D derives from classes @a B1 and @a B2. + * Example: + * + *@code + * struct B1 {}; + * struct B2 {}; + * struct D : public B1, public B2 {}; + * SG_BASES2 (D, B1, B2); + @endcode + */ +#define SG_BASES2(D, B1, B2) \ + namespace SG { \ + template<> struct Bases<D >{ \ + typedef B1 Base1; \ + typedef B2 Base2; \ + typedef NoBase Base3; \ + }; \ + template struct RegisterBaseInit<D >; \ + template struct BaseInit<D >; \ +} struct sg_dummy // to swallow semicolon + + +/** + * @brief Declare that class @a D derives from classes @a B1, @a B2, and @a B3. + * Example: + * + *@code + * struct B1 {}; + * struct B2 {}; + * struct B3 {}; + * struct D : public B1, public B2, public B3 {}; + * SG_BASES3 (D, B1, B2, B3); + @endcode + */ +#define SG_BASES3(D, B1, B2, B3) \ + namespace SG { \ + template<> struct Bases<D >{ \ + typedef B1 Base1; \ + typedef B2 Base2; \ + typedef B3 Base3; \ + }; \ + template struct RegisterBaseInit<D >; \ + template struct BaseInit<D >; \ +} struct sg_dummy // to swallow semicolon + + + +/** + * @brief Add a new base class @c B to class @c D. + * + * Sometimes, the SG_BASE macro for a class isn't present in its header. + * + * One can try to put the appropriate SG_BASE macro somewhere else, + * but this doesn't always work: if the @c BaseInfoBase for @c D has + * already been created by the time the @c SG_BASE initialization + * runs, then that @c SG_BASE macro won't do anything. + * + * @c SG_ADD_BASE, however, will add a new base to an existing @c BaseInfoBase. + * + *@code + * struct B {}; + * struct D : public B {}; + * SG_ADD_BASES (D, B); + @endcode + */ +#define SG_ADD_BASE(D, B) \ + namespace SG { \ + template struct AddBaseInit<D, B >; \ +} struct sg_dummy // to swallow semicolon + + +/** + * @brief Declare a copy conversion from class @c T using converter @c C. + * + * See the comments in the header for a detailed description. + */ +#define SG_ADD_COPY_CONVERSION(D, C) \ + namespace SG { \ + template struct AddCopyConversionInit<D, C >; \ +} struct sg_dummy // to swallow semicolon + + + +namespace SG { + + +/** + * @brief Helper metafunction to get base class types. + * + * For a class @c T, + *@code + * SG::BaseType<SG::Bases<T>::Base1>::type + @endcode + * gives the type of @c T's first base. Also, + *@code + * SG::BaseType<SG::Bases<T>::Base1>::is_virtual + @endcode + * tells whether the derivation is virtual + * (either @c true_type or @c false_type). + * + * Note that @c SG::Bases\<T>::Base1 is not the actual type + * of @c T's first base if virtual derivation was used. + */ +template <class T> +struct BaseType; + + +// Forward declaration. +template <class T> +class BaseInfoImpl; + + +struct BaseInfoBaseImpl; + + +//=========================================================================== +// Copy conversion declarations. +// + + +/** + * @brief Base class for copy conversions. + */ +class CopyConversionBase +{ +public: + /// Destructor. + virtual ~CopyConversionBase() {} + + /// Create an instance of the destination class. + virtual void* create() const = 0; + + /// Destroy an instance of the destination class. + virtual void destroy (void* p) const = 0; + + /// Convert the contents of an instance of the source class SRC + /// to an instance of the destination class DST. + virtual void convertUntyped (const void* src, void* dst) const = 0; +}; + + +/** + * @brief Base class for copy conversions, templated on source + * and destination classes. + */ +template <class SRC, class DST> +class CopyConversion + : public CopyConversionBase +{ +public: + /// The destination class. + typedef DST target_type; + + /// Create an instance of the destination class. + virtual void* create() const { return new DST; } + + /// Destroy an instance of the destination class. + virtual void destroy (void* p) const { delete reinterpret_cast<DST*>(p); } + + /// Convert the contents of an instance of the source class SRC + /// to an instance of the destination class DST. + virtual void convertUntyped (const void* src, void* dst) const + { + convert (*reinterpret_cast<const SRC*>(src), + *reinterpret_cast<DST*>(dst)); + } + + /// Convert the contents of an instance of the source class SRC + /// to an instance of the destination class DST. + /// (Type-safe version.) + virtual void convert (const SRC& src, DST& dst) const = 0; +}; + + +//=========================================================================== +// Base class declaration. +// This factors out the part of the implementation that doesn't +// depend on the template parameter @a T. +// + + +/** + * @brief The non-template portion of the @a BaseInfo implementation. + */ +class BaseInfoBase +{ +public: + /** + * @brief Return the CLID for this class. + */ + CLID clid() const; + + + /** + * @brief Return the @c std::type_info for this class. + */ + const std::type_info& typeinfo() const; + + + /** + * @brief Cast to a base pointer. + * @param p The pointer to cast (a @a T* cast to a @a void*). + * @param clid ID of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + void* cast (void* p, CLID clid) const; + + /** + * @brief Cast to a base pointer. + * @param p The pointer to cast (a @a T* cast to a @a void*). + * @param clid @a type_info of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + void* cast (void* p, const std::type_info& tinfo) const; + + + /** + * @brief Cast to a derived pointer. + * @param p The pointer to cast (a @a B* cast to a @a void*). + * @param clid ID of the class @a B from which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + void* castTo (void* p, CLID clid) const; + + /** + * @brief Cast to a derived pointer. + * @param p The pointer to cast (a @a B* cast to a @a void*). + * @param clid @a type_info of the class @a B from which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + void* castTo (void* p, const std::type_info& tinfo) const; + + + /// Type of a pointer conversion function. + typedef void* castfn_t (void* p); + + + // gcc 4.3 complains about the code genreflex generates for these. + // They're not useful from python anyway, so just suppress them. +#ifndef __REFLEX__ + /** + * @brief Return a function for casting to a base pointer. + * @param clid ID of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a clid. + * @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + castfn_t* castfn (CLID clid) const; + + + /** + * @brief Return a function for casting to a base pointer. + * @param clid @a type_info of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a tinfo. + * @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + castfn_t* castfn (const std::type_info& tinfo) const; + + /** + * @brief Return a function for casting to a derived pointer. + * @param clid ID of the class @a B from which to cast. + * @return A function to convert a pointer to a @a B to a pointer + * to a @a T. @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + castfn_t* castfnTo (CLID clid) const; + + + /** + * @brief Return a function for casting to a derived pointer. + * @param clid @a type_info of the class @a B from which to cast. + * @return A function to convert a pointer to a @a B to a pointer + * to a @a T. @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + castfn_t* castfnTo (const std::type_info& tinfo) const; +#endif + + + /** + * @brief Return the class IDs of all known bases of @a T (that + * have class IDs). The list will include @a T itself. + */ + std::vector<CLID> get_bases () const; + + /** + * @brief Return the @c type_info's of all known bases of @a T. + * The list will include @a T itself. + */ + std::vector<const std::type_info*> get_ti_bases () const; + + /** + * @brief Return true if @a clid is the ID of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param clid The ID of the class to test. + */ + bool is_base (CLID clid) const; + + /** + * @brief Return true if @a tinfo is the @a type_info of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param clid The ID of the class to test. + */ + bool is_base (const std::type_info& tinfo) const; + + + /** + * @brief Return true if @a clid is the ID of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param clid The ID of the class to test. + */ + bool is_virtual (CLID clid) const; + + /** + * @brief Return true if @a tinfo is the @a std::type_info of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param tinfo The @a std::type_info of the class to test. + */ + bool is_virtual (const std::type_info& tinfo) const; + + + /** + * @brief Search for a copy conversion to @c tinfo. + * @param tinfo The class to which we want to convert. + * + * Returns the conversion instance or 0. + */ + const CopyConversionBase* copy_conversion (const std::type_info& tinfo) const; + + + /** + * @brief Search for a copy conversion to @c clid. + * @param clid The class to which we want to convert. + * + * Returns the conversion instance or 0. + */ + const CopyConversionBase* copy_conversion (CLID clid) const; + + + /** + * @brief Add a new copy conversion. + * @param tinfo The @c std::type_info of the target class. + * @param cnv A @c CopyConversionBase instance describing the conversion. + * + * The @c BaseInfoBase takes ownership of the @c cnv object. + */ + void add_copy_conversion (const std::type_info& tinfo, + const CopyConversionBase* cnv); + + + /** + * @brief Return known copy conversions. + * + * Returns the CLIDs of all target classes that have been registered + * with this one for copy conversion. + */ + std::vector<CLID> get_copy_conversions() const; + + +#ifndef __REFLEX__ + /** + * @brief Add information about one base class. + * @param tinfo The @a std::type_info of the base. + * @param converter Converter function. This should be able to + * convert a @a T* to a pointer to this base. + * @param converterTo Converter function. This should be able to + * convert a pointer to this base to a @a T*. + * @param is_virtual True if the derivation from this base to @a T + * is via virtual derivation. + */ + void add_info (const std::type_info& tinfo, + castfn_t* converter, + castfn_t* converterTo, + bool is_virtual); +#endif + + + /** + * @brief Find the @c BaseInfoBase instance for @c clid. + * @param clid The class ID of the class for which we want information. + * + * Returns 0 if no @c BaseInfoBase instance is available. + */ + static const BaseInfoBase* find (CLID clid); + + + /** + * @brief Find the @c BaseInfoBase instance for @c tinfo. + * @param tinfo The @c std::type_info of the class + * for which we want information. + * + * Returns 0 if no @c BaseInfoBase instance is available. + */ + static const BaseInfoBase* find (const std::type_info& tinfo); + + + /// Type for an initialization function. + typedef const BaseInfoBase& init_func_t(); + + +#ifndef __REFLEX__ + /** + * @brief Register an initialization function. + * @param tinfo The @c std::type_info for the class being registered. + * @param init_func Function to initialize @c BaseInfo for the class. + */ + static void addInit (const std::type_info* tinfo, + init_func_t* init_func); +#endif + + + /** + * @brief Run initializations for this class, if needed. + */ + void maybeInit(); + + +protected: + /** + * @brief Constructor. + * @param tinfo The @c std::type_info for this class. + */ + BaseInfoBase (const std::type_info& tinfo); + + + /** + * @brief Destructor. + */ + ~BaseInfoBase(); + + +private: + /** + * @brief Helper for @c find. + * @param tinfo The @c std::type_info of the class + * for which we want information. + * + * Returns 0 if no @c BaseInfoBase instance is available. + */ + static const BaseInfoBase* find1 (const std::type_info& tinfo); + + + /// Pointer to internal state. + BaseInfoBaseImpl* m_impl; + + BaseInfoBase (const BaseInfoBase&); + BaseInfoBase& operator= (const BaseInfoBase&); +}; + + +//=========================================================================== +// The templated @c BaseInfo class. +// + +/** + * @brief Provide an interface for finding inheritance information + * at run time. See the file comments for full details. + */ +template <class T> +class BaseInfo +{ +public: + /** + * @brief Cast to a base pointer. + * @param p The pointer to cast. + * @param clid ID of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + static void* cast (T* p, CLID clid); + + /** + * @brief Cast to a base pointer. + * @param p The pointer to cast. + * @param clid @a type_info of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + static void* cast (T* p, const std::type_info& tinfo); + + + /** + * @brief Cast to a derived pointer. + * @param p The pointer to cast. + * @param clid ID of the class @a B from which to cast. + * @return The pointer cast to a @a T*. + * @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + static T* castTo (void* p, CLID clid); + + /** + * @brief Cast to a derived pointer. + * @param p The pointer to cast. + * @param clid @a type_info of the class @a B from which to cast. + * @return The pointer cast to a @a T*. + * @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + static T* castTo (void* p, const std::type_info& tinfo); + + + /** + * @brief Return a function for casting to a base pointer. + * @param clid ID of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a clid. + * @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + static BaseInfoBase::castfn_t* castfn (CLID clid); + + + /** + * @brief Return a function for casting to a base pointer. + * @param clid @a type_info of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a tinfo. + * @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ + static BaseInfoBase::castfn_t* castfn (const std::type_info& tinfo); + + + /** + * @brief Return a function for casting to a derived pointer. + * @param clid ID of the class @a B from which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to a @a T. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + static BaseInfoBase::castfn_t* castfnTo (CLID clid); + + + /** + * @brief Return a function for casting to a derived pointer. + * @param clid @a type_info of the class @a B from which to cast. + * @return A function to convert a pointer to a @c B to a pointer + * to a @a T. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ + static BaseInfoBase::castfn_t* castfnTo (const std::type_info& tinfo); + + + /** + * @brief Return the class IDs of all known bases of @a T (that + * have class IDs). The list will include @a T itself. + */ + static std::vector<CLID> get_bases (); + + + /** + * @brief Return the @c type_info's of all known bases of @a T. + * The list will include @a T itself. + */ + static std::vector<const std::type_info*> get_ti_bases (); + + + /** + * @brief Return true if @a clid is the ID of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param clid The ID of the class to test. + */ + static bool is_base (CLID clid); + + /** + * @brief Return true if @a tinfo is the @a std::type_info of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param tinfo The @a std::type_info of the class to test. + */ + static bool is_base (const std::type_info& tinfo); + + + /** + * @brief Return true if @a clid is the ID of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param clid The ID of the class to test. + */ + static bool is_virtual (CLID clid); + + /** + * @brief Return true if @a tinfo is the @a std::type_info of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param tinfo The @a std::type_info of the class to test. + */ + static bool is_virtual (const std::type_info& tinfo); + + + /** + * @brief Return the non-templated @c BaseInfoBase object for this type. + */ + static const BaseInfoBase& baseinfo (); + + + static void maybeInit (); + + +private: + /// Return a reference to the (singleton) implementation object + /// for this class. + static const BaseInfoImpl<T>& instance(); + + /// This holds the singleton implementation object instance. + struct instance_holder + { + instance_holder(); + BaseInfoImpl<T>* instance; + }; + static instance_holder s_instance; +}; + + +} // namespace SG + + +#include "AthenaKernel/BaseInfo.icc" + + +#endif // not ATHENAKERNEL_BASEINFO_H + diff --git a/Control/AthenaKernel/AthenaKernel/BaseInfo.icc b/Control/AthenaKernel/AthenaKernel/BaseInfo.icc new file mode 100755 index 0000000000000000000000000000000000000000..22f466458f10b7bfe8298eb8bd61c66142e80abd --- /dev/null +++ b/Control/AthenaKernel/AthenaKernel/BaseInfo.icc @@ -0,0 +1,675 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: BaseInfo.icc,v 1.9 2008-12-15 15:12:39 ssnyder Exp $ +/** + * @file AthenaKernel/BaseInfo.icc + * @author scott snyder + * @date Nov 2005 + * @brief Provide an interface for finding inheritance information + * at run time. + * Implementation file. + */ + + +#include <type_traits> + + +namespace SG { + + +//=========================================================================== +// Inheritance data representation classes. +// + + +/** + * @brief Marker to indicate a nonexistent base class. + */ +struct NoBase {}; + + +/** + * @brief Wrapper to indicate virtual derivation. + * @a Virtual<T> will mean that derivation from @a T is virtual. + */ +template <class T> struct Virtual {}; + + +/** + * @brief Traits class to hold derivation information for up to three + * base classes. + * + * @a Base1, etc., get typedef'd to the appropriate + * base classes. Use @a NoBase if there is no base class; use + * @a Virtual<T> to indicate virtual derivation. This class should + * be specialized for every class @a T for which we want to know + * inheritance information. + */ +template <class T> +struct Bases +{ + typedef NoBase Base1; + typedef NoBase Base2; + typedef NoBase Base3; +}; + + +// Helper metafunction to get base class types. +// Generic case. +template <class T> +struct BaseType +{ + typedef T type; + typedef std::false_type is_virtual; +}; + + +// Helper metafunction to get base class types. +// Virtual derivation case. +template <class T> +struct BaseType<Virtual<T> > +{ + typedef T type; + typedef std::true_type is_virtual; +}; + + +//=========================================================================== +// Internal implementation class for @a BaseInfo. +// This is used as a singleton, and should be accessed using the @a BaseInfo +// wrapper class. +// + +/** + * @brief Internal implementation class for @a BaseInfo. + */ +template <class T> +class BaseInfoImpl + : public BaseInfoBase +{ +public: + /** + * @brief Constructor. + */ + BaseInfoImpl(); + + + /** + * @brief Add information about base class @a B (for @a T). + * @param is_virtual True if the derivation from @a B to @a T + * is via virtual derivation. + */ +#if defined(__REFLEX__) || defined(__COVERITY__) + template <class B> + void add_base (bool is_virtual); +#else + template <class B> + void add_base (bool is_virtual) + { + // Make sure the bib for the base class exists. + BaseInfo<B>::maybeInit(); + + // Add the information for this base. + this->add_info (typeid(B), + converter<B>, converterTo<B>, is_virtual); + } +#endif + +private: + /** + * @brief Converter function. + * @param p Pointer to convert. A @a T* converted to a @a void*. + * + * Converts a @a T* to a @a B* (where @a T derives from @a B). + * The pointers are given and returned as @a void*. + */ + template <class B> + static void* converter (void* p) + { + typedef typename std::remove_const<B>::type B_nc; + typedef typename std::remove_const<T>::type T_nc; + B_nc* b = reinterpret_cast<T_nc*> (p); + return b; + } + + + /** + * @brief Converter function. + * @param p Pointer to convert. A @a B* converted to a @a void*. + * + * Converts a @a B* to a @a T* (where @a T derives from @a B). + * The pointers are given and returned as @a void*. + * Returns 0 if the conversion fails. + * + * Implementation note: to @c dynamic_cast @a B to @a T, @a B needs to have + * a vtable. If B doesn't have a vtable, then we don't attempt the + * conversion. (In principle, we could use is_virtual_base_of, and fall + * back to a static_cast if it's false. However, using is_virtual_base_of + * generates some nasty compilation warnings, so i'll avoid it for now.) + */ + template <class B> + static void* converterTo (void* p) + { + return converterToHelper<B> (p, std::is_polymorphic<B>()); + } + + + // B has a vtable. Use dynamic_cast. + template <class B> + static void* converterToHelper (void* p, std::true_type) + { + typedef typename std::remove_const<B>::type B_nc; + typedef typename std::remove_const<T>::type T_nc; + T_nc* b = dynamic_cast<T_nc*> (reinterpret_cast<B_nc*> (p)); + return b; + } + + + // B doesn't have a vtable. Don't try to convert. + template <class B> + static void* converterToHelper (void* /*p*/, std::false_type) + { + return 0; + } +}; + + +//=========================================================================== +// Initialization. +// Here we walk the class hierarchy, calling @a add_base for each base. + + +/** + * @brief Generic initializer for base @a B. + */ +template <class B> +struct BaseInfo_init +{ + template <class T> + static void init (BaseInfoImpl<T>& c, bool is_virtual) + { + // Here, we initialize the @a BaseInfo for @a T for base class @a B. + // First, we add the information for this base to the instance. + c.template add_base<B>(is_virtual); + + // Then we recurse on each possible base. + BaseInfo_init<typename Bases<B>::Base1>::init (c, is_virtual); + BaseInfo_init<typename Bases<B>::Base2>::init (c, is_virtual); + BaseInfo_init<typename Bases<B>::Base3>::init (c, is_virtual); + } +}; + + +/** + * @brief Dummy initializer. + */ +template <> +struct BaseInfo_init<NoBase> +{ + template <class T> + static void init (BaseInfoImpl<T>& /*c*/, bool /*is_virtual*/) + { + // This gets called when there is no base in a slot + // (signaled by the use of @a NoBase). + // This ends the recursion. + } +}; + + +/** + * @brief Initializer for virtual base @a B. + */ +template <class B> +struct BaseInfo_init<Virtual<B> > +{ + template <class T> + static void init (BaseInfoImpl<T>& c, bool /*is_virtual*/) + { + // Here, we initialize the @a BaseInfo for @a T for a virtual + // base class @a B. We recurse to the generic initializer + // for this base, with the @a is_virtual flag forced on. + BaseInfo_init<B>::init (c, true); + } +}; + + +/** + * @brief Constructor. + */ +template <class T> +BaseInfoImpl<T>::BaseInfoImpl () + : BaseInfoBase (typeid(T)) +{ + // This starts the walk over the bases. + // We start with @a T itself. + // The virtual flag is initially false. + BaseInfo_init<T>::init (*this, false); +} + + +//=========================================================================== +// The @a BaseInfo wrapper class. +// This will statically hold a singleton instance of @a BaseInfoImpl +// (in the instance function). + + +/** + * @brief Cast to a base pointer. + * @param p The pointer to cast. + * @param clid ID of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +template <class T> +void* BaseInfo<T>::cast (T* p, CLID clid) +{ + typedef typename std::remove_const<T>::type T_nc; + return instance().cast (const_cast<T_nc*>(p), clid); +} + + +/** + * @brief Cast to a base pointer. + * @param p The pointer to cast. + * @param clid @a type_info of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +template <class T> +void* BaseInfo<T>::cast (T* p, const std::type_info& tinfo) +{ + typedef typename std::remove_const<T>::type T_nc; + return instance().cast (const_cast<T_nc*>(p), tinfo); +} + + +/** + * @brief Cast to a derived pointer. + * @param p The pointer to cast. + * @param clid ID of the class @a B from which to cast. + * @return The pointer cast to a @a T*. + * @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +template <class T> +T* BaseInfo<T>::castTo (void* p, CLID clid) +{ + return reinterpret_cast<T*> (instance().castTo (p, clid)); +} + + +/** + * @brief Cast to a derived pointer. + * @param p The pointer to cast. + * @param clid @a type_info of the class @a B from which to cast. + * @return The pointer cast to a @a T*. + * @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +template <class T> +T* BaseInfo<T>::castTo (void* p, const std::type_info& tinfo) +{ + return reinterpret_cast<T*> (instance().castTo (p, tinfo)); +} + + +#if !defined(__REFLEX__) && !defined(__COVERITY__) +/** + * @brief Return a function for casting to a base pointer. + * @param clid ID of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a clid. + * @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +template <class T> +BaseInfoBase::castfn_t* BaseInfo<T>::castfn (CLID clid) +{ + return instance().castfn (clid); +} + + +/** + * @brief Return a function for casting to a base pointer. + * @param clid @a type_info of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a tinfo. + * @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +template <class T> +BaseInfoBase::castfn_t* +BaseInfo<T>::castfn (const std::type_info& tinfo) +{ + return instance().castfn (tinfo); +} + + +/** + * @brief Return a function for casting to a derived pointer. + * @param clid ID of the class @a B from which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to a @a T. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +template <class T> +BaseInfoBase::castfn_t* BaseInfo<T>::castfnTo (CLID clid) +{ + return instance().castfnTo (clid); +} + + +/** + * @brief Return a function for casting to a derived pointer. + * @param clid @a type_info of the class @a B from which to cast. + * @return A function to convert a pointer to a @c B to a pointer + * to a @T. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +template <class T> +BaseInfoBase::castfn_t* +BaseInfo<T>::castfnTo (const std::type_info& tinfo) +{ + return instance().castfnTo (tinfo); +} +#endif + + +/** + * @brief Return the class IDs of all known bases of @a T (that + * have class IDs). The list will include @a T itself. + */ +template <class T> +std::vector<CLID> BaseInfo<T>::get_bases () +{ + return instance().get_bases(); +} + + +/** + * @brief Return the @c type_info's of all known bases of @a T. + * The list will include @a T itself. + */ +template <class T> +std::vector<const std::type_info*> +BaseInfo<T>::get_ti_bases () +{ + return instance().get_ti_bases(); +} + + +/** + * @brief Return true if @a clid is the ID of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param clid The ID of the class to test. + */ +template <class T> +bool BaseInfo<T>::is_base (CLID clid) +{ + return instance().is_base (clid); +} + + +/** + * @brief Return true if @a tinfo is the @a std::type_info of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param tinfo The @a std::type_info of the class to test. + */ +template <class T> +bool BaseInfo<T>::is_base (const std::type_info& tinfo) +{ + return instance().is_base (tinfo); +} + + +/** + * @brief Return true if @a clid is the ID of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param clid The ID of the class to test. + */ +template <class T> +bool BaseInfo<T>::is_virtual (CLID clid) +{ + return instance().is_virtual (clid); +} + + +/** + * @brief Return true if @a tinfo is the @a std::type_info of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param tinfo The @a std::type_info of the class to test. + */ +template <class T> +bool BaseInfo<T>::is_virtual (const std::type_info& tinfo) +{ + return instance().is_virtual (tinfo); +} + + +/** + * @brief Return the non-templated @c BaseInfoBase object for this type. + */ +template <class T> +const BaseInfoBase& BaseInfo<T>::baseinfo() +{ + return instance(); +} + + +template <class T> +void BaseInfo<T>::maybeInit() +{ + BaseInfoImpl<T>* inst = s_instance.instance; + if (inst) + inst->maybeInit(); +} + + +/** + * @brief Return a reference to the (singleton) implementation object + * for this class. + */ +template <class T> +const BaseInfoImpl<T>& BaseInfo<T>::instance() +{ + BaseInfoImpl<T>* inst = s_instance.instance; + if (inst) + inst->maybeInit(); + return *inst; +} + + +/** + * @brief Constructor to get the singleton instance set up. + */ +template <class T> +BaseInfo<T>::instance_holder::instance_holder() +{ + static BaseInfoImpl<T> inst; + instance = &inst; +} + + +/// Declare the static member of @c BaseInfo. +template <class T> +typename BaseInfo<T>::instance_holder BaseInfo<T>::s_instance; + + +/** + * @brief Helper to get @c BaseInfo initialized. + */ +template <class T> +struct RegisterBaseInit +{ + RegisterBaseInit() +#ifdef __GNUC__ + // Force this function to appear as a symbol in the output file, + // even in an optimized build where it's always inlined. + // Otherwise, we get complaints from cling that it can't find the symbol + // (as of root 6.04). + __attribute__ ((used)) +#endif + ; +}; + + +#if !defined(__REFLEX__) && !defined(__COVERITY__) +template <class T> +RegisterBaseInit<T>::RegisterBaseInit() +{ + BaseInfoBase::addInit(&typeid(T), BaseInfo<T>::baseinfo); +} +#endif + + +/** + * @brief Helper to get @c BaseInfo initialized. + */ +template <class T> struct BaseInit { + static RegisterBaseInit<T> s_regbase; +}; +#ifndef __APPLE__ +template <class T> RegisterBaseInit<T> BaseInit<T>::s_regbase; +#endif + + +//********************************************************** +// SG_ADD_BASE and SG_ADD_COPY_CONVERSION implementation. + + +/** + * @brief Helper to get @c AddBaseInfo initialized. + */ +template <class D, class B> +struct RegisterAddBaseInit +{ + /// Add ourself to the init list. + RegisterAddBaseInit(); + + /// Init callback: add the new base to the BIB. + static const BaseInfoBase& doinit(); +}; + + +#if !defined(__REFLEX__) && !defined(__COVERITY__) +/** + * @brief Init callback: add the new base to the BIB. + */ +template <class D, class B> +const BaseInfoBase& RegisterAddBaseInit<D, B>::doinit() +{ + // B may either be the actual base class we want, + // or Virtual<BB>. Unwrap a surrounding Virtual<> if needed. + typedef typename BaseType<B>::type base_type; + bool is_virtual = BaseType<B>::is_virtual::value; + + // Look up the BIB. + SG::BaseInfoBase* bib = + const_cast<SG::BaseInfoBase*> (SG::BaseInfoBase::find (typeid(D))); + if (!bib) + bib = const_cast<SG::BaseInfoBase*> (&BaseInfo<D>::baseinfo()); + if (bib) { + // Add the new base to it. + SG::BaseInfoImpl<D>& impl = *static_cast<SG::BaseInfoImpl<D>*> (bib); + impl.template add_base<base_type> (is_virtual); + } + return *bib; +} + + +/** + * @brief Add ourself to the init list. + */ +template <class D, class B> +RegisterAddBaseInit<D, B>::RegisterAddBaseInit() +{ + BaseInfoBase::addInit(&typeid(D), doinit); +} +#endif + + +/** + * @brief Helper to get @c AddBaseInfo initialized. + */ +template <class D, class B> struct AddBaseInit { + static RegisterAddBaseInit<D, B> s_regbase; +}; +#ifndef __APPLE__ +template <class D, class B> +RegisterAddBaseInit<D,B> AddBaseInit<D,B>::s_regbase; +#endif + + + +/** + * @brief Helper to get the copy conversion initialized. + */ +template <class D, class B> +struct RegisterAddCopyConversionInit +{ + /// Add ourself to the init list. + RegisterAddCopyConversionInit(); + + /// Init callback: xxx + static const BaseInfoBase& doinit(); +}; + + +#if !defined(__REFLEX__) && !defined(__COVERITY__) +/** + * @brief Init callback: add the new conversion to the BIB. + */ +template <class T, class C> +const BaseInfoBase& RegisterAddCopyConversionInit<T, C>::doinit() +{ + // Look up the BIB. + SG::BaseInfoBase* bib = + const_cast<SG::BaseInfoBase*> (SG::BaseInfoBase::find (typeid(T))); + if (!bib) + bib = const_cast<SG::BaseInfoBase*> (&BaseInfo<T>::baseinfo()); + if (bib) { + typedef typename C::target_type target_type; + bib->add_copy_conversion (typeid(target_type), + new C); + } + return *bib; +} + + +/** + * @brief Add ourself to the init list. + */ +template <class T, class C> +RegisterAddCopyConversionInit<T, C>::RegisterAddCopyConversionInit() +{ + BaseInfoBase::addInit(&typeid(T), doinit); +} +#endif + + +/** + * @brief Helper to get @c AddBaseInfo initialized. + */ +template <class T, class C> struct AddCopyConversionInit { + static RegisterAddCopyConversionInit<T, C> s_regbase; +}; +#ifndef __APPLE__ +template <class T, class C> +RegisterAddCopyConversionInit<T,C> AddCopyConversionInit<T,C>::s_regbase; +#endif + + +} // namespace SG + diff --git a/Control/AthenaKernel/AthenaKernel/selection.xml b/Control/AthenaKernel/AthenaKernel/selection.xml index ba01f91974cf209144cdfd1246187130a03d1ecb..e42dbc4df73e664c38b965ecddcec9b3bd7671fd 100644 --- a/Control/AthenaKernel/AthenaKernel/selection.xml +++ b/Control/AthenaKernel/AthenaKernel/selection.xml @@ -20,4 +20,6 @@ <function name="Athena::DsoUtils::inDso" /> <function name="Athena::PackageInfo" /> + <class name="SG::BaseInfoBase" /> + </lcgdict> diff --git a/Control/AthenaKernel/CMakeLists.txt b/Control/AthenaKernel/CMakeLists.txt index 20032938bf0d1928781de80065c9683a7c093368..b0e71e6787871cfa13e0398e12c0ef72633a2a70 100644 --- a/Control/AthenaKernel/CMakeLists.txt +++ b/Control/AthenaKernel/CMakeLists.txt @@ -98,3 +98,7 @@ atlas_add_test( CLIDRegistry_test atlas_add_test( ClassName_test SOURCES test/ClassName_test.cxx LINK_LIBRARIES AthenaKernel ) + +atlas_add_test( BaseInfo_test + SOURCES test/BaseInfo_test.cxx + LINK_LIBRARIES AthenaKernel ) diff --git a/Control/AthenaKernel/share/BaseInfo_test.ref b/Control/AthenaKernel/share/BaseInfo_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..bae42c55f9e0a4e297a4d197d8aadfe147ef269b --- /dev/null +++ b/Control/AthenaKernel/share/BaseInfo_test.ref @@ -0,0 +1,2 @@ +test1 +test2 diff --git a/Control/AthenaKernel/src/BaseInfo.cxx b/Control/AthenaKernel/src/BaseInfo.cxx new file mode 100755 index 0000000000000000000000000000000000000000..8f6f28735e0b3b0def4ff2f6ace22933a968c1f3 --- /dev/null +++ b/Control/AthenaKernel/src/BaseInfo.cxx @@ -0,0 +1,704 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: BaseInfo.cxx,v 1.9 2008-11-25 21:45:04 ssnyder Exp $ +/** + * @file AthenaKernel/src/BaseInfo.cxx + * @author scott snyder + * @date Nov 2005 + * @brief Provide an interface for finding inheritance information + * at run time. + * Out-of-line implementation. + */ + +#include "AthenaKernel/BaseInfo.h" +#include "AthenaKernel/CLIDRegistry.h" +#include "GaudiKernel/System.h" +#include <mutex> +#include <map> +#include <unordered_map> +#include "string.h" + + +namespace SG { + + +struct BaseInfoBaseImpl { + /// Structure to hold information about one base. + struct info { + /// Constructor. @a converter* and @a is_virtual are as for @a add_info. + info (BaseInfoBase::castfn_t* converter = 0, + BaseInfoBase::castfn_t* converterTo = 0, + bool is_virtual = false); + + /// Converter function. Takes a @a T* and converts to a pointer + /// to this base. + BaseInfoBase::castfn_t* m_converter; + + /// Converter function. Takes a pointer to this base and converts + /// to @a T*. + /// to this base. + BaseInfoBase::castfn_t* m_converterTo; + + /// True if the derivation from this base to @a T is via + /// virtual derivation. + bool m_is_virtual; + }; + + + /// CLID of this class. + CLID m_clid; + + /// Set to true when first created. + /// Reset after we scan for init functions. + bool m_needs_init; + + /// @c std::type_info of this class. + const std::type_info* m_typeinfo; + + + /// Hold base information indexed by @a type_info. + typedef std::pair<const std::type_info*, info> ti_map_pair_type; + typedef std::vector<ti_map_pair_type> ti_map_type; + ti_map_type m_timap; + + + /// Hold copy conversion information indexed by @ type_info. + typedef std::pair<const std::type_info*, const CopyConversionBase*> + ti_copyconversion_pair_type; + typedef std::vector<ti_copyconversion_pair_type> ti_copyconversion_type; + ti_copyconversion_type m_ti_copyconversion_map; + + + /// Map of all @c type_info pointers to @c BaseInfoBase instances. + typedef std::unordered_map<const std::type_info*, BaseInfoBase*> bi_by_ti_map_type; + static bi_by_ti_map_type* s_bi_by_ti; + + + /// Used to canonicalize @c type_info instances. + typedef std::unordered_map<std::string, const std::type_info*> ti_by_name_map_type; + static ti_by_name_map_type* s_ti_by_name; + + + /// Holds @c BaseInfo classes awaiting initialization. + /// This is used to defer initialization until everything's loaded. + typedef std::unordered_multimap<const std::type_info*, + BaseInfoBase::init_func_t*> init_list_t; + static init_list_t* s_init_list; + + + // To make sure that the maps get deleted at program termination. + struct Deleter { + ~Deleter(); + }; + static Deleter s_deleter; + + /// For thread-safety. + typedef std::recursive_mutex mutex_t; + typedef std::lock_guard<mutex_t> lock_t; + static mutex_t s_mutex; + + + /** + * @brief Find a base by @c type_info. + * @param tinfo The @c type_info to find. + * + * Returns the @c info pointer for the base corresponding + * to @c info, or nullptr if there is no match. + */ + const info* findInfo (const std::type_info& tinfo) const + { + // We don't expect there to be many entries, so just use a linear search. + for (const auto& i : m_timap) { + if (i.first == &tinfo) + return &i.second; + } + + // Sometimes type_info's are not actually unique, depending on how libraries + // get loaded. Try again, comparing names. + for (const auto& i : m_timap) { + if (strcmp (i.first->name(), tinfo.name()) == 0) + return &i.second; + } + return nullptr; + } +}; + + + +/** + * @brief Return the CLID for this class. + */ +CLID BaseInfoBase::clid() const +{ + return m_impl->m_clid; +} + + +/** + * @brief Return the @c std::type_info for this class. + */ +const std::type_info& BaseInfoBase::typeinfo() const +{ + return *m_impl->m_typeinfo; +} + + +/** + * @brief Cast to a base pointer. + * @param p The pointer to cast (a @a T* cast to a @a void*). + * @param clid ID of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +void* BaseInfoBase::cast (void* p, CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->cast (p, *ti); + return 0; +} + + +/** + * @brief Cast to a base pointer. + * @param p The pointer to cast (a @a T* cast to a @a void*). + * @param clid @a type_info of the class to which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +void* BaseInfoBase::cast (void* p, const std::type_info& tinfo) const +{ + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + if (i) + return i->m_converter (p); + return nullptr; +} + + +/** + * @brief Cast to a derived pointer. + * @param p The pointer to cast (a @a B* cast to a @a void*). + * @param clid ID of the class @a B from which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +void* BaseInfoBase::castTo (void* p, CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->castTo (p, *ti); + return 0; +} + + +/** + * @brief Cast to a derived pointer. + * @param p The pointer to cast (a @a B* cast to a @a void*). + * @param clid @a type_info of the class @a B from which to cast. + * @return The pointer cast to the requested type, returned + * as a @a void*. @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +void* BaseInfoBase::castTo (void* p, const std::type_info& tinfo) const +{ + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + if (i) + return i->m_converterTo (p); + return nullptr; +} + + +/** + * @brief Return a function for casting to a base pointer. + * @param clid ID of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a clid. + * @a clid must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +BaseInfoBase::castfn_t* BaseInfoBase::castfn (CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->castfn (*ti); + return 0; +} + + +/** + * @brief Return a function for casting to a base pointer. + * @param clid @a type_info of the class to which to cast. + * @return A function to convert a pointer to a @c T to a pointer + * to the type identified by @a tinfo. + * @a tinfo must be known to be a base + * of @a T; otherwise, 0 will be returned. + */ +BaseInfoBase::castfn_t* +BaseInfoBase::castfn (const std::type_info& tinfo) const +{ + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + if (i) + return i->m_converter; + return nullptr; +} + + +/** + * @brief Return a function for casting to a derived pointer. + * @param clid ID of the class @a B from which to cast. + * @return A function to convert a pointer to a @a B to a pointer + * to a @a T. @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +BaseInfoBase::castfn_t* BaseInfoBase::castfnTo (CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->castfnTo (*ti); + return 0; +} + + +/** + * @brief Return a function for casting to a derived pointer. + * @param clid @a type_info of the class @a B from which to cast. + * @return A function to convert a pointer to a @a B to a pointer + * to a @a T. @a B must be known to be a base + * of @a T; otherwise, 0 will be returned. + * 0 will also be returned if the @a dynamic_cast fails. + */ +BaseInfoBase::castfn_t* +BaseInfoBase::castfnTo (const std::type_info& tinfo) const +{ + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + if (i) + return i->m_converterTo; + return nullptr; +} + + +/** + * @brief Return the class IDs of all known bases of @a T (that + * have class IDs). The list will include @a T itself. + */ +std::vector<CLID> BaseInfoBase::get_bases() const +{ + const BaseInfoBaseImpl::ti_map_type& map = m_impl->m_timap; + std::vector<CLID> v; + v.reserve (map.size()); + for (const auto& p : map) { + CLID clid = CLIDRegistry::typeinfoToCLID (*p.first); + if (clid != CLID_NULL) + v.push_back (clid); + } + return v; +} + + +/** + * @brief Return the @c type_info's of all known bases of @a T. + * The list will include @a T itself. + */ +std::vector<const std::type_info*> BaseInfoBase::get_ti_bases() const +{ + const BaseInfoBaseImpl::ti_map_type& map = m_impl->m_timap; + std::vector<const std::type_info*> v; + v.reserve (map.size()); + for (const auto& i : map) + v.push_back (i.first); + return v; +} + + +/** + * @brief Return true if @a clid is the ID of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param clid The ID of the class to test. + */ +bool BaseInfoBase::is_base (CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->is_base (*ti); + return 0; +} + + +/** + * @brief Return true if @a tinfo is the @a type_info of a class that + * is known to be a base of @a T. @a T is considered + * to be its own base for this purpose. + * @param clid The ID of the class to test. + */ +bool BaseInfoBase::is_base (const std::type_info& tinfo) const +{ + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + return i != 0; +} + + +/** + * @brief Return true if @a clid is the ID of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param clid The ID of the class to test. + */ +bool BaseInfoBase::is_virtual (CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->is_virtual (*ti); + return false; +} + + +/** + * @brief Return true if @a tinfo is the @a std::type_info of a class that + * is known to be a virtual base of @a T. (This will always + * be false for @a T itself.) + * @param tinfo The @a std::type_info of the class to test. + */ +bool BaseInfoBase::is_virtual (const std::type_info& tinfo) const +{ + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + if (i) + return i->m_is_virtual; + return false; +} + + +/** + * @brief Search for a copy conversion to @c tinfo. + * @param tinfo The class to which we want to convert. + * + * Returns the conversion instance or 0. + */ +const CopyConversionBase* +BaseInfoBase::copy_conversion (const std::type_info& tinfo) const +{ + for (const auto& p : m_impl->m_ti_copyconversion_map) { + if (p.first == &tinfo) + return p.second; + } + return 0; +} + + +/** + * @brief Search for a copy conversion to @c clid. + * @param clid The class to which we want to convert. + * + * Returns the conversion instance or 0. + */ +const CopyConversionBase* +BaseInfoBase::copy_conversion (CLID clid) const +{ + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return this->copy_conversion (*ti); + return 0; +} + + +/** + * @brief Add a new copy conversion. + * @param tinfo The @c std::type_info of the target class. + * @param cnv A @c CopyConversionBase instance describing the conversion. + * + * The @c BaseInfoBase takes ownership of the @c cnv object. + */ +void +BaseInfoBase::add_copy_conversion (const std::type_info& tinfo, + const CopyConversionBase* cnv) +{ + m_impl->m_ti_copyconversion_map.emplace_back (&tinfo, cnv); +} + + +/** + * @brief Return known copy conversions. + * + * Returns the CLIDs of all target classes that have been registered + * with this one for copy conversion. + */ +std::vector<CLID> +BaseInfoBase::get_copy_conversions() const +{ + std::vector<CLID> out; + out.reserve (m_impl->m_ti_copyconversion_map.size()); + for (const auto& i : m_impl->m_ti_copyconversion_map) { + CLID clid = CLIDRegistry::typeinfoToCLID (*i.first); + if (clid != CLID_NULL) + out.push_back (clid); + } + return out; +} + + +/** + * @brief Add information about one base class. + * @param tinfo The @a std::type_info of the base. + * @param converter Converter function. This should be able to + * convert a @a T* to a pointer to this base. + * @param converterTo Converter function. This should be able to + * convert a pointer to this base to a @a T*. + * @param is_virtual True if the derivation from this base to @a T + * is via virtual derivation. + */ +void BaseInfoBase::add_info (const std::type_info& tinfo, + castfn_t* converter, + castfn_t* converterTo, + bool is_virtual) +{ + { + const BaseInfoBaseImpl::info* i = m_impl->findInfo (tinfo); + if (!i) { + m_impl->m_timap.emplace_back (&tinfo, + BaseInfoBaseImpl::info (converter, converterTo, is_virtual)); + } + } + + auto i = BaseInfoBaseImpl::s_bi_by_ti->find (&tinfo); + if (i != BaseInfoBaseImpl::s_bi_by_ti->end()) { + BaseInfoBaseImpl& impl = *i->second->m_impl; + if (impl.m_clid == CLID_NULL) + impl.m_clid = CLIDRegistry::typeinfoToCLID (tinfo); + } +} + + +/** + * @brief Convenience constructor. + * @param converter Converter function. This should be able to + * convert a @a T* to a pointer to this base. + * @param converterTo Converter function. This should be able to + * convert a pointer to this base to a @a T*. + * @param is_virtual True if the derivation from this base to @a T + * is via virtual derivation. + * + * The defaults are there just so this class can be used with STL + * containers that require a default ctor. + */ +BaseInfoBaseImpl::info::info (BaseInfoBase::castfn_t* converter /*= 0*/, + BaseInfoBase::castfn_t* converterTo /*= 0*/, + bool is_virtual /*= false*/) + : m_converter (converter), + m_converterTo (converterTo), + m_is_virtual (is_virtual) +{ +} + + +/** + * @brief Constructor. + * @param tinfo The @c std::type_info for this class. + */ +BaseInfoBase::BaseInfoBase (const std::type_info& tinfo) + : m_impl (new BaseInfoBaseImpl) +{ + m_impl->m_clid = CLIDRegistry::typeinfoToCLID (tinfo); + m_impl->m_typeinfo = &tinfo; + m_impl->m_needs_init = true; + + BaseInfoBaseImpl::lock_t lock (BaseInfoBaseImpl::s_mutex); + if (!BaseInfoBaseImpl::s_bi_by_ti) + BaseInfoBaseImpl::s_bi_by_ti = new BaseInfoBaseImpl::bi_by_ti_map_type; + if (!BaseInfoBaseImpl::s_ti_by_name) + BaseInfoBaseImpl::s_ti_by_name = new BaseInfoBaseImpl::ti_by_name_map_type; + + // Register this instance in the static maps. + (*BaseInfoBaseImpl::s_bi_by_ti)[&tinfo] = this; + (*BaseInfoBaseImpl::s_ti_by_name)[tinfo.name()] = &tinfo; +} + + +/** + * @brief Destructor. + */ +BaseInfoBase::~BaseInfoBase() +{ + for (BaseInfoBaseImpl::ti_copyconversion_type::iterator it = + m_impl->m_ti_copyconversion_map.begin(); + it != m_impl->m_ti_copyconversion_map.end(); + ++it) + { + delete it->second; + } + delete m_impl; +} + + +/** + * @brief Find the @c BaseInfoBase instance for @c clid. + * @param clid The class ID of the class for which we want information. + * + * Returns 0 if no @c BaseInfoBase instance is available. + */ +const BaseInfoBase* BaseInfoBase::find (CLID clid) +{ + BaseInfoBaseImpl::lock_t lock (BaseInfoBaseImpl::s_mutex); + const std::type_info* ti = CLIDRegistry::CLIDToTypeinfo (clid); + if (ti) + return BaseInfoBase::find (*ti); + return 0; +} + + +/** + * @brief Helper for @c find. + * @param tinfo The @c std::type_info of the class + * for which we want information. + * + * Returns 0 if no @c BaseInfoBase instance is available. + */ +const BaseInfoBase* BaseInfoBase::find1 (const std::type_info& tinfo) +{ + BaseInfoBaseImpl::lock_t lock (BaseInfoBaseImpl::s_mutex); + if (!BaseInfoBaseImpl::s_bi_by_ti) return 0; + BaseInfoBaseImpl::bi_by_ti_map_type::iterator i = + BaseInfoBaseImpl::s_bi_by_ti->find (&tinfo); + if (i != BaseInfoBaseImpl::s_bi_by_ti->end()) { + if (!i->second->m_impl->m_needs_init) + return i->second; + i->second->m_impl->m_needs_init = false; + } + + // Try the initlist. + if (BaseInfoBaseImpl::s_init_list) { + while (true) { + BaseInfoBaseImpl::init_list_t::iterator it = + BaseInfoBaseImpl::s_init_list->find (&tinfo); + if (it == BaseInfoBaseImpl::s_init_list->end()) break; + BaseInfoBase::init_func_t* init = it->second; + BaseInfoBaseImpl::s_init_list->erase (it); + init(); + i = BaseInfoBaseImpl::s_bi_by_ti->find (&tinfo); + } + } + if (i != BaseInfoBaseImpl::s_bi_by_ti->end()) + return i->second; + + return 0; +} + + +/** + * @brief Find the @c BaseInfoBase instance for @c tinfo. + * @param tinfo The @c std::type_info of the class + * for which we want information. + * + * Returns 0 if no @c BaseInfoBase instance is available. + */ +const BaseInfoBase* BaseInfoBase::find (const std::type_info& tinfo) +{ + const BaseInfoBase* bib = find1 (tinfo); + + // If we didn't find it, try looking up by name. + // This to deal with the issue of sometimes getting duplicate + // @c std::type_info instances. + if (!bib && BaseInfoBaseImpl::s_ti_by_name) { + BaseInfoBaseImpl::ti_by_name_map_type::iterator i = + BaseInfoBaseImpl::s_ti_by_name->find (tinfo.name()); + if (i != BaseInfoBaseImpl::s_ti_by_name->end() && i->second != &tinfo) + bib = find1 (*i->second); + } + + if (bib) { + BaseInfoBaseImpl& impl = *bib->m_impl; + if (impl.m_clid == CLID_NULL) + impl.m_clid = CLIDRegistry::typeinfoToCLID (*impl.m_typeinfo); + } + + return bib; +} + + +/** + * @brief Register an initialization function. + * @param tinfo The @c std::type_info for the class being registered. + * @param init_func Function to initialize @c BaseInfo for the class. + */ +void BaseInfoBase::addInit (const std::type_info* tinfo, + init_func_t* init_func) +{ + BaseInfoBaseImpl::lock_t lock (BaseInfoBaseImpl::s_mutex); + if (!BaseInfoBaseImpl::s_init_list) + BaseInfoBaseImpl::s_init_list = + new BaseInfoBaseImpl::init_list_t; + BaseInfoBaseImpl::s_init_list->insert (std::make_pair (tinfo, init_func)); + + if (BaseInfoBaseImpl::s_bi_by_ti) { + auto i = BaseInfoBaseImpl::s_bi_by_ti->find (tinfo); + if (i != BaseInfoBaseImpl::s_bi_by_ti->end()) { + BaseInfoBaseImpl& impl = *i->second->m_impl; + impl.m_needs_init = true; + if (impl.m_clid == CLID_NULL) + impl.m_clid = CLIDRegistry::typeinfoToCLID (*tinfo); + } + } +} + + +/** + * @brief Run initializations for this class, if needed. + */ +void BaseInfoBase::maybeInit() +{ + if (m_impl->m_needs_init) + find (*m_impl->m_typeinfo); +} + + + +/// Declare the static members of @c BaseInfoBaseImpl. +BaseInfoBaseImpl::bi_by_ti_map_type* BaseInfoBaseImpl::s_bi_by_ti = 0; +BaseInfoBaseImpl::ti_by_name_map_type* BaseInfoBaseImpl::s_ti_by_name = 0; +BaseInfoBaseImpl::init_list_t* BaseInfoBaseImpl::s_init_list = 0; +BaseInfoBaseImpl::mutex_t BaseInfoBaseImpl::s_mutex; + +// To get them deleted. +BaseInfoBaseImpl::Deleter BaseInfoBaseImpl::s_deleter; +BaseInfoBaseImpl::Deleter::~Deleter() +{ + delete s_bi_by_ti; + delete s_ti_by_name; + delete s_init_list; +} + + +// Helper for dumping within the debugger. +void dumpBaseInfo() +{ + std::cout << "map:\n"; + if (BaseInfoBaseImpl::s_bi_by_ti) { + std::vector<const std::type_info*> vv; + for (const auto& x : *BaseInfoBaseImpl::s_bi_by_ti) + vv.push_back (x.first); + std::sort (vv.begin(), vv.end()); + for (const std::type_info* ti : vv) + { + const BaseInfoBase* bib = (*BaseInfoBaseImpl::s_bi_by_ti)[ti]; + std::cout << ti << " " << bib->clid() << " [" << System::typeinfoName (*ti) + << "]\n"; + } + } + + std::cout << "\ninitlist:\n"; + if (BaseInfoBaseImpl::s_init_list) { + for (const auto& x : *BaseInfoBaseImpl::s_init_list) + std::cout << x.first << " " << x.second << " [" + << System::typeinfoName (*x.first) << "]\n"; + } +} + + +} // namespace SG diff --git a/Control/AthenaKernel/test/BaseInfo_test.cxx b/Control/AthenaKernel/test/BaseInfo_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..981e046e1aa92932cb4ffc9bbd5e6fa06c627b2e --- /dev/null +++ b/Control/AthenaKernel/test/BaseInfo_test.cxx @@ -0,0 +1,354 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/test/BaseInfo_test.cxx + * @author scott snyder + * @date A while ago. + * @brief Regression test for BaseInfo. + */ + + +#undef NDEBUG + +#include "AthenaKernel/BaseInfo.h" +#include "AthenaKernel/CLASS_DEF.h" +#include "boost/assign/list_of.hpp" +#include <iostream> +#include <algorithm> +#include <cassert> + +using std::cout; +using boost::assign::list_of; + +struct AA +{ + AA (int the_x=0): x(the_x) {} + ~AA() { } + int x; +}; +struct BB : public AA +{ + BB (int the_x=0) : AA(the_x) {} +}; +struct CC : public BB +{ + CC (int the_x=0) : BB(the_x) {} +}; + +SG_BASE(BB, AA); +SG_BASE(CC, BB); + +CLASS_DEF (AA, 1111, 2) +CLASS_DEF (BB, 1112, 2) +CLASS_DEF (CC, 1113, 2) + +struct M +{ + M (int the_x=0) : x(the_x) {} + virtual ~M() { } + int x; +}; +struct N : virtual public M +{ + N (int the_x=0) : M(the_x) {} +}; +struct O : virtual public M +{ + O (int the_x=0) : M(the_x) {} +}; +struct P : virtual public N, virtual public O +{ + P (int the_x=0) : M(the_x) {} +}; + +CLASS_DEF (M, 1114, 2) +CLASS_DEF (N, 1115, 2) +CLASS_DEF (O, 1116, 2) +CLASS_DEF (P, 1117, 2) + +SG_BASE (N, SG_VIRTUAL (M)); +SG_BASE (O, SG_VIRTUAL (M)); +SG_BASES2 (P, SG_VIRTUAL (N), SG_VIRTUAL (O)); + +struct X1 {}; +struct X2 : public X1 {}; +SG_BASE (X2, X1); + +struct Q : virtual public M +{ + Q (int the_x=0) : M(the_x) {} +}; +struct R : virtual public N, virtual public O, virtual public Q +{ + R (int the_x=0) : M(the_x) {} +}; + +CLASS_DEF (Q, 1118, 2) +CLASS_DEF (R, 1119, 2) + +SG_BASE (Q, SG_VIRTUAL (M)); +SG_BASES3 (R, SG_VIRTUAL (N), + SG_VIRTUAL (O), + SG_VIRTUAL (Q)); + + +struct I1 : public AA {}; +struct I2 : public AA {}; +SG_BASE (I1, AA); +SG_BASE (I2, AA); +CLASS_DEF (I2, 1120, 2) + +struct J : public AA, virtual public X1, public M {}; +SG_BASE(J, AA); +SG_ADD_BASE(J, SG_VIRTUAL(X1)); +SG_ADD_BASE(J, M); + +struct K : public AA {}; +SG_ADD_BASE(K, AA); + + +int test1() +{ + std::cout << "test1\n"; + + typedef SG::BaseInfo<CC> CC_C; + typedef SG::BaseInfo<R> R_C; + + std::vector<CLID> clids; + clids = CC_C::get_bases(); + std::vector<CLID> exp1 = list_of + (ClassID_traits<CC>::ID()) + (ClassID_traits<BB>::ID()) + (ClassID_traits<AA>::ID()); + std::sort (clids.begin(), clids.end()); + std::sort (exp1.begin(), exp1.end()); + assert (clids == exp1); + + std::vector<const std::type_info*> tinfos; + tinfos = CC_C::get_ti_bases(); + std::vector<const std::type_info*> exp1ti = list_of + (&typeid(CC)) + (&typeid(BB)) + (&typeid(AA)); + std::sort (tinfos.begin(), tinfos.end()); + std::sort (exp1ti.begin(), exp1ti.end()); + assert (tinfos == exp1ti); + + clids = R_C::get_bases(); + std::vector<CLID> exp2 = list_of + (ClassID_traits<M>::ID()) + (ClassID_traits<N>::ID()) + (ClassID_traits<O>::ID()) + (ClassID_traits<Q>::ID()) + (ClassID_traits<R>::ID()); + std::sort (clids.begin(), clids.end()); + std::sort (exp2.begin(), exp2.end()); + assert (clids == exp2); + + tinfos = R_C::get_ti_bases(); + std::vector<const std::type_info*> exp2ti = list_of + (&typeid(M)) + (&typeid(N)) + (&typeid(O)) + (&typeid(Q)) + (&typeid(R)); + std::sort (tinfos.begin(), tinfos.end()); + std::sort (exp2ti.begin(), exp2ti.end()); + assert (tinfos == exp2ti); + + SG::BaseInfoBase::castfn_t* castfn; + + M* m0 = new M; + R* r1 = new R; + M* m1 = r1; + assert ((long)m1 != (long)r1); + M* m2 = (M*)R_C::cast (r1, ClassID_traits<M>::ID()); + assert ((long)m1 == (long)m2); + m2 = (M*)R_C::cast (r1, typeid (M)); + assert ((long)m1 == (long)m2); + R* r2 = (R*)R_C::castTo (m1, ClassID_traits<M>::ID()); + assert ((long)r1 == (long)r2); + r2 = (R*)R_C::castTo (m1, typeid (M)); + assert ((long)r1 == (long)r2); + r2 = (R*)R_C::castTo (m0, typeid (M)); + assert (r2 == 0); + + castfn = R_C::castfn (ClassID_traits<M>::ID()); + assert ((long)m1 == (long)castfn(r1)); + castfn = R_C::castfn (typeid (M)); + assert ((long)m1 == (long)castfn(r1)); + castfn = R_C::castfnTo (ClassID_traits<M>::ID()); + assert ((long)r1 == (long)castfn(m1)); + castfn = R_C::castfnTo (typeid (M)); + assert ((long)r1 == (long)castfn(m1)); + assert (0 == (long)castfn(m0)); + + assert (R_C::cast (r1, ClassID_traits<AA>::ID()) == 0); + assert (R_C::cast (r1, typeid (AA)) == 0); + assert (R_C::castTo (r1, ClassID_traits<AA>::ID()) == 0); + assert (R_C::castTo (r1, typeid (AA)) == 0); + assert (R_C::castfn (ClassID_traits<AA>::ID()) == 0); + assert (R_C::castfn (typeid (AA)) == 0); + assert (R_C::castfnTo (ClassID_traits<AA>::ID()) == 0); + assert (R_C::castfnTo (typeid (AA)) == 0); + + assert (R_C::is_base (ClassID_traits<M>::ID())); + assert (R_C::is_base (typeid (M))); + + assert (!R_C::is_base (ClassID_traits<AA>::ID())); + assert (!R_C::is_base (typeid (AA))); + + assert (CC_C::is_base (ClassID_traits<AA>::ID())); + assert (CC_C::is_base (typeid (AA))); + + assert (R_C::is_virtual (ClassID_traits<M>::ID())); + assert (R_C::is_virtual (typeid (M))); + + assert (!CC_C::is_virtual (ClassID_traits<AA>::ID())); + assert (!CC_C::is_virtual (typeid (AA))); + + typedef SG::BaseInfo<X2> X_C; + assert (X_C::is_base (typeid (X1))); + X2* x2 = new X2; + X1* x1 = (X1*)X_C::cast (x2, typeid (X1)); + assert (x1 == x2); + X2* x2a = (X2*)X_C::castTo (x1, typeid (X1)); + assert (x2a == 0); // castTo doesn't work now for non-polymorphic classes. + + clids = SG::BaseInfoBase::find (ClassID_traits<CC>::ID())->get_bases(); + std::sort (clids.begin(), clids.end()); + assert (clids == exp1); + tinfos = SG::BaseInfoBase::find (ClassID_traits<CC>::ID())->get_ti_bases(); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp1ti); + + clids = CC_C::baseinfo().get_bases(); + std::sort (clids.begin(), clids.end()); + assert (clids == exp1); + tinfos = CC_C::baseinfo().get_ti_bases(); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp1ti); + + clids = SG::BaseInfoBase::find (typeid (CC))->get_bases(); + std::sort (clids.begin(), clids.end()); + assert (clids == exp1); + tinfos = SG::BaseInfoBase::find (typeid (CC))->get_ti_bases(); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp1ti); + + assert (SG::BaseInfoBase::find (typeid(CC))->clid() == + ClassID_traits<CC>::ID()); + assert (SG::BaseInfoBase::find (typeid(CC))->typeinfo() == typeid(CC)); + + assert (SG::BaseInfoBase::find (99999) == 0); + assert (SG::BaseInfoBase::find (typeid(int)) == 0); + + assert (typeid(SG::BaseType<SG::Bases<BB>::Base1>::type) == typeid(AA)); + assert (typeid(SG::BaseType<SG::Bases<BB>::Base1>::is_virtual) == + typeid(std::false_type)); + + assert (typeid(SG::BaseType<SG::Bases<N>::Base1>::type) == typeid(M)); + assert (typeid(SG::BaseType<SG::Bases<N>::Base1>::is_virtual) == + typeid(std::true_type)); + + std::vector<CLID> exp3 = list_of + (ClassID_traits<AA>::ID()); + clids = SG::BaseInfoBase::find (typeid (I1))->get_bases(); + assert (clids == exp3); + + std::vector<const std::type_info*> exp3ti = list_of + (&typeid (AA)) + (&typeid (I1)); + std::sort (exp3ti.begin(), exp3ti.end()); + tinfos = SG::BaseInfoBase::find (typeid (I1))->get_ti_bases(); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp3ti); + + std::vector<CLID> exp4 = list_of + (ClassID_traits<AA>::ID()) + (ClassID_traits<I2>::ID()); + clids = SG::BaseInfoBase::find (ClassID_traits<I2>::ID())->get_bases(); + std::sort (clids.begin(), clids.end()); + assert (clids == exp4); + + std::vector<const std::type_info*> exp4ti = list_of + (&typeid (AA)) + (&typeid (I2)); + std::sort (exp4ti.begin(), exp4ti.end()); + tinfos = SG::BaseInfoBase::find (typeid (I2))->get_ti_bases(); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp4ti); + + const SG::BaseInfoBase* jbib = SG::BaseInfoBase::find (typeid (J)); + tinfos = jbib->get_ti_bases(); + std::vector<const std::type_info*> exp5ti = list_of + (&typeid (AA)) + (&typeid (X1)) + (&typeid (M)) + (&typeid (J)); + std::sort (exp5ti.begin(), exp5ti.end()); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp5ti); + assert (!jbib->is_virtual (typeid (AA))); + assert ( jbib->is_virtual (typeid (X1))); + assert (!jbib->is_virtual (typeid (M))); + + const SG::BaseInfoBase* kbib = SG::BaseInfoBase::find (typeid (K)); + tinfos = kbib->get_ti_bases(); + std::vector<const std::type_info*> exp6ti = list_of + (&typeid (AA)) + (&typeid (K)); + std::sort (exp6ti.begin(), exp6ti.end()); + std::sort (tinfos.begin(), tinfos.end()); + assert (tinfos == exp6ti); + + return 0; +} + + +class KCopyConversion + : public SG::CopyConversion<K, M> +{ +public: + void convert (const K& src, M& dst) const + { dst.x = src.x; } +}; + +SG_ADD_COPY_CONVERSION(K, KCopyConversion); + + +// Test copying conversions. +void test2() +{ + std::cout << "test2\n"; + const SG::BaseInfoBase& bib = SG::BaseInfo<K>::baseinfo(); + std::vector<CLID> clids = bib.get_copy_conversions(); + std::vector<CLID> exp1 = list_of + (ClassID_traits<M>::ID()); + assert (clids == exp1); + + const SG::CopyConversionBase* b = bib.copy_conversion (clids[0]); + assert (b == bib.copy_conversion (typeid (M))); + assert (0 == bib.copy_conversion (typeid (X1))); + assert (0 == bib.copy_conversion (typeid (Q))); + assert (0 == bib.copy_conversion (ClassID_traits<Q>::ID())); + + K k; + k.x = 10; + M m; + m.x = 0; + b->convertUntyped (&k, &m); + assert (m.x == 10); +} + + +int main() +{ + test1(); + test2(); + return 0; +} +