Explorar el Código

refactor: more unification

Sam Jaffe hace 3 años
padre
commit
925984bd1c
Se han modificado 1 ficheros con 52 adiciones y 38 borrados
  1. 52 38
      include/string_utils/cast.h

+ 52 - 38
include/string_utils/cast.h

@@ -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;
 }