Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

432 рядки
13 KiB

  1. #pragma once
  2. #include <cppcore/misc/exception.h>
  3. #include <cppcore/misc/type_helper.h>
  4. #include "enum.h"
  5. #include "string.h"
  6. #ifdef _GLIBCXX_VECTOR
  7. #define CPPCORE_HAS_VECTOR
  8. #endif
  9. #ifdef _GLIBCXX_LIST
  10. #define CPPCORE_HAS_LIST
  11. #endif
  12. namespace cppcore
  13. {
  14. /* global */
  15. template<typename T, typename T_traits>
  16. inline std::string to_string(const T& value)
  17. { return string_conversion_t<T_traits>::template to_string<T>(value); }
  18. template<typename T, typename T_traits>
  19. inline void to_string(std::ostream& os, const T& value)
  20. { string_conversion_t<T_traits>::template to_string<T>(os, value); }
  21. template<typename T, typename T_traits>
  22. inline bool try_from_string(const std::string& s, T& value)
  23. { return string_conversion_t<T_traits>::template try_from_string<T>(s, value); }
  24. template<typename T, typename T_traits>
  25. inline T from_string(const std::string& s)
  26. { return string_conversion_t<T_traits>::template from_string<T>(s); }
  27. template<typename T, typename T_traits>
  28. inline T from_string_default(const std::string& s, const T& default_value)
  29. { return string_conversion_t<T_traits>::template from_string_default<T>(s, default_value); }
  30. template<typename T_predicate>
  31. inline bool string_split(const std::string& str, char seperator, T_predicate&& predicate)
  32. {
  33. auto* i = str.c_str();
  34. auto* e = str.c_str() + str.size();
  35. auto* s = i;
  36. while (i <= e)
  37. {
  38. if ( s != e
  39. && ( *i == seperator
  40. || *i == '\0'))
  41. {
  42. std::string tmp(s, static_cast<size_t>(i - s));
  43. if (!predicate(tmp))
  44. return false;
  45. s = i + 1;
  46. }
  47. ++i;
  48. }
  49. return true;
  50. }
  51. /* string_conversion */
  52. template<typename T_traits>
  53. template<typename T>
  54. inline std::string string_conversion_t<T_traits>
  55. ::to_string(const T& value)
  56. {
  57. using predicate_type = typename traits_type::template to_string_predicate_type<T>;
  58. return predicate_type { } (value);
  59. }
  60. template<typename T_traits>
  61. template<typename T>
  62. inline void string_conversion_t<T_traits>
  63. ::to_string(std::ostream& os, const T& value)
  64. {
  65. using predicate_type = typename traits_type::template to_stream_predicate_type<T>;
  66. predicate_type { } (os, value);
  67. }
  68. template<typename T_traits>
  69. template<typename T>
  70. inline bool string_conversion_t<T_traits>
  71. ::try_from_string(const std::string& s, T& value)
  72. {
  73. using predicate_type = typename traits_type::template from_string_predicate_type<T>;
  74. return predicate_type { } (s, value);
  75. }
  76. template<typename T_traits>
  77. template<typename T>
  78. inline T string_conversion_t<T_traits>
  79. ::from_string(const std::string& s)
  80. {
  81. using namespace ::std;
  82. T ret;
  83. if (!try_from_string(s, ret))
  84. throw convert_exception("unable to convert '"s + s + "' to '"s + type_helper<T>::name() + "'"s);
  85. return ret;
  86. }
  87. template<typename T_traits>
  88. template<typename T>
  89. inline T string_conversion_t<T_traits>
  90. ::from_string_default(const std::string& s, const T& default_value)
  91. {
  92. T ret;
  93. return try_from_string(s, ret)
  94. ? ret
  95. : default_value;
  96. }
  97. namespace __impl
  98. {
  99. /* op_to_string */
  100. template<typename T, typename Enable>
  101. struct op_to_string
  102. {
  103. inline std::string operator()(const T& v) const
  104. { return std::to_string(v); }
  105. };
  106. template<typename T>
  107. struct op_to_string<T, std::enable_if_t<std::is_enum_v<T>>>
  108. {
  109. inline std::string operator()(const T& v) const
  110. { return enum_conversion<T>::to_string(v); }
  111. };
  112. template<typename T>
  113. struct op_to_string<T, std::enable_if_t<std::is_floating_point_v<T>>>
  114. {
  115. inline std::string operator()(const T& v) const
  116. {
  117. std::stringstream os;
  118. op_to_stream<T> { } (os, v);
  119. return os.str();
  120. }
  121. };
  122. template<>
  123. struct op_to_string<std::string, void>
  124. {
  125. inline std::string operator()(const std::string& v) const
  126. { return v; }
  127. };
  128. template<typename T, size_t N>
  129. struct op_to_string<T[N], std::enable_if_t<std::is_same_v<std::decay_t<T>, char>>>
  130. {
  131. using value_type = T[N];
  132. inline std::string operator()(const value_type& v) const
  133. { return std::string(v, N-1); }
  134. };
  135. template<typename T>
  136. struct op_to_string<T*, std::enable_if_t<std::is_same_v<std::decay_t<T>, char>>>
  137. {
  138. using value_type = T*;
  139. inline std::string operator()(const value_type& v) const
  140. { return std::string(v); }
  141. };
  142. template<typename T>
  143. struct op_to_string<T, decltype(std::declval<T>().to_string(std::declval<std::ostream&>()), void())>
  144. {
  145. inline std::string operator()(const T& v) const
  146. {
  147. std::ostringstream os;
  148. v.to_string(os);
  149. return os.str();
  150. }
  151. };
  152. template<typename T>
  153. struct op_to_string<T, decltype(std::declval<T>().to_string(), void())>
  154. {
  155. inline std::string operator()(const T& v) const
  156. { return v.to_string(); }
  157. };
  158. #ifdef CPPCORE_HAS_VECTOR
  159. template<typename T>
  160. struct op_to_string<std::vector<T>, void>
  161. {
  162. inline std::string operator()(const std::vector<T>& v) const
  163. {
  164. std::ostringstream os;
  165. op_to_stream<std::vector<T>> { } (os, v);
  166. return os.str();
  167. }
  168. };
  169. #endif
  170. #ifdef CPPCORE_HAS_LIST
  171. template<typename T>
  172. struct op_to_string<std::list<T>, void>
  173. {
  174. inline std::string operator()(const std::list<T>& v) const
  175. {
  176. std::ostringstream os;
  177. op_to_stream<std::list<T>> { } (os, v);
  178. return os.str();
  179. }
  180. };
  181. #endif
  182. /* op_to_stream */
  183. template<typename T, typename Enable>
  184. struct op_to_stream
  185. {
  186. inline void operator()(std::ostream& os, const T& v) const
  187. { os << v; }
  188. };
  189. template<typename T>
  190. struct op_to_stream<T, std::enable_if_t<std::is_enum_v<T>>>
  191. {
  192. inline void operator()(std::ostream& os, const T& v) const
  193. { os << enum_conversion<T>::to_string(v); }
  194. };
  195. template<typename T>
  196. struct op_to_stream<T, decltype(std::declval<T>().to_string(std::declval<std::ostream&>()), void())>
  197. {
  198. inline void operator()(std::ostream& os, const T& v) const
  199. { v.to_string(os); }
  200. };
  201. template<typename T>
  202. struct op_to_stream<T, decltype(std::declval<T>().to_string(), void())>
  203. {
  204. inline void operator()(std::ostream& os, const T& v) const
  205. { os << v.to_string(); }
  206. };
  207. #ifdef CPPCORE_HAS_VECTOR
  208. template<typename T>
  209. struct op_to_stream<std::vector<T>, void>
  210. {
  211. inline void operator()(std::ostream& os, const std::vector<T>& v) const
  212. {
  213. bool first = true;
  214. for (auto& x : v)
  215. {
  216. if (first) first = false;
  217. else os << ',';
  218. to_string(os, x);
  219. }
  220. }
  221. };
  222. #endif
  223. #ifdef CPPCORE_HAS_LIST
  224. template<typename T>
  225. struct op_to_stream<std::list<T>, void>
  226. {
  227. inline void operator()(std::ostream& os, const std::list<T>& v) const
  228. {
  229. bool first = true;
  230. for (auto& x : v)
  231. {
  232. if (first) first = false;
  233. else os << ',';
  234. to_string(os, x);
  235. }
  236. }
  237. };
  238. #endif
  239. /* op_from_string */
  240. template<typename T, typename Enable>
  241. struct op_from_string
  242. {
  243. inline bool operator()(const std::string& s, T& value) const
  244. {
  245. std::istringstream ss(s);
  246. ss >> value;
  247. return static_cast<bool>(ss);
  248. }
  249. };
  250. template<>
  251. struct op_from_string<std::string, void>
  252. {
  253. inline bool operator()(const std::string& s, std::string& value) const
  254. {
  255. value = s;
  256. return true;
  257. }
  258. };
  259. template<>
  260. struct op_from_string<const char*, void>
  261. {
  262. inline bool operator()(const std::string& s, const char*& value) const
  263. {
  264. value = s.c_str();
  265. return true;
  266. }
  267. };
  268. template<>
  269. struct op_from_string<bool, void>
  270. {
  271. inline bool operator()(const std::string& s, bool& value) const
  272. {
  273. const std::string TRUE_STR("true");
  274. int i;
  275. value = s == "T"
  276. || s == "t"
  277. || std::equal(
  278. s.begin(), s.end(),
  279. TRUE_STR.begin(), TRUE_STR.end(),
  280. [](char a, char b) {
  281. return tolower(a) == tolower(b);
  282. })
  283. || ( cppcore::try_from_string(s, i)
  284. && i != 0);
  285. return true;
  286. }
  287. };
  288. template<typename T>
  289. struct op_from_string<T, std::enable_if_t<std::is_enum_v<T>>>
  290. {
  291. inline bool operator()(const std::string& s, T& v) const
  292. { return enum_conversion<T>::try_to_enum(s, v); }
  293. };
  294. template<typename T>
  295. struct op_from_string<T, decltype(std::declval<T&>().from_string(std::declval<const std::string&>()), void())>
  296. {
  297. inline bool operator()(const std::string& s, T& v) const
  298. { return v.from_string(s); }
  299. };
  300. template<typename T>
  301. struct op_from_string<T, decltype(T::from_string(std::declval<const std::string&>(), std::declval<T&>()), void())>
  302. {
  303. inline bool operator()(const std::string& s, T& v) const
  304. { return T::from_string(s, v); }
  305. };
  306. template<typename T>
  307. struct op_from_string<T, typename std::enable_if_t<std::is_integral_v<T>>>
  308. {
  309. inline bool operator()(const std::string& s, T& v) const
  310. {
  311. char *e = nullptr;
  312. const char *c = s.c_str();
  313. v = static_cast<T>(std::strtoull(c, &e, 0));
  314. return (c != e);
  315. }
  316. };
  317. template<typename T>
  318. struct op_from_string<T, typename std::enable_if_t<std::is_floating_point_v<T>>>
  319. {
  320. inline bool operator()(const std::string& s, T& value) const
  321. {
  322. char *e = nullptr;
  323. const char *c = s.c_str();
  324. value = static_cast<T>(std::strtold(c, &e));
  325. return (c != e);
  326. }
  327. };
  328. #ifdef CPPCORE_HAS_VECTOR
  329. template<typename T>
  330. struct op_from_string<std::vector<T>, void>
  331. {
  332. inline bool operator()(const std::string& str, std::vector<T>& value) const
  333. {
  334. std::vector<T> tmp;
  335. auto ret = string_split(str, ',', [&](const std::string& s) {
  336. tmp.emplace_back();
  337. return try_from_string(s, tmp.back());
  338. });
  339. if (ret)
  340. value = std::move(tmp);
  341. return ret;
  342. }
  343. };
  344. #endif
  345. #ifdef CPPCORE_HAS_LIST
  346. template<typename T>
  347. struct op_from_string<std::list<T>, void>
  348. {
  349. inline bool operator()(const std::string& str, std::list<T>& value) const
  350. {
  351. std::list<T> tmp;
  352. auto ret = string_split(str, ',', [&tmp](auto& s) {
  353. tmp.emplace_back();
  354. return try_from_string(s, tmp.back());
  355. });
  356. if (ret)
  357. value = std::move(tmp);
  358. return ret;
  359. }
  360. };
  361. #endif
  362. }
  363. }
  364. namespace std
  365. {
  366. template<typename T_char, typename T_traits, typename X>
  367. inline auto operator<<(basic_ostream<T_char, T_traits>& os, X&& x)
  368. -> decltype(
  369. std::forward<X>(x).to_string(std::declval<basic_ostream<T_char, T_traits>&>()),
  370. std::declval<basic_ostream<T_char, T_traits>&>())
  371. {
  372. std::forward<X>(x).to_string(os);
  373. return os;
  374. }
  375. }