Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:57:41

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2024 CERN for the benefit of the LHCb and ATLAS collaborations *
0003 *                                                                                   *
0004 * This software is distributed under the terms of the Apache version 2 licence,     *
0005 * copied verbatim in the file "LICENSE".                                            *
0006 *                                                                                   *
0007 * In applying this licence, CERN does not waive the privileges and immunities       *
0008 * granted to it by virtue of its status as an Intergovernmental Organization        *
0009 * or submit itself to any jurisdiction.                                             *
0010 \***********************************************************************************/
0011 #ifndef GAUDIKERNEL_GAUDIHANDLE_H
0012 #define GAUDIKERNEL_GAUDIHANDLE_H
0013 
0014 // Includes
0015 #include <Gaudi/Property.h>
0016 #include <GaudiKernel/GaudiException.h>
0017 #include <GaudiKernel/IInterface.h>
0018 #include <GaudiKernel/System.h>
0019 
0020 #include <algorithm>
0021 #include <iostream>
0022 #include <string>
0023 #include <type_traits>
0024 #include <vector>
0025 
0026 namespace details {
0027   /// Cast a pointer to a non const type
0028   template <class T>
0029   std::remove_const_t<T>* nonConst( T* p ) {
0030     return const_cast<std::remove_const_t<T>*>( p );
0031   }
0032 } // namespace details
0033 
0034 class GAUDI_API GaudiHandleInfo {
0035 protected:
0036   /** Some basic information and helper functions shared between various handles/arrays.
0037    @param myComponentType: string indicating what type of component the handle is pointing to.
0038                         For example: "PublicTool", "PrivateTool", "Service".
0039                         This is used for printout and on the python side for type checking.
0040                         On the python side there are classes with these names with "Handle" appended:
0041                         PublicToolHandle,PrivateToolHandle,ServiceHandle
0042    @param myParentName: Name of the parent that has this handle as a member. Used in printout.
0043   */
0044   GaudiHandleInfo( std::string myComponentType, std::string myParentName )
0045       : m_componentType( std::move( myComponentType ) ), m_parentName( std::move( myParentName ) ) {}
0046 
0047 public:
0048   /** virtual destructor so that derived class destructor is called. */
0049   // Don't use =default here.  Otherwise, in c++20 mode, clang will
0050   // instantiate the handle virtual functions early, breaking the case
0051   // where handles are used with a forward-declared class.
0052   virtual ~GaudiHandleInfo() {}
0053   //
0054   // Public member functions
0055   //
0056   const std::string& componentType() const { return m_componentType; }
0057 
0058   /** name as used in declareProperty(name,gaudiHandle) */
0059   const std::string& propertyName() const { return m_propertyName; }
0060 
0061   /** set name as used in declareProperty(name,gaudiHandle). Used in printout. */
0062   void setPropertyName( std::string propName ) { m_propertyName = std::move( propName ); }
0063 
0064   /** The name of the parent */
0065   const std::string& parentName() const { return m_parentName; }
0066 
0067   /** The python class name for the property in the genconf-generated configurables.
0068       The python class is defined in GaudiPython/python/GaudiHandles.py.
0069       To be implemented in derived class. */
0070   virtual std::string pythonPropertyClassName() const = 0;
0071 
0072   /** Python representation of handle, i.e. python class name and argument.
0073       Can be used in the genconf-generated configurables.
0074       The corresponding python classes are defined in GaudiPython/GaudiHandles.py.
0075       To be implemented in derived class. */
0076   virtual std::string pythonRepr() const = 0;
0077 
0078   // Easy printing out of Handles and HandleArrays
0079   // It prints <propertyName> = <HandleType>( <HandleType(s)AndName(s)> )
0080   friend std::ostream& operator<<( std::ostream& os, const GaudiHandleInfo& handle );
0081 
0082 protected:
0083   /** The component type */
0084   void setComponentType( std::string componentType ) { m_componentType = std::move( componentType ); }
0085 
0086   /** The name of the parent */
0087   void setParentName( std::string parent ) { m_parentName = std::move( parent ); }
0088 
0089 private:
0090   //
0091   // Data members
0092   //
0093   std::string m_componentType; // e.g.: "PublicTool","PrivateTool","Service"
0094   std::string m_propertyName;  // name as used in declareProperty(name,gaudiHandle)
0095   std::string m_parentName;    // name of the parent having this handle as a member
0096 };
0097 
0098 /** @class GaudiHandleBase GaudiHandle.h GaudiKernel/GaudiHandle.h
0099 
0100     Base class to handles to be used in lieu of naked pointers to various Gaudi components.
0101     This allows better control through the framework of component loading, configuration and usage.
0102     This base class implements common features.
0103     @author Martin.Woudstra@cern.ch
0104 */
0105 class GAUDI_API GaudiHandleBase : public GaudiHandleInfo {
0106   //
0107   // Ctors etc
0108   //
0109 protected:
0110   /** Create a handle ('smart pointer') to a gaudi component
0111    @param myTypeAndName: "MyType/MyName" ("MyType" is short for "MyType/MyType")
0112                        'MyType' is the name of the concrete class of the component
0113                        'MyName' is to distinguish several instances of the same concrete class
0114    @param myComponentType: string indicating what type of component the handle is pointing to.
0115                         For example: "PublicTool", "PrivateTool", "Service".
0116                         This is used for printout and on the python side for type checking.
0117                         On the python side there are classes with these names with "Handle" appended:
0118                         PublicToolHandle,PrivateToolHandle,ServiceHandle
0119    @param myParentName: Name of the parent that has this handle as a member. Used in printout.
0120   */
0121   GaudiHandleBase( std::string myTypeAndName, std::string myComponentType, std::string myParentName )
0122       : GaudiHandleInfo( std::move( myComponentType ), std::move( myParentName ) ) {
0123     setTypeAndName( std::move( myTypeAndName ) );
0124   }
0125 
0126 public:
0127   //
0128   // Public member functions
0129   //
0130   /** The full type and name: "type/name" */
0131   const std::string& typeAndName() const { return m_typeAndName; }
0132 
0133   /** The concrete component class name: the part before the '/' */
0134   std::string type() const;
0135 
0136   /** The instance name: the part after the '/' */
0137   std::string name() const;
0138 
0139   /** Check if the handle has been set to empty string (i.e. typeAndName string is empty). */
0140   bool empty() const { return m_typeAndName.empty(); }
0141 
0142   /** The component "type/name" string */
0143   void setTypeAndName( std::string myTypeAndName );
0144 
0145   /** Set the instance name (part after the '/') without changing the class type */
0146   void setName( std::string_view myName );
0147 
0148   /** Name of the componentType with "Handle" appended. Used as the python class name
0149       for the property in the genconf-generated configurables.
0150       The python class is defined in GaudiPython/python/GaudiHandles.py. */
0151   std::string pythonPropertyClassName() const override;
0152 
0153   /** name used for printing messages */
0154   std::string messageName() const;
0155 
0156   /** Python representation of handle, i.e. python class name and argument.
0157       Can be used in the genconf-generated configurables.
0158       The corresponding python classes are defined in GaudiPython/GaudiHandles.py */
0159   std::string pythonRepr() const override;
0160 
0161   using PropertyType = GaudiHandleProperty;
0162 
0163 private:
0164   //
0165   // Data member
0166   //
0167   std::string m_typeAndName; // the full type and name: "type/name"
0168 };
0169 
0170 /** @class GaudiHandle GaudiHandle.h GaudiKernel/GaudiHandle.h
0171 
0172     Handle to be used in lieu of naked pointers to gaudis. This allows
0173     better control through the framework of gaudi loading and usage.
0174     T is the type of the component interface (or concrete class).
0175 
0176     @author Martin.Woudstra@cern.ch
0177 */
0178 template <class T>
0179 class GAUDI_API GaudiHandle : public GaudiHandleBase {
0180   //
0181   // Constructors etc.
0182   //
0183 protected:
0184   GaudiHandle( std::string myTypeAndName, std::string myComponentType, std::string myParentName )
0185       : GaudiHandleBase( std::move( myTypeAndName ), std::move( myComponentType ), std::move( myParentName ) ) {}
0186 
0187 public:
0188   /** Copy constructor needed for correct ref-counting */
0189   template <typename CT = T, typename NCT = std::remove_const_t<T>>
0190   GaudiHandle( const GaudiHandle<NCT>& other,
0191                std::enable_if_t<std::is_const_v<CT> && !std::is_same_v<CT, NCT>>* = nullptr )
0192       : GaudiHandleBase( other ) {
0193     m_pObject = other.get();
0194     if ( m_pObject ) ::details::nonConst( m_pObject.load() )->addRef();
0195   }
0196 
0197   /** Copy constructor needed for correct ref-counting */
0198   GaudiHandle( const GaudiHandle& other ) : GaudiHandleBase( other ) {
0199     m_pObject = other.m_pObject.load();
0200     if ( m_pObject ) ::details::nonConst( m_pObject.load() )->addRef();
0201   }
0202 
0203   /** Assignment operator for correct ref-counting */
0204   template <typename CT = T, typename NCT = std::remove_const_t<T>>
0205   std::enable_if_t<std::is_const_v<CT> && !std::is_same_v<CT, NCT>, GaudiHandle&>
0206   operator=( const GaudiHandle<NCT>& other ) {
0207     GaudiHandleBase::operator=( other );
0208     // release any current tool
0209     release().ignore();
0210     m_pObject = other.get();
0211     // update ref-counting
0212     if ( m_pObject ) ::details::nonConst( m_pObject.load() )->addRef();
0213     return *this;
0214   }
0215 
0216   /** Assignment operator for correct ref-counting */
0217   GaudiHandle& operator=( const GaudiHandle& other ) {
0218     GaudiHandleBase::operator=( other );
0219     // release any current tool
0220     release().ignore();
0221     m_pObject = other.m_pObject.load();
0222     // update ref-counting
0223     if ( m_pObject ) ::details::nonConst( m_pObject.load() )->addRef();
0224     return *this;
0225   }
0226 
0227   /** Retrieve the component. Release existing component if needed. */
0228   StatusCode retrieve() const {
0229     // not really const, because it updates m_pObject
0230     // Do the lookup into a temporary pointer.
0231     T* p = nullptr;
0232     if ( retrieve( p ).isFailure() ) { return StatusCode::FAILURE; }
0233 
0234     // If m_pObject is null, then copy p to m_pObject.
0235     // Otherwise, release p.
0236     T* old = nullptr;
0237     if ( m_pObject.compare_exchange_strong( old, p ) ) { return StatusCode::SUCCESS; }
0238     return release( p );
0239   }
0240 
0241   /** Release the component. */
0242   StatusCode release() const {
0243     // not really const, because it updates m_pObject
0244     StatusCode sc = StatusCode::SUCCESS;
0245     if ( m_pObject ) {
0246       sc        = release( m_pObject );
0247       m_pObject = nullptr;
0248     }
0249     return sc;
0250   }
0251 
0252   /// Check if the handle is valid (try to retrive the object is not done yet).
0253   bool isValid() const {
0254     // not really const, because it may update m_pObject
0255     return m_pObject || retrieve().isSuccess();
0256   }
0257 
0258   /** For testing if handle has component. Does retrieve() if needed.
0259       If this returns false, the component could not be retrieved. */
0260   operator bool() const {
0261     // not really const, because it may update m_pObject
0262     return isValid();
0263   }
0264 
0265   /// Return the wrapped pointer, not calling retrieve() if null.
0266   T* get() { return m_pObject; }
0267 
0268   /// Return the wrapped pointer, not calling retrieve() if null.
0269   std::add_const_t<T>* get() const { return m_pObject; }
0270 
0271   /// True if the wrapped pointer is not null.
0272   bool isSet() const { return get(); }
0273 
0274   T& operator*() {
0275     assertObject();
0276     return *m_pObject;
0277   }
0278 
0279   T* operator->() {
0280     assertObject();
0281     return m_pObject;
0282   }
0283 
0284   std::add_const_t<T>& operator*() const {
0285     // not really const, because it may update m_pObject
0286     assertObject();
0287     return *m_pObject;
0288   }
0289 
0290   std::add_const_t<T>* operator->() const {
0291     // not really const, because it may update m_pObject
0292     assertObject();
0293     return m_pObject;
0294   }
0295 
0296   /** Helper function to get default type string from the class type */
0297   std::string getDefaultType() { return System::typeinfoName( typeid( T ) ); }
0298 
0299   std::string getDefaultName() {
0300     const auto defName = GaudiHandleBase::type();
0301     return ( defName.empty() ? getDefaultType() : defName );
0302   }
0303 
0304 protected:
0305   /** Retrieve the component. To be implemented by the derived class. It will pass the pointer */
0306   virtual StatusCode retrieve( T*& ) const = 0; // not really const, because it updates m_pObject
0307 
0308   /** Release the component. Default implementation calls release() on the component.
0309       Can be overridden by the derived class if something else is needed. */
0310   virtual StatusCode release( T* comp ) const { // not really const, because it updates m_pObject
0311     // const cast to support T being a const type
0312     ::details::nonConst( comp )->release();
0313     return StatusCode::SUCCESS;
0314   }
0315 
0316 private:
0317   /** Helper function to set default name and type */
0318   void setDefaultTypeAndName() {
0319     const std::string& myType = getDefaultType();
0320     GaudiHandleBase::setTypeAndName( myType + '/' + myType );
0321   }
0322 
0323   /** Helper function to set default type from the class type T */
0324   void setDefaultType() { GaudiHandleBase::setTypeAndName( getDefaultType() ); }
0325 
0326   /** Load the pointer to the component. Do a retrieve if needed. Throw an exception if
0327       retrieval fails. */
0328   void assertObject() const { // not really const, because it may update m_pObject
0329     if ( !isValid() ) {
0330       throw GaudiException( "Failed to retrieve " + componentType() + ": " + typeAndName(),
0331                             componentType() + " retrieve", StatusCode::FAILURE );
0332     }
0333   }
0334 
0335 private:
0336   //
0337   // Data members
0338   //
0339   mutable std::atomic<T*> m_pObject = nullptr;
0340 };
0341 
0342 /**
0343    Base class of array's of various gaudihandles. Used in communication with
0344    GaudiHandleArrayProperty. For that purpose is has some pure virtual functions.
0345    This is a non-templated class to one Property can handle all kinds of concrete handles.
0346 */
0347 
0348 class GAUDI_API GaudiHandleArrayBase : public GaudiHandleInfo {
0349 protected:
0350   GaudiHandleArrayBase( std::string myComponentType, std::string myParentName )
0351       : GaudiHandleInfo( std::move( myComponentType ), std::move( myParentName ) ) {}
0352 
0353 public:
0354   using PropertyType = GaudiHandleArrayProperty;
0355   typedef std::vector<GaudiHandleBase*>       BaseHandleArray;
0356   typedef std::vector<const GaudiHandleBase*> ConstBaseHandleArray;
0357 
0358   /** Set the array of handles from list of "type/name" strings in
0359       &lt;myTypesAndNamesList&gt;. Return whether set was successful or not */
0360   bool setTypesAndNames( const std::vector<std::string>& myTypesAndNamesList );
0361 
0362   /** Return a vector with "type/name" strings of all handles in the array.
0363       Inverse of setTypesAndNames() */
0364   const std::vector<std::string> typesAndNames() const;
0365 
0366   /** Return a vector with "type" strings of all handles in the array. */
0367   const std::vector<std::string> types() const;
0368 
0369   /** Return a vector with "type/name" strings of all handles in the array. */
0370   const std::vector<std::string> names() const;
0371 
0372   /** Helper function to get a vector of strings filled with the return value
0373       of each tool of a member function if GaudiHandleBase */
0374   const std::vector<std::string> getBaseInfos( auto ( GaudiHandleBase::*pMemFunc )() const ) const;
0375 
0376   /** Name of the componentType with "HandleArray" appended. Used as the python class name
0377       for the property in the genconf-generated configurables.
0378       The python class is defined in GaudiPython/python/GaudiHandles.py. */
0379   std::string pythonPropertyClassName() const override;
0380 
0381   /** Python representation of array of handles, i.e. list of python handles.
0382       Can be used in the genconf-generated configurables.
0383       The corresponding python classes are defined in GaudiPython/GaudiHandles.py */
0384   std::string pythonRepr() const override;
0385 
0386   /** Add a handle to the array with "type/name" given in &lt;myHandleTypeAndName&gt;.
0387       Return whether addition was successful or not.
0388       Must be implemented by derived class with concrete handle category. */
0389   virtual bool push_back( const std::string& myHandleTypeAndName ) = 0;
0390 
0391   /** Clear the list of handles. Implemented in GaudiHandleArray */
0392   virtual void clear() = 0;
0393 
0394   /** Return whether the list of tools is empty. */
0395   virtual bool empty() const = 0;
0396 
0397   /** Get a read-only vector of const GaudiHandleBase* pointing to the real handles.
0398       Implemented in GaudiHandleArray. */
0399   virtual ConstBaseHandleArray getBaseArray() const = 0;
0400 
0401   /** Get a read-write vector of GaudiHandleBase* pointing to the real handles.
0402       Implemented in GaudiHandleArray. */
0403   virtual BaseHandleArray getBaseArray() = 0;
0404 
0405   /** To be able to tell if Array was ever retreived **/
0406   virtual bool retrieved() const = 0;
0407 };
0408 
0409 /** T is the concrete handle type, e.g. ToolHandle<IMyTool> */
0410 template <class T>
0411 class GAUDI_API GaudiHandleArray : public GaudiHandleArrayBase {
0412 public:
0413   //
0414   // public nested types
0415   //
0416   typedef std::vector<T>                                HandleVector;
0417   typedef typename HandleVector::value_type             value_type;
0418   typedef typename HandleVector::size_type              size_type;
0419   typedef typename HandleVector::reference              reference;
0420   typedef typename HandleVector::const_reference        const_reference;
0421   typedef typename HandleVector::iterator               iterator;
0422   typedef typename HandleVector::const_iterator         const_iterator;
0423   typedef typename HandleVector::reverse_iterator       reverse_iterator;
0424   typedef typename HandleVector::const_reverse_iterator const_reverse_iterator;
0425 
0426 protected:
0427   //
0428   // Constructors
0429   //
0430   /** Generic constructor. Probably not very useful...
0431       @param typesAndNamesList : a vector of strings with the concrete "type/name" strings
0432                                  for the list of tools
0433  */
0434   GaudiHandleArray( const std::vector<std::string>& myTypesAndNamesList, std::string myComponentType,
0435                     std::string myParentName )
0436       : GaudiHandleArrayBase( std::move( myComponentType ), std::move( myParentName ) ) {
0437     setTypesAndNames( myTypesAndNamesList );
0438   }
0439 
0440   /** Constructor creating an empty array.
0441       @param typesAndNamesList : a vector of strings with the concrete "type/name" strings
0442                                  for the list of tools
0443  */
0444   GaudiHandleArray( const std::string& myComponentType, const std::string& myParentName )
0445       : GaudiHandleArrayBase( myComponentType, myParentName ) {}
0446 
0447 public:
0448   /**Set the array of GaudiHandles from typeAndNames given in vector of strings. */
0449   GaudiHandleArray& operator=( const std::vector<std::string>& myTypesAndNamesList ) {
0450     setTypesAndNames( myTypesAndNamesList );
0451     return *this;
0452   }
0453 
0454   GaudiHandleArrayBase::BaseHandleArray getBaseArray() override {
0455     GaudiHandleArrayBase::BaseHandleArray baseArray;
0456     for ( auto& h : m_handleArray ) baseArray.push_back( &h );
0457     return baseArray;
0458   }
0459 
0460   GaudiHandleArrayBase::ConstBaseHandleArray getBaseArray() const override {
0461     GaudiHandleArrayBase::ConstBaseHandleArray baseArray;
0462     for ( auto& h : m_handleArray ) baseArray.push_back( &h );
0463     return baseArray;
0464   }
0465 
0466   //
0467   // Simulate (part of) an std::vector
0468   //
0469   iterator begin() { return m_handleArray.begin(); }
0470 
0471   iterator end() { return m_handleArray.end(); }
0472 
0473   const_iterator begin() const { return m_handleArray.begin(); }
0474 
0475   const_iterator end() const { return m_handleArray.end(); }
0476 
0477   const_iterator rbegin() const { return m_handleArray.rbegin(); }
0478 
0479   const_iterator rend() const { return m_handleArray.rend(); }
0480 
0481   size_type size() const { return m_handleArray.size(); }
0482 
0483   void clear() override { m_handleArray.clear(); }
0484 
0485   bool empty() const override { return m_handleArray.empty(); }
0486 
0487   T& operator[]( int index ) { return m_handleArray[index]; }
0488 
0489   const T& operator[]( int index ) const { return m_handleArray[index]; }
0490 
0491   /** Get pointer (!) to ToolHandle by instance name. Returns zero pointer if not found */
0492   T* operator[]( std::string_view name ) {
0493     auto it = std::find_if( begin(), end(), [&]( const_reference r ) { return r.name() == name; } );
0494     return it != end() ? &*it : nullptr;
0495   }
0496 
0497   /** Get const pointer (!) to ToolHandle by instance name. Returns zero pointer if not found */
0498   const T* operator[]( std::string_view name ) const {
0499     auto it = std::find_if( begin(), end(), [&]( const_reference r ) { return r.name() == name; } );
0500     return it != end() ? &*it : nullptr;
0501   }
0502 
0503   /** Add a handle with given type and name. Can be overridden in derived class.
0504       Return whether addition was successful or not. */
0505   using GaudiHandleArrayBase::push_back; // avoid compiler warning
0506   virtual bool push_back( const T& myHandle ) {
0507     m_handleArray.push_back( myHandle );
0508     return true;
0509   }
0510 
0511   /** Retrieve all tools */
0512   StatusCode retrieve() {
0513     StatusCode sc = StatusCode::SUCCESS;
0514     for ( auto& i : *this ) {
0515       // stop at first failure
0516       if ( i.retrieve().isFailure() ) {
0517         sc = StatusCode::FAILURE;
0518         break;
0519       }
0520     }
0521     if ( sc ) { m_retrieved = true; }
0522     return sc;
0523   }
0524 
0525   /** Release all tools */
0526   StatusCode release() {
0527     StatusCode sc = StatusCode::SUCCESS;
0528     for ( auto& i : *this ) {
0529       // continue trying to release other tools even if we fail...
0530       if ( i.release().isFailure() ) sc = StatusCode::FAILURE;
0531     }
0532     return sc;
0533   }
0534 
0535   /** has Array been retreived? **/
0536   virtual bool retrieved() const override { return m_retrieved; }
0537 
0538 private:
0539   //
0540   // Private data members
0541   //
0542   HandleVector m_handleArray;
0543   bool         m_retrieved{ false };
0544 };
0545 
0546 #endif // ! GAUDIKERNEL_GAUDIHANDLE_H