1 // Copyright (C) 2016-2018 T. Zachary Laine
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
9 #include <boost/yap/algorithm_fwd.hpp>
11 #include <boost/hana/size.hpp>
12 #include <boost/hana/tuple.hpp>
15 #include <type_traits>
18 namespace boost { namespace yap { namespace detail {
25 static constexpr T value{};
29 constexpr T static_const<T>::value;
41 struct partial_decay<T[]>
45 template<typename T, std::size_t N>
46 struct partial_decay<T[N]>
52 struct partial_decay<T (&)[]>
56 template<typename T, std::size_t N>
57 struct partial_decay<T (&)[N]>
62 template<typename R, typename... A>
63 struct partial_decay<R(A...)>
65 using type = R (*)(A...);
67 template<typename R, typename... A>
68 struct partial_decay<R(A..., ...)>
70 using type = R (*)(A..., ...);
73 template<typename R, typename... A>
74 struct partial_decay<R (&)(A...)>
76 using type = R (*)(A...);
78 template<typename R, typename... A>
79 struct partial_decay<R (&)(A..., ...)>
81 using type = R (*)(A..., ...);
84 template<typename R, typename... A>
85 struct partial_decay<R (*&)(A...)>
87 using type = R (*)(A...);
89 template<typename R, typename... A>
90 struct partial_decay<R (*&)(A..., ...)>
92 using type = R (*)(A..., ...);
96 // operand_value_type_phase_1
100 typename U = typename detail::partial_decay<T>::type,
101 bool AddRValueRef = std::is_same<T, U>::value && !std::is_const<U>::value>
102 struct operand_value_type_phase_1;
104 template<typename T, typename U>
105 struct operand_value_type_phase_1<T, U, true>
110 template<typename T, typename U>
111 struct operand_value_type_phase_1<T, U, false>
119 template<template<expr_kind, class> class ExprTemplate, typename T>
122 using type = expression_ref<ExprTemplate, T>;
125 template<template<expr_kind, class> class ExprTemplate, typename Tuple>
126 struct expr_ref<ExprTemplate, ExprTemplate<expr_kind::expr_ref, Tuple> &>
128 using type = ExprTemplate<expr_kind::expr_ref, Tuple>;
131 template<template<expr_kind, class> class ExprTemplate, typename Tuple>
134 ExprTemplate<expr_kind::expr_ref, Tuple> const &>
136 using type = ExprTemplate<expr_kind::expr_ref, Tuple>;
139 template<template<expr_kind, class> class ExprTemplate, typename T>
140 using expr_ref_t = typename expr_ref<ExprTemplate, T>::type;
142 template<template<expr_kind, class> class ExprTemplate, typename T>
143 struct expr_ref_tuple;
145 template<template<expr_kind, class> class ExprTemplate, typename Tuple>
146 struct expr_ref_tuple<
148 ExprTemplate<expr_kind::expr_ref, Tuple>>
153 template<template<expr_kind, class> class ExprTemplate, typename T>
154 using expr_ref_tuple_t = typename expr_ref_tuple<ExprTemplate, T>::type;
160 template<expr_kind, class> class ExprTemplate,
162 typename U = typename operand_value_type_phase_1<T>::type,
163 bool RemoveRefs = std::is_rvalue_reference<U>::value,
164 bool IsExpr = is_expr<T>::value,
165 bool IsLRef = std::is_lvalue_reference<T>::value>
169 template<expr_kind, class> class ExprTemplate,
173 struct operand_type<ExprTemplate, T, U, RemoveRefs, true, false>
175 using type = remove_cv_ref_t<T>;
179 template<expr_kind, class> class ExprTemplate,
183 struct operand_type<ExprTemplate, T, U, RemoveRefs, true, true>
185 using type = expr_ref_t<ExprTemplate, T>;
189 template<expr_kind, class> class ExprTemplate,
194 struct operand_type<ExprTemplate, T, U, RemoveRefs, true, IsLRef>
196 using type = remove_cv_ref_t<T>;
200 template<expr_kind, class> class ExprTemplate,
204 struct operand_type<ExprTemplate, T, U, true, false, IsLRef>
206 using type = terminal<ExprTemplate, std::remove_reference_t<U>>;
210 template<expr_kind, class> class ExprTemplate,
214 struct operand_type<ExprTemplate, T, U, false, false, IsLRef>
216 using type = terminal<ExprTemplate, U>;
219 template<template<expr_kind, class> class ExprTemplate, typename T>
220 using operand_type_t = typename operand_type<ExprTemplate, T>::type;
229 auto operator()(U && u)
231 return T{static_cast<U &&>(u)};
235 template<template<expr_kind, class> class ExprTemplate, typename Tuple>
236 struct make_operand<ExprTemplate<expr_kind::expr_ref, Tuple>>
238 auto operator()(ExprTemplate<expr_kind::expr_ref, Tuple> expr)
244 auto operator()(U && u)
246 return ExprTemplate<expr_kind::expr_ref, Tuple>{
247 Tuple{std::addressof(u)}};
252 // free_binary_op_result
255 template<expr_kind, class> class ExprTemplate,
259 bool TNonExprUExpr = !is_expr<T>::value && is_expr<U>::value,
260 bool ULvalueRef = std::is_lvalue_reference<U>::value>
261 struct free_binary_op_result;
264 template<expr_kind, class> class ExprTemplate,
268 struct free_binary_op_result<ExprTemplate, OpKind, T, U, true, true>
270 using lhs_type = operand_type_t<ExprTemplate, T>;
271 using rhs_type = expr_ref_t<ExprTemplate, U>;
272 using rhs_tuple_type = expr_ref_tuple_t<ExprTemplate, rhs_type>;
273 using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
277 template<expr_kind, class> class ExprTemplate,
281 struct free_binary_op_result<ExprTemplate, OpKind, T, U, true, false>
283 using lhs_type = operand_type_t<ExprTemplate, T>;
284 using rhs_type = remove_cv_ref_t<U>;
285 using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
289 template<expr_kind, class> class ExprTemplate,
293 using free_binary_op_result_t =
294 typename free_binary_op_result<ExprTemplate, OpKind, T, U>::type;
300 template<expr_kind, class> class ExprTemplate,
305 is_expr<T>::value || is_expr<U>::value || is_expr<V>::value>
306 struct ternary_op_result;
309 template<expr_kind, class> class ExprTemplate,
313 struct ternary_op_result<ExprTemplate, T, U, V, true>
315 using cond_type = operand_type_t<ExprTemplate, T>;
316 using then_type = operand_type_t<ExprTemplate, U>;
317 using else_type = operand_type_t<ExprTemplate, V>;
318 using type = ExprTemplate<
320 hana::tuple<cond_type, then_type, else_type>>;
324 template<expr_kind, class> class ExprTemplate,
328 using ternary_op_result_t =
329 typename ternary_op_result<ExprTemplate, T, U, V>::type;
332 // udt_any_ternary_op_result
335 template<expr_kind, class> class ExprTemplate,
339 template<class> class UdtTrait,
340 bool Valid = !is_expr<T>::value && !is_expr<U>::value &&
341 !is_expr<V>::value &&
342 (UdtTrait<remove_cv_ref_t<T>>::value ||
343 UdtTrait<remove_cv_ref_t<U>>::value ||
344 UdtTrait<remove_cv_ref_t<V>>::value)>
345 struct udt_any_ternary_op_result;
348 template<expr_kind, class> class ExprTemplate,
352 template<class> class UdtTrait>
353 struct udt_any_ternary_op_result<ExprTemplate, T, U, V, UdtTrait, true>
355 using cond_type = operand_type_t<ExprTemplate, T>;
356 using then_type = operand_type_t<ExprTemplate, U>;
357 using else_type = operand_type_t<ExprTemplate, V>;
358 using type = ExprTemplate<
360 hana::tuple<cond_type, then_type, else_type>>;
364 template<expr_kind, class> class ExprTemplate,
368 template<class> class UdtTrait>
369 using udt_any_ternary_op_result_t =
370 typename udt_any_ternary_op_result<ExprTemplate, T, U, V, UdtTrait>::
374 // udt_unary_op_result
377 template<expr_kind, class> class ExprTemplate,
380 template<class> class UdtTrait,
381 bool Valid = !is_expr<T>::value && UdtTrait<remove_cv_ref_t<T>>::value>
382 struct udt_unary_op_result;
385 template<expr_kind, class> class ExprTemplate,
388 template<class> class UdtTrait>
389 struct udt_unary_op_result<ExprTemplate, OpKind, T, UdtTrait, true>
391 using x_type = operand_type_t<ExprTemplate, T>;
392 using type = ExprTemplate<OpKind, hana::tuple<x_type>>;
396 template<expr_kind, class> class ExprTemplate,
399 template<class> class UdtTrait>
400 using udt_unary_op_result_t =
401 typename udt_unary_op_result<ExprTemplate, OpKind, T, UdtTrait>::type;
404 // udt_udt_binary_op_result
406 template<typename T, template<class> class UdtTrait>
409 static bool const value =
410 !is_expr<T>::value && UdtTrait<remove_cv_ref_t<T>>::value;
414 template<expr_kind, class> class ExprTemplate,
418 template<class> class TUdtTrait,
419 template<class> class UUdtTrait,
421 is_udt_arg<T, TUdtTrait>::value && is_udt_arg<U, UUdtTrait>::value>
422 struct udt_udt_binary_op_result;
425 template<expr_kind, class> class ExprTemplate,
429 template<class> class TUdtTrait,
430 template<class> class UUdtTrait>
431 struct udt_udt_binary_op_result<
440 using lhs_type = operand_type_t<ExprTemplate, T>;
441 using rhs_type = operand_type_t<ExprTemplate, U>;
442 using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
446 template<expr_kind, class> class ExprTemplate,
450 template<class> class TUdtTrait,
451 template<class> class UUdtTrait>
452 using udt_udt_binary_op_result_t = typename udt_udt_binary_op_result<
461 // udt_any_binary_op_result
464 template<expr_kind, class> class ExprTemplate,
468 template<class> class UdtTrait,
469 bool Valid = !is_expr<T>::value && !is_expr<U>::value &&
470 (UdtTrait<remove_cv_ref_t<T>>::value ||
471 UdtTrait<remove_cv_ref_t<U>>::value)>
472 struct udt_any_binary_op_result;
475 template<expr_kind, class> class ExprTemplate,
479 template<class> class UdtTrait>
480 struct udt_any_binary_op_result<ExprTemplate, OpKind, T, U, UdtTrait, true>
482 using lhs_type = operand_type_t<ExprTemplate, T>;
483 using rhs_type = operand_type_t<ExprTemplate, U>;
484 using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
488 template<expr_kind, class> class ExprTemplate,
492 template<class> class UdtTrait>
493 using udt_any_binary_op_result_t = typename udt_any_binary_op_result<
503 template<typename LeftT, typename RightT>
504 struct copy_or_move : std::false_type
509 struct copy_or_move<T, T const &> : std::true_type
514 struct copy_or_move<T, T &> : std::true_type
519 struct copy_or_move<T, T &&> : std::true_type
526 enum class expr_arity { invalid, one, two, three, n };
528 template<expr_kind Kind>
529 constexpr expr_arity arity_of()
532 case expr_kind::expr_ref:
534 case expr_kind::terminal:
537 case expr_kind::unary_plus: // +
538 case expr_kind::negate: // -
539 case expr_kind::dereference: // *
540 case expr_kind::complement: // ~
541 case expr_kind::address_of: // &
542 case expr_kind::logical_not: // !
543 case expr_kind::pre_inc: // ++
544 case expr_kind::pre_dec: // --
545 case expr_kind::post_inc: // ++(int)
546 case expr_kind::post_dec: // --(int)
547 return expr_arity::one;
550 case expr_kind::shift_left: // <<
551 case expr_kind::shift_right: // >>
552 case expr_kind::multiplies: // *
553 case expr_kind::divides: // /
554 case expr_kind::modulus: // %
555 case expr_kind::plus: // +
556 case expr_kind::minus: // -
557 case expr_kind::less: // <
558 case expr_kind::greater: // >
559 case expr_kind::less_equal: // <=
560 case expr_kind::greater_equal: // >=
561 case expr_kind::equal_to: // ==
562 case expr_kind::not_equal_to: // !=
563 case expr_kind::logical_or: // ||
564 case expr_kind::logical_and: // &&
565 case expr_kind::bitwise_and: // &
566 case expr_kind::bitwise_or: // |
567 case expr_kind::bitwise_xor: // ^
568 case expr_kind::comma: // :
569 case expr_kind::mem_ptr: // ->*
570 case expr_kind::assign: // =
571 case expr_kind::shift_left_assign: // <<=
572 case expr_kind::shift_right_assign: // >>=
573 case expr_kind::multiplies_assign: // *=
574 case expr_kind::divides_assign: // /=
575 case expr_kind::modulus_assign: // %=
576 case expr_kind::plus_assign: // +=
577 case expr_kind::minus_assign: // -=
578 case expr_kind::bitwise_and_assign: // &=
579 case expr_kind::bitwise_or_assign: // |=
580 case expr_kind::bitwise_xor_assign: // ^=
581 case expr_kind::subscript: // []
582 return expr_arity::two;
585 case expr_kind::if_else: // (analogous to) ?:
586 return expr_arity::three;
589 case expr_kind::call: // ()
590 return expr_arity::n;
592 default: return expr_arity::invalid;