<commit_before>#pragma once

#include <map>
#include <string>

#include <boost/any.hpp>

#include "blackhole/error.hpp"
#include "cast.hpp"

namespace blackhole {

namespace aux {

template<class T>
struct extractor {
    boost::any source;
    std::string name;

    extractor(const boost::any& source, const std::string& name = T::name()) :
        source(source),
        name(name)
    {}

    extractor<T> operator [](const std::string& name) const {
        std::map<std::string, boost::any> map;
        try {
            to(map);
        } catch (const std::exception&) {
            throw error_t("can not extract '%s': '%s' is not map", name, this->name);
        }
        return extractor<T>(map[name], name);
    }

    template<typename R>
    void to(R& value) const {
        try{
            cast_traits<R>::to(source, value);
        } catch (boost::bad_any_cast&) {
            throw error_t("conversion error for member '%s'", name);
        }
    }

    template<typename R>
    R get() const {
        R value;
        to(value);
        return value;
    }
};

} // namespace aux

}  // namespace blackhole
<commit_msg>More verbose error message now returned with exception if failed to convert `boost::any` type to necessary.<commit_after>#pragma once

#include <map>
#include <string>

#include <boost/any.hpp>

#include "blackhole/error.hpp"
#include "cast.hpp"

namespace blackhole {

namespace aux {

template<class T>
struct extractor {
    boost::any source;
    std::string name;

    extractor(const boost::any& source, const std::string& name = T::name()) :
        source(source),
        name(name)
    {}

    extractor<T> operator [](const std::string& name) const {
        std::map<std::string, boost::any> map;
        try {
            to(map);
        } catch (const std::exception&) {
            throw error_t("can not extract '%s': '%s' is not map", name, this->name);
        }
        return extractor<T>(map[name], name);
    }

    template<typename R>
    void to(R& value) const {
        try {
            cast_traits<R>::to(source, value);
        } catch (const boost::bad_any_cast&) {
            throw error_t("can not extract '%s' field from '%s': member is absent or has different type", name, T::name());
        }
    }

    template<typename R>
    R get() const {
        R value;
        to(value);
        return value;
    }
};

} // namespace aux

}  // namespace blackhole

{'fraction_non_alphanumeric': 0.1418032786885246, 'fraction_numerical': 0.0, 'mean_word_length': 2.442877291960508, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 25, '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': '7807', 'n_tokens_mistral': 763, 'n_tokens_neox': 751, 'n_words': 212}