<commit_before>#pragma once

#include <string>
#include <vector>

#include "blackhole/error.hpp"
#include "blackhole/forwards.hpp"
#include "blackhole/repository/config/base.hpp"
#include "blackhole/repository/config/log.hpp"

namespace blackhole {

namespace repository {

namespace config {

template<>
class parser_t<repository::config::base_t> {
public:
    template<class T>
    static
    typename std::enable_if<
        std::is_base_of<base_t, T>::value,
        T
    >::type
    parse(std::string component, dynamic_t value) {
        if (!value.contains("type")) {
            //!@todo: Throw specialized exception.
            throw blackhole::error_t("'type' field is missing for '%s' component", component);
        }

        std::string type = value["type"].to<std::string>();
        T config(std::move(type));
        config.config(std::move(value.to<dynamic_t::object_t>()));
        return config;
    }
};

template<>
class parser_t<formatter_config_t> {
public:
    static formatter_config_t parse(dynamic_t value) {
        return parser_t<
            repository::config::base_t
        >::parse<formatter_config_t>("formatter", std::move(value));
    }
};

template<>
class parser_t<sink_config_t> {
public:
    static sink_config_t parse(dynamic_t value) {
        return parser_t<
            repository::config::base_t
        >::parse<sink_config_t>("sink", std::move(value));
    }
};

template<>
class parser_t<frontend_config_t> {
public:
    static frontend_config_t parse(dynamic_t value) {
        if (!(value.contains("formatter") && value.contains("sink"))) {
            //!@todo: Throw specialized exception.
            throw blackhole::error_t("both 'formatter' and 'sink' sections must be specified");
        }
<commit_msg>[Aux] Using specialized exception instead of more generic while parsing configuration object.<commit_after>#pragma once

#include <string>
#include <vector>

#include "blackhole/error.hpp"
#include "blackhole/forwards.hpp"
#include "blackhole/repository/config/base.hpp"
#include "blackhole/repository/config/log.hpp"

namespace blackhole {

namespace repository {

namespace config {

namespace error {

class invalid_config_t : public error_t {
public:
    template<typename... Args>
    invalid_config_t(Args&&... args) :
        error_t(std::forward<Args>(args)...)
    {}
};

} // namespace error

template<>
class parser_t<repository::config::base_t> {
public:
    template<class T>
    static
    typename std::enable_if<
        std::is_base_of<base_t, T>::value,
        T
    >::type
    parse(std::string component, dynamic_t value) {
        if (!value.contains("type")) {
            throw error::invalid_config_t(
                "'type' field is missing for '%s' component",
                component
            );
        }

        std::string type = value["type"].to<std::string>();
        T config(std::move(type));
        config.config(std::move(value.to<dynamic_t::object_t>()));
        return config;
    }
};

template<>
class parser_t<formatter_config_t> {
public:
    static formatter_config_t parse(dynamic_t value) {
        return parser_t<
            repository::config::base_t
        >::parse<formatter_config_t>("formatter", std::move(value));
    }
};

template<>
class parser_t<sink_config_t> {
public:
    static sink_config_t parse(dynamic_t value) {
        return parser_t<
            repository::config::base_t
        >::parse<sink_config_t>("sink", std::move(value));
    }
};

template<>
class parser_t<frontend_config_t> {
public:
    static frontend_config_t parse(dynamic_t value) {
        if (!(value.contains("formatter") && value.contains("sink"))) {
            throw error::invalid_config_t(
                "both 'formatter' and 'sink' sections must be specified"
            );
        }

{'fraction_non_alphanumeric': 0.13690007867820614, 'fraction_numerical': 0.0, 'mean_word_length': 3.2519509476031216, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 43, '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': '4881010', 'n_tokens_mistral': 1177, 'n_tokens_neox': 1156, 'n_words': 239}