|
|
@@ -4,33 +4,129 @@ |
|
|
|
#include <cpputils/misc/exception.h> |
|
|
|
#include <cpputils/misc/type_helper.h> |
|
|
|
|
|
|
|
#ifdef _GLIBCXX_VECTOR |
|
|
|
#define CPPUTILS_HAS_VECTOR |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifdef _GLIBCXX_LIST |
|
|
|
#define CPPUTILS_HAS_LIST |
|
|
|
#endif |
|
|
|
|
|
|
|
namespace utl |
|
|
|
{ |
|
|
|
|
|
|
|
namespace __impl |
|
|
|
{ |
|
|
|
template<class T, class Enable = void> |
|
|
|
template<typename T, typename Enable = void> |
|
|
|
struct op_to_string; |
|
|
|
|
|
|
|
template<typename T, typename Enable = void> |
|
|
|
struct op_from_string; |
|
|
|
} |
|
|
|
|
|
|
|
template<typename T> |
|
|
|
inline void to_string(std::ostream& os, const T& t) |
|
|
|
{ __impl::op_to_string<T>()(os, t); } |
|
|
|
|
|
|
|
template<typename T> |
|
|
|
inline std::string to_string(const T& t) |
|
|
|
{ |
|
|
|
std::ostringstream ss; |
|
|
|
to_string(ss, t); |
|
|
|
return ss.str(); |
|
|
|
} |
|
|
|
|
|
|
|
template<> |
|
|
|
inline std::string to_string<std::string>(const std::string& s) |
|
|
|
{ return s; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T> |
|
|
|
inline bool try_from_string(const std::string& s, T& value) |
|
|
|
{ return __impl::op_from_string<T>()(s, value); } |
|
|
|
|
|
|
|
template<typename T> |
|
|
|
inline T from_string(const std::string& s, T defaultValue) |
|
|
|
{ |
|
|
|
T tmp; |
|
|
|
return try_from_string<T>(s, tmp) |
|
|
|
? tmp |
|
|
|
: defaultValue; |
|
|
|
} |
|
|
|
|
|
|
|
template<typename T> |
|
|
|
inline T from_string(const std::string& s) |
|
|
|
{ |
|
|
|
T tmp; |
|
|
|
if (!try_from_string<T>(s, tmp)) |
|
|
|
throw exception(std::string("unable to convert string to ") + type_helper<T>::name() + ": " + s); |
|
|
|
return tmp; |
|
|
|
} |
|
|
|
|
|
|
|
namespace __impl |
|
|
|
{ |
|
|
|
|
|
|
|
/* op_to_string */ |
|
|
|
|
|
|
|
template<typename T, typename Enable> |
|
|
|
struct op_to_string |
|
|
|
{ |
|
|
|
inline void operator()(std::ostream& os, const T& s) const |
|
|
|
{ os << s; } |
|
|
|
}; |
|
|
|
|
|
|
|
template<class T> |
|
|
|
template<typename T> |
|
|
|
struct op_to_string<T, decltype(std::declval<T>().to_string(std::declval<std::ostream&>()), void())> |
|
|
|
{ |
|
|
|
inline void operator()(std::ostream& os, const T& s) const |
|
|
|
{ s.to_string(os); } |
|
|
|
}; |
|
|
|
|
|
|
|
template<class T> |
|
|
|
template<typename T> |
|
|
|
struct op_to_string<T, decltype(std::declval<T>().to_string(), void())> |
|
|
|
{ |
|
|
|
inline void operator()(std::ostream& os, const T& s) const |
|
|
|
{ os << s.to_string(); } |
|
|
|
}; |
|
|
|
|
|
|
|
template<class T, class Enable = void> |
|
|
|
#ifdef CPPUTILS_HAS_VECTOR |
|
|
|
template<typename T> |
|
|
|
struct op_to_string<std::vector<T>, void> |
|
|
|
{ |
|
|
|
inline void operator()(std::ostream& os, const std::vector<T>& v) const |
|
|
|
{ |
|
|
|
bool first = true; |
|
|
|
for (auto& x : v) |
|
|
|
{ |
|
|
|
if (first) first = false; |
|
|
|
else os << ","; |
|
|
|
to_string(os, x); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifdef CPPUTILS_HAS_LIST |
|
|
|
template<typename T> |
|
|
|
struct op_to_string<std::list<T>, void> |
|
|
|
{ |
|
|
|
inline void operator()(std::ostream& os, const std::list<T>& v) const |
|
|
|
{ |
|
|
|
bool first = true; |
|
|
|
for (auto& x : v) |
|
|
|
{ |
|
|
|
if (first) first = false; |
|
|
|
else os << ","; |
|
|
|
to_string(os, x); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
#endif |
|
|
|
|
|
|
|
/* op_from_string */ |
|
|
|
|
|
|
|
template<typename T, typename Enable> |
|
|
|
struct op_from_string |
|
|
|
{ |
|
|
|
inline bool operator()(const std::string& s, T& value) const |
|
|
@@ -61,21 +157,42 @@ namespace utl |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
template<class T> |
|
|
|
template<> |
|
|
|
struct op_from_string<bool, void> |
|
|
|
{ |
|
|
|
inline bool operator()(const std::string& s, bool& value) const |
|
|
|
{ |
|
|
|
static const std::string TRUE_STR("true"); |
|
|
|
int i; |
|
|
|
value = s == "T" |
|
|
|
|| s == "t" |
|
|
|
|| std::equal( |
|
|
|
s.begin(), s.end(), |
|
|
|
TRUE_STR.begin(), TRUE_STR.end(), |
|
|
|
[](char a, char b) { |
|
|
|
return tolower(a) == tolower(b); |
|
|
|
}) |
|
|
|
|| ( utl::try_from_string(s, i) |
|
|
|
&& i != 0); |
|
|
|
return true; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
template<typename T> |
|
|
|
struct op_from_string<T, decltype(std::declval<T&>().from_string(std::declval<const std::string&>()), void())> |
|
|
|
{ |
|
|
|
inline bool operator()(const std::string& s, T& value) const |
|
|
|
{ return value.from_string(s); } |
|
|
|
}; |
|
|
|
|
|
|
|
template<class T> |
|
|
|
template<typename T> |
|
|
|
struct op_from_string<T, decltype(T::from_string(std::declval<const std::string&>(), std::declval<T&>()), void())> |
|
|
|
{ |
|
|
|
inline bool operator()(const std::string& s, T& value) const |
|
|
|
{ return T::from_string(s, value); } |
|
|
|
}; |
|
|
|
|
|
|
|
template<class T> |
|
|
|
template<typename T> |
|
|
|
struct op_from_string<T, typename std::enable_if<std::is_integral<T>::value>::type> |
|
|
|
{ |
|
|
|
inline bool operator()(const std::string& s, T& value) const |
|
|
@@ -87,7 +204,7 @@ namespace utl |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
template<class T> |
|
|
|
template<typename T> |
|
|
|
struct op_from_string<T, typename std::enable_if<std::is_floating_point<T>::value>::type> |
|
|
|
{ |
|
|
|
inline bool operator()(const std::string& s, T& value) const |
|
|
@@ -98,46 +215,80 @@ namespace utl |
|
|
|
return (c != e); |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
template<class T> |
|
|
|
inline void to_string(std::ostream& os, const T& t) |
|
|
|
{ __impl::op_to_string<T>()(os, t); } |
|
|
|
#ifdef CPPUTILS_HAS_VECTOR |
|
|
|
template<typename T> |
|
|
|
struct op_from_string<std::vector<T>, void> |
|
|
|
{ |
|
|
|
inline bool operator()(const std::string& str, std::vector<T>& value) const |
|
|
|
{ |
|
|
|
auto* i = str.c_str(); |
|
|
|
auto* s = i; |
|
|
|
auto* e = str.c_str() + str.size(); |
|
|
|
std::vector<T> tmp; |
|
|
|
while (i <= e) |
|
|
|
{ |
|
|
|
if ( s != e |
|
|
|
&& ( *i == ',' |
|
|
|
|| *i == '\0')) |
|
|
|
{ |
|
|
|
tmp.emplace_back(); |
|
|
|
if (!utl::try_from_string(std::string(s, static_cast<size_t>(i - s)), tmp.back())) |
|
|
|
return false; |
|
|
|
s = i + 1; |
|
|
|
} |
|
|
|
++i; |
|
|
|
} |
|
|
|
value = std::move(tmp); |
|
|
|
return true; |
|
|
|
} |
|
|
|
}; |
|
|
|
#endif |
|
|
|
|
|
|
|
template<class T> |
|
|
|
inline std::string to_string(const T& t) |
|
|
|
{ |
|
|
|
std::ostringstream ss; |
|
|
|
to_string(ss, t); |
|
|
|
return ss.str(); |
|
|
|
#ifdef CPPUTILS_HAS_LIST |
|
|
|
template<typename T> |
|
|
|
struct op_from_string<std::list<T>, void> |
|
|
|
{ |
|
|
|
inline bool operator()(const std::string& str, std::list<T>& value) const |
|
|
|
{ |
|
|
|
auto* i = str.c_str(); |
|
|
|
auto* s = i; |
|
|
|
auto* e = str.c_str() + str.size(); |
|
|
|
std::list<T> tmp; |
|
|
|
while (i <= e) |
|
|
|
{ |
|
|
|
if ( s != e |
|
|
|
&& ( *i == ',' |
|
|
|
|| *i == '\0')) |
|
|
|
{ |
|
|
|
tmp.emplace_back(); |
|
|
|
if (!utl::try_from_string(std::string(s, static_cast<size_t>(i - s)), tmp.back())) |
|
|
|
return false; |
|
|
|
s = i + 1; |
|
|
|
} |
|
|
|
++i; |
|
|
|
} |
|
|
|
value = std::move(tmp); |
|
|
|
return true; |
|
|
|
} |
|
|
|
}; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
template<> |
|
|
|
inline std::string to_string<std::string>(const std::string& s) |
|
|
|
{ return s; } |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
template<class T> |
|
|
|
inline bool try_from_string(const std::string& s, T& value) |
|
|
|
{ return __impl::op_from_string<T>()(s, value); } |
|
|
|
|
|
|
|
template<class T> |
|
|
|
inline T from_string(const std::string& s, T defaultValue) |
|
|
|
{ |
|
|
|
T tmp; |
|
|
|
return try_from_string<T>(s, tmp) |
|
|
|
? tmp |
|
|
|
: defaultValue; |
|
|
|
} |
|
|
|
namespace std |
|
|
|
{ |
|
|
|
|
|
|
|
template<class T> |
|
|
|
inline T from_string(const std::string& s) |
|
|
|
template<typename T_char, typename T_traits, typename X> |
|
|
|
inline auto operator<<(basic_ostream<T_char, T_traits>& os, X&& x) |
|
|
|
-> decltype( |
|
|
|
std::forward<X>(x).to_string(std::declval<basic_ostream<T_char, T_traits>&>()), |
|
|
|
std::declval<basic_ostream<T_char, T_traits>&>()) |
|
|
|
{ |
|
|
|
T tmp; |
|
|
|
if (!try_from_string<T>(s, tmp)) |
|
|
|
throw exception(std::string("unable to convert string to ") + type_helper<T>::name() + ": " + s); |
|
|
|
return tmp; |
|
|
|
std::forward<X>(x).to_string(os); |
|
|
|
return os; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |