tuple.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. // Copyright (C) 2020 T. Zachary Laine
  2. // Copyright Louis Dionne 2013-2017
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_PARSER_TUPLE_HPP
  8. #define BOOST_PARSER_TUPLE_HPP
  9. #include <boost/parser/config.hpp>
  10. #include <boost/parser/detail/detection.hpp>
  11. #if BOOST_PARSER_USE_STD_TUPLE
  12. #include <tuple>
  13. #else
  14. // Silence very verbose warnings about std::is_pod/std::is_literal being
  15. // deprecated.
  16. #if defined(__GNUC__) || defined(__clang__)
  17. # pragma GCC diagnostic push
  18. # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  19. # pragma GCC diagnostic ignored "-Wunused-value"
  20. #endif
  21. #include <boost/hana.hpp>
  22. #if defined(__GNUC__) || defined(__clang__)
  23. # pragma GCC diagnostic pop
  24. #endif
  25. #endif
  26. namespace boost { namespace parser {
  27. namespace detail {
  28. // to_int() and parse_llong() taken from boost/hana/bool.hpp.
  29. constexpr int to_int(char c)
  30. {
  31. int result = 0;
  32. if (c >= 'A' && c <= 'F') {
  33. result = static_cast<int>(c) - static_cast<int>('A') + 10;
  34. } else if (c >= 'a' && c <= 'f') {
  35. result = static_cast<int>(c) - static_cast<int>('a') + 10;
  36. } else {
  37. result = static_cast<int>(c) - static_cast<int>('0');
  38. }
  39. return result;
  40. }
  41. template<std::size_t N>
  42. constexpr long long parse_llong(const char (&arr)[N])
  43. {
  44. long long base = 10;
  45. std::size_t offset = 0;
  46. if constexpr (N > 2) {
  47. bool starts_with_zero = arr[0] == '0';
  48. bool is_hex = starts_with_zero && arr[1] == 'x';
  49. bool is_binary = starts_with_zero && arr[1] == 'b';
  50. if (is_hex) {
  51. // 0xDEADBEEF (hexadecimal)
  52. base = 16;
  53. offset = 2;
  54. } else if (is_binary) {
  55. // 0b101011101 (binary)
  56. base = 2;
  57. offset = 2;
  58. } else if (starts_with_zero) {
  59. // 012345 (octal)
  60. base = 8;
  61. offset = 1;
  62. }
  63. }
  64. long long number = 0;
  65. long long multiplier = 1;
  66. for (std::size_t i = 0; i < N - offset; ++i) {
  67. char c = arr[N - 1 - i];
  68. if (c != '\'') { // skip digit separators
  69. number += to_int(c) * multiplier;
  70. multiplier *= base;
  71. }
  72. }
  73. return number;
  74. }
  75. }
  76. /** The tuple template alias used within Boost.Parser. This will be
  77. `boost::hana::tuple` if `BOOST_PARSER_USE_HANA_TUPLE` is defined, and
  78. `std::tuple` otherwise. */
  79. #if BOOST_PARSER_USE_STD_TUPLE
  80. template<typename... Args>
  81. using tuple = std::tuple<Args...>;
  82. #else
  83. template<typename... Args>
  84. using tuple = hana::tuple<Args...>;
  85. #endif
  86. /** A template alias that is `boost::hana::integral_constant<T, I>` if
  87. `BOOST_PARSER_USE_HANA_TUPLE` is defined, and
  88. `std::integral_constant<T, I>` otherwise. */
  89. #if BOOST_PARSER_USE_STD_TUPLE
  90. template<typename T, T I>
  91. using integral_constant = std::integral_constant<T, I>;
  92. #else
  93. template<typename T, T I>
  94. using integral_constant = hana::integral_constant<T, I>;
  95. #endif
  96. /** An accessor that returns a reference to the `I`-th data member of an
  97. aggregate struct or `boost::parser::tuple`. */
  98. template<typename T, typename U, U I>
  99. constexpr decltype(auto) get(T && x, integral_constant<U, I> i);
  100. /** A template alias that is `boost::hana::llong<I>` if
  101. `BOOST_PARSER_USE_HANA_TUPLE` is defined, and
  102. `std::integral_constant<long long, I>` otherwise. */
  103. template<long long I>
  104. using llong = integral_constant<long long, I>;
  105. namespace literals {
  106. /** A literal that can be used to concisely name `parser::llong`
  107. integral constants. */
  108. template<char... chars>
  109. constexpr auto operator""_c()
  110. {
  111. constexpr long long n =
  112. detail::parse_llong<sizeof...(chars)>({chars...});
  113. return llong<n>{};
  114. }
  115. }
  116. namespace detail {
  117. /** A tuple accessor that returns a reference to the `I`-th element. */
  118. template<typename T, T I, typename... Args>
  119. constexpr decltype(auto)
  120. tuple_get(tuple<Args...> const & t, integral_constant<T, I>)
  121. {
  122. #if BOOST_PARSER_USE_STD_TUPLE
  123. return std::get<I>(t);
  124. #else
  125. return hana::at_c<I>(t);
  126. #endif
  127. }
  128. /** A tuple accessor that returns a reference to the `I`-th element. */
  129. template<typename T, T I, typename... Args>
  130. constexpr decltype(auto)
  131. tuple_get(tuple<Args...> & t, integral_constant<T, I>)
  132. {
  133. #if BOOST_PARSER_USE_STD_TUPLE
  134. return std::get<I>(t);
  135. #else
  136. return hana::at_c<I>(t);
  137. #endif
  138. }
  139. /** A tuple accessor that returns a reference to the `I`-th element. */
  140. template<typename T, T I, typename... Args>
  141. constexpr decltype(auto)
  142. tuple_get(tuple<Args...> && t, integral_constant<T, I>)
  143. {
  144. #if BOOST_PARSER_USE_STD_TUPLE
  145. return std::move(std::get<I>(t));
  146. #else
  147. return std::move(hana::at_c<I>(t));
  148. #endif
  149. }
  150. template<int N>
  151. struct ce_int
  152. {
  153. constexpr static int value = N;
  154. };
  155. struct whatever
  156. {
  157. int _;
  158. template<typename T>
  159. operator T() const && noexcept
  160. {
  161. // Yuck.
  162. std::remove_reference_t<T> * ptr = nullptr;
  163. ptr += 1; // warning mitigation
  164. return *ptr;
  165. }
  166. };
  167. template<typename T, int... Is>
  168. constexpr auto
  169. constructible_expr_impl(std::integer_sequence<int, Is...>)
  170. -> decltype(T{whatever{Is}...}, ce_int<1>{});
  171. template<typename T, typename N>
  172. using constructible_expr = decltype(detail::constructible_expr_impl<T>(
  173. std::make_integer_sequence<int, N::value>()));
  174. template<typename T, int... Is>
  175. constexpr int struct_arity_impl(std::integer_sequence<int, Is...>)
  176. {
  177. return (
  178. detected_or_t<ce_int<0>, constructible_expr, T, ce_int<Is>>::
  179. value +
  180. ... + 0);
  181. }
  182. // This often mistakenly returns 1 when you give it a struct with
  183. // private/protected members, because of copy/move construction.
  184. // Fortunately, we don't care -- we never assign from tuples of size
  185. // 1.
  186. template<typename T>
  187. constexpr int struct_arity_v =
  188. detail::struct_arity_impl<T>(std::make_integer_sequence<
  189. int,
  190. BOOST_PARSER_MAX_AGGREGATE_SIZE>()) -
  191. 1;
  192. template<typename T>
  193. constexpr int tuple_size_ = -1;
  194. template<typename... Elems>
  195. constexpr int tuple_size_<tuple<Elems...>> = sizeof...(Elems);
  196. template<typename T, typename Tuple, int... Is>
  197. auto assign_tuple_to_aggregate(
  198. T & x, Tuple tup, std::integer_sequence<int, Is...>)
  199. -> decltype(x = T{parser::get(std::move(tup), llong<Is>{})...});
  200. template<typename T, typename Tuple, int... Is>
  201. auto tuple_to_aggregate(Tuple && tup, std::integer_sequence<int, Is...>)
  202. -> decltype(T{std::move(parser::get(tup, llong<Is>{}))...})
  203. {
  204. return T{std::move(parser::get(tup, llong<Is>{}))...};
  205. }
  206. template<typename T, typename Tuple>
  207. using tuple_to_aggregate_expr =
  208. decltype(detail::assign_tuple_to_aggregate(
  209. std::declval<T &>(),
  210. std::declval<Tuple>(),
  211. std::make_integer_sequence<int, tuple_size_<Tuple>>()));
  212. template<typename Struct, typename Tuple>
  213. constexpr bool is_struct_assignable_v =
  214. struct_arity_v<Struct> == tuple_size_<Tuple>
  215. ? is_detected_v<tuple_to_aggregate_expr, Struct, Tuple>
  216. : false;
  217. template<int N>
  218. struct tie_aggregate_impl
  219. {
  220. template<typename T>
  221. static constexpr auto call(T & x)
  222. {
  223. static_assert(
  224. sizeof(T) && false,
  225. "It looks like you're trying to use a struct larger than "
  226. "the limit.");
  227. }
  228. };
  229. template<typename T>
  230. constexpr auto tie_aggregate(T & x)
  231. {
  232. static_assert(!std::is_union_v<T>);
  233. return tie_aggregate_impl<struct_arity_v<T>>::call(x);
  234. }
  235. template<typename Tuple, typename Tie, int... Is>
  236. auto aggregate_to_tuple(
  237. Tuple & tup, Tie tie, std::integer_sequence<int, Is...>)
  238. -> decltype((
  239. (parser::get(tup, llong<Is>{}) =
  240. std::move(parser::get(tie, llong<Is>{}))),
  241. ...,
  242. (void)0))
  243. {
  244. return (
  245. (parser::get(tup, llong<Is>{}) =
  246. std::move(parser::get(tie, llong<Is>{}))),
  247. ...,
  248. (void)0);
  249. }
  250. template<typename Tuple, typename T>
  251. using aggregate_to_tuple_expr = decltype(detail::aggregate_to_tuple(
  252. std::declval<Tuple &>(),
  253. detail::tie_aggregate(std::declval<T &>()),
  254. std::make_integer_sequence<int, tuple_size_<Tuple>>()));
  255. template<typename Tuple, typename Struct>
  256. constexpr bool is_tuple_assignable_impl()
  257. {
  258. if constexpr (
  259. std::is_aggregate_v<Struct> &&
  260. struct_arity_v<Struct> == tuple_size_<Tuple>) {
  261. return is_detected_v<aggregate_to_tuple_expr, Tuple, Struct>;
  262. } else {
  263. return false;
  264. }
  265. }
  266. template<typename Tuple, typename Struct>
  267. constexpr bool
  268. is_tuple_assignable_v = is_tuple_assignable_impl<Tuple, Struct>();
  269. template<typename T>
  270. struct is_tuple : std::false_type
  271. {};
  272. template<typename... T>
  273. struct is_tuple<tuple<T...>> : std::true_type
  274. {};
  275. }
  276. template<typename T, typename U, U I>
  277. constexpr decltype(auto) get(T && x, integral_constant<U, I> i)
  278. {
  279. using just_t = std::decay_t<T>;
  280. if constexpr (detail::is_tuple<just_t>::value) {
  281. return detail::tuple_get((T &&) x, i);
  282. } else if constexpr (std::is_aggregate_v<just_t>) {
  283. auto tup = detail::tie_aggregate(x);
  284. return detail::tuple_get(tup, i);
  285. } else {
  286. static_assert(
  287. sizeof(T) != sizeof(T),
  288. "boost::parser::get() is only defined for boost::parser::tuple "
  289. "and aggregate structs.");
  290. }
  291. }
  292. }}
  293. #include <boost/parser/detail/aggr_to_tuple_generated.hpp>
  294. #endif