// Copyright (C) 2016-2018 T. Zachary Laine // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_YAP_DETAIL_EXPRESSION_HPP_INCLUDED #define BOOST_YAP_DETAIL_EXPRESSION_HPP_INCLUDED #include #include #include #include #include namespace boost { namespace yap { namespace detail { // static_const template struct static_const { static constexpr T value{}; }; template constexpr T static_const::value; // partial_decay template struct partial_decay { using type = T; }; template struct partial_decay { using type = T *; }; template struct partial_decay { using type = T *; }; template struct partial_decay { using type = T *; }; template struct partial_decay { using type = T *; }; template struct partial_decay { using type = R (*)(A...); }; template struct partial_decay { using type = R (*)(A..., ...); }; template struct partial_decay { using type = R (*)(A...); }; template struct partial_decay { using type = R (*)(A..., ...); }; template struct partial_decay { using type = R (*)(A...); }; template struct partial_decay { using type = R (*)(A..., ...); }; // operand_value_type_phase_1 template< typename T, typename U = typename detail::partial_decay::type, bool AddRValueRef = std::is_same::value && !std::is_const::value> struct operand_value_type_phase_1; template struct operand_value_type_phase_1 { using type = U &&; }; template struct operand_value_type_phase_1 { using type = U; }; // expr_ref template class ExprTemplate, typename T> struct expr_ref { using type = expression_ref; }; template class ExprTemplate, typename Tuple> struct expr_ref &> { using type = ExprTemplate; }; template class ExprTemplate, typename Tuple> struct expr_ref< ExprTemplate, ExprTemplate const &> { using type = ExprTemplate; }; template class ExprTemplate, typename T> using expr_ref_t = typename expr_ref::type; template class ExprTemplate, typename T> struct expr_ref_tuple; template class ExprTemplate, typename Tuple> struct expr_ref_tuple< ExprTemplate, ExprTemplate> { using type = Tuple; }; template class ExprTemplate, typename T> using expr_ref_tuple_t = typename expr_ref_tuple::type; // operand_type template< template class ExprTemplate, typename T, typename U = typename operand_value_type_phase_1::type, bool RemoveRefs = std::is_rvalue_reference::value, bool IsExpr = is_expr::value, bool IsLRef = std::is_lvalue_reference::value> struct operand_type; template< template class ExprTemplate, typename T, typename U, bool RemoveRefs> struct operand_type { using type = remove_cv_ref_t; }; template< template class ExprTemplate, typename T, typename U, bool RemoveRefs> struct operand_type { using type = expr_ref_t; }; template< template class ExprTemplate, typename T, typename U, bool RemoveRefs, bool IsLRef> struct operand_type { using type = remove_cv_ref_t; }; template< template class ExprTemplate, typename T, typename U, bool IsLRef> struct operand_type { using type = terminal>; }; template< template class ExprTemplate, typename T, typename U, bool IsLRef> struct operand_type { using type = terminal; }; template class ExprTemplate, typename T> using operand_type_t = typename operand_type::type; // make_operand template struct make_operand { template auto operator()(U && u) { return T{static_cast(u)}; } }; template class ExprTemplate, typename Tuple> struct make_operand> { auto operator()(ExprTemplate expr) { return expr; } template auto operator()(U && u) { return ExprTemplate{ Tuple{std::addressof(u)}}; } }; // free_binary_op_result template< template class ExprTemplate, expr_kind OpKind, typename T, typename U, bool TNonExprUExpr = !is_expr::value && is_expr::value, bool ULvalueRef = std::is_lvalue_reference::value> struct free_binary_op_result; template< template class ExprTemplate, expr_kind OpKind, typename T, typename U> struct free_binary_op_result { using lhs_type = operand_type_t; using rhs_type = expr_ref_t; using rhs_tuple_type = expr_ref_tuple_t; using type = ExprTemplate>; }; template< template class ExprTemplate, expr_kind OpKind, typename T, typename U> struct free_binary_op_result { using lhs_type = operand_type_t; using rhs_type = remove_cv_ref_t; using type = ExprTemplate>; }; template< template class ExprTemplate, expr_kind OpKind, typename T, typename U> using free_binary_op_result_t = typename free_binary_op_result::type; // ternary_op_result template< template class ExprTemplate, typename T, typename U, typename V, bool Valid = is_expr::value || is_expr::value || is_expr::value> struct ternary_op_result; template< template class ExprTemplate, typename T, typename U, typename V> struct ternary_op_result { using cond_type = operand_type_t; using then_type = operand_type_t; using else_type = operand_type_t; using type = ExprTemplate< expr_kind::if_else, hana::tuple>; }; template< template class ExprTemplate, typename T, typename U, typename V> using ternary_op_result_t = typename ternary_op_result::type; // udt_any_ternary_op_result template< template class ExprTemplate, typename T, typename U, typename V, template class UdtTrait, bool Valid = !is_expr::value && !is_expr::value && !is_expr::value && (UdtTrait>::value || UdtTrait>::value || UdtTrait>::value)> struct udt_any_ternary_op_result; template< template class ExprTemplate, typename T, typename U, typename V, template class UdtTrait> struct udt_any_ternary_op_result { using cond_type = operand_type_t; using then_type = operand_type_t; using else_type = operand_type_t; using type = ExprTemplate< expr_kind::if_else, hana::tuple>; }; template< template class ExprTemplate, typename T, typename U, typename V, template class UdtTrait> using udt_any_ternary_op_result_t = typename udt_any_ternary_op_result:: type; // udt_unary_op_result template< template class ExprTemplate, expr_kind OpKind, typename T, template class UdtTrait, bool Valid = !is_expr::value && UdtTrait>::value> struct udt_unary_op_result; template< template class ExprTemplate, expr_kind OpKind, typename T, template class UdtTrait> struct udt_unary_op_result { using x_type = operand_type_t; using type = ExprTemplate>; }; template< template class ExprTemplate, expr_kind OpKind, typename T, template class UdtTrait> using udt_unary_op_result_t = typename udt_unary_op_result::type; // udt_udt_binary_op_result template class UdtTrait> struct is_udt_arg { static bool const value = !is_expr::value && UdtTrait>::value; }; template< template class ExprTemplate, expr_kind OpKind, typename T, typename U, template class TUdtTrait, template class UUdtTrait, bool Valid = is_udt_arg::value && is_udt_arg::value> struct udt_udt_binary_op_result; template< template class ExprTemplate, expr_kind OpKind, typename T, typename U, template class TUdtTrait, template class UUdtTrait> struct udt_udt_binary_op_result< ExprTemplate, OpKind, T, U, TUdtTrait, UUdtTrait, true> { using lhs_type = operand_type_t; using rhs_type = operand_type_t; using type = ExprTemplate>; }; template< template class ExprTemplate, expr_kind OpKind, typename T, typename U, template class TUdtTrait, template class UUdtTrait> using udt_udt_binary_op_result_t = typename udt_udt_binary_op_result< ExprTemplate, OpKind, T, U, TUdtTrait, UUdtTrait>::type; // udt_any_binary_op_result template< template class ExprTemplate, expr_kind OpKind, typename T, typename U, template class UdtTrait, bool Valid = !is_expr::value && !is_expr::value && (UdtTrait>::value || UdtTrait>::value)> struct udt_any_binary_op_result; template< template class ExprTemplate, expr_kind OpKind, typename T, typename U, template class UdtTrait> struct udt_any_binary_op_result { using lhs_type = operand_type_t; using rhs_type = operand_type_t; using type = ExprTemplate>; }; template< template class ExprTemplate, expr_kind OpKind, typename T, typename U, template class UdtTrait> using udt_any_binary_op_result_t = typename udt_any_binary_op_result< ExprTemplate, OpKind, T, U, UdtTrait>::type; // not_copy_or_move template struct copy_or_move : std::false_type { }; template struct copy_or_move : std::true_type { }; template struct copy_or_move : std::true_type { }; template struct copy_or_move : std::true_type { }; // expr_arity enum class expr_arity { invalid, one, two, three, n }; template constexpr expr_arity arity_of() { switch (Kind) { case expr_kind::expr_ref: case expr_kind::terminal: // unary case expr_kind::unary_plus: // + case expr_kind::negate: // - case expr_kind::dereference: // * case expr_kind::complement: // ~ case expr_kind::address_of: // & case expr_kind::logical_not: // ! case expr_kind::pre_inc: // ++ case expr_kind::pre_dec: // -- case expr_kind::post_inc: // ++(int) case expr_kind::post_dec: // --(int) return expr_arity::one; // binary case expr_kind::shift_left: // << case expr_kind::shift_right: // >> case expr_kind::multiplies: // * case expr_kind::divides: // / case expr_kind::modulus: // % case expr_kind::plus: // + case expr_kind::minus: // - case expr_kind::less: // < case expr_kind::greater: // > case expr_kind::less_equal: // <= case expr_kind::greater_equal: // >= case expr_kind::equal_to: // == case expr_kind::not_equal_to: // != case expr_kind::logical_or: // || case expr_kind::logical_and: // && case expr_kind::bitwise_and: // & case expr_kind::bitwise_or: // | case expr_kind::bitwise_xor: // ^ case expr_kind::comma: // : case expr_kind::mem_ptr: // ->* case expr_kind::assign: // = case expr_kind::shift_left_assign: // <<= case expr_kind::shift_right_assign: // >>= case expr_kind::multiplies_assign: // *= case expr_kind::divides_assign: // /= case expr_kind::modulus_assign: // %= case expr_kind::plus_assign: // += case expr_kind::minus_assign: // -= case expr_kind::bitwise_and_assign: // &= case expr_kind::bitwise_or_assign: // |= case expr_kind::bitwise_xor_assign: // ^= case expr_kind::subscript: // [] return expr_arity::two; // ternary case expr_kind::if_else: // (analogous to) ?: return expr_arity::three; // n-ary case expr_kind::call: // () return expr_arity::n; default: return expr_arity::invalid; } } }}} #endif