Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-31 10:08:58

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