algorithm.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. // Copyright (C) 2016-2018 T. Zachary Laine
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_YAP_DETAIL_EXPRESSION_HPP_INCLUDED
  7. #define BOOST_YAP_DETAIL_EXPRESSION_HPP_INCLUDED
  8. #include <boost/yap/algorithm_fwd.hpp>
  9. #include <boost/hana/size.hpp>
  10. #include <boost/hana/tuple.hpp>
  11. #include <memory>
  12. #include <type_traits>
  13. namespace boost { namespace yap { namespace detail {
  14. // static_const
  15. template<typename T>
  16. struct static_const
  17. {
  18. static constexpr T value{};
  19. };
  20. template<typename T>
  21. constexpr T static_const<T>::value;
  22. // partial_decay
  23. template<typename T>
  24. struct partial_decay
  25. {
  26. using type = T;
  27. };
  28. template<typename T>
  29. struct partial_decay<T[]>
  30. {
  31. using type = T *;
  32. };
  33. template<typename T, std::size_t N>
  34. struct partial_decay<T[N]>
  35. {
  36. using type = T *;
  37. };
  38. template<typename T>
  39. struct partial_decay<T (&)[]>
  40. {
  41. using type = T *;
  42. };
  43. template<typename T, std::size_t N>
  44. struct partial_decay<T (&)[N]>
  45. {
  46. using type = T *;
  47. };
  48. template<typename R, typename... A>
  49. struct partial_decay<R(A...)>
  50. {
  51. using type = R (*)(A...);
  52. };
  53. template<typename R, typename... A>
  54. struct partial_decay<R(A..., ...)>
  55. {
  56. using type = R (*)(A..., ...);
  57. };
  58. template<typename R, typename... A>
  59. struct partial_decay<R (&)(A...)>
  60. {
  61. using type = R (*)(A...);
  62. };
  63. template<typename R, typename... A>
  64. struct partial_decay<R (&)(A..., ...)>
  65. {
  66. using type = R (*)(A..., ...);
  67. };
  68. template<typename R, typename... A>
  69. struct partial_decay<R (*&)(A...)>
  70. {
  71. using type = R (*)(A...);
  72. };
  73. template<typename R, typename... A>
  74. struct partial_decay<R (*&)(A..., ...)>
  75. {
  76. using type = R (*)(A..., ...);
  77. };
  78. // operand_value_type_phase_1
  79. template<
  80. typename T,
  81. typename U = typename detail::partial_decay<T>::type,
  82. bool AddRValueRef = std::is_same<T, U>::value && !std::is_const<U>::value>
  83. struct operand_value_type_phase_1;
  84. template<typename T, typename U>
  85. struct operand_value_type_phase_1<T, U, true>
  86. {
  87. using type = U &&;
  88. };
  89. template<typename T, typename U>
  90. struct operand_value_type_phase_1<T, U, false>
  91. {
  92. using type = U;
  93. };
  94. // expr_ref
  95. template<template<expr_kind, class> class ExprTemplate, typename T>
  96. struct expr_ref
  97. {
  98. using type = expression_ref<ExprTemplate, T>;
  99. };
  100. template<template<expr_kind, class> class ExprTemplate, typename Tuple>
  101. struct expr_ref<ExprTemplate, ExprTemplate<expr_kind::expr_ref, Tuple> &>
  102. {
  103. using type = ExprTemplate<expr_kind::expr_ref, Tuple>;
  104. };
  105. template<template<expr_kind, class> class ExprTemplate, typename Tuple>
  106. struct expr_ref<
  107. ExprTemplate,
  108. ExprTemplate<expr_kind::expr_ref, Tuple> const &>
  109. {
  110. using type = ExprTemplate<expr_kind::expr_ref, Tuple>;
  111. };
  112. template<template<expr_kind, class> class ExprTemplate, typename T>
  113. using expr_ref_t = typename expr_ref<ExprTemplate, T>::type;
  114. template<template<expr_kind, class> class ExprTemplate, typename T>
  115. struct expr_ref_tuple;
  116. template<template<expr_kind, class> class ExprTemplate, typename Tuple>
  117. struct expr_ref_tuple<
  118. ExprTemplate,
  119. ExprTemplate<expr_kind::expr_ref, Tuple>>
  120. {
  121. using type = Tuple;
  122. };
  123. template<template<expr_kind, class> class ExprTemplate, typename T>
  124. using expr_ref_tuple_t = typename expr_ref_tuple<ExprTemplate, T>::type;
  125. // operand_type
  126. template<
  127. template<expr_kind, class> class ExprTemplate,
  128. typename T,
  129. typename U = typename operand_value_type_phase_1<T>::type,
  130. bool RemoveRefs = std::is_rvalue_reference<U>::value,
  131. bool IsExpr = is_expr<T>::value,
  132. bool IsLRef = std::is_lvalue_reference<T>::value>
  133. struct operand_type;
  134. template<
  135. template<expr_kind, class> class ExprTemplate,
  136. typename T,
  137. typename U,
  138. bool RemoveRefs>
  139. struct operand_type<ExprTemplate, T, U, RemoveRefs, true, false>
  140. {
  141. using type = remove_cv_ref_t<T>;
  142. };
  143. template<
  144. template<expr_kind, class> class ExprTemplate,
  145. typename T,
  146. typename U,
  147. bool RemoveRefs>
  148. struct operand_type<ExprTemplate, T, U, RemoveRefs, true, true>
  149. {
  150. using type = expr_ref_t<ExprTemplate, T>;
  151. };
  152. template<
  153. template<expr_kind, class> class ExprTemplate,
  154. typename T,
  155. typename U,
  156. bool RemoveRefs,
  157. bool IsLRef>
  158. struct operand_type<ExprTemplate, T, U, RemoveRefs, true, IsLRef>
  159. {
  160. using type = remove_cv_ref_t<T>;
  161. };
  162. template<
  163. template<expr_kind, class> class ExprTemplate,
  164. typename T,
  165. typename U,
  166. bool IsLRef>
  167. struct operand_type<ExprTemplate, T, U, true, false, IsLRef>
  168. {
  169. using type = terminal<ExprTemplate, std::remove_reference_t<U>>;
  170. };
  171. template<
  172. template<expr_kind, class> class ExprTemplate,
  173. typename T,
  174. typename U,
  175. bool IsLRef>
  176. struct operand_type<ExprTemplate, T, U, false, false, IsLRef>
  177. {
  178. using type = terminal<ExprTemplate, U>;
  179. };
  180. template<template<expr_kind, class> class ExprTemplate, typename T>
  181. using operand_type_t = typename operand_type<ExprTemplate, T>::type;
  182. // make_operand
  183. template<typename T>
  184. struct make_operand
  185. {
  186. template<typename U>
  187. constexpr auto operator()(U && u)
  188. {
  189. return T{static_cast<U &&>(u)};
  190. }
  191. };
  192. template<template<expr_kind, class> class ExprTemplate, typename Tuple>
  193. struct make_operand<ExprTemplate<expr_kind::expr_ref, Tuple>>
  194. {
  195. constexpr auto operator()(ExprTemplate<expr_kind::expr_ref, Tuple> expr)
  196. {
  197. return expr;
  198. }
  199. template<typename U>
  200. constexpr auto operator()(U && u)
  201. {
  202. return ExprTemplate<expr_kind::expr_ref, Tuple>{
  203. Tuple{std::addressof(u)}};
  204. }
  205. };
  206. // free_binary_op_result
  207. template<
  208. template<expr_kind, class> class ExprTemplate,
  209. expr_kind OpKind,
  210. typename T,
  211. typename U,
  212. bool TNonExprUExpr = !is_expr<T>::value && is_expr<U>::value,
  213. bool ULvalueRef = std::is_lvalue_reference<U>::value>
  214. struct free_binary_op_result;
  215. template<
  216. template<expr_kind, class> class ExprTemplate,
  217. expr_kind OpKind,
  218. typename T,
  219. typename U>
  220. struct free_binary_op_result<ExprTemplate, OpKind, T, U, true, true>
  221. {
  222. using lhs_type = operand_type_t<ExprTemplate, T>;
  223. using rhs_type = expr_ref_t<ExprTemplate, U>;
  224. using rhs_tuple_type = expr_ref_tuple_t<ExprTemplate, rhs_type>;
  225. using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
  226. };
  227. template<
  228. template<expr_kind, class> class ExprTemplate,
  229. expr_kind OpKind,
  230. typename T,
  231. typename U>
  232. struct free_binary_op_result<ExprTemplate, OpKind, T, U, true, false>
  233. {
  234. using lhs_type = operand_type_t<ExprTemplate, T>;
  235. using rhs_type = remove_cv_ref_t<U>;
  236. using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
  237. };
  238. template<
  239. template<expr_kind, class> class ExprTemplate,
  240. expr_kind OpKind,
  241. typename T,
  242. typename U>
  243. using free_binary_op_result_t =
  244. typename free_binary_op_result<ExprTemplate, OpKind, T, U>::type;
  245. // ternary_op_result
  246. template<
  247. template<expr_kind, class> class ExprTemplate,
  248. typename T,
  249. typename U,
  250. typename V,
  251. bool Valid =
  252. is_expr<T>::value || is_expr<U>::value || is_expr<V>::value>
  253. struct ternary_op_result;
  254. template<
  255. template<expr_kind, class> class ExprTemplate,
  256. typename T,
  257. typename U,
  258. typename V>
  259. struct ternary_op_result<ExprTemplate, T, U, V, true>
  260. {
  261. using cond_type = operand_type_t<ExprTemplate, T>;
  262. using then_type = operand_type_t<ExprTemplate, U>;
  263. using else_type = operand_type_t<ExprTemplate, V>;
  264. using type = ExprTemplate<
  265. expr_kind::if_else,
  266. hana::tuple<cond_type, then_type, else_type>>;
  267. };
  268. template<
  269. template<expr_kind, class> class ExprTemplate,
  270. typename T,
  271. typename U,
  272. typename V>
  273. using ternary_op_result_t =
  274. typename ternary_op_result<ExprTemplate, T, U, V>::type;
  275. // udt_any_ternary_op_result
  276. template<
  277. template<expr_kind, class> class ExprTemplate,
  278. typename T,
  279. typename U,
  280. typename V,
  281. template<class> class UdtTrait,
  282. bool Valid = !is_expr<T>::value && !is_expr<U>::value &&
  283. !is_expr<V>::value &&
  284. (UdtTrait<remove_cv_ref_t<T>>::value ||
  285. UdtTrait<remove_cv_ref_t<U>>::value ||
  286. UdtTrait<remove_cv_ref_t<V>>::value)>
  287. struct udt_any_ternary_op_result;
  288. template<
  289. template<expr_kind, class> class ExprTemplate,
  290. typename T,
  291. typename U,
  292. typename V,
  293. template<class> class UdtTrait>
  294. struct udt_any_ternary_op_result<ExprTemplate, T, U, V, UdtTrait, true>
  295. {
  296. using cond_type = operand_type_t<ExprTemplate, T>;
  297. using then_type = operand_type_t<ExprTemplate, U>;
  298. using else_type = operand_type_t<ExprTemplate, V>;
  299. using type = ExprTemplate<
  300. expr_kind::if_else,
  301. hana::tuple<cond_type, then_type, else_type>>;
  302. };
  303. template<
  304. template<expr_kind, class> class ExprTemplate,
  305. typename T,
  306. typename U,
  307. typename V,
  308. template<class> class UdtTrait>
  309. using udt_any_ternary_op_result_t =
  310. typename udt_any_ternary_op_result<ExprTemplate, T, U, V, UdtTrait>::
  311. type;
  312. // udt_unary_op_result
  313. template<
  314. template<expr_kind, class> class ExprTemplate,
  315. expr_kind OpKind,
  316. typename T,
  317. template<class> class UdtTrait,
  318. bool Valid = !is_expr<T>::value && UdtTrait<remove_cv_ref_t<T>>::value>
  319. struct udt_unary_op_result;
  320. template<
  321. template<expr_kind, class> class ExprTemplate,
  322. expr_kind OpKind,
  323. typename T,
  324. template<class> class UdtTrait>
  325. struct udt_unary_op_result<ExprTemplate, OpKind, T, UdtTrait, true>
  326. {
  327. using x_type = operand_type_t<ExprTemplate, T>;
  328. using type = ExprTemplate<OpKind, hana::tuple<x_type>>;
  329. };
  330. template<
  331. template<expr_kind, class> class ExprTemplate,
  332. expr_kind OpKind,
  333. typename T,
  334. template<class> class UdtTrait>
  335. using udt_unary_op_result_t =
  336. typename udt_unary_op_result<ExprTemplate, OpKind, T, UdtTrait>::type;
  337. // udt_udt_binary_op_result
  338. template<typename T, template<class> class UdtTrait>
  339. struct is_udt_arg
  340. {
  341. static bool const value =
  342. !is_expr<T>::value && UdtTrait<remove_cv_ref_t<T>>::value;
  343. };
  344. template<
  345. template<expr_kind, class> class ExprTemplate,
  346. expr_kind OpKind,
  347. typename T,
  348. typename U,
  349. template<class> class TUdtTrait,
  350. template<class> class UUdtTrait,
  351. bool Valid =
  352. is_udt_arg<T, TUdtTrait>::value && is_udt_arg<U, UUdtTrait>::value>
  353. struct udt_udt_binary_op_result;
  354. template<
  355. template<expr_kind, class> class ExprTemplate,
  356. expr_kind OpKind,
  357. typename T,
  358. typename U,
  359. template<class> class TUdtTrait,
  360. template<class> class UUdtTrait>
  361. struct udt_udt_binary_op_result<
  362. ExprTemplate,
  363. OpKind,
  364. T,
  365. U,
  366. TUdtTrait,
  367. UUdtTrait,
  368. true>
  369. {
  370. using lhs_type = operand_type_t<ExprTemplate, T>;
  371. using rhs_type = operand_type_t<ExprTemplate, U>;
  372. using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
  373. };
  374. template<
  375. template<expr_kind, class> class ExprTemplate,
  376. expr_kind OpKind,
  377. typename T,
  378. typename U,
  379. template<class> class TUdtTrait,
  380. template<class> class UUdtTrait>
  381. using udt_udt_binary_op_result_t = typename udt_udt_binary_op_result<
  382. ExprTemplate,
  383. OpKind,
  384. T,
  385. U,
  386. TUdtTrait,
  387. UUdtTrait>::type;
  388. // udt_any_binary_op_result
  389. template<
  390. template<expr_kind, class> class ExprTemplate,
  391. expr_kind OpKind,
  392. typename T,
  393. typename U,
  394. template<class> class UdtTrait,
  395. bool Valid = !is_expr<T>::value && !is_expr<U>::value &&
  396. (UdtTrait<remove_cv_ref_t<T>>::value ||
  397. UdtTrait<remove_cv_ref_t<U>>::value)>
  398. struct udt_any_binary_op_result;
  399. template<
  400. template<expr_kind, class> class ExprTemplate,
  401. expr_kind OpKind,
  402. typename T,
  403. typename U,
  404. template<class> class UdtTrait>
  405. struct udt_any_binary_op_result<ExprTemplate, OpKind, T, U, UdtTrait, true>
  406. {
  407. using lhs_type = operand_type_t<ExprTemplate, T>;
  408. using rhs_type = operand_type_t<ExprTemplate, U>;
  409. using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
  410. };
  411. template<
  412. template<expr_kind, class> class ExprTemplate,
  413. expr_kind OpKind,
  414. typename T,
  415. typename U,
  416. template<class> class UdtTrait>
  417. using udt_any_binary_op_result_t = typename udt_any_binary_op_result<
  418. ExprTemplate,
  419. OpKind,
  420. T,
  421. U,
  422. UdtTrait>::type;
  423. // not_copy_or_move
  424. template<typename LeftT, typename RightT>
  425. struct copy_or_move : std::false_type
  426. {
  427. };
  428. template<typename T>
  429. struct copy_or_move<T, T const &> : std::true_type
  430. {
  431. };
  432. template<typename T>
  433. struct copy_or_move<T, T &> : std::true_type
  434. {
  435. };
  436. template<typename T>
  437. struct copy_or_move<T, T &&> : std::true_type
  438. {
  439. };
  440. // expr_arity
  441. enum class expr_arity { invalid, one, two, three, n };
  442. template<expr_kind Kind>
  443. constexpr expr_arity arity_of()
  444. {
  445. switch (Kind) {
  446. case expr_kind::expr_ref:
  447. case expr_kind::terminal:
  448. // unary
  449. case expr_kind::unary_plus: // +
  450. case expr_kind::negate: // -
  451. case expr_kind::dereference: // *
  452. case expr_kind::complement: // ~
  453. case expr_kind::address_of: // &
  454. case expr_kind::logical_not: // !
  455. case expr_kind::pre_inc: // ++
  456. case expr_kind::pre_dec: // --
  457. case expr_kind::post_inc: // ++(int)
  458. case expr_kind::post_dec: // --(int)
  459. return expr_arity::one;
  460. // binary
  461. case expr_kind::shift_left: // <<
  462. case expr_kind::shift_right: // >>
  463. case expr_kind::multiplies: // *
  464. case expr_kind::divides: // /
  465. case expr_kind::modulus: // %
  466. case expr_kind::plus: // +
  467. case expr_kind::minus: // -
  468. case expr_kind::less: // <
  469. case expr_kind::greater: // >
  470. case expr_kind::less_equal: // <=
  471. case expr_kind::greater_equal: // >=
  472. case expr_kind::equal_to: // ==
  473. case expr_kind::not_equal_to: // !=
  474. case expr_kind::logical_or: // ||
  475. case expr_kind::logical_and: // &&
  476. case expr_kind::bitwise_and: // &
  477. case expr_kind::bitwise_or: // |
  478. case expr_kind::bitwise_xor: // ^
  479. case expr_kind::comma: // :
  480. case expr_kind::mem_ptr: // ->*
  481. case expr_kind::assign: // =
  482. case expr_kind::shift_left_assign: // <<=
  483. case expr_kind::shift_right_assign: // >>=
  484. case expr_kind::multiplies_assign: // *=
  485. case expr_kind::divides_assign: // /=
  486. case expr_kind::modulus_assign: // %=
  487. case expr_kind::plus_assign: // +=
  488. case expr_kind::minus_assign: // -=
  489. case expr_kind::bitwise_and_assign: // &=
  490. case expr_kind::bitwise_or_assign: // |=
  491. case expr_kind::bitwise_xor_assign: // ^=
  492. case expr_kind::subscript: // []
  493. return expr_arity::two;
  494. // ternary
  495. case expr_kind::if_else: // (analogous to) ?:
  496. return expr_arity::three;
  497. // n-ary
  498. case expr_kind::call: // ()
  499. return expr_arity::n;
  500. default: return expr_arity::invalid;
  501. }
  502. }
  503. }}}
  504. #endif