Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:42

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2021 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_PROPERTYHOLDER_H
0012 #define GAUDIKERNEL_PROPERTYHOLDER_H
0013 // ============================================================================
0014 // Include files
0015 // ============================================================================
0016 // STD & STL
0017 // ============================================================================
0018 #include <algorithm>
0019 #include <functional>
0020 #include <iostream>
0021 #include <stdexcept>
0022 #include <string>
0023 #include <utility>
0024 #include <vector>
0025 // ============================================================================
0026 // GaudiKernel
0027 // ============================================================================
0028 #include "GaudiKernel/Bootstrap.h"
0029 #include "GaudiKernel/DataHandleProperty.h"
0030 #include "GaudiKernel/INamedInterface.h"
0031 #include "GaudiKernel/IProperty.h"
0032 #include "GaudiKernel/ISvcLocator.h"
0033 #include "GaudiKernel/MsgStream.h"
0034 #include "GaudiKernel/detected.h"
0035 #include <Gaudi/Property.h>
0036 
0037 #include "Gaudi/Interfaces/IOptionsSvc.h"
0038 // ============================================================================
0039 namespace Gaudi {
0040   namespace Details {
0041 
0042     template <typename T>
0043     struct is_gaudi_property : std::false_type {};
0044 
0045     template <typename TYPE, typename VERIFIER, typename HANDLERS>
0046     struct is_gaudi_property<Gaudi::Property<TYPE, VERIFIER, HANDLERS>> : std::true_type {};
0047 
0048     template <typename T>
0049     using PropertyType_t = typename std::remove_reference_t<T>::PropertyType;
0050     template <typename T>
0051     using PropertyType = Gaudi::cpp17::detected_or_t<Gaudi::Property<T>, PropertyType_t, T>;
0052   } // namespace Details
0053   namespace Utils {
0054     /// Helper for case insensitive string comparison.
0055     inline bool iequal( std::string_view v1, std::string_view v2 ) {
0056       return std::equal( begin( v1 ), end( v1 ), begin( v2 ), end( v2 ),
0057                          []( char c1, char c2 ) { return toupper( c1 ) == toupper( c2 ); } );
0058     }
0059   } // namespace Utils
0060 } // namespace Gaudi
0061 /** Helper class to implement the IProperty interface.
0062  *
0063  *  PropertyHolder is used by components base classes (Algorithm, Service,
0064  *  etc.) to provide a default implementation the IProperty interface.
0065  *
0066  *  When needing to implement the IProperty interface in a class, it is
0067  *  enough to wrap the base of the class with PropertyHolder, as in
0068  *
0069  *  \code{.cpp}
0070  *  class MyClass : public PropertyHolder<BaseClass> {
0071  *    // ...
0072  *  };
0073  *  \endcode
0074  *
0075  *  where \c BaseClass should inherit from IProperty and INamedInterface.
0076  *
0077  *  \author Paul Maley
0078  *  \author David Quarrie
0079  *  \author Marco Clemencic
0080  */
0081 template <class BASE>
0082 class GAUDI_API PropertyHolder : public BASE {
0083   static_assert( std::is_base_of_v<IProperty, BASE> && std::is_base_of_v<INamedInterface, BASE>,
0084                  "PropertyHolder template argument must inherit from IProperty and INamedInterface" );
0085 
0086 public:
0087   /// Typedef used to refer to this class from derived classes, as in
0088   /// \code{.cpp}
0089   /// class MyClass : public PropertyHolder<BaseClass> {
0090   ///   using PropertyHolderImpl::declareProperty;
0091   /// };
0092   /// \endcode
0093   using PropertyHolderImpl = PropertyHolder<BASE>;
0094 
0095   PropertyHolder() = default;
0096 
0097   /// \{
0098   /// prevent copies
0099   PropertyHolder( const PropertyHolder& )            = delete;
0100   PropertyHolder& operator=( const PropertyHolder& ) = delete;
0101   /// \}
0102 
0103 public:
0104   /// Declare a property.
0105   /// Record a PropertyBase instance to be managed by PropertyHolder.
0106   inline Gaudi::Details::PropertyBase& declareProperty( Gaudi::Details::PropertyBase& prop ) {
0107     assertUniqueName( prop.name() );
0108     m_properties.push_back( &prop );
0109     return prop;
0110   }
0111 
0112   /// Helper to wrap a regular data member and use it as a regular property.
0113   /// \deprecated Prefer the signatures using a a fully initialized PropertyBase instance.
0114   template <typename TYPE, typename = std::enable_if_t<!Gaudi::Details::is_gaudi_property<TYPE>::value>>
0115   Gaudi::Details::PropertyBase* declareProperty( const std::string& name, TYPE& value,
0116                                                  const std::string& doc = "none" ) {
0117     m_todelete.push_back( std::make_unique<Gaudi::Details::PropertyType<TYPE&>>( name, value ) );
0118     Gaudi::Details::PropertyBase* p = m_todelete.back().get();
0119 
0120     p->setDocumentation( doc );
0121     return &declareProperty( *p );
0122   }
0123 
0124   /// Declare a PropertyBase instance setting name and documentation.
0125   /// \deprecated Prefer the signatures using a fully initialized PropertyBase instance.
0126   template <class TYPE, class VERIFIER, class HANDLERS>
0127   Gaudi::Details::PropertyBase* declareProperty( const std::string&                         name,
0128                                                  Gaudi::Property<TYPE, VERIFIER, HANDLERS>& prop,
0129                                                  const std::string&                         doc = "none" ) {
0130     Gaudi::Details::PropertyBase* p = &prop;
0131     p->setName( name );
0132 
0133     p->setDocumentation( doc );
0134     return &declareProperty( *p );
0135   }
0136 
0137   /// Declare a remote property.
0138   /// Bind \c name to the property \c rname of \c rsvc.
0139   Gaudi::Details::PropertyBase* declareRemoteProperty( const std::string& name, IProperty* rsvc,
0140                                                        const std::string& rname = "" ) {
0141     if ( !rsvc ) return nullptr;
0142     const std::string&            nam = rname.empty() ? name : rname;
0143     Gaudi::Details::PropertyBase* p   = property( nam, rsvc->getProperties() );
0144     m_remoteProperties.emplace_back( RemProperty{ name, rsvc, nam } );
0145     return p;
0146   }
0147 
0148   /// \}
0149 
0150   // ==========================================================================
0151   // IProperty implementation
0152   // ==========================================================================
0153   using IProperty::setProperty;
0154   /** set the property from another property with a different name
0155    *  @see IProperty
0156    */
0157   StatusCode setProperty( const std::string& name, const Gaudi::Details::PropertyBase& p ) override {
0158     Gaudi::Details::PropertyBase* pp = property( name );
0159     if ( pp && pp->assign( p ) ) return StatusCode::SUCCESS;
0160     return StatusCode::FAILURE;
0161   }
0162   // ==========================================================================
0163   /** set the property from the formatted string
0164    *  @see IProperty
0165    */
0166   StatusCode setProperty( const std::string& s ) override {
0167     std::string name;
0168     std::string value;
0169     StatusCode  sc = Gaudi::Parsers::parse( name, value, s );
0170     if ( sc.isFailure() ) return sc;
0171     return setPropertyRepr( name, value );
0172   }
0173   // ==========================================================================
0174   /** set the property from name and value string representation
0175    *  @see IProperty
0176    */
0177   StatusCode setPropertyRepr( const std::string& n, const std::string& r ) override {
0178     try {
0179       Gaudi::Details::PropertyBase* p = property( n );
0180       /// @fixme SUCCESS is not required to be checked for compatibility with Gaudi::Utils::setProperty
0181       return ( p && p->fromString( r ) ) ? StatusCode::SUCCESS : StatusCode::FAILURE;
0182     } catch ( const std::invalid_argument& err ) {
0183       throw GaudiException{ "error setting property " + n, this->name(), StatusCode::FAILURE, err };
0184     }
0185   }
0186   // ==========================================================================
0187   /** get the property
0188    *  @see IProperty
0189    */
0190   StatusCode getProperty( Gaudi::Details::PropertyBase* p ) const override {
0191     try {
0192       const Gaudi::Details::PropertyBase* pp = property( p->name() );
0193       if ( pp && pp->load( *p ) ) return StatusCode::SUCCESS;
0194     } catch ( ... ) {}
0195     return StatusCode::FAILURE;
0196   }
0197   // ==========================================================================
0198   /** get the property by name
0199    *  @see IProperty
0200    */
0201   const Gaudi::Details::PropertyBase& getProperty( std::string_view name ) const override {
0202     const Gaudi::Details::PropertyBase* p = property( name );
0203     if ( !p ) throw std::out_of_range( "Property " + std::string{ name } + " not found." );
0204     return *p;
0205   }
0206   // ==========================================================================
0207   /** convert the property to the string
0208    *  @see IProperty
0209    */
0210   StatusCode getProperty( std::string_view n, std::string& v ) const override {
0211     // get the property
0212     const Gaudi::Details::PropertyBase* p = property( n );
0213     if ( !p ) return StatusCode::FAILURE;
0214     // convert the value into the string
0215     v = p->toString();
0216     return StatusCode::SUCCESS;
0217   }
0218   // ==========================================================================
0219   /** get all properties
0220    *  @see IProperty
0221    */
0222   const std::vector<Gaudi::Details::PropertyBase*>& getProperties() const override { return m_properties; }
0223   // ==========================================================================
0224   /** Return true if we have a property with the given name.
0225    *  @see IProperty
0226    */
0227   bool hasProperty( std::string_view name ) const override {
0228     return any_of( begin( m_properties ), end( m_properties ),
0229                    [&name]( const Gaudi::Details::PropertyBase* prop ) {
0230                      return Gaudi::Utils::iequal( prop->name(), name );
0231                    } ) ||
0232            any_of( begin( m_remoteProperties ), end( m_remoteProperties ),
0233                    [&name]( const auto& prop ) { return Gaudi::Utils::iequal( prop.name, name ); } );
0234   }
0235   // ==========================================================================
0236   /// \fixme property and bindPropertiesTo should be protected
0237   // get local or remote property by name
0238   Gaudi::Details::PropertyBase* property( std::string_view name ) const {
0239     // local property ?
0240     Gaudi::Details::PropertyBase* lp = property( name, m_properties );
0241     if ( lp ) return lp;
0242     // look for remote property
0243     for ( const auto& it : m_remoteProperties ) {
0244       if ( !Gaudi::Utils::iequal( it.name, name ) ) continue;
0245       const IProperty* p = it.owner;
0246       if ( !p ) continue;
0247       return property( it.remName, p->getProperties() );
0248     }
0249     return nullptr; // RETURN
0250   }
0251 
0252   void bindPropertiesTo( Gaudi::Interfaces::IOptionsSvc& optsSvc ) {
0253     auto set_prop = [&optsSvc, this]( auto prop ) { optsSvc.bind( this->name(), prop ); };
0254     std::for_each( begin( m_properties ), end( m_properties ), set_prop );
0255     std::for_each( begin( m_remoteProperties ), end( m_remoteProperties ), [&set_prop, this]( auto& rem ) {
0256       if ( rem.owner ) set_prop( this->property( rem.remName, rem.owner->getProperties() ) );
0257     } );
0258   }
0259 
0260 private:
0261   /// get the property by name form the proposed list
0262   Gaudi::Details::PropertyBase* property( std::string_view                                  name,
0263                                           const std::vector<Gaudi::Details::PropertyBase*>& props ) const {
0264     auto it = std::find_if( props.begin(), props.end(), [name]( Gaudi::Details::PropertyBase* p ) {
0265       return p && Gaudi::Utils::iequal( p->name(), name );
0266     } );
0267     return ( it != props.end() ) ? *it : nullptr; // RETURN
0268   }
0269 
0270   /// Issue a runtime warning if the name is already present in the
0271   /// list of properties (see <a href="https://its.cern.ch/jira/browse/GAUDI-1023">GAUDI-1023</a>).
0272   void assertUniqueName( std::string_view name ) const {
0273     if ( hasProperty( name ) ) {
0274       auto msgSvc = Gaudi::svcLocator()->service<IMessageSvc>( "MessageSvc" );
0275       if ( !msgSvc ) std::cerr << "error: cannot get MessageSvc!" << std::endl;
0276       MsgStream log( msgSvc, this->name() );
0277       log << MSG::WARNING << "duplicated property name '" << name << "', see https://its.cern.ch/jira/browse/GAUDI-1023"
0278           << endmsg;
0279     }
0280   }
0281 
0282   typedef std::vector<Gaudi::Details::PropertyBase*> Properties;
0283   struct RemProperty {
0284     std::string name;
0285     IProperty*  owner = nullptr;
0286     std::string remName;
0287   };
0288   typedef std::vector<RemProperty> RemoteProperties;
0289 
0290   /// Collection of all declared properties.
0291   Properties m_properties;
0292   /// Collection of all declared remote properties.
0293   RemoteProperties m_remoteProperties;
0294   /// Properties owned by PropertyHolder, to be deleted.
0295   std::vector<std::unique_ptr<Gaudi::Details::PropertyBase>> m_todelete;
0296 };
0297 #endif