Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: /// \file repeat.hpp Chris@16: /// Contains macros to ease the generation of repetitious code constructs Chris@16: // Chris@16: // Copyright 2008 Eric Niebler. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_PROTO_REPEAT_HPP_EAN_11_24_2008 Chris@16: #define BOOST_PROTO_REPEAT_HPP_EAN_11_24_2008 Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include // for BOOST_PROTO_MAX_ARITY Chris@16: Chris@16: //////////////////////////////////////////// Chris@16: /// INTERNAL ONLY Chris@16: #define BOOST_PROTO_ref_a_aux(Z, N, DATA)\ Chris@16: boost::ref(BOOST_PP_CAT(proto_a, N)) Chris@16: Chris@16: /// \brief Generates a sequence like typename A0, typename A1, ... Chris@16: /// Chris@16: #define BOOST_PROTO_typename_A(N)\ Chris@16: BOOST_PP_ENUM_PARAMS(N, typename proto_A) Chris@16: Chris@16: /// \brief Generates a sequence like A0 const &, A1 const &, ... Chris@16: /// Chris@16: #define BOOST_PROTO_A_const_ref(N)\ Chris@16: BOOST_PP_ENUM_BINARY_PARAMS(N, proto_A, const & BOOST_PP_INTERCEPT) Chris@16: Chris@16: /// \brief Generates a sequence like A0 &, A1 &, ... Chris@16: /// Chris@16: #define BOOST_PROTO_A_ref(N)\ Chris@16: BOOST_PP_ENUM_BINARY_PARAMS(N, proto_A, & BOOST_PP_INTERCEPT) Chris@16: Chris@16: /// \brief Generates a sequence like A0, A1, ... Chris@16: /// Chris@16: #define BOOST_PROTO_A(N)\ Chris@16: BOOST_PP_ENUM_PARAMS(N, proto_A) Chris@16: Chris@16: /// \brief Generates a sequence like A0 const, A1 const, ... Chris@16: /// Chris@16: #define BOOST_PROTO_A_const(N)\ Chris@16: BOOST_PP_ENUM_PARAMS(N, const proto_A) Chris@16: Chris@16: /// \brief Generates a sequence like A0 const &a0, A1 const &a0, ... Chris@16: /// Chris@16: #define BOOST_PROTO_A_const_ref_a(N)\ Chris@16: BOOST_PP_ENUM_BINARY_PARAMS(N, proto_A, const &proto_a) Chris@16: Chris@16: /// \brief Generates a sequence like A0 &a0, A1 &a0, ... Chris@16: /// Chris@16: #define BOOST_PROTO_A_ref_a(N)\ Chris@16: BOOST_PP_ENUM_BINARY_PARAMS(N, proto_A, &proto_a) Chris@16: Chris@16: /// \brief Generates a sequence like boost::ref(a0), boost::ref(a1), ... Chris@16: /// Chris@16: #define BOOST_PROTO_ref_a(N)\ Chris@16: BOOST_PP_ENUM(N, BOOST_PROTO_ref_a_aux, ~) Chris@16: Chris@16: /// \brief Generates a sequence like a0, a1, ... Chris@16: /// Chris@16: #define BOOST_PROTO_a(N)\ Chris@16: BOOST_PP_ENUM_PARAMS(N, proto_a) Chris@16: Chris@16: //////////////////////////////////////////// Chris@16: /// INTERNAL ONLY Chris@16: #define BOOST_PROTO_invoke(Z, N, DATA)\ Chris@16: BOOST_PP_TUPLE_ELEM(5,0,DATA)(N, BOOST_PP_TUPLE_ELEM(5,1,DATA), BOOST_PP_TUPLE_ELEM(5,2,DATA), BOOST_PP_TUPLE_ELEM(5,3,DATA), BOOST_PP_TUPLE_ELEM(5,4,DATA)) Chris@16: Chris@16: /// \brief Repeatedly invoke the specified macro. Chris@16: /// Chris@16: /// BOOST_PROTO_REPEAT_FROM_TO_EX() is used generate the kind of repetitive code that is typical Chris@16: /// of EDSLs built with Proto. BOOST_PROTO_REPEAT_FROM_TO_EX(FROM, TO, MACRO, typename_A, A, A_a, a) is equivalent to: Chris@16: /// Chris@16: /// \code Chris@16: /// MACRO(FROM, typename_A, A, A_a, a) Chris@16: /// MACRO(FROM+1, typename_A, A, A_a, a) Chris@16: /// ... Chris@16: /// MACRO(TO-1, typename_A, A, A_a, a) Chris@16: /// \endcode Chris@16: #define BOOST_PROTO_REPEAT_FROM_TO_EX(FROM, TO, MACRO, typename_A, A, A_a, a)\ Chris@16: BOOST_PP_REPEAT_FROM_TO(FROM, TO, BOOST_PROTO_invoke, (MACRO, typename_A, A, A_a, a)) Chris@16: Chris@16: /// \brief Repeatedly invoke the specified macro. Chris@16: /// Chris@16: /// BOOST_PROTO_REPEAT_FROM_TO() is used generate the kind of repetitive code that is typical Chris@16: /// of EDSLs built with Proto. BOOST_PROTO_REPEAT_FROM_TO(FROM, TO, MACRO) is equivalent to: Chris@16: /// Chris@16: /// \code Chris@16: /// MACRO(FROM, BOOST_PROTO_typename_A, BOOST_PROTO_A_const_ref, BOOST_PROTO_A_const_ref_a, BOOST_PROTO_ref_a) Chris@16: /// MACRO(FROM+1, BOOST_PROTO_typename_A, BOOST_PROTO_A_const_ref, BOOST_PROTO_A_const_ref_a, BOOST_PROTO_ref_a) Chris@16: /// ... Chris@16: /// MACRO(TO-1, BOOST_PROTO_typename_A, BOOST_PROTO_A_const_ref, BOOST_PROTO_A_const_ref_a, BOOST_PROTO_ref_a) Chris@16: /// \endcode Chris@16: /// Chris@16: /// Example: Chris@16: /// Chris@16: /** \code Chris@16: Chris@16: // Generate BOOST_PROTO_MAX_ARITY-1 overloads of the Chris@16: // following construct() function template. Chris@16: #define M0(N, typename_A, A_const_ref, A_const_ref_a, ref_a) \ Chris@16: template \ Chris@16: typename proto::result_of::make_expr< \ Chris@16: proto::tag::function \ Chris@16: , construct_helper \ Chris@16: , A_const_ref(N) \ Chris@16: >::type const \ Chris@16: construct(A_const_ref_a(N)) \ Chris@16: { \ Chris@16: return proto::make_expr< \ Chris@16: proto::tag::function \ Chris@16: >( \ Chris@16: construct_helper() \ Chris@16: , ref_a(N) \ Chris@16: ); \ Chris@16: } Chris@16: BOOST_PROTO_REPEAT_FROM_TO(1, BOOST_PROTO_MAX_ARITY, M0) Chris@16: #undef M0 Chris@16: Chris@16: \endcode Chris@16: **/ Chris@16: /// The above invocation of BOOST_PROTO_REPEAT_FROM_TO() will generate Chris@16: /// the following code: Chris@16: /// Chris@16: /// \code Chris@16: /// template Chris@16: /// typename proto::result_of::make_expr< Chris@16: /// proto::tag::function Chris@16: /// , construct_helper Chris@16: /// , A0 const & Chris@16: /// >::type const Chris@16: /// construct(A0 const & a0) Chris@16: /// { Chris@16: /// return proto::make_expr< Chris@16: /// proto::tag::function Chris@16: /// >( Chris@16: /// construct_helper() Chris@16: /// , boost::ref(a0) Chris@16: /// ); Chris@16: /// } Chris@16: /// Chris@16: /// template Chris@16: /// typename proto::result_of::make_expr< Chris@16: /// proto::tag::function Chris@16: /// , construct_helper Chris@16: /// , A0 const & Chris@16: /// , A1 const & Chris@16: /// >::type const Chris@16: /// construct(A0 const & a0, A1 const & a1) Chris@16: /// { Chris@16: /// return proto::make_expr< Chris@16: /// proto::tag::function Chris@16: /// >( Chris@16: /// construct_helper() Chris@16: /// , boost::ref(a0) Chris@16: /// , boost::ref(a1) Chris@16: /// ); Chris@16: /// } Chris@16: /// Chris@16: /// // ... and so on, up to BOOST_PROTO_MAX_ARITY-1 arguments ... Chris@16: /// \endcode Chris@16: #define BOOST_PROTO_REPEAT_FROM_TO(FROM, TO, MACRO)\ Chris@16: BOOST_PROTO_REPEAT_FROM_TO_EX(FROM, TO, MACRO, BOOST_PROTO_typename_A, BOOST_PROTO_A_const_ref, BOOST_PROTO_A_const_ref_a, BOOST_PROTO_ref_a) Chris@16: Chris@16: /// \brief Repeatedly invoke the specified macro. Chris@16: /// Chris@16: /// BOOST_PROTO_REPEAT_EX() is used generate the kind of repetitive code that is typical Chris@16: /// of EDSLs built with Proto. BOOST_PROTO_REPEAT_EX(MACRO, typename_A, A, A_a, a) is equivalent to: Chris@16: /// Chris@16: /// \code Chris@16: /// MACRO(1, typename_A, A, A_a, a) Chris@16: /// MACRO(2, typename_A, A, A_a, a) Chris@16: /// ... Chris@16: /// MACRO(BOOST_PROTO_MAX_ARITY, typename_A, A, A_a, a) Chris@16: /// \endcode Chris@16: #define BOOST_PROTO_REPEAT_EX(MACRO, typename_A, A, A_a, a)\ Chris@16: BOOST_PROTO_REPEAT_FROM_TO_EX(1, BOOST_PP_INC(BOOST_PROTO_MAX_ARITY), MACRO, BOOST_PROTO_typename_A, BOOST_PROTO_A_const_ref, BOOST_PROTO_A_const_ref_a, BOOST_PROTO_ref_a) Chris@16: Chris@16: /// \brief Repeatedly invoke the specified macro. Chris@16: /// Chris@16: /// BOOST_PROTO_REPEAT() is used generate the kind of repetitive code that is typical Chris@16: /// of EDSLs built with Proto. BOOST_PROTO_REPEAT(MACRO) is equivalent to: Chris@16: /// Chris@16: /// \code Chris@16: /// MACRO(1, BOOST_PROTO_typename_A, BOOST_PROTO_A_const_ref, BOOST_PROTO_A_const_ref_a, BOOST_PROTO_ref_a) Chris@16: /// MACRO(2, BOOST_PROTO_typename_A, BOOST_PROTO_A_const_ref, BOOST_PROTO_A_const_ref_a, BOOST_PROTO_ref_a) Chris@16: /// ... Chris@16: /// MACRO(BOOST_PROTO_MAX_ARITY, BOOST_PROTO_typename_A, BOOST_PROTO_A_const_ref, BOOST_PROTO_A_const_ref_a, BOOST_PROTO_ref_a) Chris@16: /// \endcode Chris@16: #define BOOST_PROTO_REPEAT(MACRO)\ Chris@16: BOOST_PROTO_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_PROTO_MAX_ARITY), MACRO) Chris@16: Chris@16: /// \brief Repeatedly invoke the specified macro. Chris@16: /// Chris@16: /// BOOST_PROTO_LOCAL_ITERATE() is used generate the kind of repetitive code that is typical Chris@16: /// of EDSLs built with Proto. This macro causes the user-defined macro BOOST_PROTO_LOCAL_MACRO to Chris@16: /// be expanded with values in the range specified by BOOST_PROTO_LOCAL_LIMITS. Chris@16: /// Chris@16: /// Usage: Chris@16: /// Chris@16: /// \code Chris@16: /// #include BOOST_PROTO_LOCAL_ITERATE() Chris@16: /// \endcode Chris@16: /// Chris@16: /// Example: Chris@16: /// Chris@16: /** \code Chris@16: Chris@16: // Generate BOOST_PROTO_MAX_ARITY-1 overloads of the Chris@16: // following construct() function template. Chris@16: #define BOOST_PROTO_LOCAL_MACRO(N, typename_A, A_const_ref, \ Chris@16: A_const_ref_a, ref_a) \ Chris@16: template \ Chris@16: typename proto::result_of::make_expr< \ Chris@16: proto::tag::function \ Chris@16: , construct_helper \ Chris@16: , A_const_ref(N) \ Chris@16: >::type const \ Chris@16: construct(A_const_ref_a(N)) \ Chris@16: { \ Chris@16: return proto::make_expr< \ Chris@16: proto::tag::function \ Chris@16: >( \ Chris@16: construct_helper() \ Chris@16: , ref_a(N) \ Chris@16: ); \ Chris@16: } Chris@16: #define BOOST_PROTO_LOCAL_LIMITS (1, BOOST_PP_DEC(BOOST_PROTO_MAX_ARITY)) Chris@16: #include BOOST_PROTO_LOCAL_ITERATE() Chris@16: Chris@16: \endcode Chris@16: **/ Chris@16: /// The above inclusion of BOOST_PROTO_LOCAL_ITERATE() will generate Chris@16: /// the following code: Chris@16: /// Chris@16: /// \code Chris@16: /// template Chris@16: /// typename proto::result_of::make_expr< Chris@16: /// proto::tag::function Chris@16: /// , construct_helper Chris@16: /// , A0 const & Chris@16: /// >::type const Chris@16: /// construct(A0 const & a0) Chris@16: /// { Chris@16: /// return proto::make_expr< Chris@16: /// proto::tag::function Chris@16: /// >( Chris@16: /// construct_helper() Chris@16: /// , boost::ref(a0) Chris@16: /// ); Chris@16: /// } Chris@16: /// Chris@16: /// template Chris@16: /// typename proto::result_of::make_expr< Chris@16: /// proto::tag::function Chris@16: /// , construct_helper Chris@16: /// , A0 const & Chris@16: /// , A1 const & Chris@16: /// >::type const Chris@16: /// construct(A0 const & a0, A1 const & a1) Chris@16: /// { Chris@16: /// return proto::make_expr< Chris@16: /// proto::tag::function Chris@16: /// >( Chris@16: /// construct_helper() Chris@16: /// , boost::ref(a0) Chris@16: /// , boost::ref(a1) Chris@16: /// ); Chris@16: /// } Chris@16: /// Chris@16: /// // ... and so on, up to BOOST_PROTO_MAX_ARITY-1 arguments ... Chris@16: /// \endcode Chris@16: /// Chris@16: /// If BOOST_PROTO_LOCAL_LIMITS is not defined by the user, it defaults Chris@16: /// to (1, BOOST_PROTO_MAX_ARITY) Chris@16: /// Chris@16: /// At each iteration, BOOST_PROTO_LOCAL_MACRO is invoked with the current Chris@16: /// iteration number and the following 4 macro parameters: Chris@16: /// Chris@16: /// \li BOOST_PROTO_LOCAL_typename_A Chris@16: /// \li BOOST_PROTO_LOCAL_A Chris@16: /// \li BOOST_PROTO_LOCAL_A_a Chris@16: /// \li BOOST_PROTO_LOCAL_a Chris@16: /// Chris@16: /// If these macros are not defined by the user, they default respectively to: Chris@16: /// Chris@16: /// \li BOOST_PROTO_typename_A Chris@16: /// \li BOOST_PROTO_A_const_ref Chris@16: /// \li BOOST_PROTO_A_const_ref_a Chris@16: /// \li BOOST_PROTO_ref_a Chris@16: /// Chris@16: /// After including BOOST_PROTO_LOCAL_ITERATE(), the following macros are Chris@16: /// automatically undefined: Chris@16: /// Chris@16: /// \li BOOST_PROTO_LOCAL_MACRO Chris@16: /// \li BOOST_PROTO_LOCAL_LIMITS Chris@16: /// \li BOOST_PROTO_LOCAL_typename_A Chris@16: /// \li BOOST_PROTO_LOCAL_A Chris@16: /// \li BOOST_PROTO_LOCAL_A_a Chris@16: /// \li BOOST_PROTO_LOCAL_a Chris@16: #define BOOST_PROTO_LOCAL_ITERATE() Chris@16: Chris@16: #endif