diff --git a/Control/AthContainersRoot/AthContainersRoot/AthContainersRootTestDict.h b/Control/AthContainersRoot/AthContainersRoot/AthContainersRootTestDict.h new file mode 100644 index 0000000000000000000000000000000000000000..4dc5747140c8474150a5af3fbf5b1dfcc223e5cc --- /dev/null +++ b/Control/AthContainersRoot/AthContainersRoot/AthContainersRootTestDict.h @@ -0,0 +1,39 @@ +// 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$ +/** + * @file AthContainersRoot/AthContainersRootTestDict.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2016 + * @brief For AthContainersRoot unit tests. + */ + + +#ifndef ATHCONTAINERSROOT_ATHCONTAINERSROOTTESTDICT_H +#define ATHCONTAINERSROOT_ATHCONTAINERSROOTTESTDICT_H + + +#include "AthContainers/tools/AuxTypeVectorFactory.h" + + +namespace AthContainersRootTest { + + +class Foo {}; +class Bar {}; +class Baz {}; + + +} // namespace AthContainersRootTest + + +namespace SG { +template class AuxTypeVectorFactory<AthContainersRootTest::Foo>; +} + + +#endif // not ATHCONTAINERSROOT_ATHCONTAINERSROOTTESTDICT_H diff --git a/Control/AthContainersRoot/AthContainersRoot/AuxStoreRoot.h b/Control/AthContainersRoot/AthContainersRoot/AuxStoreRoot.h new file mode 100644 index 0000000000000000000000000000000000000000..93e4749b8047862bc80ed0a3a5dd9b2d3b44661e --- /dev/null +++ b/Control/AthContainersRoot/AthContainersRoot/AuxStoreRoot.h @@ -0,0 +1,215 @@ +// 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$ +/** + * @file AthContainersRoot/AuxStoreRoot.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2016 + * @brief Base class for root-based dynamic auxiliary store. + */ + + +#ifndef ATHCONTAINERSROOT_AUXSTOREROOT_H +#define ATHCONTAINERSROOT_AUXSTOREROOT_H + + +#include "AthContainers/AuxStoreInternal.h" +#include "AthContainersRoot/IAuxBranches.h" +class TClass; + + +namespace SG { + + +/** + * @brief Base class for root-based dynamic auxiliary store. + * + * This class is used to implement the dynamic part of an auxiliary store + * where the data are stored in root. It is the result of factoring + * common code from AuxStoreAPR (pool) and AuxStoreARA (AthenaROOTAccess). + * + * The class is based on @c AuxStoreInternal. Derived classes must implement + * two methods: @c resolveAuxID, to assign an auxiliary ID to a branch, + * and @c doReadData to actually read data from the file into the store. + * The derived class constructor should also call @c fillAuxIDs + * to complete initialization. + * + * Communication is via an instance of @c IAuxBranches, which provides + * interfaces to enumerate the dynamic branches and to read data. + */ +class AuxStoreRoot + : public SG::AuxStoreInternal +{ +public: + /** + * @brief Constructor. + * @param container Representation of the object for which we're reading. + * @param entry The entry in the root tree to read. + * @param standalone If true, this is a standalone auxiliary object. + */ + AuxStoreRoot (IAuxBranches& container, long long entry, bool standalone); + + + /// Destructor. + virtual ~AuxStoreRoot() {} + + + /// implementation of the IAuxStore interface + + /** + * @brief Return the data vector for one aux data item + * @param auxid The identifier of the desired aux data item. + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * This should return 0 if the item doesn't exist. + */ + virtual const void* getData(SG::auxid_t auxid) const override; + + + /** + * @brief Return the data vector for one aux data item + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * If the data item does not exist, it should be created and initialized + * to default values. @c size and @c capacity give the size for the + * new aux data item vector. + * + * If the container is locked, throw an exception. + */ + virtual void* + getData(SG::auxid_t auxid, size_t size, size_t capacity) override; + + + /** + * @brief Return the data vector for one aux data decoration item. + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + */ + virtual void* + getDecoration (SG::auxid_t auxid, size_t size, size_t capacity) override; + + + /// Implementation of the IAuxStoreIO interface + + + /** + * @brief Return a pointer to the data to be stored for one aux data item. + * @param auxid The identifier of the desired aux data item. + * + * This will usually be a pointer to a @c std::vector; however, it may + * be something different for a standalone object. + * + * Returns 0 and reports an error if the requested aux data item + * does not exist. + */ + virtual const void* getIOData(SG::auxid_t auxid) const override; + + + /// Methods to be implemented by derived classes. + + + /** + * @brief Determine auxiliary ID for a branch. + * @param container Representation of the object being read. + * @param ti @c type_info for the element, or nullptr. + * @param name Name of the attribute. + * @param elemTypeName Name of the type of this attribute. + * @param branchTypeName Name of the type of the object stored + * in the branch. Should be the same as @c elemTypeName + * for standalone objects. + */ + virtual SG::auxid_t resolveAuxID (IAuxBranches& container, + const std::type_info* ti, + const std::string& name, + const std::string& elemTypeName, + const std::string& branchTypeName) = 0; + + + /** + * @brief Actually read data into the attribute. + * @param container Representation of the object being read. + * @param auxid ID of the variable being read. + * @param branch Root branch being read. + * @param cl Class of the data stored in the branch. + * @param vector Pointer to the I/O data for this attribute. + * (Will be a vector for the normal case, the element + * itself for standalone objects.) + * @param entry Entry being read in the TTree. + * + * Returns true on success, false on failure. + */ + virtual bool doReadData (IAuxBranches& container, + SG::auxid_t auxid, + TBranch& branch, + TClass* cl, + void* vector, + long long entry) = 0; + + + +protected: + /// Methods to be called by derived classes. + + /** + * @brief Derived classes should call this from their constructor + * to complete initialization. + * + * Creates the auxid set from the list of branches. + * This cannot be done from the @c AuxStoreRoot constructor as it needs + * to call the @c resolveAuxID virtual method. + */ + void fillAuxIDs(); + + + /** + * @brief Change the TTree entry being read. + * @param entry New entry being read. + */ + void setEntry (long long entry); + + +private: + /** + * @brief Read data from ROOT and store it in the internal vector. + * + * Returns true on success, false on failure. + */ + bool readData(SG::auxid_t auxid); + + + /// Current TTree entry being read. + long long m_entry; + + /// Representation of the object being read. + IAuxBranches& m_container; + + + /// Mutex used to synchronize modifications to the cache vector. + typedef AthContainers_detail::mutex mutex_t; + typedef AthContainers_detail::lock_guard<mutex_t> guard_t; + mutable mutex_t m_mutex; +}; + + +} // namespace SG + + +#endif // not ATHCONTAINERSROOT_AUXSTOREROOT_H diff --git a/Control/AthContainersRoot/AthContainersRoot/IAuxBranches.h b/Control/AthContainersRoot/AthContainersRoot/IAuxBranches.h new file mode 100644 index 0000000000000000000000000000000000000000..91fb068eaf2ed2adfed540e73b46aa854a9d3b2b --- /dev/null +++ b/Control/AthContainersRoot/AthContainersRoot/IAuxBranches.h @@ -0,0 +1,50 @@ +// 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$ +/** + * @file AthContainersRoot/IAuxBranches.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2016 + * @brief + */ + + +#ifndef ATHCONTAINERSROOT_IAUXBRANCHES_H +#define ATHCONTAINERSROOT_IAUXBRANCHES_H + + +#include "AthContainersInterfaces/AuxTypes.h" +#include "GaudiKernel/StatusCode.h" +#include <utility> +#include <string> +#include <vector> +#include <typeinfo> +class TBranch; + + +namespace SG { + + +class IAuxBranches +{ +public: + virtual ~IAuxBranches() {} + + virtual const std::string& getName() const = 0; + typedef std::pair<std::string, TBranch*> auxpair_t; + virtual std::vector<auxpair_t> auxBranches() const = 0; + virtual TBranch* findAuxBranch (SG::auxid_t auxid) = 0; + virtual StatusCode readAuxBranch (TBranch& br, void* p, long long entry) = 0; + virtual StatusCode readAuxBranch (TBranch& br, void* p, + const std::type_info& ti, long long entry) = 0; +}; + + +} // namespace SG + + +#endif // not ATHCONTAINERSROOT_IAUXBRANCHES_H diff --git a/Control/AthContainersRoot/AthContainersRoot/RootAuxVectorFactory.h b/Control/AthContainersRoot/AthContainersRoot/RootAuxVectorFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..aa19a699cf608f98c3f7d4fbe7c04c8922a2835c --- /dev/null +++ b/Control/AthContainersRoot/AthContainersRoot/RootAuxVectorFactory.h @@ -0,0 +1,361 @@ +// 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$ +/** + * @file AthContainersRoot/RootAuxVectorFactory.h + * @author scott snyder <snyder@bnl.gov> + * @date May, 2014 + * @brief Dynamic implementation of @c IAuxVectorFactory, + * relying on root's vector proxy. + */ + + +#ifndef ATHCONTAINERSROOT_ROOTAUXVECTORFACTORY_H +#define ATHCONTAINERSROOT_ROOTAUXVECTORFACTORY_H + + +#include "AthContainersInterfaces/IAuxTypeVectorFactory.h" +#include "AthContainersInterfaces/IAuxTypeVector.h" +#include "RootUtils/Type.h" + + +class TClass; +class TVirtualCollectionProxy; + + +namespace SG { + + +class RootAuxVectorFactory; + + +/** + * @brief Dynamic implementation of @c IAuxTypeVector, + * relying on root vector proxy. + * + * This is used for the case when we need to manipulate an aux data vector + * present in an input data file but we have neither a proper template + * instantiation for the factory (because the variable was never explicitly + * referenced), nor can we find a dictionary entry for the factory.j + * + * This implementation works by relying entirely on the root + * dictionary information. + */ +class RootAuxVector + : public SG::IAuxTypeVector +{ +public: + /** + * @brief Constructor. Makes a new vector. + * @param factory The factory object for this type. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + */ + RootAuxVector (const RootAuxVectorFactory* factory, + size_t size, + size_t capacity); + + + /** + * @brief Constructor, from a pointer to a vector object. + * @param data The vector object. + * @param isPacked If true, @c data is a @c PackedContainer. + * @param ownFlag If true, then take ownership of @c data. + * + * If the element type is T, then @c data should be a pointer + * to a std::vector<T> object, which was obtained with @c new. + * + * This version does not support packed containers, so @c isPacked + * must be false. + */ + RootAuxVector (const RootAuxVectorFactory* factory, + void* data, + bool isPacked, + bool ownFlag); + + + + /** + * @brief Copy constructor. + * @param other The vector to copy. + */ + RootAuxVector (const RootAuxVector& other); + + + // Disallow assignment. + RootAuxVector& operator= (const RootAuxVector&) = delete; + + + /** + * @brief Destructor. + * + * This will free the vector data. + */ + virtual ~RootAuxVector() override; + + + /** + * @brief Make a copy of this vector. + */ + virtual SG::IAuxTypeVector* clone() const override; + + + /** + * @brief Return a pointer to the start of the vector's data. + */ + virtual void* toPtr() override; + + + /** + * @brief Return a pointer to the overall object. + */ + virtual void* toVector() override; + + + + /** + * @brief Return the size of the vector. + */ + virtual size_t size() const override; + + + /** + * @brief Change the size of the vector. + * @param sz The new vector size. + */ + virtual void resize (size_t sz) override; + + + /** + * @brief Change the capacity of the vector. + * @param sz The new vector capacity. + */ + virtual void reserve (size_t sz) override; + + + /** + * @brief Shift the elements of the vector. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * This operation shifts the elements in the vectors for all + * aux data items, to implement an insertion or deletion. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ + virtual void shift (size_t pos, ptrdiff_t offs) override; + + + /** + * @brief Return the type of the complete object to be saved. + * + * For example, if the object is a @c std::vector, then we return + * the @c type_info of the vector. But if we're holding + * a @c PackedContainer, then we return the @c type_info of the + * @c PackedContainer. + * + * Can return null if the operation is not supported. In that case, + * I/O will use the type found from the variable registry. + */ + virtual const std::type_info* objType() const override; + + +private: + /// Pointer back to the factory class for this type. + const RootAuxVectorFactory* m_factory; + + /// The collection proxy for the vector. + TVirtualCollectionProxy* m_proxy; + + /// Pointer to the overall object itself. + void* m_obj; + + /// Pointer to the vector object itself. + void* m_vec; + + /// Should be delete the vector object? + bool m_ownFlag; +}; + + +/** + * @brief Dynamic implementation of @c IAuxVectorFactory, + * relying on root's vector proxy. + * + * This is used for the case when we need to manipulate an aux data vector + * present in an input data file but we have neither a proper template + * instantiation for the factory (because the variable was never explicitly + * referenced), nor can we find a dictionary entry for the factory.j + * + * This implementation works by relying entirely on the root + * dictionary information. + * + * We may either be dealing directly with an STL vector class, or with + * embedded in another class (as for PackedContainer). Here, @a vecClass + * is the class of the STL vector and @a objClass is the overall object + * class. In the case of a direct STL vector, these are identical. + */ +class RootAuxVectorFactory + : public SG::IAuxTypeVectorFactory +{ +public: + /** + * @brief Constructor. + * @param vecClass The @c TClass for the vector object. + */ + RootAuxVectorFactory (TClass* objClass); + + + /** + * @brief Destructor. + */ + virtual ~RootAuxVectorFactory() override; + + + /** + * @brief Return the ROOT type wrapper. + */ + const RootUtils::Type& rootType() const { return m_type; } + + + /** + * @brief Return the @c TClass for the overall object. + */ + TClass* objClass() const { return m_objClass; } + + + /** + * @brief Return the @c TClass for the @c std::vector. + */ + TClass* vecClass() const { return m_vecClass; } + + + /** + * @brief Return the offset of the vector within the object. + */ + size_t offset() const { return m_offset; } + + + /** + * @brief Create a vector object of this type. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + * + * Returns a newly-allocated object. + * FIXME: Should return a unique_ptr. + */ + virtual SG::IAuxTypeVector* create (size_t size, size_t capacity) const + override; + + + /** + * @brief Create a vector object of this type from a data blob. + * @param data The vector object. + * @param isPacked If true, @c data is a @c PackedContainer. + * @param ownFlag If true, the newly-created IAuxTypeVector object + * will take ownership of @c data. + * + * If the element type is T, then @c data should be a pointer + * to a std::vector<T> object, which was obtained with @c new. + * + * This version does not support packed containers, so @c isPacked + * must be false. + * + * Returns a newly-allocated object. + * FIXME: Should return a unique_ptr. + */ + virtual SG::IAuxTypeVector* createFromData (void* data, + bool isPacked, + bool ownFlag) const + override; + + + /** + * @brief Copy an element between vectors. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ + virtual void copy (void* dst, size_t dst_index, + const void* src, size_t src_index) const override; + + + /** + * @brief Swap an element between vectors. + * @param a Pointer to the start of the first vector's data. + * @param aindex Index of the element in the first vector. + * @param b Pointer to the start of the second vector's data. + * @param bindex Index of the element in the second vector. + * + * @c a and @ b can be either the same or different. + */ + virtual void swap (void* a, size_t aindex, + void* b, size_t bindex) const override; + + + /** + * @brief Clear an element within a vector (static method). + * @param dst Pointer to the start of the vector's data. + * @param dst_index Index of the element in the vector. + */ + virtual void clear (void* dst, size_t dst_index) const override; + + + /** + * @brief Return the size of an element of this vector type. + */ + virtual size_t getEltSize() const override; + + + /** + * @brief Return the @c type_info of the overall object. + */ + virtual const std::type_info* tiVec() const override; + + + /** + * @brief True if the vectors created by this factory work by dynamic + * emulation (via @c TVirtualCollectionProxy or similar); false + * if the std::vector code is used directly. + */ + virtual bool isDynamic() const override; + + +private: + /// The @c TClass for the overall object. + TClass* m_objClass; + + /// The @c TClass for the std::vector. + TClass* m_vecClass; + + /// Offset of the STL vector within the overall object. + size_t m_offset; + + /// Wrapper for the ROOT type of the element. + RootUtils::Type m_type; +}; + + +} // namespace SG + + +#endif // not ATHCONTAINERSROOT_ROOTAUXVECTORFACTORY_H diff --git a/Control/AthContainersRoot/AthContainersRoot/getDynamicAuxID.h b/Control/AthContainersRoot/AthContainersRoot/getDynamicAuxID.h new file mode 100644 index 0000000000000000000000000000000000000000..19ad34f5594b21fc8555acbdbe29f2c1974cbda1 --- /dev/null +++ b/Control/AthContainersRoot/AthContainersRoot/getDynamicAuxID.h @@ -0,0 +1,51 @@ +// 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$ +/** + * @file AthContainersRoot/getDynamicAuxID.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2016 + * @brief Find the auxid for a dynamic branch. + */ + + +#ifndef ATHCONTAINERSROOT_GETDYNAMICAUXID_H +#define ATHCONTAINERSROOT_GETDYNAMICAUXID_H + + +#include "AthContainersInterfaces/AuxTypes.h" +#include <typeinfo> +#include <string> + + + +namespace SG { + + +/** + * @brief Find the auxid for a dynamic branch. + * @param ti Type of the auxiliary variable. + * Usually the type of the vector payload, but if @c standalone + * is true, then this is the type of the stored object. + * @param name Auxiliary variable name. + * @param elementTypeName Name of the type for one aux data element. + * Should be the samr as @c branchTypeName + * if @c standalone is true. + * @param branchTypeName Name of the type for this branch. + * @param standalone True if this is a standalone object. + */ +SG::auxid_t getDynamicAuxID (const std::type_info& ti, + const std::string& name, + const std::string& elementTypeName, + const std::string& branch_type_name, + bool standalone); + + +} // namespace SG + + +#endif // not ATHCONTAINERSROOT_GETDYNAMICAUXID_H diff --git a/Control/AthContainersRoot/AthContainersRoot/selection.xml b/Control/AthContainersRoot/AthContainersRoot/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..907467a8a1e0db18d5535ee406cbe791a73a6ab0 --- /dev/null +++ b/Control/AthContainersRoot/AthContainersRoot/selection.xml @@ -0,0 +1,11 @@ +<lcgdict> + +<class name="AthContainersRootTest::Foo"/> +<class name="AthContainersRootTest::Bar"/> +<class name="AthContainersRootTest::Baz"/> +<class name="std::vector<AthContainersRootTest::Foo>"/> +<class name="std::vector<AthContainersRootTest::Bar>"/> +<class name="std::vector<AthContainersRootTest::Baz>"/> +<class name="SG::AuxTypeVectorFactory<AthContainersRootTest::Foo>"/> + +</lcgdict> diff --git a/Control/AthContainersRoot/CMakeLists.txt b/Control/AthContainersRoot/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..15ae2c6f986f1ccef92c4283051e017f9bd827df --- /dev/null +++ b/Control/AthContainersRoot/CMakeLists.txt @@ -0,0 +1,55 @@ +################################################################################ +# Package: AthContainersRoot +################################################################################ + +# Declare the package name: +atlas_subdir( AthContainersRoot ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( PUBLIC + GaudiKernel + Control/AthContainersInterfaces + Control/RootUtils + PRIVATE + AtlasTest/TestTools + Control/AthContainers + Control/CxxUtils ) + +# External dependencies: +find_package( ROOT COMPONENTS Core ) + +# Component(s) in the package: +atlas_add_library( AthContainersRoot + src/*.cxx + PUBLIC_HEADERS AthContainersRoot + PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} AthContainers RootUtils ) + + +atlas_add_dictionary( AthContainersRootTestDict + AthContainersRoot/AthContainersRootTestDict.h + AthContainersRoot/selection.xml + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} AthContainersRoot AthContainers ) + + +atlas_add_test( RootAuxVectorFactory_test + SOURCES + test/RootAuxVectorFactory_test.cxx + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} AthContainers CxxUtils RootUtils AthContainersRoot ) + + +atlas_add_test( getDynamicAuxID_test + SOURCES + test/getDynamicAuxID_test.cxx + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} AthContainers CxxUtils RootUtils AthContainersRoot ) + + +atlas_add_test( AuxStoreRoot_test + SOURCES + test/AuxStoreRoot_test.cxx + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} AthContainers CxxUtils RootUtils AthContainersRoot ) + diff --git a/Control/AthContainersRoot/cmt/requirements b/Control/AthContainersRoot/cmt/requirements new file mode 100644 index 0000000000000000000000000000000000000000..f12fd3db6ddc103c626aadf67715a2f1dcb03e40 --- /dev/null +++ b/Control/AthContainersRoot/cmt/requirements @@ -0,0 +1,32 @@ +package AthContainersRoot + +author Scott Snyder <snyder@fnal.gov> + +use AtlasPolicy AtlasPolicy-* +use AtlasROOT AtlasROOT-* External +use GaudiInterface GaudiInterface-* External +use RootUtils RootUtils-* Control +use AthContainersInterfaces AthContainersInterfaces-* Control +use AthContainers AthContainers-* Control + +private +use CxxUtils CxxUtils-* Control + +public +apply_pattern installed_library +library AthContainersRoot *.cxx + +macro_append DOXYGEN_INPUT " ../doc" + +private +use TestTools TestTools-* AtlasTest +apply_pattern UnitTest_run unit_test=RootAuxVectorFactory +apply_pattern UnitTest_run unit_test=getDynamicAuxID +apply_pattern UnitTest_run unit_test=AuxStoreRoot + + +private +use AtlasReflex AtlasReflex-* External +apply_pattern lcgdict dict=AthContainersRootTest selectionfile=selection.xml \ + headerfiles="../AthContainersRoot/AthContainersRootTestDict.h" + diff --git a/Control/AthContainersRoot/share/AuxStoreRoot_test.ref b/Control/AthContainersRoot/share/AuxStoreRoot_test.ref new file mode 100644 index 0000000000000000000000000000000000000000..bae42c55f9e0a4e297a4d197d8aadfe147ef269b --- /dev/null +++ b/Control/AthContainersRoot/share/AuxStoreRoot_test.ref @@ -0,0 +1,2 @@ +test1 +test2 diff --git a/Control/AthContainersRoot/share/RootAuxVectorFactory_test.ref b/Control/AthContainersRoot/share/RootAuxVectorFactory_test.ref new file mode 100644 index 0000000000000000000000000000000000000000..45aaa06da1e7fc094ff05eb350b62d7b3dbc746e --- /dev/null +++ b/Control/AthContainersRoot/share/RootAuxVectorFactory_test.ref @@ -0,0 +1,5 @@ +test1 +test2 +test3 +test4 +test5 diff --git a/Control/AthContainersRoot/share/getDynamicAuxID_test.ref b/Control/AthContainersRoot/share/getDynamicAuxID_test.ref new file mode 100644 index 0000000000000000000000000000000000000000..a5bce3fd2565d8f458555a0c6f42d0504a848bd5 --- /dev/null +++ b/Control/AthContainersRoot/share/getDynamicAuxID_test.ref @@ -0,0 +1 @@ +test1 diff --git a/Control/AthContainersRoot/src/AuxStoreRoot.cxx b/Control/AthContainersRoot/src/AuxStoreRoot.cxx new file mode 100644 index 0000000000000000000000000000000000000000..cdbcbd28f2bd2bd09a31ce8a1e81867c713c0ab6 --- /dev/null +++ b/Control/AthContainersRoot/src/AuxStoreRoot.cxx @@ -0,0 +1,306 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainersRoot/src/AuxStoreRoot.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2016 + * @brief Base class for root-based dynamic auxiliary store. + */ + + +#include "AthContainersRoot/AuxStoreRoot.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainers/exceptions.h" +#include "AthContainers/tools/error.h" +#include "RootUtils/Type.h" +#include "TROOT.h" +#include "TBranch.h" +#include "TLeaf.h" +#include "TClass.h" +#include "TClassEdit.h" +#include "TVirtualCollectionProxy.h" + + +namespace { + + +/** + * @brief Decode a ROOT @c EDataType. + * @param type ROOT type to decode. + * @param[out] typeName Name of the type. + * + * Returns the @c std::type_info for the type. + */ +const std::type_info* dataTypeToTypeInfo (EDataType type, std::string& typeName) +{ + RootUtils::Type typ (type); + typeName = typ.getTypeName(); + return typ.getTypeInfo(); +} + + +/** + * @brief Given a branch, return the aux data type for that branch. + * @param br The branch for which we want to get the type. + * @param standalone Is this for a standalone object? + * @param[out] elementTypeName Name of the type for one aux data element. + * Same as branchTypeName if @c standalone is true. + * @param[out] branchTypeName Name of the type for this branch. + * + * If standalone is true, then we return the type of the branch + * directly. Otherwise, the branch should be a STL vector; + * we return the type of the vector's payload. + * + * Returns 0 on failure. + */ +const std::type_info* getElementType (TBranch* br, + bool standalone, + std::string& elementTypeName, + std::string& branchTypeName) +{ + TClass* expectedClass = 0; + EDataType expectedType = kOther_t; + if (br->GetExpectedType (expectedClass, expectedType) != 0) { + return 0; + } + + if (standalone) { + if (expectedClass) { + elementTypeName = expectedClass->GetName(); + branchTypeName = elementTypeName; + return expectedClass->GetTypeInfo(); + } + const std::type_info* ret = dataTypeToTypeInfo (expectedType, + elementTypeName); + branchTypeName = elementTypeName; + return ret; + } + + // Not standalone; branch should be a vector. + if (!expectedClass) return 0; + + branchTypeName = expectedClass->GetName(); + if (strncmp (expectedClass->GetName(), "vector<", 7) == 0) { + TVirtualCollectionProxy* prox = expectedClass->GetCollectionProxy(); + if (!prox) return 0; + if (prox->GetValueClass()) { + elementTypeName = prox->GetValueClass()->GetName(); + return prox->GetValueClass()->GetTypeInfo(); + } + return dataTypeToTypeInfo (prox->GetType(), elementTypeName); + } + else if (strncmp (expectedClass->GetName(), "SG::PackedContainer<", 20) == 0){ + TClassEdit::TSplitType split (expectedClass->GetName()); + if (split.fElements.size() > 1) { + elementTypeName = split.fElements[1]; + RootUtils::Type typ (elementTypeName); + return typ.getTypeInfo(); + } + } + return 0; +} + + +} // Anonymous namespace + + +namespace SG { + + +/** + * @brief Constructor. + * @param container Representation of the object for which we're reading. + * @param entry The entry in the root tree to read. + * @param standalone If true, this is a standalone auxiliary object. + */ +AuxStoreRoot::AuxStoreRoot(IAuxBranches& container, + long long entry, + bool standalone) : + SG::AuxStoreInternal (standalone), + m_entry(entry), + m_container(container) +{ +} + + +/** + * @brief Return the data vector for one aux data item + * @param auxid The identifier of the desired aux data item. + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * This should return 0 if the item doesn't exist. + */ +const void* AuxStoreRoot::getData(SG::auxid_t auxid) const +{ + guard_t guard (m_mutex); + // lock + const void* ret = SG::AuxStoreInternal::getData (auxid); + if (!ret) { + if (const_cast<AuxStoreRoot*>(this)->readData(auxid)) + ret = SG::AuxStoreInternal::getData (auxid); + } + return ret; +} + + +/** + * @brief Return the data vector for one aux data item + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * If the data item does not exist, it should be created and initialized + * to default values. @c size and @c capacity give the size for the + * new aux data item vector. + * + * If the container is locked, throw an exception. + */ +void* AuxStoreRoot::getData(SG::auxid_t auxid, + size_t /*size*/, size_t /*capacity*/) +{ + // MN: how do we add new attributes to this store? A:for now we don't + return const_cast<void*>(getData(auxid)); +} + + + + +/** + * @brief Return the data vector for one aux data decoration item. + * @param auxid The identifier of the desired aux data item. + * @param size The current size of the container (in case the data item + * does not already exist). + * @param capacity The current capacity of the container (in case + * the data item does not already exist). + * + * Each aux data item is stored as a vector, with one entry + * per entry in the owning container. This returns a pointer + * to the start of the vector. + * + * The base class implementation works except for the case where we have + * not yet created a vector for an item in the root file. We need to + * detect that case and raise an exception. + */ +void* +AuxStoreRoot::getDecoration (SG::auxid_t auxid, size_t size, size_t capacity) +{ + guard_t guard (m_mutex); + if (SG::AuxStoreInternal::getIODataInternal (auxid, true) == 0 && + SG::AuxStoreInternal::getAuxIDs().count (auxid) > 0) + { + throw SG::ExcStoreLocked (auxid); + } + return SG::AuxStoreInternal::getDecoration (auxid, size, capacity); +} + + +/** + * @brief Return a pointer to the data to be stored for one aux data item. + * @param auxid The identifier of the desired aux data item. + * + * This will usually be a pointer to a @c std::vector; however, it may + * be something different for a standalone object. + * + * Returns 0 and reports an error if the requested aux data item + * does not exist. + */ +const void* AuxStoreRoot::getIOData(SG::auxid_t auxid) const +{ + guard_t guard (m_mutex); + const void* ret = SG::AuxStoreInternal::getIODataInternal (auxid, true); + if (!ret) { + if (const_cast<AuxStoreRoot*>(this)->readData(auxid)) + ret = SG::AuxStoreInternal::getIOData (auxid); + } + return ret; +} + + +/** + * @brief Derived classes should call this from their constructor + * to complete initialization. + * + * Creates the auxid set from the list of branches. + * This cannot be done from the @c AuxStoreRoot constructor as it needs + * to call the @c resolveAuxID virtual method. + */ +void AuxStoreRoot::fillAuxIDs() +{ + for( const auto& attr2branch: m_container.auxBranches() ) { + const std::string& attr = attr2branch.first; + std::string elemen_type_name; + std::string branch_type_name; + const std::type_info* ti = getElementType(attr2branch.second, + standalone(), + elemen_type_name, + branch_type_name); + SG::auxid_t auxid = resolveAuxID (m_container, + ti, attr, + elemen_type_name, + branch_type_name); + + // add AuxID to the list + // May still be null if we don't have a dictionary for the branch. + if (auxid != SG::null_auxid) + addAuxID (auxid); + } + + //lock(); +} + + +/** + * @brief Change the TTree entry being read. + * @param entry New entry being read. + */ +void AuxStoreRoot::setEntry (long long entry) +{ + m_entry = entry; +} + + +/** + * @brief Read data from ROOT and store it in the internal vector. + * + * Returns true on success, false on failure. + */ +bool AuxStoreRoot::readData(SG::auxid_t auxid) +{ + TBranch* branch = m_container.findAuxBranch(auxid); + // check if there is a branch in the file + if( !branch ) return false; + + TClass* cl = 0; + EDataType typ; + if( branch->GetExpectedType(cl, typ) ) { + ATHCONTAINERS_ERROR("AuxStoreRoot::readData", + std::string("Error getting branch type for ") + branch->GetName() ); + return false; + } + + // Make a 1-element vector. + SG::AuxStoreInternal::getDataInternal(auxid, 1, 1, true); + if (!standalone()) { + if (cl && strncmp (cl->GetName(), "SG::PackedContainer<", 20) == 0) + setOption (auxid, SG::AuxDataOption ("nbits", 32)); + } + + void* vector = const_cast<void*>(SG::AuxStoreInternal::getIOData (auxid)); // xxx + + return doReadData (m_container, auxid, *branch, cl, vector, m_entry); +} + + +} // namespace SG diff --git a/Control/AthContainersRoot/src/RootAuxVectorFactory.cxx b/Control/AthContainersRoot/src/RootAuxVectorFactory.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0d9ff588ac8232d7e357d7c01a1be53300d58715 --- /dev/null +++ b/Control/AthContainersRoot/src/RootAuxVectorFactory.cxx @@ -0,0 +1,433 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainersRoot/src/RootAuxVectorFactory.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2014 + * @brief Dynamic implementation of @c IAuxVectorFactory, + * relying on root vector proxy. + */ + + +#include "AthContainersRoot/RootAuxVectorFactory.h" +#include "AthContainers/tools/error.h" +#include "TClass.h" +#include "TVirtualCollectionProxy.h" +#include "TROOT.h" +#include <iostream> +#include <stdexcept> + + +namespace { + + +/** + * @brief Find the vector type associated with @c CL by looking + * up the @c vector_type typedef. + * @param cl The class for which to find the associated vector type. + * + * Given type CL, looks for a typedef CL::vector_type and returns the TClass + * for that if found. Works for, eg, SG::PackedContainer. + */ +TClass* lookupVectorType (TClass *cl) +{ + std::string tname = cl->GetName(); + tname += "::vector_type"; + TDataType* typ = gROOT->GetType (tname.c_str()); + if (typ) + return TClass::GetClass (typ->GetFullTypeName()); + return nullptr; +} + + +} // anonymous namespace + + +namespace SG { + + +/** + * @brief Constructor. Makes a new vector. + * @param factory The factory object for this type. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + */ +RootAuxVector::RootAuxVector (const RootAuxVectorFactory* factory, + size_t size, size_t /*capacity*/) + : m_factory (factory), + m_ownFlag (true) +{ + TClass* vecClass = factory->vecClass(); + m_proxy = vecClass->GetCollectionProxy(); + m_obj = factory->objClass()->New (); + m_vec = reinterpret_cast<char*> (m_obj) + factory->offset(); + this->resize (size); +} + + +/** + * @brief Constructor, from a pointer to a vector object. + * @param data The vector object. + * @param isPacked If true, @c data is a @c PackedContainer. + * @param ownFlag If true, then take ownership of @c data. + * + * If the element type is T, then @c data should be a pointer + * to a std::vector<T> object, which was obtained with @c new. + * + * This version does not support packed containers, so @c isPacked + * must be false. + */ +RootAuxVector::RootAuxVector (const RootAuxVectorFactory* factory, + void* data, + bool isPacked, + bool ownFlag) + : m_factory (factory), + m_ownFlag (ownFlag) +{ + if (isPacked) std::abort(); + TClass* vecClass = factory->vecClass(); + m_proxy = vecClass->GetCollectionProxy(); + m_obj = data; + m_vec = reinterpret_cast<char*> (m_obj) + factory->offset(); +} + + +/** + * @brief Copy constructor. + * @param other The vector to copy. + */ +RootAuxVector::RootAuxVector (const RootAuxVector& other) + : m_factory (other.m_factory), + m_proxy (other.m_proxy), + m_ownFlag (true) +{ + m_obj = m_factory->objClass()->New (); + m_vec = reinterpret_cast<char*> (m_obj) + m_factory->offset(); + size_t sz = other.size(); + this->resize (sz); + + if (sz > 0) { + const RootUtils::Type& rootType = m_factory->rootType(); + + const void* otherPtr = 0; + { + TVirtualCollectionProxy::TPushPop bind (m_proxy, other.m_vec); + otherPtr = m_proxy->At(0); + } + + rootType.copyRange (this->toPtr(), otherPtr, sz); + } +} + + +/** + * @brief Destructor. + * + * This will free the vector data. + */ +RootAuxVector::~RootAuxVector() +{ + if (m_ownFlag) + m_factory->objClass()->Destructor (m_obj); +} + + +/** + * @brief Make a copy of this vector. + */ +SG::IAuxTypeVector* RootAuxVector::clone() const +{ + return new RootAuxVector (*this); +} + + +/** + * @brief Return a pointer to the start of the vector's data. + */ +void* RootAuxVector::toPtr () +{ + TVirtualCollectionProxy::TPushPop bind (m_proxy, m_vec); + if (m_proxy->Size() == 0) + return 0; + return m_proxy->At(0); +} + + +/** + * @brief Return a pointer to the overall object. + */ +void* RootAuxVector::toVector () +{ + return m_obj; +} + + +/** + * @brief Return the size of the vector. + */ +size_t RootAuxVector::size() const +{ + TVirtualCollectionProxy::TPushPop bind (m_proxy, m_vec); + return m_proxy->Size(); +} + + +/** + * @brief Change the size of the vector. + * @param sz The new vector size. + */ +void RootAuxVector::resize (size_t sz) +{ + TVirtualCollectionProxy::TPushPop bind (m_proxy, m_vec); + m_proxy->Allocate(sz, false); +} + + +/** + * @brief Change the capacity of the vector. + * @param sz The new vector capacity. + */ +void RootAuxVector::reserve (size_t /*sz*/) +{ +} + + +/** + * @brief Shift the elements of the vector. + * @param pos The starting index for the shift. + * @param offs The (signed) amount of the shift. + * + * This operation shifts the elements in the vectors for all + * aux data items, to implement an insertion or deletion. + * @c offs may be either positive or negative. + * + * If @c offs is positive, then the container is growing. + * The container size should be increased by @c offs, + * the element at @c pos moved to @c pos + @c offs, + * and similarly for following elements. + * The elements between @c pos and @c pos + @c offs should + * be default-initialized. + * + * If @c offs is negative, then the container is shrinking. + * The element at @c pos should be moved to @c pos + @c offs, + * and similarly for following elements. + * The container should then be shrunk by @c -offs elements + * (running destructors as appropriate). + */ +void RootAuxVector::shift (size_t pos, ptrdiff_t offs) +{ + TVirtualCollectionProxy::TPushPop bind (m_proxy, m_vec); + size_t eltsz = m_proxy->GetIncrement(); + + const RootUtils::Type& rootType = m_factory->rootType(); + + if (offs < 0) { + if (-offs > static_cast<ptrdiff_t>(pos)) offs = -pos; + char* beg = reinterpret_cast<char*>(m_proxy->At(0)); + rootType.copyRange (beg + eltsz*(pos+offs), + beg + eltsz*pos, + m_proxy->Size() - pos); + m_proxy->Allocate (m_proxy->Size() + offs, false); + } + else if (offs > 0) { + size_t oldsz = m_proxy->Size(); + m_proxy->Allocate (oldsz + offs, false); + char* beg = reinterpret_cast<char*>(m_proxy->At(0)); + rootType.copyRange (beg + eltsz*(pos+offs), + beg + eltsz*pos, + m_proxy->Size() - pos - offs); + rootType.clearRange (beg + eltsz*pos, offs); + } +} + + +/** + * @brief Return the type of the complete object to be saved. + * + * For example, if the object is a @c std::vector, then we return + * the @c type_info of the vector. But if we're holding + * a @c PackedContainer, then we return the @c type_info of the + * @c PackedContainer. + * + * Can return null if the operation is not supported. In that case, + * I/O will use the type found from the variable registry. + */ +const std::type_info* RootAuxVector::objType() const +{ + return m_factory->objClass()->GetTypeInfo(); +} + + +//================================================================== + + +/** + * @brief Constructor. + * @param vecClass The @c TClass for the vector object. + */ +RootAuxVectorFactory::RootAuxVectorFactory (TClass* objClass) + : m_objClass (objClass), + m_vecClass (objClass), + m_offset (0) +{ + TVirtualCollectionProxy* proxy = m_vecClass->GetCollectionProxy(); + + if (!proxy) { + TClass* vecClass = lookupVectorType (objClass); + if (vecClass) { + m_vecClass = vecClass; + Int_t offs = objClass->GetBaseClassOffset (vecClass); + if (offs >= 0) { + m_offset = offs; + proxy = vecClass->GetCollectionProxy(); + } + else { + ATHCONTAINERS_ERROR("RootAuxVectorFactory::RootAuxVectorFactory", + std::string("Can't find vector base class in ") + + objClass->GetName()); + } + } + } + + if (!proxy) { + std::string err = "Can't find collection proxy for "; + err += m_vecClass->GetName(); + throw std::runtime_error (err.c_str()); + } + + if (m_vecClass->GetTypeInfo() == 0) { + ATHCONTAINERS_ERROR("RootAuxVectorFactory::RootAuxVectorFactory", + std::string("No type_info available for class ") + + m_vecClass->GetName() + + std::string(". There is probably a missing dictionary. We will likely crash further on.")); + } + + TClass* eltClass = proxy->GetValueClass(); + if (eltClass) + m_type.init (eltClass); + else + m_type.init (proxy->GetType()); +} + + +/** + * @brief Destructor. + */ +RootAuxVectorFactory::~RootAuxVectorFactory() +{ +} + + +/** + * @brief Create a vector object of this type. + * @param size Initial size of the new vector. + * @param capacity Initial capacity of the new vector. + */ +SG::IAuxTypeVector* +RootAuxVectorFactory::create (size_t size, size_t capacity) const +{ + return new RootAuxVector (this, size, capacity); +} + + +/** + * @brief Create a vector object of this type from a data blob. + * @param data The vector object. + * @param isPacked If true, @c data is a @c PackedContainer. + * @param ownFlag If true, the newly-created IAuxTypeVector object + * will take ownership of @c data. + * + * If the element type is T, then @c data should be a pointer + * to a std::vector<T> object, which was obtained with @c new. + * + * This version does not support packed containers, so @c isPacked + * must be false. + * + * Returns a newly-allocated object. + * FIXME: Should return a unique_ptr. + */ +SG::IAuxTypeVector* +RootAuxVectorFactory::createFromData (void* data, + bool isPacked, + bool ownFlag) const +{ + return new RootAuxVector (this, data, isPacked, ownFlag); +} + + +/** + * @brief Copy an element between vectors. + * @param dst Pointer to the start of the destination vector's data. + * @param dst_index Index of destination element in the vector. + * @param src Pointer to the start of the source vector's data. + * @param src_index Index of source element in the vector. + * + * @c dst and @ src can be either the same or different. + */ +void RootAuxVectorFactory::copy (void* dst, size_t dst_index, + const void* src, size_t src_index) const +{ + m_type.assign (dst, dst_index, src, src_index); +} + + +/** + * @brief Swap an element between vectors. + * @param a Pointer to the start of the first vector's data. + * @param aindex Index of the element in the first vector. + * @param b Pointer to the start of the second vector's data. + * @param bindex Index of the element in the second vector. + * + * @c a and @ b can be either the same or different. + */ +void RootAuxVectorFactory::swap (void* a, size_t aindex, + void* b, size_t bindex) const +{ + m_type.swap (a, aindex, b, bindex); +} + + +/** + * @brief Clear an element within a vector (static method). + * @param dst Pointer to the start of the vector's data. + * @param dst_index Index of the element in the vector. + */ +void RootAuxVectorFactory::clear (void* dst, size_t dst_index) const +{ + m_type.clear (dst, dst_index); +} + + +/** + * @brief Return the size of an element of this vector type. + */ +size_t RootAuxVectorFactory::getEltSize() const +{ + return m_type.getSize(); +} + + +/** + * @brief Return the @c type_info of the overall object. + */ +const std::type_info* RootAuxVectorFactory::tiVec() const +{ + return m_objClass->GetTypeInfo(); +} + + +/** + * @brief True if the vectors created by this factory work by dynamic + * emulation (via @c TVirtualCollectionProxy or similar); false + * if the std::vector code is used directly. + */ +bool RootAuxVectorFactory::isDynamic() const +{ + return true; +} + + +} // namespace SG diff --git a/Control/AthContainersRoot/src/getDynamicAuxID.cxx b/Control/AthContainersRoot/src/getDynamicAuxID.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f25bbccb4940a480287a727cdcb57ac27d0a2d4c --- /dev/null +++ b/Control/AthContainersRoot/src/getDynamicAuxID.cxx @@ -0,0 +1,111 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainersRoot/src/getDynamicAuxID.h + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2016 + * @brief Find the auxid for a dynamic branch. + */ + + +#include "AthContainersRoot/getDynamicAuxID.h" +#include "AthContainersRoot/RootAuxVectorFactory.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "TClass.h" +#include "TROOT.h" + + +namespace SG { + + +/** + * @brief Look up a @c TClass given a name. Try to avoid autoparsing. + * @param cname Name of the class to find. + */ +TClass* getClassIfDictionaryExists (const std::string& cname) +{ + if (TClass* cl = (TClass*)gROOT->GetListOfClasses()->FindObject(cname.c_str())) { + if (cl->IsLoaded() && cl->HasDictionary()) return cl; + return nullptr; + } + + if (gInterpreter->GetClassSharedLibs (cname.c_str())) { + TClass* cl = TClass::GetClass (cname.c_str()); + if (cl->HasDictionary()) + return cl; + } + return nullptr; +} + + +/** + * @brief Find the auxid for a dynamic branch. + * @param ti Type of the auxiliary variable. + * Usually the type of the vector payload, but if @c standalone + * is true, then this is the type of the stored object. + * @param name Auxiliary variable name. + * @param elementTypeName Name of the type for one aux data element. + * Should be the samr as @c branchTypeName + * if @c standalone is true. + * @param branchTypeName Name of the type for this branch. + * @param standalone True if this is a standalone object. + */ +SG::auxid_t getDynamicAuxID (const std::type_info& ti, + const std::string& name, + const std::string& elementTypeName, + const std::string& branchTypeName, + bool standalone) +{ + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + SG::auxid_t auxid = SG::null_auxid; + + auxid = r.getAuxID (ti, name); + if (auxid != SG::null_auxid) return auxid; + + std::string fac_class_name = "SG::AuxTypeVectorFactory<" + + elementTypeName; + if (fac_class_name[fac_class_name.size()-1] == '>') + fac_class_name += ' '; + fac_class_name += '>'; + TClass* fac_class = getClassIfDictionaryExists (fac_class_name); + if (fac_class) + { + TClass* base_class = getClassIfDictionaryExists ("SG::IAuxTypeVectorFactory"); + if (base_class) { + int offs = fac_class->GetBaseClassOffset (base_class); + if (offs >= 0) { + void* fac_vp = fac_class->New(); + if (fac_vp) { + SG::IAuxTypeVectorFactory* fac = reinterpret_cast<SG::IAuxTypeVectorFactory*> (reinterpret_cast<unsigned long>(fac_vp) + offs); + r.addFactory (ti, fac); + auxid = r.getAuxID(ti, name); + } + } + } + } + + if (auxid == SG::null_auxid) { + std::string vec_name = branchTypeName; + if (standalone) { + vec_name = "std::vector<" + branchTypeName; + if (vec_name[vec_name.size()-1] == '>') + vec_name += " "; + vec_name += ">"; + } + TClass* vec_class = TClass::GetClass (vec_name.c_str()); + + if (vec_class) { + SG::IAuxTypeVectorFactory* fac = new SG::RootAuxVectorFactory (vec_class); + r.addFactory (ti, fac); + auxid = r.getAuxID(ti, name); + } + } + + return auxid; +} + + +} // namespace SG diff --git a/Control/AthContainersRoot/test/AthContainersRoot.xml b/Control/AthContainersRoot/test/AthContainersRoot.xml new file mode 100644 index 0000000000000000000000000000000000000000..5a8c28aa94b8255506b1e89114a3f515bcf18b79 --- /dev/null +++ b/Control/AthContainersRoot/test/AthContainersRoot.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<atn> + <TEST name="AthContainersRootTest" type="makecheck" suite="Examples"> + <package>Control/AthContainersRoot</package> + <timelimit>40</timelimit> + <author> scott snyder </author> + <mailto> snyder@bnl.gov </mailto> + <expectations> + <errorMessage>Athena exited abnormally</errorMessage> + <errorMessage>differ</errorMessage> + <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage> + <successMessage>check ok</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/Control/AthContainersRoot/test/AuxStoreRoot_test.cxx b/Control/AthContainersRoot/test/AuxStoreRoot_test.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a29ea4385e2eb8e92e8e2eeabc96152864af533e --- /dev/null +++ b/Control/AthContainersRoot/test/AuxStoreRoot_test.cxx @@ -0,0 +1,345 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainersRoot/test/AuxStoreRoot_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2016 + * @brief Regression test for AuxStoreRoot. + */ + + +#undef NDEBUG +#include "AthContainersRoot/AuxStoreRoot.h" +#include "AthContainersRoot/AthContainersRootTestDict.h" +#include "AthContainers/AuxElement.h" +#include "TestTools/expect_exception.h" +#include "TTree.h" +#include "TBranch.h" +#include <iostream> +#include <cassert> + + +class TestBranches + : public SG::IAuxBranches +{ +public: + TestBranches (bool standalone); + virtual const std::string& getName() const override; + virtual std::vector<auxpair_t> auxBranches() const override; + virtual TBranch* findAuxBranch (SG::auxid_t auxid) override; + virtual StatusCode readAuxBranch (TBranch& br, void* p, long long entry) override; + virtual StatusCode readAuxBranch (TBranch& br, void* p, + const std::type_info& ti, long long entry) override; + + + std::string m_name; + TTree m_tree; + TBranch* m_br_foo; + TBranch* m_br_bar; + TBranch* m_br_baz; + + SG::auxid_t m_foo_id; + SG::auxid_t m_bar_id; + SG::auxid_t m_baz_id; + SG::auxid_t m_fee_id; +}; + + +TestBranches::TestBranches (bool standalone) + : m_name("TestBranches"), + m_tree (m_name.c_str(), m_name.c_str()) +{ + if (standalone) { + m_br_foo = + m_tree.Branch ("foo", "AthContainersRootTest::Foo", nullptr); + m_br_bar = + m_tree.Branch ("bar", "AthContainersRootTest::Bar", nullptr); + m_br_baz = + m_tree.Branch ("baz", static_cast<void*>(nullptr), "baz/I"); + } + else { + m_br_foo = + m_tree.Branch ("foo", "std::vector<AthContainersRootTest::Foo>", nullptr); + m_br_bar = + m_tree.Branch ("bar", "std::vector<AthContainersRootTest::Bar>", nullptr); + m_br_baz = + m_tree.Branch ("baz", "SG::PackedContainer<int>", nullptr); + } + + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + m_foo_id = r.getAuxID<AthContainersRootTest::Foo> ("foo"); + m_bar_id = r.getAuxID<AthContainersRootTest::Bar> ("bar"); + m_baz_id = r.getAuxID<int> ("baz"); + m_fee_id = r.getAuxID<float> ("fee"); +} + + +const std::string& TestBranches::getName() const +{ + return m_name; +} + + +std::vector<SG::IAuxBranches::auxpair_t> TestBranches::auxBranches() const +{ + std::vector<SG::IAuxBranches::auxpair_t> v; + v.emplace_back ("foo", m_br_foo); + v.emplace_back ("bar", m_br_bar); + v.emplace_back ("baz", m_br_baz); + return v; +} + + +TBranch* TestBranches::findAuxBranch (SG::auxid_t auxid) +{ + if (auxid == m_foo_id) + return m_br_foo; + if (auxid == m_bar_id) + return m_br_bar; + if (auxid == m_baz_id) + return m_br_baz; + return nullptr; +} + + +StatusCode +TestBranches::readAuxBranch (TBranch& /*br*/, void* /*p*/, long long /*entry*/) +{ + std::abort(); +} + + +StatusCode +TestBranches::readAuxBranch (TBranch& /*br*/, void* /*p*/, + const std::type_info& /*ti*/, + long long /*entry*/) +{ + std::abort(); +} + + +class AuxStoreRootTest + : public SG::AuxStoreRoot +{ +public: + AuxStoreRootTest (SG::IAuxBranches& container, + long long entry, + bool standalone); + + using SG::AuxStoreRoot::setEntry; + + virtual SG::auxid_t resolveAuxID (SG::IAuxBranches& container, + const std::type_info* ti, + const std::string& name, + const std::string& elem_type_name, + const std::string& branch_type_name) override; + + virtual bool doReadData (SG::IAuxBranches& container, + SG::auxid_t auxid, + TBranch& branch, + TClass* cl, + void* vector, + long long entry) override; + + struct DRDLog + { + SG::IAuxBranches& m_container; + SG::auxid_t m_auxid; + TBranch& m_branch; + TClass* m_cl; + void* m_vector; + long long m_entry; + + DRDLog (SG::IAuxBranches& container, + SG::auxid_t auxid, + TBranch& branch, + TClass* cl, + void* vector, + long long entry) + : m_container (container), + m_auxid (auxid), + m_branch (branch), + m_cl (cl), + m_vector (vector), + m_entry (entry) + { + } + }; + + std::vector<DRDLog> m_log; +}; + + +AuxStoreRootTest::AuxStoreRootTest (SG::IAuxBranches& container, + long long entry, + bool standalone) + : SG::AuxStoreRoot (container, entry, standalone) +{ + fillAuxIDs(); +} + + +SG::auxid_t +AuxStoreRootTest::resolveAuxID (SG::IAuxBranches& /*container*/, + const std::type_info* ti, + const std::string& name, + const std::string& elem_type_name, + const std::string& branch_type_name) +{ + if (name == "foo") { + SG::AuxElement::Accessor<AthContainersRootTest::Foo> a ("foo"); + assert (elem_type_name == "AthContainersRootTest::Foo"); + if (standalone()) { + assert (branch_type_name == "AthContainersRootTest::Foo"); + } + else { + assert (branch_type_name == "vector<AthContainersRootTest::Foo>"); + } + assert (*ti == typeid (AthContainersRootTest::Foo)); + return a.auxid(); + } + else if (name == "bar") { + SG::AuxElement::Accessor<AthContainersRootTest::Bar> a ("bar"); + assert (elem_type_name == "AthContainersRootTest::Bar"); + if (standalone()) { + assert (branch_type_name == "AthContainersRootTest::Bar"); + } + else { + assert (branch_type_name == "vector<AthContainersRootTest::Bar>"); + } + assert (*ti == typeid (AthContainersRootTest::Bar)); + return a.auxid(); + } + else if (name == "baz") { + SG::AuxElement::Accessor<int> a ("baz"); + if (standalone()) { + assert (elem_type_name == "Int_t"); + assert (branch_type_name == "Int_t"); + } + else { + assert (elem_type_name == "int"); + assert (branch_type_name == "SG::PackedContainer<int>"); + } + assert (*ti == typeid (int)); + return a.auxid(); + } + return SG::null_auxid; +} + + +bool AuxStoreRootTest::doReadData (SG::IAuxBranches& container, + SG::auxid_t auxid, + TBranch& branch, + TClass* cl, + void* vector, + long long entry) +{ + m_log.emplace_back (container, auxid, branch, + cl, vector, entry); + + if ((entry&1) == 0) + return true; + return false; +} + + +void test1() +{ + std::cout << "test1\n"; + + TestBranches branches (false); + AuxStoreRootTest store (branches, 122, false); + std::set<SG::auxid_t> aset { branches.m_foo_id, branches.m_bar_id, branches.m_baz_id }; + assert (std::set<SG::auxid_t> (store.getAuxIDs().begin(), + store.getAuxIDs().end()) == aset); + store.m_log.clear(); + + const void* d = store.getData (branches.m_foo_id); + assert (d != nullptr); + assert (store.m_log.size() == 1); + assert (&store.m_log[0].m_container == &branches); + assert (store.m_log[0].m_auxid == branches.m_foo_id); + assert (&store.m_log[0].m_branch == branches.m_br_foo); + assert (std::string(store.m_log[0].m_cl->GetName()) == "vector<AthContainersRootTest::Foo>"); + assert (store.m_log[0].m_entry == 122); + auto foo_vec = reinterpret_cast<std::vector<AthContainersRootTest::Foo>* > (store.m_log[0].m_vector); + assert (foo_vec->size() == 1); + assert (foo_vec->data() == d); + + d = store.getData (branches.m_foo_id); + assert (foo_vec->data() == d); + assert (store.m_log.size() == 1); + + d = store.getIOData (branches.m_foo_id); + assert (foo_vec == d); + assert (store.m_log.size() == 1); + + d = store.getDecoration (branches.m_foo_id, 1, 1); + assert (foo_vec->data() == d); + assert (store.m_log.size() == 1); + + d = store.getDecoration (branches.m_fee_id, 1, 1); + assert (d != nullptr); + assert (store.m_log.size() == 1); + + EXPECT_EXCEPTION (SG::ExcStoreLocked, + store.getDecoration (branches.m_bar_id, 1, 1)); + + d = store.getData (branches.m_baz_id); + assert (store.m_log.size() == 2); + assert (&store.m_log[1].m_container == &branches); + assert (store.m_log[1].m_auxid == branches.m_baz_id); + assert (&store.m_log[1].m_branch == branches.m_br_baz); + assert (std::string(store.m_log[1].m_cl->GetName()) == "SG::PackedContainer<int>"); + assert (store.m_log[1].m_entry == 122); + auto baz_vec = reinterpret_cast<SG::PackedContainer<int>* > (store.m_log[1].m_vector); + assert (baz_vec->size() == 1); + assert (baz_vec->data() == d); + assert (baz_vec->parms().nbits() == 32); + + store.setEntry (123); + d = store.getData (branches.m_bar_id); + assert (d == nullptr); + assert (store.m_log.size() == 3); + assert (&store.m_log[2].m_container == &branches); + assert (store.m_log[2].m_auxid == branches.m_bar_id); + assert (&store.m_log[2].m_branch == branches.m_br_bar); + assert (std::string(store.m_log[2].m_cl->GetName()) == "vector<AthContainersRootTest::Bar>"); + assert (store.m_log[2].m_entry == 123); +} + + +// Standalone case +void test2() +{ + std::cout << "test2\n"; + + TestBranches branches (true); + AuxStoreRootTest store (branches, 122, true); + std::set<SG::auxid_t> aset { branches.m_foo_id, branches.m_bar_id, branches.m_baz_id }; + assert (std::set<SG::auxid_t> (store.getAuxIDs().begin(), + store.getAuxIDs().end()) == aset); + store.m_log.clear(); + + const void* d = store.getData (branches.m_foo_id); + assert (d != nullptr); + assert (store.m_log.size() == 1); + assert (&store.m_log[0].m_container == &branches); + assert (store.m_log[0].m_auxid == branches.m_foo_id); + assert (&store.m_log[0].m_branch == branches.m_br_foo); + assert (std::string(store.m_log[0].m_cl->GetName()) == "AthContainersRootTest::Foo"); + assert (store.m_log[0].m_entry == 122); + assert (store.m_log[0].m_vector == d); +} + + +int main() +{ + test1(); + test2(); + return 0; +} + diff --git a/Control/AthContainersRoot/test/RootAuxVectorFactory_test.cxx b/Control/AthContainersRoot/test/RootAuxVectorFactory_test.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8847097923dec9f5017842955c686b5518f4de76 --- /dev/null +++ b/Control/AthContainersRoot/test/RootAuxVectorFactory_test.cxx @@ -0,0 +1,251 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainersRoot/test/RootAuxVectorFactory_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2014 + * @brief Regression test for RootAuxVectorFactory. + */ + + +#undef NDEBUG +#include "AthContainersRoot/RootAuxVectorFactory.h" +#include "CxxUtils/StrFormat.h" +#include "TClass.h" +#include <iostream> +#include <cassert> + + +std::string str (int x) +{ + return CxxUtils::strformat ("%d", x); +} + + +void test1() +{ + std::cout << "test1\n"; + TClass* cl = TClass::GetClass ("vector<int>"); + SG::RootAuxVectorFactory fac (cl); + SG::IAuxTypeVector* vec = new SG::RootAuxVector (&fac, 10, 10); + assert (vec->size() == 10); + int* ptr = reinterpret_cast<int*> (vec->toPtr()); + for (int i=0; i < 10; i++) + ptr[i] = i+1; + vec->resize (100); + vec->reserve (100); + ptr = reinterpret_cast<int*> (vec->toPtr()); + for (int i=0; i < 10; i++) + assert (ptr[i] == i+1); + std::vector<int>* pvec = reinterpret_cast<std::vector<int>*> (vec->toVector()); + assert (pvec->size() == 100); + for (int i=0; i < 10; i++) + assert ((*pvec)[i] == i+1); + + // 1 2 3 4 5 6 7 8 9 10 + + vec->resize (10); + vec->shift (7, -3); + assert (vec->size() == 7); + // 1 2 3 4 8 9 10 + ptr = reinterpret_cast<int*> (vec->toPtr()); + assert (ptr[0] == 1); + assert (ptr[1] == 2); + assert (ptr[2] == 3); + assert (ptr[3] == 4); + assert (ptr[4] == 8); + assert (ptr[5] == 9); + assert (ptr[6] == 10); + + vec->shift (3, 2); + assert (vec->size() == 9); + // 1 2 3 0 0 4 8 9 10 + ptr = reinterpret_cast<int*> (vec->toPtr()); + assert (ptr[0] == 1); + assert (ptr[1] == 2); + assert (ptr[2] == 3); + assert (ptr[3] == 0); + assert (ptr[4] == 0); + assert (ptr[5] == 4); + assert (ptr[6] == 8); + assert (ptr[7] == 9); + assert (ptr[8] == 10); + + SG::IAuxTypeVector* vec2 = vec->clone(); + int* ptr2 = reinterpret_cast<int*> (vec2->toPtr()); + assert (ptr != ptr2); + assert (ptr2[0] == 1); + assert (ptr2[1] == 2); + assert (ptr2[2] == 3); + assert (ptr2[3] == 0); + assert (ptr2[4] == 0); + assert (ptr2[5] == 4); + assert (ptr2[6] == 8); + assert (ptr2[7] == 9); + assert (ptr2[8] == 10); + + + vec->resize (0); + assert (vec->toPtr() == 0); + + delete vec; +} + + +void test2() +{ + std::cout << "test2\n"; + TClass* cl = TClass::GetClass ("vector<std::string>"); + SG::RootAuxVectorFactory fac (cl); + SG::IAuxTypeVector* vec = new SG::RootAuxVector (&fac, 10, 10); + assert (vec->size() == 10); + std::string* ptr = reinterpret_cast<std::string*> (vec->toPtr()); + for (int i=0; i < 10; i++) + ptr[i] = str(i+1); + vec->resize (100); + vec->reserve (100); + ptr = reinterpret_cast<std::string*> (vec->toPtr()); + for (int i=0; i < 10; i++) + assert (ptr[i] == str(i+1)); + std::vector<std::string>* pvec = reinterpret_cast<std::vector<std::string>*> (vec->toVector()); + assert (pvec->size() == 100); + for (int i=0; i < 10; i++) + assert ((*pvec)[i] == str(i+1)); + + // 1 2 3 4 5 6 7 8 9 10 + + vec->resize (10); + vec->shift (7, -3); + assert (vec->size() == 7); + // 1 2 3 4 8 9 10 + ptr = reinterpret_cast<std::string*> (vec->toPtr()); + assert (ptr[0] == str(1)); + assert (ptr[1] == str(2)); + assert (ptr[2] == str(3)); + assert (ptr[3] == str(4)); + assert (ptr[4] == str(8)); + assert (ptr[5] == str(9)); + assert (ptr[6] == str(10)); + + vec->shift (3, 2); + assert (vec->size() == 9); + // 1 2 3 "" "" 4 8 9 10 + ptr = reinterpret_cast<std::string*> (vec->toPtr()); + assert (ptr[0] == str(1)); + assert (ptr[1] == str(2)); + assert (ptr[2] == str(3)); + assert (ptr[3] == ""); + assert (ptr[4] == ""); + assert (ptr[5] == str(4)); + assert (ptr[6] == str(8)); + assert (ptr[7] == str(9)); + assert (ptr[8] == str(10)); + + delete vec; +} + + +void test3() +{ + std::cout << "test3\n"; + TClass* cl = TClass::GetClass ("vector<int>"); + SG::RootAuxVectorFactory fac (cl); + assert (fac.vecClass() == cl); + assert (fac.getEltSize() == sizeof(int)); + assert (fac.tiVec() == &typeid(std::vector<int>)); + assert (fac.isDynamic()); + SG::IAuxTypeVector* vec = fac.create (10, 10); + assert (vec->size() == 10); + + int* ptr = reinterpret_cast<int*> (vec->toPtr()); + ptr[0] = 1; + ptr[1] = 2; + fac.copy (ptr, 5, ptr, 1); + assert (ptr[1] == 2); + assert (ptr[5] == 2); + + fac.clear (ptr, 1); + assert (ptr[1] == 0); + + fac.swap (ptr, 0, ptr, 5); + assert (ptr[0] == 2); + assert (ptr[5] == 1); + + delete vec; +} + + +void test4() +{ + std::cout << "test4\n"; + TClass* cl = TClass::GetClass ("vector<std::string>"); + SG::RootAuxVectorFactory fac (cl); + assert (fac.vecClass() == cl); + assert (fac.getEltSize() == sizeof(std::string)); + assert (fac.tiVec() == &typeid(std::vector<std::string>)); + assert (fac.isDynamic()); + SG::IAuxTypeVector* vec = fac.create (10, 10); + assert (vec->size() == 10); + + std::string* ptr = reinterpret_cast<std::string*> (vec->toPtr()); + ptr[0] = "1"; + ptr[1] = "2"; + fac.copy (ptr, 5, ptr, 1); + assert (ptr[1] == "2"); + assert (ptr[5] == "2"); + + fac.clear (ptr, 1); + assert (ptr[1] == ""); + + fac.swap (ptr, 0, ptr, 5); + assert (ptr[0] == "2"); + assert (ptr[5] == "1"); + + delete vec; +} + + +void test5() +{ + std::cout << "test5\n"; + + TClass* cl = TClass::GetClass ("vector<int>"); + SG::RootAuxVectorFactory fac (cl); + + std::vector<int>* vec1 = new std::vector<int>; + vec1->push_back(3); + vec1->push_back(2); + vec1->push_back(1); + SG::IAuxTypeVector* v1 = fac.createFromData (vec1, false, true); + assert (v1->size() == 3); + int* ptr1 = reinterpret_cast<int*> (v1->toPtr()); + assert (ptr1[0] == 3); + assert (ptr1[1] == 2); + assert (ptr1[2] == 1); + delete v1; + + std::vector<int>* vec2 = new std::vector<int>; + vec2->push_back(4); + vec2->push_back(5); + SG::IAuxTypeVector* v2 = fac.createFromData (vec2, false, false); + assert (v2->size() == 2); + int* ptr2 = reinterpret_cast<int*> (v2->toPtr()); + assert (ptr2[0] == 4); + assert (ptr2[1] == 5); + delete v2; + delete vec2; +} + + +int main() +{ + test1(); + test2(); + test3(); + test4(); + test5(); + return 0; +} diff --git a/Control/AthContainersRoot/test/getDynamicAuxID_test.cxx b/Control/AthContainersRoot/test/getDynamicAuxID_test.cxx new file mode 100644 index 0000000000000000000000000000000000000000..bc9c3b32adc1a8606a6fc77b625955817974a1b9 --- /dev/null +++ b/Control/AthContainersRoot/test/getDynamicAuxID_test.cxx @@ -0,0 +1,98 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthContainersRoot/test/getDynamicAuxID_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Oct, 2016 + * @brief Regression test for getDynamicAuxID. + */ + + +#undef NDEBUG +#include "AthContainersRoot/getDynamicAuxID.h" +#include "AthContainersRoot/AthContainersRootTestDict.h" +#include "AthContainersRoot/RootAuxVectorFactory.h" +#include "AthContainers/AuxElement.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "TInterpreter.h" +#include "TROOT.h" +#include "TClass.h" +#include <iostream> +#include <cassert> + + +void test1 (SG::auxid_t a1_id) +{ + std::cout << "test1\n"; + SG::AuxTypeRegistry& r = SG::AuxTypeRegistry::instance(); + + assert (SG::getDynamicAuxID (typeid(int), + "a1", + "int", + "std::vector<int>", + false) == a1_id); + + const SG::IAuxTypeVectorFactory* fac; + fac = r.getFactory (typeid(AthContainersRootTest::Foo)); + assert (fac == nullptr); + SG::auxid_t foo_id = SG::getDynamicAuxID (typeid(AthContainersRootTest::Foo), + "foo", + "AthContainersRootTest::Foo", + "std::vector<AthContainersRootTest::Foo>", + false); + assert (foo_id != SG::null_auxid); + fac = r.getFactory (typeid(AthContainersRootTest::Foo)); + assert (fac != nullptr); + assert (dynamic_cast<const SG::AuxTypeVectorFactory<AthContainersRootTest::Foo>*>(fac) != nullptr); + assert (r.getName(foo_id) == "foo"); + assert (r.getTypeName(foo_id) == "AthContainersRootTest::Foo"); + assert (r.getVecTypeName(foo_id) == "std::vector<AthContainersRootTest::Foo>"); + + fac = r.getFactory (typeid(AthContainersRootTest::Bar)); + assert (fac == nullptr); + SG::auxid_t bar_id = SG::getDynamicAuxID (typeid(AthContainersRootTest::Bar), + "bar", + "AthContainersRootTest::Bar", + "std::vector<AthContainersRootTest::Bar>", + false); + assert (bar_id != SG::null_auxid); + fac = r.getFactory (typeid(AthContainersRootTest::Bar)); + assert (fac != nullptr); + assert (dynamic_cast<const SG::RootAuxVectorFactory*>(fac) != nullptr); + assert (r.getName(bar_id) == "bar"); + assert (r.getTypeName(bar_id) == "AthContainersRootTest::Bar"); + assert (r.getVecTypeName(bar_id) == "std::vector<AthContainersRootTest::Bar>"); + + fac = r.getFactory (typeid(AthContainersRootTest::Baz)); + assert (fac == nullptr); + SG::auxid_t baz_id = SG::getDynamicAuxID (typeid(AthContainersRootTest::Baz), + "baz", + "AthContainersRootTest::Baz", + "AthContainersRootTest::Baz", + true); + assert (baz_id != SG::null_auxid); + fac = r.getFactory (typeid(AthContainersRootTest::Baz)); + assert (fac != nullptr); + assert (dynamic_cast<const SG::RootAuxVectorFactory*>(fac) != nullptr); + assert (r.getName(baz_id) == "baz"); + assert (r.getTypeName(baz_id) == "AthContainersRootTest::Baz"); + assert (r.getVecTypeName(baz_id) == "std::vector<AthContainersRootTest::Baz>"); +} + + +SG::auxid_t init() +{ + static SG::AuxElement::Accessor<int> a1 ("a1"); + return a1.auxid(); +} + + +int main() +{ + SG::auxid_t a1_auxid = init(); + test1(a1_auxid); + return 0; +}