File indexing completed on 2025-01-18 09:53:55
0001
0002
0003
0004
0005
0006 #ifndef BOOST_YAP_DETAIL_TRANSFORM_HPP_INCLUDED
0007 #define BOOST_YAP_DETAIL_TRANSFORM_HPP_INCLUDED
0008
0009 #include <boost/yap/algorithm_fwd.hpp>
0010
0011 #include <boost/hana/transform.hpp>
0012
0013 #include <cassert>
0014
0015
0016 namespace boost { namespace yap { namespace detail {
0017
0018 template<int I, typename T, typename... Ts>
0019 struct nth_element_impl
0020 {
0021 using type = typename nth_element_impl<I - 1, Ts...>::type;
0022 };
0023
0024 template<typename T, typename... Ts>
0025 struct nth_element_impl<0, T, Ts...>
0026 {
0027 using type = T;
0028 };
0029
0030 template<int I, typename... Ts>
0031 using nth_element = typename nth_element_impl<I, Ts...>::type;
0032
0033 template<typename T, bool RemoveRefs = std::is_rvalue_reference<T>::value>
0034 struct rvalue_ref_to_value;
0035
0036 template<typename T>
0037 struct rvalue_ref_to_value<T, true>
0038 {
0039 using type = typename std::remove_reference<T>::type;
0040 };
0041
0042 template<typename T>
0043 struct rvalue_ref_to_value<T, false>
0044 {
0045 using type = T;
0046 };
0047
0048 template<typename T>
0049 using rvalue_ref_to_value_t = typename rvalue_ref_to_value<T>::type;
0050
0051 template<bool IsRvalueRef>
0052 struct rvalue_mover
0053 {
0054 template<typename T>
0055 constexpr decltype(auto) operator()(T && t) const
0056 {
0057 return static_cast<T &&>(t);
0058 }
0059 };
0060
0061 template<>
0062 struct rvalue_mover<true>
0063 {
0064 template<typename T>
0065 constexpr std::remove_reference_t<T> operator()(T && t) const
0066 {
0067 return std::move(t);
0068 }
0069 };
0070
0071 template<typename... PlaceholderArgs>
0072 struct placeholder_transform_t
0073 {
0074 using tuple_t = hana::tuple<rvalue_ref_to_value_t<PlaceholderArgs>...>;
0075
0076 constexpr placeholder_transform_t(PlaceholderArgs &&... args) :
0077 placeholder_args_(static_cast<PlaceholderArgs &&>(args)...)
0078 {}
0079
0080 template<long long I>
0081 constexpr decltype(auto)
0082 operator()(expr_tag<expr_kind::terminal>, boost::yap::placeholder<I>) const
0083 {
0084 static_assert(
0085 I <= decltype(hana::size(std::declval<tuple_t>()))::value,
0086 "Out of range placeholder index,");
0087 using nth_type = nth_element<I - 1, PlaceholderArgs...>;
0088 return as_expr<minimal_expr>(
0089 rvalue_mover<!std::is_lvalue_reference<nth_type>::value>{}(
0090 placeholder_args_[hana::llong<I - 1>{}]));
0091 }
0092
0093 tuple_t placeholder_args_;
0094 };
0095
0096 template<typename... PlaceholderArgs>
0097 struct evaluation_transform_t
0098 {
0099 using tuple_t = hana::tuple<rvalue_ref_to_value_t<PlaceholderArgs>...>;
0100
0101 constexpr evaluation_transform_t(PlaceholderArgs &&... args) :
0102 placeholder_args_(static_cast<PlaceholderArgs &&>(args)...)
0103 {}
0104
0105 template<long long I>
0106 constexpr decltype(auto)
0107 operator()(expr_tag<expr_kind::terminal>, boost::yap::placeholder<I>) const
0108 {
0109 static_assert(
0110 I <= decltype(hana::size(std::declval<tuple_t>()))::value,
0111 "Out of range placeholder index,");
0112 using nth_type = nth_element<I - 1, PlaceholderArgs...>;
0113 return rvalue_mover<!std::is_lvalue_reference<nth_type>::value>{}(
0114 placeholder_args_[hana::llong<I - 1>{}]);
0115 }
0116
0117 template<typename T>
0118 constexpr decltype(auto) operator()(expr_tag<expr_kind::terminal>, T && t) const
0119 {
0120 return static_cast<T &&>(t);
0121 }
0122
0123 #define BOOST_YAP_UNARY_OPERATOR_CASE(op, op_name) \
0124 template<typename T> \
0125 constexpr decltype(auto) operator()(expr_tag<expr_kind::op_name>, T && t) const \
0126 { \
0127 return op transform( \
0128 as_expr<minimal_expr>(static_cast<T &&>(t)), *this); \
0129 }
0130
0131 BOOST_YAP_UNARY_OPERATOR_CASE(+, unary_plus)
0132 BOOST_YAP_UNARY_OPERATOR_CASE(-, negate)
0133 BOOST_YAP_UNARY_OPERATOR_CASE(*, dereference)
0134 BOOST_YAP_UNARY_OPERATOR_CASE(~, complement)
0135 BOOST_YAP_UNARY_OPERATOR_CASE(&, address_of)
0136 BOOST_YAP_UNARY_OPERATOR_CASE(!, logical_not)
0137 BOOST_YAP_UNARY_OPERATOR_CASE(++, pre_inc)
0138 BOOST_YAP_UNARY_OPERATOR_CASE(--, pre_dec)
0139
0140 template<typename T>
0141 constexpr decltype(auto) operator()(expr_tag<expr_kind::post_inc>, T && t) const
0142 {
0143 return transform(
0144 as_expr<minimal_expr>(static_cast<T &&>(t)), *this)++;
0145 }
0146 template<typename T>
0147 constexpr decltype(auto) operator()(expr_tag<expr_kind::post_dec>, T && t) const
0148 {
0149 return transform(
0150 as_expr<minimal_expr>(static_cast<T &&>(t)), *this)--;
0151 }
0152
0153 #undef BOOST_YAP_UNARY_OPERATOR_CASE
0154
0155 #define BOOST_YAP_BINARY_OPERATOR_CASE(op, op_name) \
0156 template<typename T, typename U> \
0157 constexpr decltype(auto) operator()(expr_tag<expr_kind::op_name>, T && t, U && u) const \
0158 { \
0159 return transform(as_expr<minimal_expr>(static_cast<T &&>(t)), *this) \
0160 op transform(as_expr<minimal_expr>(static_cast<U &&>(u)), *this); \
0161 }
0162
0163 BOOST_YAP_BINARY_OPERATOR_CASE(<<, shift_left)
0164 BOOST_YAP_BINARY_OPERATOR_CASE(>>, shift_right)
0165 BOOST_YAP_BINARY_OPERATOR_CASE(*, multiplies)
0166 BOOST_YAP_BINARY_OPERATOR_CASE(/, divides)
0167 BOOST_YAP_BINARY_OPERATOR_CASE(%, modulus)
0168 BOOST_YAP_BINARY_OPERATOR_CASE(+, plus)
0169 BOOST_YAP_BINARY_OPERATOR_CASE(-, minus)
0170 BOOST_YAP_BINARY_OPERATOR_CASE(<, less)
0171 BOOST_YAP_BINARY_OPERATOR_CASE(>, greater)
0172 BOOST_YAP_BINARY_OPERATOR_CASE(<=, less_equal)
0173 BOOST_YAP_BINARY_OPERATOR_CASE(>=, greater_equal)
0174 BOOST_YAP_BINARY_OPERATOR_CASE(==, equal_to)
0175 BOOST_YAP_BINARY_OPERATOR_CASE(!=, not_equal_to)
0176 BOOST_YAP_BINARY_OPERATOR_CASE(||, logical_or)
0177 BOOST_YAP_BINARY_OPERATOR_CASE(&&, logical_and)
0178 BOOST_YAP_BINARY_OPERATOR_CASE(&, bitwise_and)
0179 BOOST_YAP_BINARY_OPERATOR_CASE(|, bitwise_or)
0180 BOOST_YAP_BINARY_OPERATOR_CASE (^, bitwise_xor)
0181
0182
0183
0184 template<typename T, typename U>
0185 constexpr decltype(auto) operator()(expr_tag<expr_kind::comma>, T && t, U && u) const
0186 {
0187 return transform(
0188 as_expr<minimal_expr>(static_cast<T &&>(t)), *this),
0189 transform(
0190 as_expr<minimal_expr>(static_cast<U &&>(u)), *this);
0191 }
0192
0193
0194
0195 BOOST_YAP_BINARY_OPERATOR_CASE(->*, mem_ptr)
0196 BOOST_YAP_BINARY_OPERATOR_CASE(=, assign)
0197 BOOST_YAP_BINARY_OPERATOR_CASE(<<=, shift_left_assign)
0198 BOOST_YAP_BINARY_OPERATOR_CASE(>>=, shift_right_assign)
0199 BOOST_YAP_BINARY_OPERATOR_CASE(*=, multiplies_assign)
0200 BOOST_YAP_BINARY_OPERATOR_CASE(/=, divides_assign)
0201 BOOST_YAP_BINARY_OPERATOR_CASE(%=, modulus_assign)
0202 BOOST_YAP_BINARY_OPERATOR_CASE(+=, plus_assign)
0203 BOOST_YAP_BINARY_OPERATOR_CASE(-=, minus_assign)
0204 BOOST_YAP_BINARY_OPERATOR_CASE(&=, bitwise_and_assign)
0205 BOOST_YAP_BINARY_OPERATOR_CASE(|=, bitwise_or_assign)
0206 BOOST_YAP_BINARY_OPERATOR_CASE(^=, bitwise_xor_assign)
0207
0208 template<typename T, typename U>
0209 constexpr decltype(auto)
0210 operator()(expr_tag<expr_kind::subscript>, T && t, U && u) const
0211 {
0212 return transform(
0213 as_expr<minimal_expr>(static_cast<T &&>(t)), *this)[transform(
0214 as_expr<minimal_expr>(static_cast<U &&>(u)), *this)];
0215 }
0216
0217 #undef BOOST_YAP_BINARY_OPERATOR_CASE
0218
0219 template<typename T, typename U, typename V>
0220 constexpr decltype(auto)
0221 operator()(expr_tag<expr_kind::if_else>, T && t, U && u, V && v) const
0222 {
0223 return transform(as_expr<minimal_expr>(static_cast<T &&>(t)), *this)
0224 ? transform(
0225 as_expr<minimal_expr>(static_cast<U &&>(u)), *this)
0226 : transform(
0227 as_expr<minimal_expr>(static_cast<V &&>(v)),
0228 *this);
0229 }
0230
0231
0232
0233 template<typename Callable, typename... Args>
0234 constexpr decltype(auto) operator()(
0235 expr_tag<expr_kind::call>, Callable && callable, Args &&... args) const
0236 {
0237 return transform(as_expr<minimal_expr>(static_cast<Callable &&>(callable)), *this)(
0238 transform(as_expr<minimal_expr>(static_cast<Args &&>(args)), *this)...
0239 );
0240 }
0241
0242
0243
0244 tuple_t placeholder_args_;
0245 };
0246
0247
0248 template<bool Strict, int I, bool IsExprRef>
0249 struct transform_impl;
0250
0251 template<
0252 bool Strict,
0253 typename Expr,
0254 typename TransformTuple,
0255 int I,
0256 expr_arity Arity,
0257 typename = void_t<>>
0258 struct transform_expression_tag;
0259
0260
0261
0262
0263 template<bool IsLvalueRef, bool IsTerminal, bool Strict>
0264 struct default_transform
0265 {
0266 template<typename Expr, typename TransformTuple>
0267 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0268 {
0269 return static_cast<Expr &&>(expr);
0270 }
0271 };
0272
0273 template<bool IsLvalueRef, bool IsTerminal>
0274 struct default_transform<IsLvalueRef, IsTerminal, true>
0275 {
0276 struct incomplete;
0277
0278
0279
0280
0281
0282 template<typename Expr, typename TransformTuple>
0283 constexpr incomplete operator()(Expr && expr, TransformTuple transforms) const;
0284 };
0285
0286 template<
0287 expr_kind Kind,
0288 template<expr_kind, class> class ExprTemplate,
0289 typename OldTuple,
0290 typename NewTuple>
0291 constexpr auto make_expr_from_tuple(
0292 ExprTemplate<Kind, OldTuple> const & expr, NewTuple && tuple)
0293 {
0294 return ExprTemplate<Kind, NewTuple>{std::move(tuple)};
0295 }
0296
0297 template<expr_kind Kind, typename Expr, typename NewTuple>
0298 constexpr auto make_expr_from_tuple(Expr const & expr, NewTuple && tuple)
0299 {
0300 return minimal_expr<Kind, NewTuple>{std::move(tuple)};
0301 }
0302
0303 template<typename Expr, typename Tuple, typename TransformTuple>
0304 constexpr decltype(auto) transform_nonterminal(
0305 Expr const & expr, Tuple && tuple, TransformTuple transforms)
0306 {
0307 auto transformed_tuple =
0308 hana::transform(static_cast<Tuple &&>(tuple), [&](auto && element) {
0309 using element_t = decltype(element);
0310 auto const kind = remove_cv_ref_t<element_t>::kind;
0311 ::boost::yap::detail::
0312 transform_impl<false, 0, kind == expr_kind::expr_ref>
0313 xform;
0314 return xform(static_cast<element_t &&>(element), transforms);
0315 });
0316 auto const kind = remove_cv_ref_t<Expr>::kind;
0317 return make_expr_from_tuple<kind>(expr, std::move(transformed_tuple));
0318 }
0319
0320 template<>
0321 struct default_transform<true, false, false>
0322 {
0323 template<typename Expr, typename TransformTuple>
0324 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0325 {
0326 return transform_nonterminal(expr, expr.elements, transforms);
0327 }
0328 };
0329
0330 template<>
0331 struct default_transform<false, false, false>
0332 {
0333 template<typename Expr, typename TransformTuple>
0334 constexpr decltype(auto)
0335 operator()(Expr && expr, TransformTuple transforms) const
0336 {
0337 return transform_nonterminal(
0338 expr, std::move(expr.elements), transforms);
0339 }
0340 };
0341
0342
0343
0344
0345 template<
0346 bool Strict,
0347 typename Expr,
0348 typename TransformTuple,
0349 int I,
0350 bool NextTransformExists>
0351 struct next_or_default_transform
0352 {
0353 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0354 {
0355
0356 constexpr expr_kind kind = remove_cv_ref_t<Expr>::kind;
0357 return detail::
0358 transform_impl<Strict, I + 1, kind == expr_kind::expr_ref>{}(
0359 static_cast<Expr &&>(expr), transforms);
0360 }
0361 };
0362
0363 template<bool Strict, typename Expr, typename TransformTuple, int I>
0364 struct next_or_default_transform<Strict, Expr, TransformTuple, I, false>
0365 {
0366 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0367 {
0368
0369 constexpr expr_kind kind = remove_cv_ref_t<Expr>::kind;
0370 return default_transform<
0371 std::is_lvalue_reference<Expr>::value,
0372 kind == expr_kind::terminal,
0373 Strict>{}(static_cast<Expr &&>(expr), transforms);
0374 }
0375 };
0376
0377
0378
0379 template<
0380 bool Strict,
0381 typename Expr,
0382 typename TransformTuple,
0383 int I,
0384 typename = detail::void_t<>>
0385 struct transform_expression_expr
0386 {
0387 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0388 {
0389
0390 return next_or_default_transform<
0391 Strict,
0392 Expr,
0393 TransformTuple,
0394 I,
0395 I + 1 < decltype(hana::size(
0396 std::declval<TransformTuple>()))::value>{}(
0397 static_cast<Expr &&>(expr), transforms);
0398 }
0399 };
0400
0401 template<bool Strict, typename Expr, typename TransformTuple, int I>
0402 struct transform_expression_expr<
0403 Strict,
0404 Expr,
0405 TransformTuple,
0406 I,
0407 void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
0408 std::declval<Expr>()))>>
0409 {
0410 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0411 {
0412 return (*transforms[hana::llong<I>{}])(static_cast<Expr &&>(expr));
0413 }
0414 };
0415
0416
0417
0418
0419 template<
0420 bool Strict,
0421 typename Expr,
0422 typename TransformTuple,
0423 int I,
0424 expr_arity Arity,
0425 typename>
0426 struct transform_expression_tag
0427 {
0428 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0429 {
0430
0431 return transform_expression_expr<Strict, Expr, TransformTuple, I>{}(
0432 static_cast<Expr &&>(expr), transforms);
0433 }
0434 };
0435
0436 template<typename T>
0437 constexpr decltype(auto) terminal_value(T && x)
0438 {
0439 return value_impl<true>(static_cast<T &&>(x));
0440 }
0441
0442
0443 template<bool Strict, typename Expr, typename TransformTuple, int I>
0444 struct transform_expression_tag<
0445 Strict,
0446 Expr,
0447 TransformTuple,
0448 I,
0449 expr_arity::one,
0450 void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
0451 expr_tag<remove_cv_ref_t<Expr>::kind>{},
0452 terminal_value(::boost::yap::value(std::declval<Expr>()))))>>
0453 {
0454 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0455 {
0456 return (*transforms[hana::llong<I>{}])(
0457 expr_tag<remove_cv_ref_t<Expr>::kind>{},
0458 terminal_value(
0459 ::boost::yap::value(static_cast<Expr &&>(expr))));
0460 }
0461 };
0462
0463 template<bool Strict, typename Expr, typename TransformTuple, int I>
0464 struct transform_expression_tag<
0465 Strict,
0466 Expr,
0467 TransformTuple,
0468 I,
0469 expr_arity::two,
0470 void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
0471 expr_tag<remove_cv_ref_t<Expr>::kind>{},
0472 terminal_value(::boost::yap::left(std::declval<Expr>())),
0473 terminal_value(::boost::yap::right(std::declval<Expr>()))))>>
0474 {
0475 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0476 {
0477 return (*transforms[hana::llong<I>{}])(
0478 expr_tag<remove_cv_ref_t<Expr>::kind>{},
0479 terminal_value(::boost::yap::left(static_cast<Expr &&>(expr))),
0480 terminal_value(
0481 ::boost::yap::right(static_cast<Expr &&>(expr))));
0482 }
0483 };
0484
0485 template<bool Strict, typename Expr, typename TransformTuple, int I>
0486 struct transform_expression_tag<
0487 Strict,
0488 Expr,
0489 TransformTuple,
0490 I,
0491 expr_arity::three,
0492 void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
0493 expr_tag<remove_cv_ref_t<Expr>::kind>{},
0494 terminal_value(::boost::yap::cond(std::declval<Expr>())),
0495 terminal_value(::boost::yap::then(std::declval<Expr>())),
0496 terminal_value(::boost::yap::else_(std::declval<Expr>()))))>>
0497 {
0498 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0499 {
0500 return (*transforms[hana::llong<I>{}])(
0501 expr_tag<remove_cv_ref_t<Expr>::kind>{},
0502 terminal_value(::boost::yap::cond(static_cast<Expr &&>(expr))),
0503 terminal_value(::boost::yap::then(static_cast<Expr &&>(expr))),
0504 terminal_value(
0505 ::boost::yap::else_(static_cast<Expr &&>(expr))));
0506 }
0507 };
0508
0509 template<typename Expr, typename Transform>
0510 struct transform_call_unpacker
0511 {
0512 template<long long... I>
0513 constexpr auto operator()(
0514 Expr && expr,
0515 Transform & transform,
0516 std::integer_sequence<long long, I...>) const
0517 -> decltype(transform(
0518 expr_tag<expr_kind::call>{},
0519 terminal_value(::boost::yap::get(
0520 static_cast<Expr &&>(expr), hana::llong_c<I>))...))
0521 {
0522 return transform(
0523 expr_tag<expr_kind::call>{},
0524 terminal_value(::boost::yap::get(
0525 static_cast<Expr &&>(expr), hana::llong_c<I>))...);
0526 }
0527 };
0528
0529 template<typename Expr>
0530 constexpr auto indices_for(Expr const & expr)
0531 {
0532 constexpr long long size = decltype(hana::size(expr.elements))::value;
0533 return std::make_integer_sequence<long long, size>();
0534 }
0535
0536 template<bool Strict, typename Expr, typename TransformTuple, int I>
0537 struct transform_expression_tag<
0538 Strict,
0539 Expr,
0540 TransformTuple,
0541 I,
0542 expr_arity::n,
0543 void_t<decltype(
0544 transform_call_unpacker<
0545 Expr,
0546 decltype(*std::declval<TransformTuple>()[hana::llong<I>{}])>{}(
0547 std::declval<Expr>(),
0548 *std::declval<TransformTuple>()[hana::llong<I>{}],
0549 indices_for(std::declval<Expr>())))>>
0550 {
0551 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0552 {
0553 using transform_t = decltype(*transforms[hana::llong<I>{}]);
0554 return transform_call_unpacker<Expr, transform_t>{}(
0555 static_cast<Expr &&>(expr),
0556 *transforms[hana::llong<I>{}],
0557 indices_for(expr));
0558 }
0559 };
0560
0561 template<bool Strict, int I, bool IsExprRef>
0562 struct transform_impl
0563 {
0564 template<typename Expr, typename TransformTuple>
0565 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0566 {
0567 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0568 return detail::transform_expression_tag<
0569 Strict,
0570 Expr,
0571 TransformTuple,
0572 I,
0573 detail::arity_of<kind>()>{}(
0574 static_cast<Expr &&>(expr), transforms);
0575 }
0576 };
0577
0578 template<bool Strict, int I>
0579 struct transform_impl<Strict, I, true>
0580 {
0581 template<typename Expr, typename TransformTuple>
0582 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
0583 {
0584 return detail::transform_impl<Strict, I, false>{}(
0585 ::boost::yap::deref(static_cast<Expr &&>(expr)), transforms);
0586 }
0587 };
0588
0589 }}}
0590
0591 #endif