|
|
@@ -49,6 +49,11 @@ struct is_associative<T, std::void_t<typename T::mapped_type>> : std::true_type
|
|
|
template <typename, typename = void> struct is_container : std::false_type {};
|
|
|
template <typename T>
|
|
|
struct is_container<T, std::void_t<typename T::value_type>> : std::true_type {};
|
|
|
+
|
|
|
+template <typename T> struct decay { using type = std::decay_t<T>; };
|
|
|
+template <template <typename...> class C, typename... Ts>
|
|
|
+struct decay<C<Ts...>> { using type = C<std::decay_t<Ts>...>; };
|
|
|
+template <typename T> using decay_t = typename decay<std::decay_t<T>>::type;
|
|
|
}
|
|
|
|
|
|
namespace string_utils::detail {
|
|
|
@@ -83,11 +88,9 @@ bool cast(std::vector<S> const &strs, T & to) noexcept {
|
|
|
return strs.size() == N && detail::cast_tuple(strs, to, std::make_index_sequence<N>{});
|
|
|
} else if constexpr (detail::is_associative<T>{}) {
|
|
|
for (S const &elem : strs) {
|
|
|
- size_t const pos = elem.find('=');
|
|
|
- auto [key, sk] = cast<typename T::key_type>(elem.substr(0, pos));
|
|
|
- auto [value, sv] = cast<typename T::key_type>(elem.substr(pos + 1));
|
|
|
- if (pos == S::npos || !sk || !sv) { return false; }
|
|
|
- to.insert(std::move(key), std::move(value));
|
|
|
+ auto [tmp, success] = cast<typename T::value_type>(detail::keyval(elem));
|
|
|
+ if (!success) { return false; }
|
|
|
+ to.insert(std::move(tmp));
|
|
|
}
|
|
|
} else if constexpr (detail::is_container<T>{}) {
|
|
|
for (S const &elem : strs) {
|
|
|
@@ -178,16 +181,23 @@ bool cast_number(std::string_view str, T & to, F func) noexcept {
|
|
|
to = func(str.data(), &counter);
|
|
|
return counter == str.end();
|
|
|
}
|
|
|
+
|
|
|
+template <typename S> std::vector<S> keyval(S const &input) {
|
|
|
+ size_t const pos = input.find('=');
|
|
|
+ return pos == S::npos ? std::vector{input}
|
|
|
+ : std::vector{input.substr(0, pos), input.substr(pos + 1)};
|
|
|
+}
|
|
|
}
|
|
|
|
|
|
// This should be placed last in the file
|
|
|
namespace string_utils {
|
|
|
template <typename T, typename S> std::pair<T, bool> cast(S const & str) noexcept {
|
|
|
using string_utils::cast;
|
|
|
- std::pair<std::decay_t<T>, bool> rval;
|
|
|
+ std::pair<detail::decay_t<T>, bool> rval;
|
|
|
rval.second = cast(str, rval.first);
|
|
|
return rval;
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
|
|
|
#undef CAST_NUMBER_IMPL
|