123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 |
- // 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 <boost/yap/algorithm_fwd.hpp>
- #include <boost/hana/size.hpp>
- #include <boost/hana/tuple.hpp>
- #include <memory>
- #include <type_traits>
- namespace boost { namespace yap { namespace detail {
- // static_const
- template<typename T>
- struct static_const
- {
- static constexpr T value{};
- };
- template<typename T>
- constexpr T static_const<T>::value;
- // partial_decay
- template<typename T>
- struct partial_decay
- {
- using type = T;
- };
- template<typename T>
- struct partial_decay<T[]>
- {
- using type = T *;
- };
- template<typename T, std::size_t N>
- struct partial_decay<T[N]>
- {
- using type = T *;
- };
- template<typename T>
- struct partial_decay<T (&)[]>
- {
- using type = T *;
- };
- template<typename T, std::size_t N>
- struct partial_decay<T (&)[N]>
- {
- using type = T *;
- };
- template<typename R, typename... A>
- struct partial_decay<R(A...)>
- {
- using type = R (*)(A...);
- };
- template<typename R, typename... A>
- struct partial_decay<R(A..., ...)>
- {
- using type = R (*)(A..., ...);
- };
- template<typename R, typename... A>
- struct partial_decay<R (&)(A...)>
- {
- using type = R (*)(A...);
- };
- template<typename R, typename... A>
- struct partial_decay<R (&)(A..., ...)>
- {
- using type = R (*)(A..., ...);
- };
- template<typename R, typename... A>
- struct partial_decay<R (*&)(A...)>
- {
- using type = R (*)(A...);
- };
- template<typename R, typename... A>
- struct partial_decay<R (*&)(A..., ...)>
- {
- using type = R (*)(A..., ...);
- };
- // operand_value_type_phase_1
- template<
- typename T,
- typename U = typename detail::partial_decay<T>::type,
- bool AddRValueRef = std::is_same<T, U>::value && !std::is_const<U>::value>
- struct operand_value_type_phase_1;
- template<typename T, typename U>
- struct operand_value_type_phase_1<T, U, true>
- {
- using type = U &&;
- };
- template<typename T, typename U>
- struct operand_value_type_phase_1<T, U, false>
- {
- using type = U;
- };
- // expr_ref
- template<template<expr_kind, class> class ExprTemplate, typename T>
- struct expr_ref
- {
- using type = expression_ref<ExprTemplate, T>;
- };
- template<template<expr_kind, class> class ExprTemplate, typename Tuple>
- struct expr_ref<ExprTemplate, ExprTemplate<expr_kind::expr_ref, Tuple> &>
- {
- using type = ExprTemplate<expr_kind::expr_ref, Tuple>;
- };
- template<template<expr_kind, class> class ExprTemplate, typename Tuple>
- struct expr_ref<
- ExprTemplate,
- ExprTemplate<expr_kind::expr_ref, Tuple> const &>
- {
- using type = ExprTemplate<expr_kind::expr_ref, Tuple>;
- };
- template<template<expr_kind, class> class ExprTemplate, typename T>
- using expr_ref_t = typename expr_ref<ExprTemplate, T>::type;
- template<template<expr_kind, class> class ExprTemplate, typename T>
- struct expr_ref_tuple;
- template<template<expr_kind, class> class ExprTemplate, typename Tuple>
- struct expr_ref_tuple<
- ExprTemplate,
- ExprTemplate<expr_kind::expr_ref, Tuple>>
- {
- using type = Tuple;
- };
- template<template<expr_kind, class> class ExprTemplate, typename T>
- using expr_ref_tuple_t = typename expr_ref_tuple<ExprTemplate, T>::type;
- // operand_type
- template<
- template<expr_kind, class> class ExprTemplate,
- typename T,
- typename U = typename operand_value_type_phase_1<T>::type,
- bool RemoveRefs = std::is_rvalue_reference<U>::value,
- bool IsExpr = is_expr<T>::value,
- bool IsLRef = std::is_lvalue_reference<T>::value>
- struct operand_type;
- template<
- template<expr_kind, class> class ExprTemplate,
- typename T,
- typename U,
- bool RemoveRefs>
- struct operand_type<ExprTemplate, T, U, RemoveRefs, true, false>
- {
- using type = remove_cv_ref_t<T>;
- };
- template<
- template<expr_kind, class> class ExprTemplate,
- typename T,
- typename U,
- bool RemoveRefs>
- struct operand_type<ExprTemplate, T, U, RemoveRefs, true, true>
- {
- using type = expr_ref_t<ExprTemplate, T>;
- };
- template<
- template<expr_kind, class> class ExprTemplate,
- typename T,
- typename U,
- bool RemoveRefs,
- bool IsLRef>
- struct operand_type<ExprTemplate, T, U, RemoveRefs, true, IsLRef>
- {
- using type = remove_cv_ref_t<T>;
- };
- template<
- template<expr_kind, class> class ExprTemplate,
- typename T,
- typename U,
- bool IsLRef>
- struct operand_type<ExprTemplate, T, U, true, false, IsLRef>
- {
- using type = terminal<ExprTemplate, std::remove_reference_t<U>>;
- };
- template<
- template<expr_kind, class> class ExprTemplate,
- typename T,
- typename U,
- bool IsLRef>
- struct operand_type<ExprTemplate, T, U, false, false, IsLRef>
- {
- using type = terminal<ExprTemplate, U>;
- };
- template<template<expr_kind, class> class ExprTemplate, typename T>
- using operand_type_t = typename operand_type<ExprTemplate, T>::type;
- // make_operand
- template<typename T>
- struct make_operand
- {
- template<typename U>
- constexpr auto operator()(U && u)
- {
- return T{static_cast<U &&>(u)};
- }
- };
- template<template<expr_kind, class> class ExprTemplate, typename Tuple>
- struct make_operand<ExprTemplate<expr_kind::expr_ref, Tuple>>
- {
- constexpr auto operator()(ExprTemplate<expr_kind::expr_ref, Tuple> expr)
- {
- return expr;
- }
- template<typename U>
- constexpr auto operator()(U && u)
- {
- return ExprTemplate<expr_kind::expr_ref, Tuple>{
- Tuple{std::addressof(u)}};
- }
- };
- // free_binary_op_result
- template<
- template<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- typename U,
- bool TNonExprUExpr = !is_expr<T>::value && is_expr<U>::value,
- bool ULvalueRef = std::is_lvalue_reference<U>::value>
- struct free_binary_op_result;
- template<
- template<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- typename U>
- struct free_binary_op_result<ExprTemplate, OpKind, T, U, true, true>
- {
- using lhs_type = operand_type_t<ExprTemplate, T>;
- using rhs_type = expr_ref_t<ExprTemplate, U>;
- using rhs_tuple_type = expr_ref_tuple_t<ExprTemplate, rhs_type>;
- using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
- };
- template<
- template<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- typename U>
- struct free_binary_op_result<ExprTemplate, OpKind, T, U, true, false>
- {
- using lhs_type = operand_type_t<ExprTemplate, T>;
- using rhs_type = remove_cv_ref_t<U>;
- using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
- };
- template<
- template<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- typename U>
- using free_binary_op_result_t =
- typename free_binary_op_result<ExprTemplate, OpKind, T, U>::type;
- // ternary_op_result
- template<
- template<expr_kind, class> class ExprTemplate,
- typename T,
- typename U,
- typename V,
- bool Valid =
- is_expr<T>::value || is_expr<U>::value || is_expr<V>::value>
- struct ternary_op_result;
- template<
- template<expr_kind, class> class ExprTemplate,
- typename T,
- typename U,
- typename V>
- struct ternary_op_result<ExprTemplate, T, U, V, true>
- {
- using cond_type = operand_type_t<ExprTemplate, T>;
- using then_type = operand_type_t<ExprTemplate, U>;
- using else_type = operand_type_t<ExprTemplate, V>;
- using type = ExprTemplate<
- expr_kind::if_else,
- hana::tuple<cond_type, then_type, else_type>>;
- };
- template<
- template<expr_kind, class> class ExprTemplate,
- typename T,
- typename U,
- typename V>
- using ternary_op_result_t =
- typename ternary_op_result<ExprTemplate, T, U, V>::type;
- // udt_any_ternary_op_result
- template<
- template<expr_kind, class> class ExprTemplate,
- typename T,
- typename U,
- typename V,
- template<class> class UdtTrait,
- bool Valid = !is_expr<T>::value && !is_expr<U>::value &&
- !is_expr<V>::value &&
- (UdtTrait<remove_cv_ref_t<T>>::value ||
- UdtTrait<remove_cv_ref_t<U>>::value ||
- UdtTrait<remove_cv_ref_t<V>>::value)>
- struct udt_any_ternary_op_result;
- template<
- template<expr_kind, class> class ExprTemplate,
- typename T,
- typename U,
- typename V,
- template<class> class UdtTrait>
- struct udt_any_ternary_op_result<ExprTemplate, T, U, V, UdtTrait, true>
- {
- using cond_type = operand_type_t<ExprTemplate, T>;
- using then_type = operand_type_t<ExprTemplate, U>;
- using else_type = operand_type_t<ExprTemplate, V>;
- using type = ExprTemplate<
- expr_kind::if_else,
- hana::tuple<cond_type, then_type, else_type>>;
- };
- template<
- template<expr_kind, class> class ExprTemplate,
- typename T,
- typename U,
- typename V,
- template<class> class UdtTrait>
- using udt_any_ternary_op_result_t =
- typename udt_any_ternary_op_result<ExprTemplate, T, U, V, UdtTrait>::
- type;
- // udt_unary_op_result
- template<
- template<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- template<class> class UdtTrait,
- bool Valid = !is_expr<T>::value && UdtTrait<remove_cv_ref_t<T>>::value>
- struct udt_unary_op_result;
- template<
- template<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- template<class> class UdtTrait>
- struct udt_unary_op_result<ExprTemplate, OpKind, T, UdtTrait, true>
- {
- using x_type = operand_type_t<ExprTemplate, T>;
- using type = ExprTemplate<OpKind, hana::tuple<x_type>>;
- };
- template<
- template<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- template<class> class UdtTrait>
- using udt_unary_op_result_t =
- typename udt_unary_op_result<ExprTemplate, OpKind, T, UdtTrait>::type;
- // udt_udt_binary_op_result
- template<typename T, template<class> class UdtTrait>
- struct is_udt_arg
- {
- static bool const value =
- !is_expr<T>::value && UdtTrait<remove_cv_ref_t<T>>::value;
- };
- template<
- template<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- typename U,
- template<class> class TUdtTrait,
- template<class> class UUdtTrait,
- bool Valid =
- is_udt_arg<T, TUdtTrait>::value && is_udt_arg<U, UUdtTrait>::value>
- struct udt_udt_binary_op_result;
- template<
- template<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- typename U,
- template<class> class TUdtTrait,
- template<class> class UUdtTrait>
- struct udt_udt_binary_op_result<
- ExprTemplate,
- OpKind,
- T,
- U,
- TUdtTrait,
- UUdtTrait,
- true>
- {
- using lhs_type = operand_type_t<ExprTemplate, T>;
- using rhs_type = operand_type_t<ExprTemplate, U>;
- using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
- };
- template<
- template<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- typename U,
- template<class> class TUdtTrait,
- template<class> 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<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- typename U,
- template<class> class UdtTrait,
- bool Valid = !is_expr<T>::value && !is_expr<U>::value &&
- (UdtTrait<remove_cv_ref_t<T>>::value ||
- UdtTrait<remove_cv_ref_t<U>>::value)>
- struct udt_any_binary_op_result;
- template<
- template<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- typename U,
- template<class> class UdtTrait>
- struct udt_any_binary_op_result<ExprTemplate, OpKind, T, U, UdtTrait, true>
- {
- using lhs_type = operand_type_t<ExprTemplate, T>;
- using rhs_type = operand_type_t<ExprTemplate, U>;
- using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
- };
- template<
- template<expr_kind, class> class ExprTemplate,
- expr_kind OpKind,
- typename T,
- typename U,
- template<class> 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<typename LeftT, typename RightT>
- struct copy_or_move : std::false_type
- {
- };
- template<typename T>
- struct copy_or_move<T, T const &> : std::true_type
- {
- };
- template<typename T>
- struct copy_or_move<T, T &> : std::true_type
- {
- };
- template<typename T>
- struct copy_or_move<T, T &&> : std::true_type
- {
- };
- // expr_arity
- enum class expr_arity { invalid, one, two, three, n };
- template<expr_kind Kind>
- 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
|