<commit_before>#include "option_manager.hh"
#include "assert.hh"

#include <sstream>

namespace Kakoune
{

namespace
{

String option_to_string(const String& opt) { return opt; }
void option_from_string(const String& str, String& opt) { opt = str; }

String option_to_string(int opt) { return int_to_str(opt); }
void option_from_string(const String& str, int& opt) { opt = str_to_int(str); }

String option_to_string(bool opt) { return opt ? "true" : "false"; }
void option_from_string(const String& str, bool& opt)
{
    if (str == "true" or str == "yes")
        opt = true;
    else if (str == "false" or str == "no")
        opt = false;
    else
        throw runtime_error("boolean values are either true, yes, false or no");
}

template<typename T>
String option_to_string(const std::vector<T>& opt)
{
    String res;
    for (size_t i = 0; i < opt.size(); ++i)
    {
        res += option_to_string(opt[i]);
        if (i != opt.size() - 1)
            res += ",";
    }
    return res;
}

template<typename T>
void option_from_string(const String& str, std::vector<T>& opt)
{
    opt.clear();
    std::vector<String> elems = split(str, ',');
    for (auto& elem: elems)
    {
        T opt_elem;
        option_from_string(elem, opt_elem);
        opt.push_back(opt_elem);
    }
}

}

template<typename T>
class TypedOption : public Option
{
public:
    TypedOption(OptionManager& manager, String name, const T& value)
        : Option(manager, std::move(name)), m_value(value) {}

    void set(const T& value)
    {
        if (m_value != value)
        {
            m_value = value;
            m_manager.on_option_changed(*this);
        }
    }
    const T& get() const { return m_value; }

    String get_as_string() const override
    {
        return option_to_string(m_value);
    }
    void   set_from_string(const String& str) override
    {
        T val;
        option_from_string(str, val);
        set(val);
    }

    Option* clone(OptionManager& manager) const override
    {
        return new TypedOption{manager, name(), m_value};
    }
private:
    T m_value;
};

Option::Option(OptionManager& manager, String name)
    : m_manager(manager), m_name(std::move(name)) {}

template<typename T> const T& Option::get() const { return dynamic_cast<const TypedOption<T>*>(this)->get(); }
template<typename T> void     Option::set(const T& val) { return dynamic_cast<TypedOption<T>*>(this)->set(val); }

template const String& Option::get<String>() const;
template void Option::set<String>(const String&);

template const int& Option::get<int>() const;
template void Option::set<int>(const int&);

template const bool& Option::get<bool>() const;
template void Option::set<bool>(const bool&);

template const std::vector<int>& Option::get<std::vector<int>>() const;
template void Option::set<std::vector<int>>(const std::vector<int>&);

OptionManager::OptionManager(OptionManager& parent)
    : m_parent(&parent)
{
    parent.register_watcher(*this);
}

OptionManager::~OptionManager()
{<commit_msg>throw a runtime error when a wrong type is requested for an option<commit_after>#include "option_manager.hh"
#include "assert.hh"

#include <sstream>

namespace Kakoune
{

namespace
{

String option_to_string(const String& opt) { return opt; }
void option_from_string(const String& str, String& opt) { opt = str; }

String option_to_string(int opt) { return int_to_str(opt); }
void option_from_string(const String& str, int& opt) { opt = str_to_int(str); }

String option_to_string(bool opt) { return opt ? "true" : "false"; }
void option_from_string(const String& str, bool& opt)
{
    if (str == "true" or str == "yes")
        opt = true;
    else if (str == "false" or str == "no")
        opt = false;
    else
        throw runtime_error("boolean values are either true, yes, false or no");
}

template<typename T>
String option_to_string(const std::vector<T>& opt)
{
    String res;
    for (size_t i = 0; i < opt.size(); ++i)
    {
        res += option_to_string(opt[i]);
        if (i != opt.size() - 1)
            res += ",";
    }
    return res;
}

template<typename T>
void option_from_string(const String& str, std::vector<T>& opt)
{
    opt.clear();
    std::vector<String> elems = split(str, ',');
    for (auto& elem: elems)
    {
        T opt_elem;
        option_from_string(elem, opt_elem);
        opt.push_back(opt_elem);
    }
}

}

template<typename T>
class TypedOption : public Option
{
public:
    TypedOption(OptionManager& manager, String name, const T& value)
        : Option(manager, std::move(name)), m_value(value) {}

    void set(const T& value)
    {
        if (m_value != value)
        {
            m_value = value;
            m_manager.on_option_changed(*this);
        }
    }
    const T& get() const { return m_value; }

    String get_as_string() const override
    {
        return option_to_string(m_value);
    }
    void   set_from_string(const String& str) override
    {
        T val;
        option_from_string(str, val);
        set(val);
    }

    Option* clone(OptionManager& manager) const override
    {
        return new TypedOption{manager, name(), m_value};
    }
private:
    T m_value;
};

Option::Option(OptionManager& manager, String name)
    : m_manager(manager), m_name(std::move(name)) {}

template<typename T> const T& Option::get() const
{
    auto* typed_opt = dynamic_cast<const TypedOption<T>*>(this);
    if (not typed_opt)
        throw runtime_error("option " + name() + " is not of type " + typeid(T).name());
    return typed_opt->get();
}

template<typename T> void     Option::set(const T& val)
{
    auto* typed_opt = dynamic_cast<TypedOption<T>*>(this);
    if (not typed_opt)
        throw runtime_error("option " + name() + " is not of type " + typeid(T).name());
    return typed_opt->set(val);
}

template const String& Option::get<String>() const;
template void Option::set<String>(const String&);

template const int& Option::get<int>() const;
template void Option::set<int>(const int&);

template const bool& Option::get<bool>() const;
template void Option::set<bool>(const bool&);

template const std::vector<int>& Option::get<std::vector<int>>() const;
template void Option::set<std::vector<int>>(const std::vector<int>&);

OptionManager::OptionManager(OptionManager& parent)
    : m_parent(&parent)
{
    parent.register_watcher(*this);
}

OptionManager::~OptionManager()
{
{'fraction_non_alphanumeric': 0.143572098842665, 'fraction_numerical': 0.0006255864873318737, 'mean_word_length': 3.5613409415121255, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4515294', 'n_tokens_mistral': 2094, 'n_tokens_neox': 2089, 'n_words': 536}