From 3f991c475999925356dd1630e2cbaf3571b155d6 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 10 Dec 2018 15:58:20 +0900 Subject: [PATCH] improve power of get --- toml/get.hpp | 199 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 152 insertions(+), 47 deletions(-) diff --git a/toml/get.hpp b/toml/get.hpp index cbd48a8..2c84de1 100644 --- a/toml/get.hpp +++ b/toml/get.hpp @@ -6,91 +6,175 @@ namespace toml { +// ============================================================================ +// exact toml::* type + template::value, std::nullptr_t>::type = nullptr> inline T& get(value& v) { - constexpr value_t kind = detail::check_type(); - return v.cast(); + return v.cast::value>(); } template::value, std::nullptr_t>::type = nullptr> inline T const& get(const value& v) { - constexpr value_t kind = detail::check_type(); - return v.cast(); + return v.cast::value>(); } +template::value, std::nullptr_t>::type = nullptr> +inline T && get(value&& v) +{ + return v.cast::value>(); +} + +// ============================================================================ +// integer convertible from toml::Integer + template>, - detail::negation>, std::is_integral + std::is_integral, // T is integral + detail::negation>, // but not bool + detail::negation> // but not toml::integer >::value, std::nullptr_t>::type = nullptr> inline T get(const value& v) { return static_cast(v.cast()); } + +// ============================================================================ +// floating point convertible from toml::Float + template>, std::is_floating_point + std::is_floating_point, // T is floating_point + detail::negation> // but not toml::Float >::value, std::nullptr_t>::type = nullptr> inline T get(const value& v) { return static_cast(v.cast()); } -// array-like type +// ============================================================================ +// std::string; toml uses its own toml::string, but it should be convertible to +// std::string seamlessly + +template::value, std::nullptr_t>::type = nullptr> +inline std::string& get(value& v) +{ + return v.cast().str; +} + +template::value, std::nullptr_t>::type = nullptr> +inline std::string const& get(const value& v) +{ + return v.cast().str; +} + +template::value, std::nullptr_t>::type = nullptr> +inline std::string get(value&& v) +{ + return std::move(v.cast().str); +} + + +// ============================================================================ +// forward declaration. ignore this. template>, detail::is_container + detail::is_container, // T is container + detail::has_resize_method, // T::resize(N) works + detail::negation> // but not toml::array + >::value, std::nullptr_t>::type = nullptr> +T get(const value& v); +template, // T is container + detail::negation>, // no T::resize() exists + detail::negation> // not toml::array + >::value, std::nullptr_t>::type = nullptr> +T get(const value& v); +template::value, std::nullptr_t>::type = nullptr> +T get(const value& v); +template::value, std::nullptr_t>::type = nullptr> +T get(const value& v); +template, // T is map + detail::negation> // but not toml::table + >::value, std::nullptr_t>::type = nullptr> +T get(const toml::value& v); + +// ============================================================================ +// array-like types; most likely STL container, like std::vector, etc. + +template, // T is container + detail::has_resize_method, // T::resize(N) works + detail::negation> // but not toml::array >::value, std::nullptr_t>::type = nullptr> T get(const value& v) { + using value_type = typename T::value_type; const auto& ar = v.cast(); - T tmp; - try - { - ::toml::resize(tmp, ar.size()); - } - catch(std::invalid_argument& iv) - { - throw type_error("toml::get: static array: size is not enough"); - } - std::transform(ar.cbegin(), ar.cend(), tmp.begin(), - [](value const& elem){return get(elem);}); - return tmp; + + T container; container.resize(ar.size()); + std::transform(ar.cbegin(), ar.cend(), container.begin(), + [](const value& x){return ::toml::get(x);}); + return container; } -// table-like case +// ============================================================================ +// array-like types; but does not have resize(); most likely std::array. + template>, detail::is_map + detail::is_container, // T is container + detail::negation>, // no T::resize() exists + detail::negation> // not toml::array >::value, std::nullptr_t>::type = nullptr> -T get(const toml::value& v) +T get(const value& v) { - const auto& tb = v.cast(); - T tmp; - for(const auto& kv : tb){tmp.insert(kv);} - return tmp; + using value_type = typename T::value_type; + const auto& ar = v.cast(); + + T container; + if(ar.size() != container.size()) + { + throw std::out_of_range(detail::format_error_for_value(v, concat_to_string( + "[erorr] toml::get specified container size is ", container.size(), + " but there are ", ar.size(), " elements in toml array."), "here")); + } + std::transform(ar.cbegin(), ar.cend(), container.begin(), + [](const value& x){return ::toml::get(x);}); + return container; } -// array -> pair -template::value, - std::nullptr_t>::type = nullptr> +// ============================================================================ +// std::pair. + +template::value, std::nullptr_t>::type = nullptr> T get(const value& v) { using first_type = typename T::first_type; using second_type = typename T::second_type; + const auto& ar = v.cast(); if(ar.size() != 2) { - throw std::out_of_range( - "toml::get: value does not have 2 elements."); + throw std::out_of_range(detail::format_error_for_value(v, concat_to_string( + "[erorr] toml::get specified std::pair but there are ", ar.size(), + " elements in toml array."), "here")); } - - T tmp; - tmp.first = get(ar.at(0)); - tmp.second = get(ar.at(1)); - return tmp; + return std::make_pair(::toml::get(ar.at(0)), + ::toml::get(ar.at(1))); } +// ============================================================================ +// std::tuple. + namespace detail { @@ -103,25 +187,46 @@ T get_tuple_impl(const toml::Array& a, index_sequence) } // detail -// array -> tuple -template::value, - std::nullptr_t>::type = nullptr> +template::value, std::nullptr_t>::type = nullptr> T get(const value& v) { const auto& ar = v.cast(); if(ar.size() != std::tuple_size::value) { - throw std::out_of_range( - "toml::get: array value does not have " + - std::to_string(std::tuple_size::value) + - std::string(" elements (array has ") + std::to_string(ar.size()) + - std::string(" elements).")); + throw std::out_of_range(detail::format_error_for_value(v, concat_to_string( + "[erorr] toml::get specified std::tuple with ", + std::tuple_size::value, "elements, but there are ", ar.size(), + " elements in toml array."), "here")); } return detail::get_tuple_impl(ar, detail::make_index_sequence::value>{}); } -// get_or ----------------------------------------------------------------- +// ============================================================================ +// map-like types; most likely STL map, like std::map or std::unordered_map. + +template, // T is map + detail::negation> // but not toml::table + >::value, std::nullptr_t>::type = nullptr> +T get(const toml::value& v) +{ + using key_type = typename T::key_type; + using mapped_type = typename T::mapped_type; + static_assert(std::is_convertible::value, + "toml::get only supports map type of which key_type is " + "convertible from std::string."); + T map; + for(const auto& kv : v.cast()) + { + map[key_type(kv.first)] = ::toml::get(kv.second); + } + return map; +} + +// ============================================================================ +// get_or template inline typename std::remove_cv::type>::type