// Boost Lambda Library -- switch.hpp ----------------------------------- // // Copyright (C) 2000 Gary Powell (powellg@amazon.com) // Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) // // 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) // // For more information, see www.boost.org // -------------------------------------------------------------------------- #if !defined(BOOST_LAMBDA_SWITCH_HPP) #define BOOST_LAMBDA_SWITCH_HPP #include "boost/lambda/core.hpp" #include "boost/lambda/detail/control_constructs_common.hpp" #include "boost/preprocessor/enum_shifted_params.hpp" #include "boost/preprocessor/repeat_2nd.hpp" #include "boost/preprocessor/tuple.hpp" namespace boost { namespace lambda { // Switch actions template struct switch_action {}; namespace detail { // templates to represent special lambda functors for the cases in // switch statements template struct case_label {}; struct default_label {}; template struct switch_case_tag {}; // a normal case is represented as: // tagged_lambda_functor > >, LambdaFunctor> // the default case as: // tagged_lambda_functor >, LambdaFunctor> } // end detail /// create switch_case_tag tagged_lambda_functors template inline const tagged_lambda_functor< detail::switch_case_tag >, lambda_functor > case_statement(const lambda_functor& a) { return tagged_lambda_functor< detail::switch_case_tag >, lambda_functor >(a); } // No case body case. template inline const tagged_lambda_functor< detail::switch_case_tag >, lambda_functor< lambda_functor_base< do_nothing_action, null_type > > > case_statement() { return tagged_lambda_functor< detail::switch_case_tag >, lambda_functor< lambda_functor_base< do_nothing_action, null_type > > > () ; } // default label template inline const tagged_lambda_functor< detail::switch_case_tag, lambda_functor > default_statement(const lambda_functor& a) { return tagged_lambda_functor< detail::switch_case_tag, lambda_functor >(a); } // default lable, no case body case. inline const tagged_lambda_functor< detail::switch_case_tag, lambda_functor< lambda_functor_base< do_nothing_action, null_type > > > default_statement() { return lambda_functor_base< do_nothing_action, null_type > () ; } // Specializations for lambda_functor_base of case_statement ----------------- // 0 case type: // useless (just the condition part) but provided for completeness. template class lambda_functor_base< switch_action<1>, Args > { public: Args args; template struct sig { typedef void type; }; public: explicit lambda_functor_base(const Args& a) : args(a) {} template RET call(CALL_FORMAL_ARGS) const { detail::select(::boost::tuples::get<1>(args), CALL_ACTUAL_ARGS); } }; // 1 case type: // template // class // lambda_functor_base< // action< // 2, // return_void_action > > // >, // Args // > // { // Args args; // public: // explicit lambda_functor_base(const Args& a) : args(a) {} // template // RET call(A& a, B& b, C& c) const { // switch( detail::select(::boost::tuples::get<0>(args), a, b, c) ) // { // case Case1: // detail::select(::boost::tuples::get<1>(args), a, b, c); // break; // } // } // }; // switch with default being the sole label - doesn't make much sense but // it is there for completeness // template // class // lambda_functor_base< // action< // 2, // return_void_action > // >, // Args // > // { // Args args; // public: // explicit lambda_functor_base(const Args& a) : args(a) {} // // template // RET call(A& a, B& b, C& c) const { // switch( detail::select(::boost::tuples::get<0>(args), a, b, c) ) // { // default: // detail::select(::boost::tuples::get<1>(args), a, b, c); // break; // } // } // }; // // 2 case type: // The different specializations are generated with Vesa Karvonen's // preprocessor library. // This is just a comment to show what the generated classes look like // template // class // lambda_functor_base< // action<3, // return_void_action< // switch_action< // detail::case_label, // detail::case_label // > // > // >, // Args // > // { // Args args; // public: // explicit lambda_functor_base(const Args& a) : args(a) {} // template // RET call(A& a, B& b, C& c) const { // switch( detail::select(::boost::tuples::get<0>(args), a, b, c) ) // { // case Case1: // detail::select(::boost::tuples::get<1>(args), a, b, c); // break; // case Case2: // detail::select(::boost::tuples::get<2>(args), a, b, c); // break; // } // } // }; // template // class // lambda_functor_base< // action<3, // return_void_action< // switch_action< // detail::case_label, // detail::default_label // > // > // >, // Args // > // { // Args args; // public: // explicit lambda_functor_base(const Args& a) : args(a) {} // template // RET call(A& a, B& b, C& c) const { // switch( detail::select(::boost::tuples::get<0>(args), a, b, c) ) // { // case Case1: // detail::select(::boost::tuples::get<1>(args), a, b, c); // break; // default: // detail::select(::boost::tuples::get<2>(args), a, b, c); // break; // } // } // }; // ------------------------- // Some helper preprocessor macros --------------------------------- // BOOST_LAMBDA_A_I_LIST(N, X) is a list of form X0, X1, ..., XN // BOOST_LAMBDA_A_I_B_LIST(N, X, Y) is a list of form X0 Y, X1 Y, ..., XN Y #define BOOST_LAMBDA_A_I(z, i, A) \ BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(A,i) #define BOOST_LAMBDA_A_I_B(z, i, T) \ BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2,0,T),i) BOOST_PP_TUPLE_ELEM(2,1,T) #define BOOST_LAMBDA_A_I_LIST(i, A) \ BOOST_PP_REPEAT(i,BOOST_LAMBDA_A_I, A) #define BOOST_LAMBDA_A_I_B_LIST(i, A, B) \ BOOST_PP_REPEAT(i,BOOST_LAMBDA_A_I_B, (A,B)) // Switch related macros ------------------------------------------- #define BOOST_LAMBDA_SWITCH_CASE_BLOCK(z, N, A) \ case Case##N: \ detail::select(::boost::tuples::get(args), CALL_ACTUAL_ARGS); \ break; #define BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(N) \ BOOST_PP_REPEAT(N, BOOST_LAMBDA_SWITCH_CASE_BLOCK, FOO) // 2 case type: #define BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE(N) \ template \ class \ lambda_functor_base< \ switch_action) \ >, \ Args \ > \ { \ public: \ Args args; \ template struct sig { typedef void type; }; \ public: \ explicit lambda_functor_base(const Args& a) : args(a) {} \ \ template \ RET call(CALL_FORMAL_ARGS) const { \ switch( detail::select(::boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) ) \ { \ BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(N) \ } \ } \ }; #define BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE(N) \ template< \ class Args BOOST_PP_COMMA_IF(BOOST_PP_DEC(N)) \ BOOST_LAMBDA_A_I_LIST(BOOST_PP_DEC(N), int Case) \ > \ class \ lambda_functor_base< \ switch_action) \ BOOST_PP_COMMA_IF(BOOST_PP_DEC(N)) \ detail::default_label \ >, \ Args \ > \ { \ public: \ Args args; \ template struct sig { typedef void type; }; \ public: \ explicit lambda_functor_base(const Args& a) : args(a) {} \ \ template \ RET call(CALL_FORMAL_ARGS) const { \ switch( detail::select(::boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) ) \ { \ BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(BOOST_PP_DEC(N)) \ default: \ detail::select(::boost::tuples::get(args), CALL_ACTUAL_ARGS); \ break; \ } \ } \ }; // switch_statement bind functions ------------------------------------- // The zero argument case, for completeness sake inline const lambda_functor< lambda_functor_base< do_nothing_action, null_type > > switch_statement() { return lambda_functor_base< do_nothing_action, null_type > (); } // 1 argument case, this is useless as well, just the condition part template inline const lambda_functor< lambda_functor_base< switch_action<1>, tuple > > > switch_statement(const lambda_functor& a1) { return lambda_functor_base< switch_action<1>, tuple< lambda_functor > > ( tuple >(a1)); } #define HELPER(z, N, FOO) \ BOOST_PP_COMMA_IF(N) \ BOOST_PP_CAT( \ const tagged_lambda_functor) \ BOOST_PP_COMMA() Arg##N>& a##N #define HELPER_LIST(N) BOOST_PP_REPEAT(N, HELPER, FOO) #define BOOST_LAMBDA_SWITCH_STATEMENT(N) \ template \ inline const \ lambda_functor< \ lambda_functor_base< \ switch_action, \ tuple, BOOST_LAMBDA_A_I_LIST(N, Arg)> \ > \ > \ switch_statement( \ const lambda_functor& ta, \ HELPER_LIST(N) \ ) \ { \ return \ lambda_functor_base< \ switch_action, \ tuple, BOOST_LAMBDA_A_I_LIST(N, Arg)> \ > \ ( tuple, BOOST_LAMBDA_A_I_LIST(N, Arg)> \ (ta, BOOST_LAMBDA_A_I_LIST(N, a) )); \ } // Here's the actual generation #define BOOST_LAMBDA_SWITCH(N) \ BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE(N) \ BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE(N) // Use this to avoid case 0, these macros work only from case 1 upwards #define BOOST_LAMBDA_SWITCH_HELPER(z, N, A) \ BOOST_LAMBDA_SWITCH( BOOST_PP_INC(N) ) // Use this to avoid cases 0 and 1, these macros work only from case 2 upwards #define BOOST_LAMBDA_SWITCH_STATEMENT_HELPER(z, N, A) \ BOOST_LAMBDA_SWITCH_STATEMENT(BOOST_PP_INC(N)) #ifdef BOOST_MSVC #pragma warning(push) #pragma warning(disable:4065) #endif // up to 9 cases supported (counting default:) BOOST_PP_REPEAT_2ND(9,BOOST_LAMBDA_SWITCH_HELPER,FOO) BOOST_PP_REPEAT_2ND(9,BOOST_LAMBDA_SWITCH_STATEMENT_HELPER,FOO) #ifdef BOOST_MSVC #pragma warning(pop) #endif } // namespace lambda } // namespace boost #undef HELPER #undef HELPER_LIST #undef BOOST_LAMBDA_SWITCH_HELPER #undef BOOST_LAMBDA_SWITCH #undef BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE #undef BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE #undef BOOST_LAMBDA_SWITCH_CASE_BLOCK #undef BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST #undef BOOST_LAMBDA_SWITCH_STATEMENT #undef BOOST_LAMBDA_SWITCH_STATEMENT_HELPER #endif