diff --git a/eo/src/eoForge.h b/eo/src/eoForge.h index bc2dbb67d..6fcccf811 100644 --- a/eo/src/eoForge.h +++ b/eo/src/eoForge.h @@ -192,13 +192,13 @@ class eoForgeOperator : public eoForgeInterface * with different parametrization (or not). * * @warning When passing a reference (as it is often the case within ParadisEO), - * it is MANDATORY to wrap it in `std::ref`, or else it will default to use copy. - * This is is a source of bug which your compiler will to detect and that would - * disable any link between operators. + * it is MANDATORY to wrap it in `std::ref`, or else it will default to use copy. + * This is is a source of bug which your compiler will fail to detect and that would + * disable any link between operators. * * @warning You may want to enable instantiation cache to grab some performances. - * The default is set to disable the cache, because its use with operators - * which hold a state will lead to unwanted behaviour. + * The default is set to disable the cache, because its use with operators + * which hold a state will lead to unwanted behaviour. * * @code eoForgeVector> factories(false); @@ -320,6 +320,134 @@ class eoForgeVector : public std::vector*> bool _no_cache; }; +/** A map holding an operator (with deferred instantiation) at a given name. + * + * @note You can actually store several instances of the same class, + * with different parametrization (or not). + * + * @warning When passing a reference (as it is often the case within ParadisEO), + * it is MANDATORY to wrap it in `std::ref`, or else it will default to use copy. + * This is is a source of bug which your compiler will fail to detect and that would + * disable any link between operators. + * + * @warning You may want to enable instantiation cache to grab some performances. + * The default is set to disable the cache, because its use with operators + * which hold a state will lead to unwanted behaviour. + * + * @code + eoForgeMap> factories(false); + + // Capture constructor's parameters and defer instantiation. + factories.add>(1); + factories.setup>(0, 5); // Edit + + // Actually instantiate. + eoSelect& op = factories.instantiate(0); + + // Call. + op(); + * @endcode + * + * @ingroup Foundry + */ +template +class eoForgeMap : public std::map*> +{ + public: + using Interface = Itf; + + /** Default constructor do not cache instantiations. + * + * @warning + * You most probably want to disable caching for operators that hold a state. + * If you enable the cache, the last used instantiation will be used, + * at its last state. + * For example, continuators should most probably not be cached, + * as they very often hold a state in the form of a counter. + * At the end of a search, the continuator will be in the end state, + * and thus always ask for a stop. + * Reusing an instance in this state will de facto disable further searches. + * + * @param always_reinstantiate If false, will enable cache for the forges in this container. + */ + eoForgeMap( bool always_reinstantiate = true ) : + _no_cache(always_reinstantiate) + { } + + /** instantiate the operator managed at the given name. + */ + Itf& instantiate(const std::string& name) + { + return this->at(name)->instantiate(_no_cache); + } + + /** Add an operator to the list. + * + * @warning When passing a reference (as it is often the case within ParadisEO), + * it is MANDATORY to wrap it in `std::ref`, or else it will default to use copy. + * This is is a source of bug which your compiler will to detect and that would + * disable any link between operators. + * + */ + template + void add(const std::string& name, Args... args) + { + // We decay all args to ensure storing everything by value within the forge. + // The references should thus be wrapped in a std::ref. + auto pfo = new eoForgeOperator...>( + std::forward(args)...); + this->insert({name, pfo}); + } + + /** Specialization for operators with empty constructors. + */ + template + void add(const std::string& name) + { + eoForgeInterface* pfo = new eoForgeOperator; + this->insert({name, pfo}); + } + + /** Change the set up arguments to the constructor. + * + * @warning When passing a reference (as it is often the case within ParadisEO), + * it is MANDATORY to wrap it in `std::ref`, or else it will default to use copy. + * This is is a source of bug which your compiler will to detect and that would + * disable any link between operators. + * + * @warning The operator at `name` should have been added with eoForgeMap::add already.. + */ + template + void setup(const std::string& name, Args... args) + { + delete this->at(name); // Silent on nullptr. + auto pfo = new eoForgeOperator...>( + std::forward(args)...); + this->emplace({name, pfo}); + } + + /** Specialization for empty constructors. + */ + template + void setup(const std::string& name) + { + delete this->at(name); + auto pfo = new eoForgeOperator; + this->emplace({name, pfo}); + } + + virtual ~eoForgeMap() + { + for(auto kv : *this) { + delete kv.second; + } + } + + protected: + bool _no_cache; +}; + + /** A range holding a parameter value at a given index. * * This is essential a scalar numerical parameter, with bounds check