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