1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
|
#ifndef RFL_PARSING_MAPREADER_HPP_
#define RFL_PARSING_MAPREADER_HPP_
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#include <vector>
#include "../Result.hpp"
#include "../always_false.hpp"
namespace rfl::parsing {
template <class R, class W, class MapType, class ProcessorsType>
class MapReader {
private:
using InputVarType = typename R::InputVarType;
using KeyType = std::remove_cvref_t<typename MapType::value_type::first_type>;
using ValueType =
std::remove_cvref_t<typename MapType::value_type::second_type>;
public:
MapReader(const R* _r, MapType* _map, std::vector<Error>* _errors)
: r_(_r), map_(_map), errors_(_errors) {}
~MapReader() = default;
void read(const std::string_view& _name,
const InputVarType& _var) const noexcept {
auto res = get_pair(_name, _var);
if (res) {
map_->emplace(std::move(*res));
} else {
errors_->push_back(Error("Failed to parse field '" + std::string(_name) +
"': " + res.error().what()));
}
}
private:
template <class T>
Result<T> key_to_numeric(auto& _pair) const noexcept {
try {
if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
return static_cast<T>(std::stoll(_pair.first));
} else if constexpr (std::is_integral_v<T> && std::is_unsigned_v<T>) {
return static_cast<T>(std::stoull(_pair.first));
} else if constexpr (std::is_floating_point_v<T>) {
return static_cast<T>(std::stod(_pair.first));
} else {
static_assert(always_false_v<T>, "Unsupported type");
}
} catch (std::exception& e) {
return error(e.what());
}
}
Result<std::pair<KeyType, ValueType>> make_key(auto& _pair) const noexcept {
const auto to_pair =
[&](auto _key) -> Result<std::pair<KeyType, ValueType>> {
try {
return std::make_pair(KeyType(std::move(_key)),
std::move(_pair.second));
} catch (std::exception& e) {
return error(e.what());
}
};
if constexpr (std::is_integral_v<KeyType> ||
std::is_floating_point_v<KeyType>) {
return key_to_numeric<KeyType>(_pair).and_then(to_pair);
} else if constexpr (internal::has_reflection_type_v<KeyType>) {
using ReflT = typename KeyType::ReflectionType;
if constexpr (std::is_integral_v<ReflT> ||
std::is_floating_point_v<ReflT>) {
return key_to_numeric<ReflT>(_pair).and_then(to_pair);
} else {
return to_pair(_pair.first);
}
} else {
return std::move(_pair);
}
}
Result<std::pair<KeyType, ValueType>> get_pair(
const std::string_view& _name, const InputVarType& _var) const noexcept {
const auto to_pair = [&](ValueType&& _val) {
auto pair = std::make_pair(std::string(_name), std::move(_val));
return make_key(pair);
};
return Parser<R, W, std::remove_cvref_t<ValueType>, ProcessorsType>::read(
*r_, _var)
.and_then(to_pair);
}
private:
/// The underlying reader.
const R* r_;
/// The underlying map.
MapType* map_;
/// Collects any errors we may have come across.
std::vector<Error>* errors_;
};
} // namespace rfl::parsing
#endif
|