|
|
@@ -24,7 +24,7 @@
|
|
|
|
|
|
namespace string_utils {
|
|
|
// A helper object for providing partial specializations for casting
|
|
|
-template <typename, typename = void> struct cast_helper {};
|
|
|
+template <typename, typename = void> struct cast_helper;
|
|
|
|
|
|
// The main parser
|
|
|
template <typename T, typename S> std::pair<T, bool> cast(S const &str) noexcept;
|
|
|
@@ -33,9 +33,10 @@ template <typename S, typename T> bool cast(std::vector<S> const &strs, T & to)
|
|
|
}
|
|
|
|
|
|
namespace string_utils::detail {
|
|
|
+template <typename> struct always_false : std::false_type {};
|
|
|
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)>>>
|
|
|
+struct has_cast_helper<T, S, std::void_t<decltype(cast_helper<T>{}(S{}, T{}))>>
|
|
|
: std::true_type {};
|
|
|
|
|
|
template <typename, typename = void> struct is_tuple : std::false_type {};
|
|
|
@@ -68,22 +69,11 @@ 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<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<T, std::string>{}, "no cast available");
|
|
|
- }
|
|
|
- return true;
|
|
|
-}
|
|
|
+bool cast(std::string_view str, T & to) noexcept { return cast_helper<T>{}(str, to); }
|
|
|
|
|
|
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>{}) {
|
|
|
+ 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>{}) {
|
|
|
@@ -99,12 +89,12 @@ bool cast(std::vector<S> const &strs, T & to) noexcept {
|
|
|
to.insert(to.end(), std::move(tmp));
|
|
|
}
|
|
|
} else {
|
|
|
- static_assert(!detail::has_cast_helper<T, std::vector<S>>{}, "no cast available");
|
|
|
+ return cast_helper<T>{}(strs, to);
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-template <typename V, typename T> bool maybe_cast(std::string const & str, T & to) noexcept {
|
|
|
+template <typename V, typename S, typename T> bool maybe_cast(S const & str, T & to) noexcept {
|
|
|
auto [rval, found] = cast<V>(str);
|
|
|
if (found) { to = std::move(rval); }
|
|
|
return found;
|
|
|
@@ -112,14 +102,14 @@ template <typename V, typename T> bool maybe_cast(std::string const & str, T & t
|
|
|
|
|
|
template <typename... Ts>
|
|
|
struct cast_helper<std::variant<Ts...>> {
|
|
|
- bool operator()(std::string const &str, std::variant<Ts...> & to) const noexcept {
|
|
|
+ bool operator()(std::string_view str, std::variant<Ts...> & to) const noexcept {
|
|
|
return (maybe_cast<Ts>(str, to) || ...);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
template <typename T>
|
|
|
struct cast_helper<std::optional<T>> {
|
|
|
- bool operator()(std::string const &str, std::optional<T> & to) const noexcept {
|
|
|
+ bool operator()(std::string_view str, std::optional<T> & to) const noexcept {
|
|
|
return maybe_cast<T>(str, to) || true;
|
|
|
}
|
|
|
};
|
|
|
@@ -128,6 +118,11 @@ struct cast_helper<std::optional<T>> {
|
|
|
|
|
|
namespace string_utils {
|
|
|
|
|
|
+inline bool cast(std::string_view str, std::string & to) noexcept {
|
|
|
+ to = std::string(str);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
inline bool cast(std::string_view str, long & to) noexcept {
|
|
|
return detail::cast_number(str, to, SAFE_NUMBER_PARSE(std::strtol, 10));
|
|
|
}
|
|
|
@@ -149,10 +144,9 @@ inline bool cast(std::string_view str, long double & to) noexcept {
|
|
|
}
|
|
|
|
|
|
inline bool cast(std::string_view str, int & to) noexcept {
|
|
|
- long tmp;
|
|
|
- bool rval = cast(str, tmp);
|
|
|
+ auto [tmp, success] = cast<long>(str);
|
|
|
to = static_cast<int>(tmp);
|
|
|
- return rval && tmp == static_cast<long>(to);
|
|
|
+ return success && tmp == static_cast<long>(to);
|
|
|
}
|
|
|
|
|
|
inline bool cast(std::string_view str, bool & to) noexcept {
|
|
|
@@ -192,7 +186,6 @@ template <typename S> std::vector<S> keyval(S const &input) {
|
|
|
// 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<detail::decay_t<T>, bool> rval;
|
|
|
rval.second = cast(str, rval.first);
|
|
|
return rval;
|