algorithm.hpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  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_ALGORITHM_HPP_INCLUDED
  7. #define BOOST_YAP_ALGORITHM_HPP_INCLUDED
  8. #include <boost/yap/algorithm_fwd.hpp>
  9. #include <boost/yap/user_macros.hpp>
  10. #include <boost/yap/detail/algorithm.hpp>
  11. #include <boost/hana/size.hpp>
  12. #include <boost/hana/comparing.hpp>
  13. namespace boost { namespace yap {
  14. #ifdef BOOST_NO_CONSTEXPR_IF
  15. namespace detail {
  16. template<typename Expr, bool MutableRvalueRef>
  17. struct deref_impl
  18. {
  19. constexpr decltype(auto) operator()(Expr && expr)
  20. {
  21. return std::move(*expr.elements[hana::llong_c<0>]);
  22. }
  23. };
  24. template<typename Expr>
  25. struct deref_impl<Expr, false>
  26. {
  27. constexpr decltype(auto) operator()(Expr && expr)
  28. {
  29. return *expr.elements[hana::llong_c<0>];
  30. }
  31. };
  32. }
  33. #endif
  34. /** "Dereferences" a reference-expression, forwarding its referent to
  35. the caller. */
  36. template<typename Expr>
  37. constexpr decltype(auto) deref(Expr && expr)
  38. {
  39. static_assert(
  40. is_expr<Expr>::value, "deref() is only defined for expressions.");
  41. static_assert(
  42. detail::remove_cv_ref_t<Expr>::kind == expr_kind::expr_ref,
  43. "deref() is only defined for expr_ref-kind expressions.");
  44. #ifdef BOOST_NO_CONSTEXPR_IF
  45. return detail::deref_impl < Expr,
  46. std::is_rvalue_reference<Expr>::value &&
  47. !std::is_const<std::remove_reference_t<Expr>>::value >
  48. {}(static_cast<Expr &&>(expr));
  49. #else
  50. using namespace hana::literals;
  51. if constexpr (
  52. std::is_rvalue_reference<Expr>::value &&
  53. !std::is_const<std::remove_reference_t<Expr>>::value) {
  54. return std::move(*expr.elements[0_c]);
  55. } else {
  56. return *expr.elements[0_c];
  57. }
  58. #endif
  59. }
  60. namespace detail {
  61. template<typename Tuple, long long I>
  62. struct lvalue_ref_ith_element
  63. : std::is_lvalue_reference<decltype(
  64. std::declval<Tuple>()[hana::llong<I>{}])>
  65. {
  66. };
  67. #ifdef BOOST_NO_CONSTEXPR_IF
  68. template<bool ValueOfTerminalsOnly, typename T>
  69. constexpr decltype(auto) value_impl(T && x);
  70. template<
  71. typename T,
  72. bool IsExprRef,
  73. bool ValueOfTerminalsOnly,
  74. bool TakeValue,
  75. bool IsLvalueRef>
  76. struct value_expr_impl;
  77. template<
  78. typename T,
  79. bool ValueOfTerminalsOnly,
  80. bool TakeValue,
  81. bool IsLvalueRef>
  82. struct value_expr_impl<
  83. T,
  84. true,
  85. ValueOfTerminalsOnly,
  86. TakeValue,
  87. IsLvalueRef>
  88. {
  89. constexpr decltype(auto) operator()(T && x)
  90. {
  91. return ::boost::yap::detail::value_impl<ValueOfTerminalsOnly>(
  92. ::boost::yap::deref(static_cast<T &&>(x)));
  93. }
  94. };
  95. template<typename T, bool ValueOfTerminalsOnly>
  96. struct value_expr_impl<T, false, ValueOfTerminalsOnly, true, true>
  97. {
  98. constexpr decltype(auto) operator()(T && x)
  99. {
  100. return x.elements[hana::llong_c<0>];
  101. }
  102. };
  103. template<typename T, bool ValueOfTerminalsOnly>
  104. struct value_expr_impl<T, false, ValueOfTerminalsOnly, true, false>
  105. {
  106. constexpr decltype(auto) operator()(T && x)
  107. {
  108. return std::move(x.elements[hana::llong_c<0>]);
  109. }
  110. };
  111. template<typename T, bool ValueOfTerminalsOnly, bool IsLvalueRef>
  112. struct value_expr_impl<
  113. T,
  114. false,
  115. ValueOfTerminalsOnly,
  116. false,
  117. IsLvalueRef>
  118. {
  119. constexpr decltype(auto) operator()(T && x)
  120. {
  121. return static_cast<T &&>(x);
  122. }
  123. };
  124. template<typename T, bool IsExpr, bool ValueOfTerminalsOnly>
  125. struct value_impl_t
  126. {
  127. constexpr decltype(auto) operator()(T && x)
  128. {
  129. constexpr expr_kind kind = detail::remove_cv_ref_t<T>::kind;
  130. constexpr detail::expr_arity arity = detail::arity_of<kind>();
  131. return value_expr_impl < T, kind == expr_kind::expr_ref,
  132. ValueOfTerminalsOnly,
  133. (ValueOfTerminalsOnly && kind == expr_kind::terminal) ||
  134. (!ValueOfTerminalsOnly &&
  135. arity == detail::expr_arity::one),
  136. std::is_lvalue_reference<T>::value ||
  137. detail::lvalue_ref_ith_element<
  138. decltype(x.elements),
  139. 0>::value > {}(static_cast<T &&>(x));
  140. }
  141. };
  142. template<typename T, bool ValueOfTerminalsOnly>
  143. struct value_impl_t<T, false, ValueOfTerminalsOnly>
  144. {
  145. constexpr decltype(auto) operator()(T && x)
  146. {
  147. return static_cast<T &&>(x);
  148. }
  149. };
  150. template<bool ValueOfTerminalsOnly, typename T>
  151. constexpr decltype(auto) value_impl(T && x)
  152. {
  153. return detail::
  154. value_impl_t<T, is_expr<T>::value, ValueOfTerminalsOnly>{}(
  155. static_cast<T &&>(x));
  156. }
  157. #else
  158. template<bool ValueOfTerminalsOnly, typename T>
  159. constexpr decltype(auto) value_impl(T && x)
  160. {
  161. if constexpr (is_expr<T>::value) {
  162. using namespace hana::literals;
  163. constexpr expr_kind kind = remove_cv_ref_t<T>::kind;
  164. constexpr expr_arity arity = arity_of<kind>();
  165. if constexpr (kind == expr_kind::expr_ref) {
  166. return value_impl<ValueOfTerminalsOnly>(
  167. ::boost::yap::deref(static_cast<T &&>(x)));
  168. } else if constexpr (
  169. kind == expr_kind::terminal ||
  170. (!ValueOfTerminalsOnly && arity == expr_arity::one)) {
  171. if constexpr (
  172. std::is_lvalue_reference<T>::value ||
  173. detail::
  174. lvalue_ref_ith_element<decltype(x.elements), 0>{}) {
  175. return x.elements[0_c];
  176. } else {
  177. return std::move(x.elements[0_c]);
  178. }
  179. } else {
  180. return static_cast<T &&>(x);
  181. }
  182. } else {
  183. return static_cast<T &&>(x);
  184. }
  185. }
  186. #endif
  187. }
  188. /** Forwards the sole element of \a x to the caller, possibly calling
  189. <code>deref()</code> first if \a x is a reference expression, or
  190. forwards \a x to the caller unchanged.
  191. More formally:
  192. - If \a x is not an expression, \a x is forwarded to the caller.
  193. - Otherwise, if \a x is a reference expression, the result is
  194. <code>value(deref(x))</code>.
  195. - Otherwise, if \a x is an expression with only one value (a unary
  196. expression or a terminal expression), the result is the forwarded
  197. first element of \a x.
  198. - Otherwise, \a x is forwarded to the caller. */
  199. template<typename T>
  200. constexpr decltype(auto) value(T && x)
  201. {
  202. return detail::value_impl<false>(static_cast<T &&>(x));
  203. }
  204. #ifdef BOOST_NO_CONSTEXPR_IF
  205. template<typename Expr, typename I>
  206. constexpr decltype(auto) get(Expr && expr, I const & i);
  207. namespace detail {
  208. template<long long I, typename Expr, bool IsExpr, bool IsLvalueRef>
  209. struct get_impl;
  210. template<long long I, typename Expr, bool IsLvalueRef>
  211. struct get_impl<I, Expr, true, IsLvalueRef>
  212. {
  213. constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i)
  214. {
  215. return ::boost::yap::get(
  216. ::boost::yap::deref(static_cast<Expr &&>(expr)), i);
  217. }
  218. };
  219. template<long long I, typename Expr>
  220. struct get_impl<I, Expr, false, true>
  221. {
  222. constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i)
  223. {
  224. return expr.elements[i];
  225. }
  226. };
  227. template<long long I, typename Expr>
  228. struct get_impl<I, Expr, false, false>
  229. {
  230. constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i)
  231. {
  232. return std::move(expr.elements[i]);
  233. }
  234. };
  235. }
  236. #endif
  237. /** Forwards the <i>i</i>-th element of \a expr to the caller. If \a
  238. expr is a reference expression, the result is <code>get(deref(expr),
  239. i)</code>.
  240. \note <code>get()</code> is only valid if \a Expr is an expression.
  241. */
  242. template<typename Expr, typename I>
  243. constexpr decltype(auto) get(Expr && expr, I const & i)
  244. {
  245. static_assert(
  246. is_expr<Expr>::value, "get() is only defined for expressions.");
  247. static_assert(
  248. hana::IntegralConstant<I>::value,
  249. "'i' must be an IntegralConstant");
  250. constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
  251. static_assert(
  252. kind == expr_kind::expr_ref ||
  253. (0 <= I::value &&
  254. I::value < decltype(hana::size(expr.elements))::value),
  255. "In get(expr, I), I must be a valid index into expr's tuple "
  256. "elements.");
  257. #ifdef BOOST_NO_CONSTEXPR_IF
  258. return detail::get_impl<
  259. I::value,
  260. Expr,
  261. kind == expr_kind::expr_ref,
  262. std::is_lvalue_reference<Expr>::value>{}(static_cast<Expr &&>(expr), i);
  263. #else
  264. using namespace hana::literals;
  265. if constexpr (kind == expr_kind::expr_ref) {
  266. return ::boost::yap::get(
  267. ::boost::yap::deref(static_cast<Expr &&>(expr)), i);
  268. } else {
  269. if constexpr (std::is_lvalue_reference<Expr>::value) {
  270. return expr.elements[i];
  271. } else {
  272. return std::move(expr.elements[i]);
  273. }
  274. }
  275. #endif
  276. }
  277. /** Returns <code>get(expr, boost::hana::llong_c<I>)</code>. */
  278. template<long long I, typename Expr>
  279. constexpr decltype(auto) get_c(Expr && expr)
  280. {
  281. return ::boost::yap::get(static_cast<Expr &&>(expr), hana::llong_c<I>);
  282. }
  283. /** Returns the left operand in a binary operator expression.
  284. Equivalent to <code>get(expr, 0_c)</code>.
  285. \note <code>left()</code> is only valid if \a Expr is a binary
  286. operator expression.
  287. */
  288. template<typename Expr>
  289. constexpr decltype(auto) left(Expr && expr)
  290. {
  291. using namespace hana::literals;
  292. return ::boost::yap::get(static_cast<Expr &&>(expr), 0_c);
  293. constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
  294. static_assert(
  295. kind == expr_kind::expr_ref ||
  296. detail::arity_of<kind>() == detail::expr_arity::two,
  297. "left() is only defined for binary expressions.");
  298. }
  299. /** Returns the right operand in a binary operator expression.
  300. Equivalent to <code>get(expr, 1_c)</code>.
  301. \note <code>right()</code> is only valid if \a Expr is a binary
  302. operator expression.
  303. */
  304. template<typename Expr>
  305. constexpr decltype(auto) right(Expr && expr)
  306. {
  307. using namespace hana::literals;
  308. return ::boost::yap::get(static_cast<Expr &&>(expr), 1_c);
  309. constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
  310. static_assert(
  311. kind == expr_kind::expr_ref ||
  312. detail::arity_of<kind>() == detail::expr_arity::two,
  313. "right() is only defined for binary expressions.");
  314. }
  315. /** Returns the condition expression in an if_else expression.
  316. Equivalent to <code>get(expr, 0_c)</code>.
  317. \note <code>cond()</code> is only valid if \a Expr is an
  318. <code>expr_kind::if_else</code> expression.
  319. */
  320. template<typename Expr>
  321. constexpr decltype(auto) cond(Expr && expr)
  322. {
  323. using namespace hana::literals;
  324. return ::boost::yap::get(static_cast<Expr &&>(expr), 0_c);
  325. constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
  326. static_assert(
  327. kind == expr_kind::expr_ref || kind == expr_kind::if_else,
  328. "cond() is only defined for if_else expressions.");
  329. }
  330. /** Returns the then-expression in an if_else expression.
  331. Equivalent to <code>get(expr, 1_c)</code>.
  332. \note <code>then()</code> is only valid if \a Expr is an
  333. <code>expr_kind::if_else</code> expression.
  334. */
  335. template<typename Expr>
  336. constexpr decltype(auto) then(Expr && expr)
  337. {
  338. using namespace hana::literals;
  339. return ::boost::yap::get(static_cast<Expr &&>(expr), 1_c);
  340. constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
  341. static_assert(
  342. kind == expr_kind::expr_ref || kind == expr_kind::if_else,
  343. "then() is only defined for if_else expressions.");
  344. }
  345. /** Returns the else-expression in an if_else expression.
  346. Equivalent to <code>get(expr, 2_c)</code>.
  347. \note <code>else_()</code> is only valid if \a Expr is an
  348. <code>expr_kind::if_else</code> expression.
  349. */
  350. template<typename Expr>
  351. constexpr decltype(auto) else_(Expr && expr)
  352. {
  353. using namespace hana::literals;
  354. return ::boost::yap::get(static_cast<Expr &&>(expr), 2_c);
  355. constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
  356. static_assert(
  357. kind == expr_kind::expr_ref || kind == expr_kind::if_else,
  358. "else_() is only defined for if_else expressions.");
  359. }
  360. /** Returns the callable in a call expression.
  361. Equivalent to <code>get(expr, 0)</code>.
  362. \note <code>callable()</code> is only valid if \a Expr is an
  363. <code>expr_kind::call</code> expression.
  364. */
  365. template<typename Expr>
  366. constexpr decltype(auto) callable(Expr && expr)
  367. {
  368. return ::boost::yap::get(static_cast<Expr &&>(expr), hana::llong_c<0>);
  369. constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
  370. static_assert(
  371. kind == expr_kind::expr_ref ||
  372. detail::arity_of<kind>() == detail::expr_arity::n,
  373. "callable() is only defined for call expressions.");
  374. }
  375. /** Returns the <i>i-th</i> argument expression in a call expression.
  376. Equivalent to <code>get(expr, i + 1)</code>.
  377. \note <code>argument()</code> is only valid if \a Expr is an
  378. <code>expr_kind::call</code> expression.
  379. */
  380. template<long long I, typename Expr>
  381. constexpr decltype(auto) argument(Expr && expr, hana::llong<I> i)
  382. {
  383. return ::boost::yap::get(
  384. static_cast<Expr &&>(expr), hana::llong_c<I + 1>);
  385. constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
  386. static_assert(
  387. kind == expr_kind::expr_ref ||
  388. detail::arity_of<kind>() == detail::expr_arity::n,
  389. "argument() is only defined for call expressions.");
  390. static_assert(
  391. kind == expr_kind::expr_ref ||
  392. (0 <= I && I < decltype(hana::size(expr.elements))::value - 1),
  393. "I must be a valid call-expression argument index.");
  394. }
  395. /** Makes a new expression instantiated from the expression template \a
  396. ExprTemplate, of kind \a Kind, with the given values as its
  397. elements.
  398. For each parameter P:
  399. - If P is an expression, P is moved into the result if P is an
  400. rvalue and captured by reference into the result otherwise.
  401. - Otherwise, P is wrapped in a terminal expression.
  402. \note <code>make_expression()</code> is only valid if the number of
  403. parameters passed is appropriate for \a Kind.
  404. */
  405. template<
  406. template<expr_kind, class> class ExprTemplate,
  407. expr_kind Kind,
  408. typename... T>
  409. constexpr auto make_expression(T &&... t)
  410. {
  411. constexpr detail::expr_arity arity = detail::arity_of<Kind>();
  412. static_assert(
  413. (arity == detail::expr_arity::one && sizeof...(T) == 1) ||
  414. (arity == detail::expr_arity::two && sizeof...(T) == 2) ||
  415. (arity == detail::expr_arity::three && sizeof...(T) == 3) ||
  416. arity == detail::expr_arity::n,
  417. "The number of parameters passed to make_expression() must "
  418. "match the arity "
  419. "implied by the expr_kind template parameter.");
  420. using tuple_type =
  421. hana::tuple<detail::operand_type_t<ExprTemplate, T>...>;
  422. return ExprTemplate<Kind, tuple_type>{tuple_type{
  423. detail::make_operand<detail::operand_type_t<ExprTemplate, T>>{}(
  424. static_cast<T &&>(t))...}};
  425. }
  426. /** Makes a new terminal expression instantiated from the expression
  427. template \a ExprTemplate, with the given value as its sole element.
  428. \note <code>make_terminal()</code> is only valid if \a T is \b not
  429. an expression.
  430. */
  431. template<template<expr_kind, class> class ExprTemplate, typename T>
  432. constexpr auto make_terminal(T && t)
  433. {
  434. static_assert(
  435. !is_expr<T>::value,
  436. "make_terminal() is only defined for non expressions.");
  437. using result_type = detail::operand_type_t<ExprTemplate, T>;
  438. using tuple_type = decltype(std::declval<result_type>().elements);
  439. return result_type{tuple_type{static_cast<T &&>(t)}};
  440. }
  441. #ifdef BOOST_NO_CONSTEXPR_IF
  442. namespace detail {
  443. template<
  444. template<expr_kind, class> class ExprTemplate,
  445. typename T,
  446. bool IsExpr>
  447. struct as_expr_impl
  448. {
  449. constexpr decltype(auto) operator()(T && t)
  450. {
  451. return static_cast<T &&>(t);
  452. }
  453. };
  454. template<template<expr_kind, class> class ExprTemplate, typename T>
  455. struct as_expr_impl<ExprTemplate, T, false>
  456. {
  457. constexpr decltype(auto) operator()(T && t)
  458. {
  459. return make_terminal<ExprTemplate>(static_cast<T &&>(t));
  460. }
  461. };
  462. }
  463. #endif
  464. /** Returns an expression formed from \a t as follows:
  465. - If \a t is an expression, \a t is forwarded to the caller.
  466. - Otherwise, \a t is wrapped in a terminal expression.
  467. */
  468. template<template<expr_kind, class> class ExprTemplate, typename T>
  469. constexpr decltype(auto) as_expr(T && t)
  470. {
  471. #ifdef BOOST_NO_CONSTEXPR_IF
  472. return detail::as_expr_impl<ExprTemplate, T, is_expr<T>::value>{}(
  473. static_cast<T &&>(t));
  474. #else
  475. if constexpr (is_expr<T>::value) {
  476. return static_cast<T &&>(t);
  477. } else {
  478. return make_terminal<ExprTemplate>(static_cast<T &&>(t));
  479. }
  480. #endif
  481. }
  482. /** A callable type that evaluates its contained expression when called.
  483. \see <code>make_expression_function()</code>
  484. */
  485. template<typename Expr>
  486. struct expression_function
  487. {
  488. template<typename... U>
  489. constexpr decltype(auto) operator()(U &&... u)
  490. {
  491. return ::boost::yap::evaluate(expr, static_cast<U &&>(u)...);
  492. }
  493. Expr expr;
  494. };
  495. namespace detail {
  496. template<expr_kind Kind, typename Tuple>
  497. struct expression_function_expr
  498. {
  499. static const expr_kind kind = Kind;
  500. Tuple elements;
  501. };
  502. }
  503. /** Returns a callable object that \a expr has been forwarded into. This
  504. is useful for using expressions as function objects.
  505. Lvalue expressions are stored in the result by reference; rvalue
  506. expressions are moved into the result.
  507. \note <code>make_expression_function()</code> is only valid if \a
  508. Expr is an expression.
  509. */
  510. template<typename Expr>
  511. constexpr auto make_expression_function(Expr && expr)
  512. {
  513. static_assert(
  514. is_expr<Expr>::value,
  515. "make_expression_function() is only defined for expressions.");
  516. using stored_type =
  517. detail::operand_type_t<detail::expression_function_expr, Expr &&>;
  518. return expression_function<stored_type>{
  519. detail::make_operand<stored_type>{}(static_cast<Expr &&>(expr))};
  520. }
  521. }}
  522. #include <boost/yap/detail/transform.hpp>
  523. namespace boost { namespace yap {
  524. /** Returns a transform object that replaces placeholders within an
  525. expression with the given values.
  526. */
  527. template<typename... T>
  528. constexpr auto replacements(T &&... t)
  529. {
  530. return detail::placeholder_transform_t<T...>(static_cast<T &&>(t)...);
  531. }
  532. /** Returns \a expr with the placeholders replaced by YAP terminals
  533. containing the given values.
  534. \note <code>replace_placeholders(expr, t...)</code> is only valid if
  535. \a expr is an expression, and <code>max_p <= sizeof...(t)</code>,
  536. where <code>max_p</code> is the maximum placeholder index in \a expr.
  537. */
  538. template<typename Expr, typename... T>
  539. constexpr decltype(auto) replace_placeholders(Expr && expr, T &&... t)
  540. {
  541. static_assert(
  542. is_expr<Expr>::value,
  543. "evaluate() is only defined for expressions.");
  544. return transform(
  545. static_cast<Expr &&>(expr), replacements(static_cast<T &&>(t)...));
  546. }
  547. /** Returns a transform object that evaluates an expression using the
  548. built-in semantics. The transform replaces any placeholders with the
  549. given values.
  550. */
  551. template<typename... T>
  552. constexpr auto evaluation(T &&... t)
  553. {
  554. return detail::evaluation_transform_t<T...>(static_cast<T &&>(t)...);
  555. }
  556. /** Evaluates \a expr using the built-in semantics, replacing any
  557. placeholders with the given values.
  558. \note <code>evaluate(expr)</code> is only valid if \a expr is an
  559. expression.
  560. */
  561. template<typename Expr, typename... T>
  562. constexpr decltype(auto) evaluate(Expr && expr, T &&... t)
  563. {
  564. static_assert(
  565. is_expr<Expr>::value,
  566. "evaluate() is only defined for expressions.");
  567. return transform(
  568. static_cast<Expr &&>(expr), evaluation(static_cast<T &&>(t)...));
  569. }
  570. namespace detail {
  571. template<typename... Transforms>
  572. constexpr auto make_transform_tuple(Transforms &... transforms)
  573. {
  574. return hana::tuple<Transforms *...>{&transforms...};
  575. }
  576. template<bool Strict>
  577. struct transform_
  578. {
  579. template<typename Expr, typename Transform, typename... Transforms>
  580. constexpr decltype(auto) operator()(
  581. Expr && expr, Transform & transform, Transforms &... transforms) const
  582. {
  583. auto transform_tuple =
  584. detail::make_transform_tuple(transform, transforms...);
  585. constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
  586. return detail::
  587. transform_impl<Strict, 0, kind == expr_kind::expr_ref>{}(
  588. static_cast<Expr &&>(expr), transform_tuple);
  589. }
  590. };
  591. }
  592. /** Returns the result of transforming (all or part of) \a expr using
  593. whatever overloads of <code>Transform::operator()</code> match \a
  594. expr.
  595. \note Transformations can do anything: they may have side effects;
  596. they may mutate values; they may mutate types; and they may do any
  597. combination of these.
  598. */
  599. template<typename Expr, typename Transform, typename... Transforms>
  600. constexpr decltype(auto)
  601. transform(Expr && expr, Transform && transform, Transforms &&... transforms)
  602. {
  603. static_assert(
  604. is_expr<Expr>::value,
  605. "transform() is only defined for expressions.");
  606. return detail::transform_<false>{}(
  607. static_cast<Expr &&>(expr), transform, transforms...);
  608. }
  609. /** Returns the result of transforming \a expr using whichever overload of
  610. <code>Transform::operator()</code> best matches \a expr. If no
  611. overload of <code>Transform::operator()</code> matches, a compile-time
  612. error results.
  613. \note Transformations can do anything: they may have side effects;
  614. they may mutate values; they may mutate types; and they may do any
  615. combination of these.
  616. */
  617. template<typename Expr, typename Transform, typename... Transforms>
  618. constexpr decltype(auto) transform_strict(
  619. Expr && expr, Transform && transform, Transforms &&... transforms)
  620. {
  621. static_assert(
  622. is_expr<Expr>::value,
  623. "transform() is only defined for expressions.");
  624. return detail::transform_<true>{}(
  625. static_cast<Expr &&>(expr), transform, transforms...);
  626. }
  627. }}
  628. #endif