File indexing completed on 2025-01-18 09:53:56
0001
0002
0003
0004
0005
0006 #ifndef BOOST_YAP_ALGORITHM_HPP_INCLUDED
0007 #define BOOST_YAP_ALGORITHM_HPP_INCLUDED
0008
0009 #include <boost/yap/algorithm_fwd.hpp>
0010 #include <boost/yap/user_macros.hpp>
0011 #include <boost/yap/detail/algorithm.hpp>
0012
0013 #include <boost/hana/size.hpp>
0014 #include <boost/hana/comparing.hpp>
0015
0016
0017 namespace boost { namespace yap {
0018
0019 #ifdef BOOST_NO_CONSTEXPR_IF
0020
0021 namespace detail {
0022
0023 template<typename Expr, bool MutableRvalueRef>
0024 struct deref_impl
0025 {
0026 constexpr decltype(auto) operator()(Expr && expr)
0027 {
0028 return std::move(*expr.elements[hana::llong_c<0>]);
0029 }
0030 };
0031
0032 template<typename Expr>
0033 struct deref_impl<Expr, false>
0034 {
0035 constexpr decltype(auto) operator()(Expr && expr)
0036 {
0037 return *expr.elements[hana::llong_c<0>];
0038 }
0039 };
0040 }
0041
0042 #endif
0043
0044
0045
0046 template<typename Expr>
0047 constexpr decltype(auto) deref(Expr && expr)
0048 {
0049 static_assert(
0050 is_expr<Expr>::value, "deref() is only defined for expressions.");
0051
0052 static_assert(
0053 detail::remove_cv_ref_t<Expr>::kind == expr_kind::expr_ref,
0054 "deref() is only defined for expr_ref-kind expressions.");
0055
0056 #ifdef BOOST_NO_CONSTEXPR_IF
0057 return detail::deref_impl < Expr,
0058 std::is_rvalue_reference<Expr>::value &&
0059 !std::is_const<std::remove_reference_t<Expr>>::value >
0060 {}(static_cast<Expr &&>(expr));
0061 #else
0062 using namespace hana::literals;
0063 if constexpr (
0064 std::is_rvalue_reference<Expr>::value &&
0065 !std::is_const<std::remove_reference_t<Expr>>::value) {
0066 return std::move(*expr.elements[0_c]);
0067 } else {
0068 return *expr.elements[0_c];
0069 }
0070 #endif
0071 }
0072
0073 namespace detail {
0074
0075 template<typename Tuple, long long I>
0076 struct lvalue_ref_ith_element
0077 : std::is_lvalue_reference<decltype(
0078 std::declval<Tuple>()[hana::llong<I>{}])>
0079 {
0080 };
0081
0082 #ifdef BOOST_NO_CONSTEXPR_IF
0083
0084 template<bool ValueOfTerminalsOnly, typename T>
0085 constexpr decltype(auto) value_impl(T && x);
0086
0087 template<
0088 typename T,
0089 bool IsExprRef,
0090 bool ValueOfTerminalsOnly,
0091 bool TakeValue,
0092 bool IsLvalueRef>
0093 struct value_expr_impl;
0094
0095 template<
0096 typename T,
0097 bool ValueOfTerminalsOnly,
0098 bool TakeValue,
0099 bool IsLvalueRef>
0100 struct value_expr_impl<
0101 T,
0102 true,
0103 ValueOfTerminalsOnly,
0104 TakeValue,
0105 IsLvalueRef>
0106 {
0107 constexpr decltype(auto) operator()(T && x)
0108 {
0109 return ::boost::yap::detail::value_impl<ValueOfTerminalsOnly>(
0110 ::boost::yap::deref(static_cast<T &&>(x)));
0111 }
0112 };
0113
0114 template<typename T, bool ValueOfTerminalsOnly>
0115 struct value_expr_impl<T, false, ValueOfTerminalsOnly, true, true>
0116 {
0117 constexpr decltype(auto) operator()(T && x)
0118 {
0119 return x.elements[hana::llong_c<0>];
0120 }
0121 };
0122
0123 template<typename T, bool ValueOfTerminalsOnly>
0124 struct value_expr_impl<T, false, ValueOfTerminalsOnly, true, false>
0125 {
0126 constexpr decltype(auto) operator()(T && x)
0127 {
0128 return std::move(x.elements[hana::llong_c<0>]);
0129 }
0130 };
0131
0132 template<typename T, bool ValueOfTerminalsOnly, bool IsLvalueRef>
0133 struct value_expr_impl<
0134 T,
0135 false,
0136 ValueOfTerminalsOnly,
0137 false,
0138 IsLvalueRef>
0139 {
0140 constexpr decltype(auto) operator()(T && x)
0141 {
0142 return static_cast<T &&>(x);
0143 }
0144 };
0145
0146 template<typename T, bool IsExpr, bool ValueOfTerminalsOnly>
0147 struct value_impl_t
0148 {
0149 constexpr decltype(auto) operator()(T && x)
0150 {
0151 constexpr expr_kind kind = detail::remove_cv_ref_t<T>::kind;
0152 constexpr detail::expr_arity arity = detail::arity_of<kind>();
0153 return value_expr_impl < T, kind == expr_kind::expr_ref,
0154 ValueOfTerminalsOnly,
0155 (ValueOfTerminalsOnly && kind == expr_kind::terminal) ||
0156 (!ValueOfTerminalsOnly &&
0157 arity == detail::expr_arity::one),
0158 std::is_lvalue_reference<T>::value ||
0159 detail::lvalue_ref_ith_element<
0160 decltype(x.elements),
0161 0>::value > {}(static_cast<T &&>(x));
0162 }
0163 };
0164
0165 template<typename T, bool ValueOfTerminalsOnly>
0166 struct value_impl_t<T, false, ValueOfTerminalsOnly>
0167 {
0168 constexpr decltype(auto) operator()(T && x)
0169 {
0170 return static_cast<T &&>(x);
0171 }
0172 };
0173
0174 template<bool ValueOfTerminalsOnly, typename T>
0175 constexpr decltype(auto) value_impl(T && x)
0176 {
0177 return detail::
0178 value_impl_t<T, is_expr<T>::value, ValueOfTerminalsOnly>{}(
0179 static_cast<T &&>(x));
0180 }
0181
0182 #else
0183
0184 template<bool ValueOfTerminalsOnly, typename T>
0185 constexpr decltype(auto) value_impl(T && x)
0186 {
0187 if constexpr (is_expr<T>::value) {
0188 using namespace hana::literals;
0189 constexpr expr_kind kind = remove_cv_ref_t<T>::kind;
0190 constexpr expr_arity arity = arity_of<kind>();
0191 if constexpr (kind == expr_kind::expr_ref) {
0192 return value_impl<ValueOfTerminalsOnly>(
0193 ::boost::yap::deref(static_cast<T &&>(x)));
0194 } else if constexpr (
0195 kind == expr_kind::terminal ||
0196 (!ValueOfTerminalsOnly && arity == expr_arity::one)) {
0197 if constexpr (
0198 std::is_lvalue_reference<T>::value ||
0199 detail::
0200 lvalue_ref_ith_element<decltype(x.elements), 0>{}) {
0201 return x.elements[0_c];
0202 } else {
0203 return std::move(x.elements[0_c]);
0204 }
0205 } else {
0206 return static_cast<T &&>(x);
0207 }
0208 } else {
0209 return static_cast<T &&>(x);
0210 }
0211 }
0212
0213 #endif
0214 }
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232 template<typename T>
0233 constexpr decltype(auto) value(T && x)
0234 {
0235 return detail::value_impl<false>(static_cast<T &&>(x));
0236 }
0237
0238 #ifdef BOOST_NO_CONSTEXPR_IF
0239
0240 template<typename Expr, typename I>
0241 constexpr decltype(auto) get(Expr && expr, I const & i);
0242
0243 namespace detail {
0244
0245 template<long long I, typename Expr, bool IsExpr, bool IsLvalueRef>
0246 struct get_impl;
0247
0248 template<long long I, typename Expr, bool IsLvalueRef>
0249 struct get_impl<I, Expr, true, IsLvalueRef>
0250 {
0251 constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i)
0252 {
0253 return ::boost::yap::get(
0254 ::boost::yap::deref(static_cast<Expr &&>(expr)), i);
0255 }
0256 };
0257
0258 template<long long I, typename Expr>
0259 struct get_impl<I, Expr, false, true>
0260 {
0261 constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i)
0262 {
0263 return expr.elements[i];
0264 }
0265 };
0266
0267 template<long long I, typename Expr>
0268 struct get_impl<I, Expr, false, false>
0269 {
0270 constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i)
0271 {
0272 return std::move(expr.elements[i]);
0273 }
0274 };
0275 }
0276
0277 #endif
0278
0279
0280
0281
0282
0283
0284
0285 template<typename Expr, typename I>
0286 constexpr decltype(auto) get(Expr && expr, I const & i)
0287 {
0288 static_assert(
0289 is_expr<Expr>::value, "get() is only defined for expressions.");
0290 static_assert(
0291 hana::IntegralConstant<I>::value,
0292 "'i' must be an IntegralConstant");
0293
0294 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0295
0296 static_assert(
0297 kind == expr_kind::expr_ref ||
0298 (0 <= I::value &&
0299 I::value < decltype(hana::size(expr.elements))::value),
0300 "In get(expr, I), I must be a valid index into expr's tuple "
0301 "elements.");
0302
0303 #ifdef BOOST_NO_CONSTEXPR_IF
0304 return detail::get_impl<
0305 I::value,
0306 Expr,
0307 kind == expr_kind::expr_ref,
0308 std::is_lvalue_reference<Expr>::value>{}(static_cast<Expr &&>(expr), i);
0309 #else
0310 using namespace hana::literals;
0311 if constexpr (kind == expr_kind::expr_ref) {
0312 return ::boost::yap::get(
0313 ::boost::yap::deref(static_cast<Expr &&>(expr)), i);
0314 } else {
0315 if constexpr (std::is_lvalue_reference<Expr>::value) {
0316 return expr.elements[i];
0317 } else {
0318 return std::move(expr.elements[i]);
0319 }
0320 }
0321 #endif
0322 }
0323
0324
0325 template<long long I, typename Expr>
0326 constexpr decltype(auto) get_c(Expr && expr)
0327 {
0328 return ::boost::yap::get(static_cast<Expr &&>(expr), hana::llong_c<I>);
0329 }
0330
0331
0332
0333
0334
0335
0336
0337
0338 template<typename Expr>
0339 constexpr decltype(auto) left(Expr && expr)
0340 {
0341 using namespace hana::literals;
0342 return ::boost::yap::get(static_cast<Expr &&>(expr), 0_c);
0343 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0344 static_assert(
0345 kind == expr_kind::expr_ref ||
0346 detail::arity_of<kind>() == detail::expr_arity::two,
0347 "left() is only defined for binary expressions.");
0348 }
0349
0350
0351
0352
0353
0354
0355
0356
0357 template<typename Expr>
0358 constexpr decltype(auto) right(Expr && expr)
0359 {
0360 using namespace hana::literals;
0361 return ::boost::yap::get(static_cast<Expr &&>(expr), 1_c);
0362 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0363 static_assert(
0364 kind == expr_kind::expr_ref ||
0365 detail::arity_of<kind>() == detail::expr_arity::two,
0366 "right() is only defined for binary expressions.");
0367 }
0368
0369
0370
0371
0372
0373
0374
0375
0376 template<typename Expr>
0377 constexpr decltype(auto) cond(Expr && expr)
0378 {
0379 using namespace hana::literals;
0380 return ::boost::yap::get(static_cast<Expr &&>(expr), 0_c);
0381 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0382 static_assert(
0383 kind == expr_kind::expr_ref || kind == expr_kind::if_else,
0384 "cond() is only defined for if_else expressions.");
0385 }
0386
0387
0388
0389
0390
0391
0392
0393
0394 template<typename Expr>
0395 constexpr decltype(auto) then(Expr && expr)
0396 {
0397 using namespace hana::literals;
0398 return ::boost::yap::get(static_cast<Expr &&>(expr), 1_c);
0399 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0400 static_assert(
0401 kind == expr_kind::expr_ref || kind == expr_kind::if_else,
0402 "then() is only defined for if_else expressions.");
0403 }
0404
0405
0406
0407
0408
0409
0410
0411
0412 template<typename Expr>
0413 constexpr decltype(auto) else_(Expr && expr)
0414 {
0415 using namespace hana::literals;
0416 return ::boost::yap::get(static_cast<Expr &&>(expr), 2_c);
0417 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0418 static_assert(
0419 kind == expr_kind::expr_ref || kind == expr_kind::if_else,
0420 "else_() is only defined for if_else expressions.");
0421 }
0422
0423
0424
0425
0426
0427
0428
0429
0430 template<typename Expr>
0431 constexpr decltype(auto) callable(Expr && expr)
0432 {
0433 return ::boost::yap::get(static_cast<Expr &&>(expr), hana::llong_c<0>);
0434 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0435 static_assert(
0436 kind == expr_kind::expr_ref ||
0437 detail::arity_of<kind>() == detail::expr_arity::n,
0438 "callable() is only defined for call expressions.");
0439 }
0440
0441
0442
0443
0444
0445
0446
0447
0448 template<long long I, typename Expr>
0449 constexpr decltype(auto) argument(Expr && expr, hana::llong<I> i)
0450 {
0451 return ::boost::yap::get(
0452 static_cast<Expr &&>(expr), hana::llong_c<I + 1>);
0453 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0454 static_assert(
0455 kind == expr_kind::expr_ref ||
0456 detail::arity_of<kind>() == detail::expr_arity::n,
0457 "argument() is only defined for call expressions.");
0458 static_assert(
0459 kind == expr_kind::expr_ref ||
0460 (0 <= I && I < decltype(hana::size(expr.elements))::value - 1),
0461 "I must be a valid call-expression argument index.");
0462 }
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478 template<
0479 template<expr_kind, class> class ExprTemplate,
0480 expr_kind Kind,
0481 typename... T>
0482 constexpr auto make_expression(T &&... t)
0483 {
0484 constexpr detail::expr_arity arity = detail::arity_of<Kind>();
0485 static_assert(
0486 (arity == detail::expr_arity::one && sizeof...(T) == 1) ||
0487 (arity == detail::expr_arity::two && sizeof...(T) == 2) ||
0488 (arity == detail::expr_arity::three && sizeof...(T) == 3) ||
0489 arity == detail::expr_arity::n,
0490 "The number of parameters passed to make_expression() must "
0491 "match the arity "
0492 "implied by the expr_kind template parameter.");
0493 using tuple_type =
0494 hana::tuple<detail::operand_type_t<ExprTemplate, T>...>;
0495 return ExprTemplate<Kind, tuple_type>{tuple_type{
0496 detail::make_operand<detail::operand_type_t<ExprTemplate, T>>{}(
0497 static_cast<T &&>(t))...}};
0498 }
0499
0500
0501
0502
0503
0504
0505
0506 template<template<expr_kind, class> class ExprTemplate, typename T>
0507 constexpr auto make_terminal(T && t)
0508 {
0509 static_assert(
0510 !is_expr<T>::value,
0511 "make_terminal() is only defined for non expressions.");
0512 using result_type = detail::operand_type_t<ExprTemplate, T>;
0513 using tuple_type = decltype(std::declval<result_type>().elements);
0514 return result_type{tuple_type{static_cast<T &&>(t)}};
0515 }
0516
0517 #ifdef BOOST_NO_CONSTEXPR_IF
0518
0519 namespace detail {
0520
0521 template<
0522 template<expr_kind, class> class ExprTemplate,
0523 typename T,
0524 bool IsExpr>
0525 struct as_expr_impl
0526 {
0527 constexpr decltype(auto) operator()(T && t)
0528 {
0529 return static_cast<T &&>(t);
0530 }
0531 };
0532
0533 template<template<expr_kind, class> class ExprTemplate, typename T>
0534 struct as_expr_impl<ExprTemplate, T, false>
0535 {
0536 constexpr decltype(auto) operator()(T && t)
0537 {
0538 return make_terminal<ExprTemplate>(static_cast<T &&>(t));
0539 }
0540 };
0541 }
0542
0543 #endif
0544
0545
0546
0547
0548
0549
0550
0551 template<template<expr_kind, class> class ExprTemplate, typename T>
0552 constexpr decltype(auto) as_expr(T && t)
0553 {
0554 #ifdef BOOST_NO_CONSTEXPR_IF
0555 return detail::as_expr_impl<ExprTemplate, T, is_expr<T>::value>{}(
0556 static_cast<T &&>(t));
0557 #else
0558 if constexpr (is_expr<T>::value) {
0559 return static_cast<T &&>(t);
0560 } else {
0561 return make_terminal<ExprTemplate>(static_cast<T &&>(t));
0562 }
0563 #endif
0564 }
0565
0566
0567
0568
0569
0570 template<typename Expr>
0571 struct expression_function
0572 {
0573 template<typename... U>
0574 constexpr decltype(auto) operator()(U &&... u)
0575 {
0576 return ::boost::yap::evaluate(expr, static_cast<U &&>(u)...);
0577 }
0578
0579 Expr expr;
0580 };
0581
0582 namespace detail {
0583
0584 template<expr_kind Kind, typename Tuple>
0585 struct expression_function_expr
0586 {
0587 static const expr_kind kind = Kind;
0588 Tuple elements;
0589 };
0590 }
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600
0601 template<typename Expr>
0602 constexpr auto make_expression_function(Expr && expr)
0603 {
0604 static_assert(
0605 is_expr<Expr>::value,
0606 "make_expression_function() is only defined for expressions.");
0607 using stored_type =
0608 detail::operand_type_t<detail::expression_function_expr, Expr &&>;
0609 return expression_function<stored_type>{
0610 detail::make_operand<stored_type>{}(static_cast<Expr &&>(expr))};
0611 }
0612 }}
0613
0614 #include <boost/yap/detail/transform.hpp>
0615
0616 namespace boost { namespace yap {
0617
0618
0619
0620
0621 template<typename... T>
0622 constexpr auto replacements(T &&... t)
0623 {
0624 return detail::placeholder_transform_t<T...>(static_cast<T &&>(t)...);
0625 }
0626
0627
0628
0629
0630
0631
0632
0633
0634 template<typename Expr, typename... T>
0635 constexpr decltype(auto) replace_placeholders(Expr && expr, T &&... t)
0636 {
0637 static_assert(
0638 is_expr<Expr>::value,
0639 "evaluate() is only defined for expressions.");
0640 return transform(
0641 static_cast<Expr &&>(expr), replacements(static_cast<T &&>(t)...));
0642 }
0643
0644
0645
0646
0647
0648 template<typename... T>
0649 constexpr auto evaluation(T &&... t)
0650 {
0651 return detail::evaluation_transform_t<T...>(static_cast<T &&>(t)...);
0652 }
0653
0654
0655
0656
0657
0658
0659
0660 template<typename Expr, typename... T>
0661 constexpr decltype(auto) evaluate(Expr && expr, T &&... t)
0662 {
0663 static_assert(
0664 is_expr<Expr>::value,
0665 "evaluate() is only defined for expressions.");
0666 return transform(
0667 static_cast<Expr &&>(expr), evaluation(static_cast<T &&>(t)...));
0668 }
0669
0670 namespace detail {
0671
0672 template<typename... Transforms>
0673 constexpr auto make_transform_tuple(Transforms &... transforms)
0674 {
0675 return hana::tuple<Transforms *...>{&transforms...};
0676 }
0677
0678 template<bool Strict>
0679 struct transform_
0680 {
0681 template<typename Expr, typename Transform, typename... Transforms>
0682 constexpr decltype(auto) operator()(
0683 Expr && expr, Transform & transform, Transforms &... transforms) const
0684 {
0685 auto transform_tuple =
0686 detail::make_transform_tuple(transform, transforms...);
0687 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0688 return detail::
0689 transform_impl<Strict, 0, kind == expr_kind::expr_ref>{}(
0690 static_cast<Expr &&>(expr), transform_tuple);
0691 }
0692 };
0693 }
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703 template<typename Expr, typename Transform, typename... Transforms>
0704 constexpr decltype(auto)
0705 transform(Expr && expr, Transform && transform, Transforms &&... transforms)
0706 {
0707 static_assert(
0708 is_expr<Expr>::value,
0709 "transform() is only defined for expressions.");
0710 return detail::transform_<false>{}(
0711 static_cast<Expr &&>(expr), transform, transforms...);
0712 }
0713
0714
0715
0716
0717
0718
0719
0720
0721
0722
0723 template<typename Expr, typename Transform, typename... Transforms>
0724 constexpr decltype(auto) transform_strict(
0725 Expr && expr, Transform && transform, Transforms &&... transforms)
0726 {
0727 static_assert(
0728 is_expr<Expr>::value,
0729 "transform() is only defined for expressions.");
0730 return detail::transform_<true>{}(
0731 static_cast<Expr &&>(expr), transform, transforms...);
0732 }
0733
0734 }}
0735
0736 #endif