diff --git a/CepGen/Core/ModuleFactory.h b/CepGen/Core/ModuleFactory.h index 5582d78..e9f4204 100644 --- a/CepGen/Core/ModuleFactory.h +++ b/CepGen/Core/ModuleFactory.h @@ -1,96 +1,101 @@ #ifndef CepGen_Core_ModuleFactory_h #define CepGen_Core_ModuleFactory_h #include "CepGen/Core/ParametersList.h" #include #include #include #include #define BUILDERNM( obj ) obj ## Builder #define STRINGIFY( name ) #name namespace cepgen { /// A generic factory to build modules /// \tparam T Base class to build /// \tparam I Indexing variable type template class ModuleFactory { public: /// Retrieve a unique instance of this factory static ModuleFactory& get() { static ModuleFactory instance; return instance; } /// Default destructor ~ModuleFactory() = default; /// Register a named module in the database /// \tparam U Class to register (inherited from T base class) template void registerModule( const I& name, const ParametersList& def_params = ParametersList() ) { static_assert( std::is_base_of::value, "\n\n *** Failed to register an object with improper inheritance into the factory. ***\n" ); + if ( map_.count( name ) > 0 || params_map_.count( name ) > 0 ) { + std::ostringstream oss; + oss << __PRETTY_FUNCTION__ << "\n\n *** Duplicate module registration detected for index/name \"" << name << "\"! ***\n"; + throw std::invalid_argument( oss.str() ); + } map_[name] = &build; params_map_[name] = def_params; } /// Build one instance of a named module /// \param[in] name Module name to retrieve /// \param[in] params List of parameters to be invoked by the constructor std::unique_ptr build( const I& name, ParametersList params = ParametersList() ) const { if ( name == I() || map_.count( name ) == 0 ) { std::ostringstream oss; oss << __PRETTY_FUNCTION__ << "\n\n *** Failed to build a module with index/name \"" << name << "\" from factory! ***\n"; throw std::invalid_argument( oss.str() ); } if ( params_map_.count( name ) > 0 ) params += params_map_.at( name ); return map_.at( name )( params ); } /// Build one instance of a named module /// \param[in] params List of parameters to be invoked by the constructor std::unique_ptr build( ParametersList params = ParametersList() ) const { if ( params.has( KEY ) ) { const I& idx = params.get( KEY ); if ( map_.count( idx ) == 0 ) throw std::invalid_argument( std::string( __PRETTY_FUNCTION__ )+"\n\n *** Failed to build a module with index/name \""+std::to_string( idx )+"\" from factory! ***\n" ); if ( params_map_.count( idx ) > 0 ) params += params_map_.at( idx ); return map_.at( idx )( params ); } else throw std::invalid_argument( std::string( __PRETTY_FUNCTION__ )+"\n\n *** Failed to retrieve an indexing key from parameters to build from factory! ***\n" ); } /// List of modules registred in the database std::vector modules() const { std::vector out; for ( const auto& p : map_ ) out.emplace_back( p.first ); return out; } static constexpr const char* KEY = "id"; private: explicit ModuleFactory() = default; /// Construct a module with its parameters set template static std::unique_ptr build( const ParametersList& params ) { return std::unique_ptr( new U( params ) ); } protected: /// Constructor type for a module typedef std::unique_ptr (*ModCreate)( const ParametersList& ); /// Database of modules handled by this instance std::unordered_map map_; /// Database of default parameters associated to modules std::unordered_map params_map_; public: ModuleFactory( const ModuleFactory& ) = delete; void operator=( const ModuleFactory& ) = delete; }; } #endif