Program Listing for File Configured.hpp

Return to documentation for file (src/include/Configured.hpp)

#ifndef SRC_INCLUDE_CONFIGURED_HPP
#define SRC_INCLUDE_CONFIGURED_HPP

#include "Configurator.hpp"

#include <boost/program_options.hpp>
#include <map>
#include <string>
#include <typeinfo>

namespace Nextsim {

class ConfiguredBase {
public:
    virtual ~ConfiguredBase() = default;
    virtual void configure() = 0;
};

template <typename C> class Configured : public ConfiguredBase {
public:
    Configured() = default;
    virtual ~Configured() = default;

    virtual void configure() = 0;

    template <typename T> static void tryConfigure(T& ref);

    template <typename T> static void tryConfigure(T* ptr);

    template <typename T>
    static inline T getConfiguration(const std::string& name, const T& defaultValue)
    {
        boost::program_options::options_description opt;
        addOption(name, defaultValue, opt);
        return retrieveValue<T>(name, opt);
    }

    static void clearConfigurationMap() { singleOptions.clear(); }

    static const std::map<int, std::string> keyMap;

protected:
    template <typename T> void addOption(const std::string& name, const T& defaultValue)
    {
        addOption(name, defaultValue, singleOptions[name]);
    }

    template <typename T> T retrieveValue(const std::string& name)
    {
        return retrieveValue<T>(name, singleOptions.at(name));
    }

private:
    template <typename T>
    static void addOption(const std::string& name, const T& defaultValue,
        boost::program_options::options_description& opt)
    {
        opt.add_options()(
            name.c_str(), boost::program_options::value<T>()->default_value(defaultValue), "");
    }

    template <typename T>
    static T retrieveValue(
        const std::string& name, boost::program_options::options_description& opt)
    {
        return Configurator::parse(opt)[name].as<T>();
    }

    static std::map<std::string, boost::program_options::options_description> singleOptions;
};

template <typename C>
std::map<std::string, boost::program_options::options_description> Configured<C>::singleOptions;

template <typename C> template <typename T> void Configured<C>::tryConfigure(T& ref)
{
    try {
        dynamic_cast<ConfiguredBase&>(ref).configure();
    } catch (const std::bad_cast& bc) {
        // Do nothing. If the reference is not a derived class of Configured, ignore it.
    }
}

template <typename C> template <typename T> void Configured<C>::tryConfigure(T* ptr)
{
    ConfiguredBase* cfg = dynamic_cast<ConfiguredBase*>(ptr);
    if (cfg)
        cfg->configure();
}

template <typename T> void tryConfigure(T* p_t) { Configured<int>::tryConfigure(p_t); }

template <typename T> void tryConfigure(T& t) { Configured<int>::tryConfigure(t); }
}

#endif /* SRC_INCLUDE_CONFIGURED_HPP */