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