|
|
@@ -27,42 +27,76 @@ namespace string_utils {
|
|
|
template <typename, typename = void> struct cast_helper {};
|
|
|
|
|
|
// The main parser
|
|
|
-template <typename T> std::pair<T, bool> cast(std::string_view str) noexcept;
|
|
|
+template <typename T, typename S> std::pair<T, bool> cast(S const &str) noexcept;
|
|
|
template <typename T> bool cast(std::string_view str, T & to) noexcept;
|
|
|
-
|
|
|
-// A section of multi-argument parsers
|
|
|
-template <typename... Ts>
|
|
|
-bool cast(std::vector<std::string> const & str, std::tuple<Ts...> & to) noexcept;
|
|
|
-template <typename K, typename V>
|
|
|
-bool cast(std::vector<std::string> const & str, std::pair<K, V> & to) noexcept;
|
|
|
+template <typename S, typename T> bool cast(std::vector<S> const &strs, T & to) noexcept;
|
|
|
}
|
|
|
|
|
|
namespace string_utils::detail {
|
|
|
-template <typename, typename = void> struct has_cast_helper : std::false_type {};
|
|
|
-template <typename T>
|
|
|
-struct has_cast_helper<T, std::void_t<std::result_of_t<cast_helper<T>(std::string, T)>>>
|
|
|
+template <typename, typename, typename = void> struct has_cast_helper : std::false_type {};
|
|
|
+template <typename T, typename S>
|
|
|
+struct has_cast_helper<T, S, std::void_t<std::result_of_t<cast_helper<T>(S, T)>>>
|
|
|
: std::true_type {};
|
|
|
|
|
|
-template <typename T> constexpr bool has_cast_helper_v = has_cast_helper<T>{};
|
|
|
+template <typename, typename = void> struct is_tuple : std::false_type {};
|
|
|
+template <typename T>
|
|
|
+struct is_tuple<T, std::void_t<typename std::tuple_size<T>::type>> : std::true_type {};
|
|
|
+
|
|
|
+template <typename, typename = void> struct is_associative : std::false_type {};
|
|
|
+template <typename T>
|
|
|
+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 {};
|
|
|
}
|
|
|
|
|
|
namespace string_utils::detail {
|
|
|
-template <typename Tuple>
|
|
|
-bool cast_tuple(std::vector<std::string> const & str, Tuple & to) noexcept;
|
|
|
+template <typename Tuple, size_t... Is>
|
|
|
+bool cast_tuple(std::vector<std::string> const & str, Tuple & to,
|
|
|
+ std::index_sequence<Is...>) noexcept;
|
|
|
template <typename T, typename F>
|
|
|
bool cast_number(std::string_view str, T & to, F func) noexcept;
|
|
|
+template <typename S> std::vector<S> keyval(S const &input);
|
|
|
}
|
|
|
|
|
|
namespace string_utils {
|
|
|
|
|
|
template <typename T>
|
|
|
bool cast(std::string_view str, T & to) noexcept {
|
|
|
- if constexpr (detail::has_cast_helper_v<T>) {
|
|
|
+ if constexpr (detail::has_cast_helper<T, std::string>{}) {
|
|
|
return cast_helper<T>{}(str, to);
|
|
|
} else if constexpr (std::is_same_v<T, std::string>) {
|
|
|
to = T(str);
|
|
|
} else {
|
|
|
- static_assert(!detail::has_cast_helper_v<T>, "no cast available");
|
|
|
+ static_assert(!detail::has_cast_helper<T, std::string>{}, "no cast available");
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+template <typename S, typename T>
|
|
|
+bool cast(std::vector<S> const &strs, T & to) noexcept {
|
|
|
+ if constexpr(detail::has_cast_helper<T, std::vector<S>>{}) {
|
|
|
+ return cast_helper<T>{}(strs, to);
|
|
|
+ } else if constexpr (detail::is_tuple<T>{}) {
|
|
|
+ constexpr size_t N = std::tuple_size_v<T>;
|
|
|
+ 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));
|
|
|
+ }
|
|
|
+ } else if constexpr (detail::is_container<T>{}) {
|
|
|
+ for (S const &elem : strs) {
|
|
|
+ auto [tmp, success] = cast<typename T::value_type>(elem);
|
|
|
+ if (!success) { return false; }
|
|
|
+ to.insert(to.end(), std::move(tmp));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ static_assert(!detail::has_cast_helper<T, std::vector<S>>{}, "no cast available");
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
@@ -131,33 +165,13 @@ inline bool cast(std::string_view str, bool & to) noexcept {
|
|
|
|
|
|
}
|
|
|
|
|
|
-namespace string_utils {
|
|
|
-
|
|
|
-template <typename... Ts>
|
|
|
-bool cast(std::vector<std::string> const & str, std::tuple<Ts...> & to) noexcept {
|
|
|
- return detail::cast_tuple(str, to);
|
|
|
-}
|
|
|
-
|
|
|
-template <typename K, typename V>
|
|
|
-bool cast(std::vector<std::string> const & str, std::pair<K, V> & to) noexcept {
|
|
|
- return detail::cast_tuple(str, to);
|
|
|
-}
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
namespace string_utils::detail {
|
|
|
template <typename Tuple, size_t... Is>
|
|
|
bool cast_tuple(std::vector<std::string> const & str, Tuple & to,
|
|
|
- std::index_sequence<Is...>) {
|
|
|
+ std::index_sequence<Is...>) noexcept {
|
|
|
return ((cast(str[Is], std::get<Is>(to))) && ...);
|
|
|
}
|
|
|
|
|
|
-template <typename Tuple>
|
|
|
-bool cast_tuple(std::vector<std::string> const & str, Tuple & to) noexcept {
|
|
|
- constexpr size_t N = std::tuple_size_v<Tuple>;
|
|
|
- return str.size() == N && cast_tuple(str, to, std::make_index_sequence<N>{});
|
|
|
-}
|
|
|
-
|
|
|
template <typename T, typename F>
|
|
|
bool cast_number(std::string_view str, T & to, F func) noexcept {
|
|
|
char *counter = nullptr;
|
|
|
@@ -168,9 +182,9 @@ bool cast_number(std::string_view str, T & to, F func) noexcept {
|
|
|
|
|
|
// This should be placed last in the file
|
|
|
namespace string_utils {
|
|
|
-template <typename T> std::pair<T, bool> cast(std::string_view str) noexcept {
|
|
|
+template <typename T, typename S> std::pair<T, bool> cast(S const & str) noexcept {
|
|
|
using string_utils::cast;
|
|
|
- std::pair<T, bool> rval;
|
|
|
+ std::pair<std::decay_t<T>, bool> rval;
|
|
|
rval.second = cast(str, rval.first);
|
|
|
return rval;
|
|
|
}
|