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