選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

176 行
5.1 KiB

  1. #pragma once
  2. #include <map>
  3. #include <type_traits>
  4. #include <cpputils/misc/string.h>
  5. #include <cpputils/misc/exception.h>
  6. #define DEFINE_ENUM_TO_STRING_MAP(enum, ...) \
  7. namespace utl { \
  8. namespace __impl { \
  9. template<> \
  10. struct map_enum_to_string<enum> \
  11. { \
  12. using enum_to_string_map_type = std::map<enum, std::string>; \
  13. static inline enum_to_string_map_type value() \
  14. { \
  15. static const enum_to_string_map_type map({ \
  16. __VA_ARGS__ \
  17. }); \
  18. return map; \
  19. } \
  20. }; } }
  21. #define DEFINE_STRING_TO_ENUM_MAP(enum, less, ...) \
  22. namespace utl { \
  23. namespace __impl { \
  24. template<> \
  25. struct map_string_to_enum<enum> \
  26. { \
  27. using string_to_enum_map_type = std::map<std::string, enum, less>; \
  28. static inline string_to_enum_map_type value() \
  29. { \
  30. static const string_to_enum_map_type map({ \
  31. __VA_ARGS__ \
  32. }); \
  33. return map; \
  34. } \
  35. }; } }
  36. #define DEFINE_DEFAULT_ENUM_VALUE(enum, value) \
  37. namespace utl { \
  38. namespace __impl { \
  39. template<> \
  40. struct default_enum_value<enum> \
  41. { \
  42. static inline enum value() \
  43. { return value; } \
  44. }; } }
  45. namespace utl
  46. {
  47. namespace __impl
  48. {
  49. struct invariant_string_less
  50. {
  51. inline bool operator()(const std::string& lhs, const std::string& rhs) const
  52. {
  53. auto c1 = lhs.c_str();
  54. auto c2 = rhs.c_str();
  55. auto l1 = lhs.size();
  56. auto l2 = rhs.size();
  57. while (l1 > 0 && l2 > 0 && std::tolower(*c1) == std::tolower(*c2))
  58. {
  59. ++c1;
  60. ++c2;
  61. --l1;
  62. --l2;
  63. }
  64. return l1 > 0 && l2 > 0
  65. ? std::tolower(*c1) < std::tolower(*c2)
  66. : l1 < l2;
  67. }
  68. };
  69. template<class T>
  70. struct map_enum_to_string
  71. {
  72. using enum_to_string_map_type = std::map<T, std::string>;
  73. static inline enum_to_string_map_type value()
  74. {
  75. static const enum_to_string_map_type map;
  76. return map;
  77. }
  78. };
  79. template<class T>
  80. struct map_string_to_enum
  81. {
  82. using string_to_enum_map_type = std::map<std::string, T>;
  83. static inline string_to_enum_map_type value()
  84. {
  85. static const string_to_enum_map_type map;
  86. return map;
  87. }
  88. };
  89. template<class T>
  90. struct default_enum_value
  91. {
  92. static inline T value()
  93. { throw exception("unable to convert string to enum"); }
  94. };
  95. }
  96. using invariant_string_less = __impl::invariant_string_less;
  97. template<class T>
  98. struct enum_conversion
  99. {
  100. using map_enum_to_string_type = __impl::map_enum_to_string<T>;
  101. using map_string_to_enum_type = __impl::map_string_to_enum<T>;
  102. using default_enum_value_type = __impl::default_enum_value<T>;
  103. using base_type = typename std::underlying_type<T>::type;
  104. static inline std::string to_string(T value, bool addValue)
  105. {
  106. static const auto& map = map_enum_to_string_type::value();
  107. auto it = map.find(value);
  108. std::string ret;
  109. if (it != map.end())
  110. {
  111. ret = it->second;
  112. if (addValue)
  113. ret += '(' + std::to_string(static_cast<base_type>(value)) + ')';
  114. }
  115. else
  116. ret = std::to_string(static_cast<base_type>(value));
  117. return ret;
  118. }
  119. static inline bool try_to_enum(const std::string& str, T& value, bool acceptNumeric)
  120. {
  121. static const auto& map = map_string_to_enum_type::value();
  122. auto it = map.find(str);
  123. if (it != map.end())
  124. {
  125. value = it->second;
  126. return true;
  127. }
  128. if (!acceptNumeric)
  129. return false;
  130. char *e = nullptr;
  131. const char *c = str.c_str();
  132. value = static_cast<T>(std::strtoull(c, &e, 0));
  133. return (c != e);
  134. }
  135. static inline T to_enum(const std::string& str)
  136. {
  137. T value;
  138. return try_to_enum(str, value)
  139. ? value
  140. : default_enum_value_type::value();
  141. }
  142. };
  143. namespace __impl
  144. {
  145. template<class T>
  146. struct op_to_string<T, typename std::enable_if<std::is_enum<T>::value>::type>
  147. {
  148. inline void operator()(std::ostream& os, const T& s) const
  149. { os << enum_conversion<T>::to_string(s, true); }
  150. };
  151. template<class T>
  152. struct op_from_string<T, typename std::enable_if<std::is_enum<T>::value>::type>
  153. {
  154. inline bool operator()(const std::string& s, T& value) const
  155. { return enum_conversion<T>::try_to_enum(s, value, true); }
  156. };
  157. }
  158. }