Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

469 linhas
14 KiB

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