Back to home page

EIC code displayed by LXR

 
 

    


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

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2019 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 "COPYING".                                            *
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 #pragma once
0012 
0013 #include <Gaudi/Details/PropertyBase.h>
0014 #include <Gaudi/Parsers/CommonParsers.h>
0015 #include <Gaudi/Parsers/InputData.h>
0016 #include <Gaudi/PropertyFwd.h>
0017 #include <GaudiKernel/TaggedBool.h>
0018 #include <GaudiKernel/ToStream.h>
0019 #include <string>
0020 #include <utility>
0021 
0022 namespace Gaudi::Details::Property {
0023   using ImmediatelyInvokeHandler = Gaudi::tagged_bool<class ImmediatelyInvokeHandler_tag>;
0024 
0025   // ==========================================================================
0026   // The following code is going to be a bit unpleasant, but as far as its
0027   // author can tell, it is as simple as the design constraints and C++'s
0028   // implementation constraints will allow. If you disagree, please submit
0029   // a patch which simplifies it. Here is the underlying design rationale:
0030   //
0031   // - For any given type T used in a Property, we want to have an
0032   //   associated StringConverter<T> struct which explains how to convert a
0033   //   value of that type into a string (toString) and parse that string
0034   //   back (fromString).
0035   // - There is a default implementation, called DefaultStringConverter<T>,
0036   //   which is based on the overloadable parse() and toStream() global
0037   //   methods of Gaudi. Its exact behaviour varies depending on whether T
0038   //   is default-constructible or only copy-constructible, which requires a
0039   //   layer of SFINAE indirection.
0040   // - Some people want to be able to specialize StringConverter as an
0041   //   alternative to defining parse/toStream overloads. This interferes
0042   //   with the SFINAE tricks used by DefaultStringConverter, so we cannot
0043   //   just call a DefaultStringConverter a StringConverter and must add one
0044   //   more layer to the StringConverter type hierarchy.
0045 
0046   // This class factors out commonalities between DefaultStringConverters
0047   template <class TYPE>
0048   struct DefaultStringConverterImpl {
0049   public:
0050     virtual ~DefaultStringConverterImpl() = default;
0051     std::string toString( const TYPE& v ) {
0052       using Gaudi::Utils::toString;
0053       return toString( v );
0054     }
0055 
0056     // Implementation of fromString depends on whether TYPE is default-
0057     // constructible (fastest, easiest) or only copy-constructible (still
0058     // doable as long as the caller can provide a valid value of TYPE)
0059     virtual TYPE fromString( const TYPE& ref_value, const std::string& s ) = 0;
0060 
0061   protected:
0062     void fromStringImpl( TYPE& buffer, const std::string& s ) {
0063       using Gaudi::Parsers::InputData;
0064       if ( !parse( buffer, InputData{ s } ).isSuccess() ) {
0065         throw std::invalid_argument( "cannot parse '" + s + "' to " + System::typeinfoName( typeid( TYPE ) ) );
0066       }
0067     }
0068   };
0069 
0070   // Specialization of toString for strings (identity function)
0071   template <>
0072   inline std::string DefaultStringConverterImpl<std::string>::toString( const std::string& v ) {
0073     return v;
0074   }
0075 
0076   // This class provides a default implementation of StringConverter based
0077   // on the overloadable parse() and toStream() global Gaudi methods.
0078   //
0079   // It leverages the fact that TYPE is default-constructible if it can, and
0080   // falls back fo a requirement of copy-constructibility if it must. So
0081   // here is the "default" implementation for copy-constructible types...
0082   //
0083   template <typename TYPE, typename Enable = void>
0084   struct DefaultStringConverter : DefaultStringConverterImpl<TYPE> {
0085     TYPE fromString( const TYPE& ref_value, const std::string& s ) final override {
0086       TYPE buffer = ref_value;
0087       this->fromStringImpl( buffer, s );
0088       return buffer;
0089     }
0090   };
0091   // ...and here is the preferred impl for default-constructible types:
0092   template <class TYPE>
0093   struct DefaultStringConverter<TYPE, std::enable_if_t<std::is_default_constructible_v<TYPE>>>
0094       : DefaultStringConverterImpl<TYPE> {
0095     TYPE fromString( const TYPE& /* ref_value */, const std::string& s ) final override {
0096       TYPE buffer{};
0097       this->fromStringImpl( buffer, s );
0098       return buffer;
0099     }
0100   };
0101 
0102   // Specializable StringConverter struct with a default implementation
0103   template <typename TYPE>
0104   struct StringConverter : DefaultStringConverter<TYPE> {};
0105 
0106   struct NullVerifier {
0107     template <class TYPE>
0108     void operator()( const TYPE& ) const {}
0109   };
0110   template <class TYPE>
0111   struct BoundedVerifier {
0112     void operator()( const TYPE& value ) const {
0113       using Gaudi::Utils::toString;
0114       // throw the exception if the limit is defined and value is outside
0115       if ( ( m_hasLowerBound && ( value < m_lowerBound ) ) || ( m_hasUpperBound && ( m_upperBound < value ) ) )
0116         throw std::out_of_range( "value " + toString( value ) + " outside range" );
0117     }
0118 
0119     /// Return if it has a lower bound
0120     bool hasLower() const { return m_hasLowerBound; }
0121     /// Return if it has a lower bound
0122     bool hasUpper() const { return m_hasUpperBound; }
0123     /// Return the lower bound value
0124     const TYPE& lower() const { return m_lowerBound; }
0125     /// Return the upper bound value
0126     const TYPE& upper() const { return m_upperBound; }
0127 
0128     /// Set lower bound value
0129     void setLower( const TYPE& value ) {
0130       m_hasLowerBound = true;
0131       m_lowerBound    = value;
0132     }
0133     /// Set upper bound value
0134     void setUpper( const TYPE& value ) {
0135       m_hasUpperBound = true;
0136       m_upperBound    = value;
0137     }
0138     /// Clear lower bound value
0139     void clearLower() {
0140       m_hasLowerBound = false;
0141       m_lowerBound    = TYPE();
0142     }
0143     /// Clear upper bound value
0144     void clearUpper() {
0145       m_hasUpperBound = false;
0146       m_upperBound    = TYPE();
0147     }
0148 
0149     /// Set both bounds (lower and upper) at the same time
0150     void setBounds( const TYPE& lower, const TYPE& upper ) {
0151       setLower( lower );
0152       setUpper( upper );
0153     }
0154 
0155     /// Clear both bounds (lower and upper) at the same time
0156     void clearBounds() {
0157       clearLower();
0158       clearUpper();
0159     }
0160 
0161   private:
0162     /// Data members
0163     bool m_hasLowerBound{ false };
0164     bool m_hasUpperBound{ false };
0165     TYPE m_lowerBound{};
0166     TYPE m_upperBound{};
0167   };
0168 
0169   /// helper to disable a while triggering it, to avoid infinite recursion
0170   struct SwapCall {
0171     using callback_t = std::function<void( PropertyBase& )>;
0172     callback_t tmp, &orig;
0173     SwapCall( callback_t& input ) : orig( input ) { tmp.swap( orig ); }
0174     ~SwapCall() { orig.swap( tmp ); }
0175     void operator()( PropertyBase& p ) const { tmp( p ); }
0176   };
0177 
0178   struct NoHandler {
0179     void useReadHandler( const PropertyBase& ) const {}
0180     void setReadHandler( std::function<void( PropertyBase& )> ) {
0181       throw std::logic_error( "setReadHandler not implemented for this class" );
0182     }
0183     std::function<void( PropertyBase& )> getReadHandler() const { return nullptr; }
0184     void                                 useUpdateHandler( const PropertyBase& ) const {}
0185     void                                 setUpdateHandler( std::function<void( PropertyBase& )> ) {
0186       throw std::logic_error( "setUpdateHandler not implemented for this class" );
0187     }
0188     std::function<void( PropertyBase& )> getUpdateHandler() const { return nullptr; }
0189   };
0190   struct ReadHandler : NoHandler {
0191     mutable std::function<void( PropertyBase& )> m_readCallBack;
0192     void                                         useReadHandler( const PropertyBase& p ) const {
0193       if ( m_readCallBack ) { SwapCall{ m_readCallBack }( const_cast<PropertyBase&>( p ) ); }
0194     }
0195     void setReadHandler( std::function<void( PropertyBase& )> fun ) { m_readCallBack = std::move( fun ); }
0196     std::function<void( PropertyBase& )> getReadHandler() const { return m_readCallBack; }
0197   };
0198   struct UpdateHandler : NoHandler {
0199     std::function<void( PropertyBase& )> m_updateCallBack;
0200     void                                 useUpdateHandler( PropertyBase& p ) {
0201       if ( m_updateCallBack ) {
0202         try {
0203           SwapCall{ m_updateCallBack }( p );
0204         } catch ( const std::exception& x ) {
0205           throw std::invalid_argument( "failure in update handler of '" + p.name() + "': " + x.what() );
0206         }
0207       }
0208     }
0209     void setUpdateHandler( std::function<void( PropertyBase& )> fun ) { m_updateCallBack = std::move( fun ); }
0210     std::function<void( PropertyBase& )> getUpdateHandler() const { return m_updateCallBack; }
0211   };
0212   struct ReadUpdateHandler : ReadHandler, UpdateHandler {
0213     using ReadHandler::getReadHandler;
0214     using ReadHandler::setReadHandler;
0215     using ReadHandler::useReadHandler;
0216     using UpdateHandler::getUpdateHandler;
0217     using UpdateHandler::setUpdateHandler;
0218     using UpdateHandler::useUpdateHandler;
0219   };
0220 
0221   enum class ParsingErrorPolicy { Ignore, Warning, Exception, Abort };
0222   ParsingErrorPolicy parsingErrorPolicy();
0223   ParsingErrorPolicy setParsingErrorPolicy( ParsingErrorPolicy p );
0224 } // namespace Gaudi::Details::Property