|
- #pragma once
-
- #include <limits>
-
- #include <cppcore/misc/exception.h>
- #include <cppcore/misc/type_helper.h>
-
- #include "enum.h"
- #include "string.h"
- #include "convert_cast.h"
-
- #ifdef _GLIBCXX_VECTOR
- #define CPPCORE_HAS_VECTOR
- #endif
-
- #ifdef _GLIBCXX_LIST
- #define CPPCORE_HAS_LIST
- #endif
-
- namespace cppcore
- {
-
- /* global */
-
- template<typename T, typename T_traits>
- inline std::string to_string(const T& value)
- { return string_conversion_t<T_traits>::template to_string<T>(value); }
-
- template<typename T, typename T_traits>
- inline void to_string(std::ostream& os, const T& value)
- { string_conversion_t<T_traits>::template to_string<T>(os, value); }
-
- template<typename T, typename T_traits>
- inline bool try_from_string(const std::string& s, T& value)
- { return string_conversion_t<T_traits>::template try_from_string<T>(s, value); }
-
- template<typename T, typename T_traits>
- inline T from_string(const std::string& s)
- { return string_conversion_t<T_traits>::template from_string<T>(s); }
-
- template<typename T, typename T_traits>
- inline T from_string_default(const std::string& s, const T& default_value)
- { return string_conversion_t<T_traits>::template from_string_default<T>(s, default_value); }
-
- template<typename T_predicate>
- inline bool string_split(const std::string& str, char seperator, T_predicate&& predicate)
- {
- auto* i = str.c_str();
- auto* e = str.c_str() + str.size();
- auto* s = i;
- while (i <= e)
- {
- if ( s != e
- && ( *i == seperator
- || *i == '\0'))
- {
- std::string tmp(s, convert_cast<size_t>(i - s));
- if (!predicate(std::move(tmp)))
- return false;
- s = i + 1;
- }
- ++i;
- }
- return true;
- }
-
- /* string_conversion */
-
- template<typename T_traits>
- template<typename T>
- inline std::string string_conversion_t<T_traits>
- ::to_string(const T& value)
- {
- using predicate_type = typename traits_type::template to_string_predicate_type<T>;
- return predicate_type { } (value);
- }
-
- template<typename T_traits>
- template<typename T>
- inline void string_conversion_t<T_traits>
- ::to_string(std::ostream& os, const T& value)
- {
- using predicate_type = typename traits_type::template to_stream_predicate_type<T>;
- predicate_type { } (os, value);
- }
-
- template<typename T_traits>
- template<typename T>
- inline bool string_conversion_t<T_traits>
- ::try_from_string(const std::string& s, T& value)
- {
- using predicate_type = typename traits_type::template from_string_predicate_type<T>;
- return predicate_type { } (s, value);
- }
-
- template<typename T_traits>
- template<typename T>
- inline T string_conversion_t<T_traits>
- ::from_string(const std::string& s)
- {
- using namespace ::std;
- T ret;
- if (!try_from_string(s, ret))
- throw convert_exception("unable to convert '"s + s + "' to '"s + type_helper<T>::name() + "'"s);
- return ret;
- }
-
- template<typename T_traits>
- template<typename T>
- inline T string_conversion_t<T_traits>
- ::from_string_default(const std::string& s, const T& default_value)
- {
- T ret;
- return try_from_string(s, ret)
- ? ret
- : default_value;
- }
-
- namespace __impl
- {
-
- /* op_to_string */
-
- template<typename T, typename Enable>
- struct op_to_string
- {
- inline std::string operator()(const T& v) const
- { return std::to_string(v); }
- };
-
- template<typename T>
- struct op_to_string<T, std::enable_if_t<std::is_enum_v<T>>>
- {
- inline std::string operator()(const T& v) const
- { return enum_conversion<T>::to_string(v); }
- };
-
- template<typename T>
- struct op_to_string<T, std::enable_if_t<std::is_floating_point_v<T>>>
- {
- inline std::string operator()(const T& v) const
- {
- std::stringstream os;
- op_to_stream<T> { } (os, v);
- return os.str();
- }
- };
-
- template<>
- struct op_to_string<std::string, void>
- {
- inline std::string operator()(const std::string& v) const
- { return v; }
- };
-
- template<typename T, size_t N>
- struct op_to_string<T[N], std::enable_if_t<std::is_same_v<std::decay_t<T>, char>>>
- {
- using value_type = T[N];
-
- inline std::string operator()(const value_type& v) const
- { return std::string(v, N-1); }
- };
-
- template<typename T>
- struct op_to_string<T*, std::enable_if_t<std::is_same_v<std::decay_t<T>, char>>>
- {
- using value_type = T*;
-
- inline std::string operator()(const value_type& v) const
- { return std::string(v); }
- };
-
- template<typename T>
- struct op_to_string<T, decltype(std::declval<T>().to_string(std::declval<std::ostream&>()), void())>
- {
- inline std::string operator()(const T& v) const
- {
- std::ostringstream os;
- v.to_string(os);
- return os.str();
- }
- };
-
- template<typename T>
- struct op_to_string<T, decltype(std::declval<T>().to_string(), void())>
- {
- inline std::string operator()(const T& v) const
- { return v.to_string(); }
- };
-
- #ifdef CPPCORE_HAS_VECTOR
- template<typename T>
- struct op_to_string<std::vector<T>, void>
- {
- inline std::string operator()(const std::vector<T>& v) const
- {
- std::ostringstream os;
- op_to_stream<std::vector<T>> { } (os, v);
- return os.str();
- }
- };
- #endif
-
- #ifdef CPPCORE_HAS_LIST
- template<typename T>
- struct op_to_string<std::list<T>, void>
- {
- inline std::string operator()(const std::list<T>& v) const
- {
- std::ostringstream os;
- op_to_stream<std::list<T>> { } (os, v);
- return os.str();
- }
- };
- #endif
-
- /* op_to_stream */
-
- template<typename T, typename Enable>
- struct op_to_stream
- {
- inline void operator()(std::ostream& os, const T& v) const
- { os << v; }
- };
-
- template<typename T>
- struct op_to_stream<T, std::enable_if_t<std::is_enum_v<T>>>
- {
- static constexpr decltype(auto) enable_streaming = true;
-
- inline void operator()(std::ostream& os, const T& v) const
- { os << enum_conversion<T>::to_string(v); }
- };
-
- template<typename T>
- struct op_to_stream<T, decltype(std::declval<T>().to_string(std::declval<std::ostream&>()), void())>
- {
- static constexpr decltype(auto) enable_streaming = true;
-
- inline void operator()(std::ostream& os, const T& v) const
- { v.to_string(os); }
- };
-
- template<typename T>
- struct op_to_stream<T, decltype(std::declval<T>().to_string(), void())>
- {
- static constexpr decltype(auto) enable_streaming = true;
-
- inline void operator()(std::ostream& os, const T& v) const
- { os << v.to_string(); }
- };
-
- #ifdef CPPCORE_HAS_VECTOR
- template<typename T>
- struct op_to_stream<std::vector<T>, void>
- {
- static constexpr decltype(auto) enable_streaming = true;
-
- 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 CPPCORE_HAS_LIST
- template<typename T>
- struct op_to_stream<std::list<T>, void>
- {
- static constexpr decltype(auto) enable_streaming = true;
-
- 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
- {
- std::istringstream ss(s);
- ss >> value;
- return static_cast<bool>(ss);
- }
- };
-
- template<>
- struct op_from_string<std::string, void>
- {
- inline bool operator()(const std::string& s, std::string& value) const
- {
- value = s;
- return true;
- }
- };
-
- template<>
- struct op_from_string<const char*, void>
- {
- inline bool operator()(const std::string& s, const char*& value) const
- {
- value = s.c_str();
- return true;
- }
- };
-
- template<>
- struct op_from_string<bool, void>
- {
- inline bool operator()(const std::string& s, bool& value) const
- {
- 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);
- })
- || ( cppcore::try_from_string(s, i)
- && i != 0);
- return true;
- }
- };
-
- template<typename T>
- struct op_from_string<T, std::enable_if_t<std::is_enum_v<T>>>
- {
- inline bool operator()(const std::string& s, T& v) const
- { return enum_conversion<T>::try_to_enum(s, v); }
- };
-
- 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& v) const
- { return v.from_string(s); }
- };
-
- 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& v) const
- { return T::from_string(s, v); }
- };
-
- template<typename T>
- struct op_from_string<T, typename std::enable_if_t<std::is_unsigned_v<T> && std::is_integral_v<T>>>
- {
- inline bool operator()(const std::string& s, T& value) const
- {
- char *e = nullptr;
- const char *c = s.c_str();
- auto tmp = std::strtoull(c, &e, 0);
- if (tmp > std::numeric_limits<T>::max())
- return false;
- value = static_cast<T>(tmp);
- return (c != e);
- }
- };
-
- template<typename T>
- struct op_from_string<T, typename std::enable_if_t<std::is_signed_v<T> && std::is_integral_v<T>>>
- {
- inline bool operator()(const std::string& s, T& value) const
- {
- char *e = nullptr;
- const char *c = s.c_str();
- auto tmp = std::strtoll(c, &e, 0);
- if ( tmp > std::numeric_limits<T>::max()
- || tmp < std::numeric_limits<T>::min())
- return false;
- value = static_cast<T>(tmp);
- return (c != e);
- }
- };
-
- template<typename T>
- struct op_from_string<T, typename std::enable_if_t<std::is_floating_point_v<T>>>
- {
- inline bool operator()(const std::string& s, T& value) const
- {
- char *e = nullptr;
- const char *c = s.c_str();
- auto tmp = std::strtold(c, &e);
- if ( tmp > static_cast<long double>(std::numeric_limits<T>::max())
- || tmp < static_cast<long double>(std::numeric_limits<T>::min()))
- return false;
- value = static_cast<T>(tmp);
- return (c != e);
- }
- };
-
- #ifdef CPPCORE_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
- {
- std::vector<T> tmp;
- auto ret = string_split(str, ',', [&](const std::string& s) {
- tmp.emplace_back();
- return try_from_string(s, tmp.back());
- });
- if (ret)
- value = std::move(tmp);
- return ret;
- }
- };
- #endif
-
- #ifdef CPPCORE_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
- {
- std::list<T> tmp;
- auto ret = string_split(str, ',', [&tmp](auto&& s) {
- tmp.emplace_back();
- return try_from_string(s, tmp.back());
- });
- if (ret)
- value = std::move(tmp);
- return ret;
- }
- };
- #endif
- }
-
- }
-
-
- namespace std
- {
-
- template<typename T_char, typename T_traits, typename X>
- inline auto operator<<(basic_ostream<T_char, T_traits>& os, X&& x)
- -> std::enable_if_t<
- cppcore::__impl::op_to_stream<std::decay_t<X>>::enable_streaming,
- basic_ostream<T_char, T_traits>&>
- {
- using op_type = cppcore::__impl::op_to_stream<std::decay_t<X>>;
- op_type()(os, std::forward<X>(x));
- return os;
- }
-
- }
|