Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-05 08:54:31

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