cast.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. //
  2. // cast.h
  3. // string-utils
  4. //
  5. // Created by Sam Jaffe on 2/13/21.
  6. // Copyright © 2021 Sam Jaffe. All rights reserved.
  7. //
  8. #pragma once
  9. #include <cstdlib>
  10. #include <optional>
  11. #include <string>
  12. #include <type_traits>
  13. #include <utility>
  14. #include <variant>
  15. #include <vector>
  16. #include "any_of.h"
  17. #define CAST_NUMBER_IMPL(type, func, ...) \
  18. inline bool cast(std::string const & str, type & to) { \
  19. char * rval; \
  20. to = func(str.c_str(), &rval, ##__VA_ARGS__); \
  21. return rval == str.c_str() + str.length(); \
  22. }
  23. namespace string_utils { namespace traits {
  24. template <typename T, typename = void> struct is_stringy : std::false_type {};
  25. template <typename> struct is_variant : std::false_type {};
  26. template <typename... Ts>
  27. struct is_variant<std::variant<Ts...>> : std::true_type {};
  28. template <typename T>
  29. struct is_stringy<
  30. T, std::enable_if_t<std::is_constructible<T, std::string const &>{} &&
  31. !is_variant<T>{}>> : std::true_type {};
  32. }}
  33. namespace string_utils {
  34. template <typename T> std::pair<T, bool> cast(std::string const & str);
  35. template <typename T> bool cast(std::string const & str, std::optional<T> & to);
  36. template <typename... Ts>
  37. bool cast(std::string const & str, std::variant<Ts...> & to);
  38. template <typename... Ts>
  39. bool cast(std::vector<std::string> const & str, std::tuple<Ts...> & to);
  40. template <typename K, typename V>
  41. bool cast(std::vector<std::string> const & str, std::pair<K, V> & to);
  42. }
  43. namespace string_utils {
  44. template <typename T, typename = std::enable_if_t<traits::is_stringy<T>{}>>
  45. bool cast(std::string const & str, T & to) {
  46. to = T(str);
  47. return true;
  48. }
  49. CAST_NUMBER_IMPL(long, std::strtol, 10);
  50. CAST_NUMBER_IMPL(long long, std::strtoll, 10);
  51. CAST_NUMBER_IMPL(float, std::strtof);
  52. CAST_NUMBER_IMPL(double, std::strtod);
  53. CAST_NUMBER_IMPL(long double, std::strtold);
  54. inline bool cast(std::string const & str, int & to) {
  55. long tmp;
  56. bool rval = cast(str, tmp);
  57. to = static_cast<int>(tmp);
  58. return rval && tmp == static_cast<long>(to);
  59. }
  60. inline bool cast(std::string const & str, bool & to) {
  61. if (any_of(str, "true", "TRUE", "YES", "1")) {
  62. to = true;
  63. return true;
  64. } else if (any_of(str, "false", "FALSE", "NO", "0")) {
  65. to = false;
  66. return true;
  67. }
  68. return false;
  69. }
  70. }
  71. namespace string_utils::detail {
  72. template <typename T, typename... Ts>
  73. bool cast_alternative(std::string const & str, std::variant<Ts...> & to) {
  74. auto [rval, found] = cast<T>(str);
  75. if (found) { to = std::move(rval); }
  76. return found;
  77. }
  78. template <typename Tuple, size_t... Is>
  79. bool cast_tuple(std::vector<std::string> const & str, Tuple & to,
  80. std::index_sequence<Is...>) {
  81. return ((cast(str[Is], std::get<Is>(to))) && ...);
  82. }
  83. template <typename Tuple>
  84. bool cast_tuple(std::vector<std::string> const & str, Tuple & to) {
  85. constexpr size_t N = std::tuple_size_v<Tuple>;
  86. return str.size() == N && cast_tuple(str, to, std::make_index_sequence<N>{});
  87. }
  88. }
  89. namespace string_utils {
  90. template <typename... Ts>
  91. bool cast(std::string const & str, std::variant<Ts...> & to) {
  92. return (detail::cast_alternative<Ts>(str, to) || ...);
  93. }
  94. template <typename T>
  95. bool cast(std::string const & str, std::optional<T> & to) {
  96. auto [value, success] = cast<T>(str);
  97. if (success) { to = std::move(value); }
  98. return true;
  99. }
  100. template <typename... Ts>
  101. bool cast(std::vector<std::string> const & str, std::tuple<Ts...> & to) {
  102. return detail::cast_tuple(str, to);
  103. }
  104. template <typename K, typename V>
  105. bool cast(std::vector<std::string> const & str, std::pair<K, V> & to) {
  106. return detail::cast_tuple(str, to);
  107. }
  108. }
  109. // This should be placed last in the file
  110. namespace string_utils {
  111. template <typename T> std::pair<T, bool> cast(std::string const & str) {
  112. using string_utils::cast;
  113. std::pair<T, bool> rval;
  114. rval.second = cast(str, rval.first);
  115. return rval;
  116. }
  117. }
  118. #undef CAST_NUMBER_IMPL