fork download
  1. #include <cstring>
  2. #include <stdexcept>
  3. #include <type_traits>
  4.  
  5. namespace tmp
  6. {
  7. template <typename T>
  8. struct identity
  9. {
  10. typedef T type;
  11. };
  12.  
  13. template <typename T, T V>
  14. struct constant
  15. {
  16. static constexpr T value = V;
  17. };
  18.  
  19. template <bool B>
  20. struct bool_ : constant<bool, B>
  21. {};
  22.  
  23. template <typename First, typename Second>
  24. struct tpair
  25. {};
  26.  
  27. template <typename Pair>
  28. struct first;
  29.  
  30. template <typename First, typename Second>
  31. struct first<tpair<First, Second>> : identity<First>
  32. {};
  33.  
  34. template <typename Pair>
  35. struct second;
  36.  
  37. template <typename First, typename Second>
  38. struct second<tpair<First, Second>> : identity<Second>
  39. {};
  40.  
  41. template <char... S>
  42. struct tstring
  43. {};
  44.  
  45. template <typename S>
  46. struct c_str;
  47.  
  48. template <char... S>
  49. struct c_str<tstring<S...>>
  50. {
  51. static char const value[];
  52. };
  53.  
  54. template <char... S>
  55. char const c_str<tstring<S...>>::value[] = { S..., 0 };
  56.  
  57. template <typename... List>
  58. struct tlist : identity<tlist<List...>>
  59. {};
  60.  
  61. template <typename List>
  62. struct empty : bool_<false>
  63. {};
  64.  
  65. template <>
  66. struct empty<tlist<>> : bool_<true>
  67. {};
  68.  
  69. template <typename T, typename List>
  70. struct push_front;
  71.  
  72. template <typename T, typename... List>
  73. struct push_front<T, tlist<List...>>
  74. : tlist<T, List...>
  75. {};
  76.  
  77. template <typename List>
  78. struct pop_front;
  79.  
  80. template <typename Head, typename... Tail>
  81. struct pop_front<tlist<Head, Tail...>>
  82. : tlist<Tail...>
  83. {};
  84.  
  85. template <typename List>
  86. struct front;
  87.  
  88. template <typename Head, typename... Tail>
  89. struct front<tlist<Head, Tail...>> : identity<Head>
  90. {};
  91.  
  92. template
  93. <
  94. typename T,
  95. typename List,
  96. template <typename, typename> class Less
  97. >
  98. struct insert_sorted;
  99.  
  100. template
  101. <
  102. typename T,
  103. template <typename, typename> class Less
  104. >
  105. struct insert_sorted<T, tlist<>, Less>
  106. : tlist<T>
  107. {};
  108.  
  109. template
  110. <
  111. typename T,
  112. typename Head, typename... Tail,
  113. template <typename, typename> class Less
  114. >
  115. struct insert_sorted<T, tlist<Head, Tail...>, Less>
  116. : std::conditional
  117. <
  118. Less<T, Head>::value,
  119. tlist<T, Head, Tail...>,
  120. typename push_front<Head, typename insert_sorted<T, tlist<Tail...>, Less>::type>::type
  121. >::type
  122. {};
  123.  
  124. template
  125. <
  126. template <typename, typename> class Less,
  127. typename List
  128. >
  129. struct sort;
  130.  
  131. template
  132. <
  133. template <typename, typename> class Less
  134. >
  135. struct sort<Less, tlist<>>
  136. : tlist<>
  137. {};
  138.  
  139. template
  140. <
  141. template <typename, typename> class Less,
  142. typename Head, typename... Tail
  143. >
  144. struct sort<Less, tlist<Head, Tail...>>
  145. : insert_sorted<Head, typename sort<Less, tlist<Tail...>>::type, Less>
  146. {};
  147.  
  148. template <typename S1, typename S2>
  149. struct string_less;
  150.  
  151. template <>
  152. struct string_less<tstring<>, tstring<>>
  153. : bool_<false>
  154. {};
  155.  
  156. template <char... S>
  157. struct string_less<tstring<S...>, tstring<>>
  158. : bool_<false>
  159. {};
  160.  
  161. template <char... S>
  162. struct string_less<tstring<>, tstring<S...>>
  163. : bool_<true>
  164. {};
  165.  
  166. template <char Head1, char... Tail1, char Head2, char... Tail2>
  167. struct string_less<tstring<Head1, Tail1...>, tstring<Head2, Tail2...>>
  168. : bool_
  169. <
  170. Head1 == Head2
  171. ? string_less<tstring<Tail1...>, tstring<Tail2...>>::value
  172. : (Head1 < Head2)
  173. >
  174. {};
  175.  
  176. template <typename Pair1, typename Pair2>
  177. struct pair_less;
  178.  
  179. template <typename Enum1, typename String1, typename Enum2, typename String2>
  180. struct pair_less<tpair<Enum1, String1>, tpair<Enum2, String2>>
  181. : string_less<String1, String2>
  182. {};
  183.  
  184. template <unsigned N, typename List>
  185. struct take_n;
  186.  
  187. template <>
  188. struct take_n<0, tlist<>>
  189. {
  190. typedef tlist<> left;
  191. typedef tlist<> right;
  192. };
  193.  
  194. template <typename Head, typename... Tail>
  195. struct take_n<0, tlist<Head, Tail...>>
  196. {
  197. typedef tlist<> left;
  198. typedef tlist<Head, Tail...> right;
  199. };
  200.  
  201. template <unsigned N, typename Head, typename... Tail>
  202. class take_n<N, tlist<Head, Tail...>>
  203. {
  204. typedef take_n<N - 1, tlist<Tail...>> recurse;
  205.  
  206. public:
  207. typedef typename push_front<Head, typename recurse::left>::type left;
  208. typedef typename recurse::right right;
  209. };
  210.  
  211. template <typename List>
  212. struct cut_half_with_median;
  213.  
  214. template <typename... List>
  215. class cut_half_with_median<tlist<List...>>
  216. {
  217. typedef take_n<sizeof...(List) / 2, tlist<List...>> left_without_median;
  218. typedef take_n<1, typename left_without_median::right> median_with_right;
  219.  
  220. public:
  221. typedef typename left_without_median::left left;
  222. typedef typename front<typename median_with_right::left>::type median;
  223. typedef typename median_with_right::right right;
  224. };
  225.  
  226. template <typename Enum, typename Mappings>
  227. class decision_tree
  228. {
  229. typedef cut_half_with_median<Mappings> cut;
  230. typedef typename cut::median median;
  231.  
  232. Enum not_found(std::string const& value) const
  233. {
  234. throw std::invalid_argument{ "string '" + value + "' has no enum value" };
  235. }
  236.  
  237. Enum less(char const* value, bool_<true>) const
  238. {
  239. return not_found(value);
  240. }
  241.  
  242. Enum less(char const* value, bool_<false>) const
  243. {
  244. return decision_tree<Enum, typename cut::left>()(value);
  245. }
  246.  
  247. Enum greater(char const* value, bool_<true>) const
  248. {
  249. return not_found(value);
  250. }
  251.  
  252. Enum greater(char const* value, bool_<false>) const
  253. {
  254. return decision_tree<Enum, typename cut::right>()(value);
  255. }
  256.  
  257. public:
  258. Enum operator () (char const* value) const
  259. {
  260. auto cmp = std::strcmp(value, c_str<typename second<median>::type>::value);
  261.  
  262. if(cmp < 0)
  263. return less(value, bool_<empty<typename cut::left>::value>());
  264.  
  265. if(cmp > 0)
  266. return greater(value, bool_<empty<typename cut::right>::value>());
  267.  
  268. return first<median>::type::value;
  269. }
  270. };
  271.  
  272. template <typename Enum, typename... Mappings>
  273. struct enum_mapper;
  274.  
  275. template <typename Enum, typename... Strings, Enum... Values>
  276. class enum_mapper<Enum, tpair<constant<Enum, Values>, Strings>...>
  277. {
  278. typedef tlist<tpair<constant<Enum, Values>, Strings>...> mappings;
  279. typedef typename sort<pair_less, mappings>::type sorted_mappings;
  280.  
  281. public:
  282. Enum operator () (char const* value) const
  283. {
  284. return decision_tree<Enum, sorted_mappings>()(value);
  285. }
  286. };
  287. }
  288.  
  289. #define EMAP(E, ...) tmp::tpair<tmp::constant<decltype(E), E>, tmp::tstring<__VA_ARGS__>>
  290.  
  291. ////////////////////////////////////////////////////////////////
  292.  
  293. #include <iostream>
  294.  
  295. enum struct my_enum : unsigned
  296. {
  297. foo,
  298. bar,
  299. baz,
  300. qux,
  301. };
  302.  
  303. std::ostream& operator << (std::ostream& os, my_enum e)
  304. {
  305. static char const* const table[] = { "foo", "bar", "baz", "qux" };
  306. return os << table[static_cast<unsigned>(e)];
  307. }
  308.  
  309. int main()
  310. {
  311. typedef tmp::enum_mapper
  312. <
  313. my_enum,
  314. EMAP(my_enum::baz, 'b','a','z'),
  315. EMAP(my_enum::bar, 'b','a','r'),
  316. EMAP(my_enum::foo, 'f','o','o'),
  317. EMAP(my_enum::qux, 'q','u','x')
  318. > my_enum_mapper;
  319.  
  320. my_enum_mapper mapper;
  321.  
  322. std::cout << mapper("foo") << '\n';
  323. std::cout << mapper("bar") << '\n';
  324. std::cout << mapper("baz") << '\n';
  325. std::cout << mapper("qux") << '\n';
  326.  
  327. try
  328. {
  329. std::cout << mapper("garbage") << '\n';
  330. }
  331.  
  332. catch(std::invalid_argument const& iv)
  333. {
  334. std::cout << iv.what() << '\n';
  335. }
  336. }
  337.  
Success #stdin #stdout 0s 3072KB
stdin
Standard input is empty
stdout
foo
bar
baz
qux
string 'garbage' has no enum value