/////////////////////////////////////////////////////////////////////////////// /// \file extends.hpp /// Macros and a base class for defining end-user expression types // // Copyright 2008 Eric Niebler. 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_PROTO_EXTENDS_HPP_EAN_11_1_2006 #define BOOST_PROTO_EXTENDS_HPP_EAN_11_1_2006 #include // for offsetof #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma warning(push) # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined #endif namespace boost { namespace proto { #ifdef __GNUC__ /// INTERNAL ONLY /// # define BOOST_PROTO_ADDROF(x) ((char const volatile*)boost::addressof(x)) /// INTERNAL ONLY /// # define BOOST_PROTO_OFFSETOF(s,m) (BOOST_PROTO_ADDROF((((s *)this)->m)) - BOOST_PROTO_ADDROF(*((s *)this))) #else /// INTERNAL ONLY /// # define BOOST_PROTO_OFFSETOF offsetof #endif /// INTERNAL ONLY /// #define BOOST_PROTO_CONST() const /// INTERNAL ONLY /// #define BOOST_PROTO_TYPENAME() typename /// INTERNAL ONLY /// #define BOOST_PROTO_TEMPLATE_YES_(Z, N) template /// INTERNAL ONLY /// #define BOOST_PROTO_TEMPLATE_NO_(Z, N) /// INTERNAL ONLY /// #define BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, Const) \ BOOST_PP_IF(N, BOOST_PROTO_TEMPLATE_YES_, BOOST_PROTO_TEMPLATE_NO_)(Z, N) \ BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ typename BOOST_PROTO_RESULT_OF< \ proto_generator( \ typename boost::proto::result_of::BOOST_PP_CAT(funop, N)< \ proto_derived_expr Const() \ , proto_domain \ BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, const A) \ >::type \ ) \ >::type const \ operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, const &a)) Const() \ { \ typedef boost::proto::result_of::BOOST_PP_CAT(funop, N)< \ proto_derived_expr Const() \ , proto_domain \ BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, const A) \ > funop; \ return proto_generator()( \ funop::call( \ *static_cast(this) \ BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, a) \ ) \ ); \ } \ /**/ /// INTERNAL ONLY /// #define BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(Const) \ template \ BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ typename BOOST_PROTO_RESULT_OF< \ proto_generator( \ typename boost::proto::result_of::funop< \ proto_derived_expr Const()(A const &...) \ , proto_derived_expr \ , proto_domain \ >::type \ ) \ >::type const \ operator ()(A const &...a) Const() \ { \ typedef boost::proto::result_of::funop< \ proto_derived_expr Const()(A const &...) \ , proto_derived_expr \ , proto_domain \ > funop; \ return proto_generator()( \ funop::call( \ *static_cast(this) \ , a... \ ) \ ); \ } \ /**/ /// INTERNAL ONLY /// #define BOOST_PROTO_DEFINE_FUN_OP_CONST(Z, N, DATA) \ BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, BOOST_PROTO_CONST) \ /**/ /// INTERNAL ONLY /// #define BOOST_PROTO_DEFINE_FUN_OP_NON_CONST(Z, N, DATA) \ BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, BOOST_PP_EMPTY) \ /**/ /// INTERNAL ONLY /// #define BOOST_PROTO_DEFINE_FUN_OP(Z, N, DATA) \ BOOST_PROTO_DEFINE_FUN_OP_CONST(Z, N, DATA) \ BOOST_PROTO_DEFINE_FUN_OP_NON_CONST(Z, N, DATA) \ /**/ /// INTERNAL ONLY /// #define BOOST_PROTO_EXTENDS_CHILD(Z, N, DATA) \ typedef \ typename proto_base_expr::BOOST_PP_CAT(proto_child, N) \ BOOST_PP_CAT(proto_child, N); \ /**/ #define BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain) \ Expr proto_expr_; \ \ typedef Expr proto_base_expr_; /**< INTERNAL ONLY */ \ typedef typename proto_base_expr_::proto_base_expr proto_base_expr; \ typedef BOOST_PROTO_REMOVE_TYPENAME(Domain) proto_domain; \ typedef Derived proto_derived_expr; \ typedef Domain::proto_generator proto_generator; \ typedef typename proto_base_expr::proto_tag proto_tag; \ typedef typename proto_base_expr::proto_args proto_args; \ typedef typename proto_base_expr::proto_arity proto_arity; \ typedef typename proto_base_expr::proto_grammar proto_grammar; \ typedef typename proto_base_expr::address_of_hack_type_ proto_address_of_hack_type_; \ typedef void proto_is_expr_; /**< INTERNAL ONLY */ \ static const long proto_arity_c = proto_base_expr::proto_arity_c; \ typedef boost::proto::tag::proto_expr fusion_tag; \ BOOST_PP_REPEAT(BOOST_PROTO_MAX_ARITY, BOOST_PROTO_EXTENDS_CHILD, ~) \ \ BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ static proto_derived_expr const make(Expr const &e) \ { \ proto_derived_expr that = {e}; \ return that; \ } \ \ BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ proto_base_expr &proto_base() \ { \ return this->proto_expr_.proto_base(); \ } \ \ BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ proto_base_expr const &proto_base() const \ { \ return this->proto_expr_.proto_base(); \ } \ \ BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ operator proto_address_of_hack_type_() const \ { \ return boost::addressof(this->proto_base().child0); \ } \ /**/ #define BOOST_PROTO_BASIC_EXTENDS(Expr, Derived, Domain) \ BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain) \ typedef void proto_is_aggregate_; \ /**< INTERNAL ONLY */ #define BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, Const, Typename) \ BOOST_PROTO_DISABLE_MSVC_C4522 \ BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ Typename() BOOST_PROTO_RESULT_OF< \ Typename() This::proto_generator( \ Typename() boost::proto::base_expr< \ Typename() This::proto_domain \ , boost::proto::tag::assign \ , boost::proto::list2< \ This & \ , This Const() & \ > \ >::type \ ) \ >::type const \ operator =(This Const() &a) \ { \ typedef \ Typename() boost::proto::base_expr< \ Typename() This::proto_domain \ , boost::proto::tag::assign \ , boost::proto::list2< \ This & \ , This Const() & \ > \ >::type \ that_type; \ that_type const that = { \ *this \ , a \ }; \ return Typename() This::proto_generator()(that); \ } \ /**/ // MSVC 8.0 and higher seem to need copy-assignment operator to be overloaded on *both* // const and non-const rhs arguments. #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) && (BOOST_MSVC > 1310) #define BOOST_PROTO_EXTENDS_COPY_ASSIGN_(This, Typename) \ BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, BOOST_PP_EMPTY, Typename) \ BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, BOOST_PROTO_CONST, Typename) \ /**/ #else #define BOOST_PROTO_EXTENDS_COPY_ASSIGN_(This, Typename) \ BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, BOOST_PROTO_CONST, Typename) \ /**/ #endif /// INTERNAL ONLY /// #define BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(ThisConst, ThatConst) \ template \ BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ typename BOOST_PROTO_RESULT_OF< \ proto_generator( \ typename boost::proto::base_expr< \ proto_domain \ , boost::proto::tag::assign \ , boost::proto::list2< \ proto_derived_expr ThisConst() & \ , typename boost::proto::result_of::as_child::type \ > \ >::type \ ) \ >::type const \ operator =(A ThatConst() &a) ThisConst() \ { \ typedef \ typename boost::proto::base_expr< \ proto_domain \ , boost::proto::tag::assign \ , boost::proto::list2< \ proto_derived_expr ThisConst() & \ , typename boost::proto::result_of::as_child::type \ > \ >::type \ that_type; \ that_type const that = { \ *static_cast(this) \ , boost::proto::as_child(a) \ }; \ return proto_generator()(that); \ } \ /**/ #define BOOST_PROTO_EXTENDS_ASSIGN_CONST_() \ BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PROTO_CONST, BOOST_PP_EMPTY) \ BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PROTO_CONST, BOOST_PROTO_CONST) \ /**/ #define BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST_() \ BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PP_EMPTY, BOOST_PP_EMPTY) \ BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PP_EMPTY, BOOST_PROTO_CONST) \ /**/ #define BOOST_PROTO_EXTENDS_ASSIGN_() \ BOOST_PROTO_EXTENDS_ASSIGN_CONST_() \ BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST_() \ /**/ #define BOOST_PROTO_EXTENDS_ASSIGN_CONST() \ BOOST_PROTO_EXTENDS_COPY_ASSIGN_(proto_derived_expr, BOOST_PROTO_TYPENAME) \ BOOST_PROTO_EXTENDS_ASSIGN_CONST_() \ /**/ #define BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST() \ BOOST_PROTO_EXTENDS_COPY_ASSIGN_(proto_derived_expr, BOOST_PROTO_TYPENAME) \ BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST_() \ /**/ #define BOOST_PROTO_EXTENDS_ASSIGN() \ BOOST_PROTO_EXTENDS_COPY_ASSIGN_(proto_derived_expr, BOOST_PROTO_TYPENAME) \ BOOST_PROTO_EXTENDS_ASSIGN_() \ /**/ /// INTERNAL ONLY /// #define BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(ThisConst, ThatConst) \ template \ BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ typename BOOST_PROTO_RESULT_OF< \ proto_generator( \ typename boost::proto::base_expr< \ proto_domain \ , boost::proto::tag::subscript \ , boost::proto::list2< \ proto_derived_expr ThisConst() & \ , typename boost::proto::result_of::as_child::type \ > \ >::type \ ) \ >::type const \ operator [](A ThatConst() &a) ThisConst() \ { \ typedef \ typename boost::proto::base_expr< \ proto_domain \ , boost::proto::tag::subscript \ , boost::proto::list2< \ proto_derived_expr ThisConst() & \ , typename boost::proto::result_of::as_child::type \ > \ >::type \ that_type; \ that_type const that = { \ *static_cast(this) \ , boost::proto::as_child(a) \ }; \ return proto_generator()(that); \ } \ /**/ #define BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST() \ BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PROTO_CONST, BOOST_PP_EMPTY) \ BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PROTO_CONST, BOOST_PROTO_CONST) \ /**/ #define BOOST_PROTO_EXTENDS_SUBSCRIPT_NON_CONST() \ BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PP_EMPTY, BOOST_PP_EMPTY) \ BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PP_EMPTY, BOOST_PROTO_CONST) \ /**/ #define BOOST_PROTO_EXTENDS_SUBSCRIPT() \ BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST() \ BOOST_PROTO_EXTENDS_SUBSCRIPT_NON_CONST() \ /**/ /// INTERNAL ONLY /// #define BOOST_PROTO_EXTENDS_FUNCTION_() \ template \ struct result \ { \ typedef \ typename BOOST_PROTO_RESULT_OF< \ proto_generator( \ typename boost::proto::result_of::funop< \ Sig \ , proto_derived_expr \ , proto_domain \ >::type \ ) \ >::type const \ type; \ }; \ /**/ #ifndef BOOST_NO_VARIADIC_TEMPLATES #define BOOST_PROTO_EXTENDS_FUNCTION_CONST() \ BOOST_PROTO_EXTENDS_FUNCTION_() \ BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PROTO_CONST) \ /**/ #define BOOST_PROTO_EXTENDS_FUNCTION_NON_CONST() \ BOOST_PROTO_EXTENDS_FUNCTION_() \ BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PP_EMPTY) \ /**/ #define BOOST_PROTO_EXTENDS_FUNCTION() \ BOOST_PROTO_EXTENDS_FUNCTION_() \ BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PP_EMPTY) \ BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PROTO_CONST) \ /**/ #else #define BOOST_PROTO_EXTENDS_FUNCTION_CONST() \ BOOST_PROTO_EXTENDS_FUNCTION_() \ BOOST_PP_REPEAT_FROM_TO( \ 0 \ , BOOST_PROTO_MAX_FUNCTION_CALL_ARITY \ , BOOST_PROTO_DEFINE_FUN_OP_CONST \ , ~ \ ) \ /**/ #define BOOST_PROTO_EXTENDS_FUNCTION_NON_CONST() \ BOOST_PROTO_EXTENDS_FUNCTION_() \ BOOST_PP_REPEAT_FROM_TO( \ 0 \ , BOOST_PROTO_MAX_FUNCTION_CALL_ARITY \ , BOOST_PROTO_DEFINE_FUN_OP_NON_CONST \ , ~ \ ) \ /**/ #define BOOST_PROTO_EXTENDS_FUNCTION() \ BOOST_PROTO_EXTENDS_FUNCTION_() \ BOOST_PP_REPEAT_FROM_TO( \ 0 \ , BOOST_PROTO_MAX_FUNCTION_CALL_ARITY \ , BOOST_PROTO_DEFINE_FUN_OP \ , ~ \ ) \ /**/ #endif #define BOOST_PROTO_EXTENDS(Expr, Derived, Domain) \ BOOST_PROTO_BASIC_EXTENDS(Expr, Derived, Domain) \ BOOST_PROTO_EXTENDS_ASSIGN() \ BOOST_PROTO_EXTENDS_SUBSCRIPT() \ BOOST_PROTO_EXTENDS_FUNCTION() \ /**/ #define BOOST_PROTO_EXTENDS_USING_ASSIGN(Derived) \ typedef typename Derived::proto_extends proto_extends; \ using proto_extends::operator =; \ BOOST_PROTO_EXTENDS_COPY_ASSIGN_(Derived, BOOST_PROTO_TYPENAME) \ /**/ #define BOOST_PROTO_EXTENDS_USING_ASSIGN_NON_DEPENDENT(Derived) \ typedef Derived::proto_extends proto_extends; \ using proto_extends::operator =; \ BOOST_PROTO_EXTENDS_COPY_ASSIGN_(Derived, BOOST_PP_EMPTY) \ /**/ namespace exprns_ { /// \brief Empty type to be used as a dummy template parameter of /// POD expression wrappers. It allows argument-dependent lookup /// to find Proto's operator overloads. /// /// \c proto::is_proto_expr allows argument-dependent lookup /// to find Proto's operator overloads. For example: /// /// \code /// template /// struct my_terminal /// { /// BOOST_PROTO_BASIC_EXTENDS( /// typename proto::terminal::type /// , my_terminal /// , default_domain /// ) /// }; /// /// // ... /// my_terminal _1, _2; /// _1 + _2; // OK, uses proto::operator+ /// \endcode /// /// Without the second \c Dummy template parameter, Proto's operator /// overloads would not be considered by name lookup. struct is_proto_expr {}; /// \brief extends\<\> class template for adding behaviors to a Proto expression template /// template< typename Expr , typename Derived , typename Domain // = proto::default_domain , long Arity // = Expr::proto_arity_c > struct extends { BOOST_FORCEINLINE extends() : proto_expr_() {} BOOST_FORCEINLINE extends(extends const &that) : proto_expr_(that.proto_expr_) {} BOOST_FORCEINLINE extends(Expr const &expr_) : proto_expr_(expr_) {} typedef extends proto_extends; BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, typename Domain) BOOST_PROTO_EXTENDS_ASSIGN_CONST_() BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST() // Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses // nested preprocessor loops, use file iteration here to generate // the operator() overloads, which is more efficient. #include }; /// \brief extends\<\> class template for adding behaviors to a Proto expression template /// template struct extends { BOOST_FORCEINLINE extends() : proto_expr_() {} BOOST_FORCEINLINE extends(extends const &that) : proto_expr_(that.proto_expr_) {} BOOST_FORCEINLINE extends(Expr const &expr_) : proto_expr_(expr_) {} typedef extends proto_extends; BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, typename Domain) BOOST_PROTO_EXTENDS_ASSIGN_() BOOST_PROTO_EXTENDS_SUBSCRIPT() // Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses // nested preprocessor loops, use file iteration here to generate // the operator() overloads, which is more efficient. #include }; /// INTERNAL ONLY /// template struct virtual_member { typedef Domain proto_domain; typedef typename Domain::proto_generator proto_generator; typedef virtual_member proto_derived_expr; typedef tag::member proto_tag; typedef list2 > const &> proto_args; typedef mpl::long_<2> proto_arity; typedef detail::not_a_valid_type proto_address_of_hack_type_; typedef void proto_is_expr_; /**< INTERNAL ONLY */ static const long proto_arity_c = 2; typedef boost::proto::tag::proto_expr fusion_tag; typedef This &proto_child0; typedef expr > const &proto_child1; typedef expr proto_base_expr; typedef basic_expr proto_grammar; typedef void proto_is_aggregate_; /**< INTERNAL ONLY */ BOOST_PROTO_EXTENDS_ASSIGN_() BOOST_PROTO_EXTENDS_SUBSCRIPT() // Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses // nested preprocessor loops, use file iteration here to generate // the operator() overloads, which is more efficient. #define BOOST_PROTO_NO_WAVE_OUTPUT #include #undef BOOST_PROTO_NO_WAVE_OUTPUT BOOST_FORCEINLINE proto_base_expr const proto_base() const { proto_base_expr that = {this->child0(), this->child1()}; return that; } BOOST_FORCEINLINE proto_child0 child0() const { using std::size_t; return *(This *)((char *)this - BOOST_PROTO_OFFSETOF(This, proto_member_union_start_)); } BOOST_FORCEINLINE proto_child1 child1() const { static expr, 0> const that = {Fun()}; return that; } }; /// INTERNAL ONLY /// #define BOOST_PROTO_EXTENDS_MEMBER_(R, DOMAIN, ELEM) \ boost::proto::exprns_::virtual_member< \ proto_derived_expr \ , BOOST_PP_TUPLE_ELEM(2, 0, ELEM) \ , DOMAIN \ > BOOST_PP_TUPLE_ELEM(2, 1, ELEM); \ /**/ /// \brief For declaring virtual data members in an extension class. /// #define BOOST_PROTO_EXTENDS_MEMBERS_WITH_DOMAIN(SEQ, DOMAIN) \ union \ { \ char proto_member_union_start_; \ BOOST_PP_SEQ_FOR_EACH(BOOST_PROTO_EXTENDS_MEMBER_, DOMAIN, SEQ) \ }; \ /**/ /// \brief For declaring virtual data members in an extension class. /// #define BOOST_PROTO_EXTENDS_MEMBERS(SEQ) \ BOOST_PROTO_EXTENDS_MEMBERS_WITH_DOMAIN(SEQ, proto_domain) \ /**/ } }} #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma warning(pop) #endif #endif