// 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 <int N, class Switch1 = null_type, class Switch2 = null_type, | |
class Switch3 = null_type, class Switch4 = null_type, | |
class Switch5 = null_type, class Switch6 = null_type, | |
class Switch7 = null_type, class Switch8 = null_type, | |
class Switch9 = null_type> | |
struct switch_action {}; | |
namespace detail { | |
// templates to represent special lambda functors for the cases in | |
// switch statements | |
template <int Value> struct case_label {}; | |
struct default_label {}; | |
template<class Type> struct switch_case_tag {}; | |
// a normal case is represented as: | |
// tagged_lambda_functor<switch_case_tag<case_label<N> > >, LambdaFunctor> | |
// the default case as: | |
// tagged_lambda_functor<switch_case_tag<default_label> >, LambdaFunctor> | |
} // end detail | |
/// create switch_case_tag tagged_lambda_functors | |
template <int CaseValue, class Arg> | |
inline const | |
tagged_lambda_functor< | |
detail::switch_case_tag<detail::case_label<CaseValue> >, | |
lambda_functor<Arg> | |
> | |
case_statement(const lambda_functor<Arg>& a) { | |
return | |
tagged_lambda_functor< | |
detail::switch_case_tag<detail::case_label<CaseValue> >, | |
lambda_functor<Arg> | |
>(a); | |
} | |
// No case body case. | |
template <int CaseValue> | |
inline const | |
tagged_lambda_functor< | |
detail::switch_case_tag<detail::case_label<CaseValue> >, | |
lambda_functor< | |
lambda_functor_base< | |
do_nothing_action, | |
null_type | |
> | |
> | |
> | |
case_statement() { | |
return | |
tagged_lambda_functor< | |
detail::switch_case_tag<detail::case_label<CaseValue> >, | |
lambda_functor< | |
lambda_functor_base< | |
do_nothing_action, | |
null_type | |
> | |
> | |
> () ; | |
} | |
// default label | |
template <class Arg> | |
inline const | |
tagged_lambda_functor< | |
detail::switch_case_tag<detail::default_label>, | |
lambda_functor<Arg> | |
> | |
default_statement(const lambda_functor<Arg>& a) { | |
return | |
tagged_lambda_functor< | |
detail::switch_case_tag<detail::default_label>, | |
lambda_functor<Arg> | |
>(a); | |
} | |
// default lable, no case body case. | |
inline const | |
tagged_lambda_functor< | |
detail::switch_case_tag<detail::default_label>, | |
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 Args> | |
class | |
lambda_functor_base< | |
switch_action<1>, | |
Args | |
> | |
{ | |
public: | |
Args args; | |
template <class SigArgs> struct sig { typedef void type; }; | |
public: | |
explicit lambda_functor_base(const Args& a) : args(a) {} | |
template<class RET, CALL_TEMPLATE_ARGS> | |
RET call(CALL_FORMAL_ARGS) const { | |
detail::select(::boost::tuples::get<1>(args), CALL_ACTUAL_ARGS); | |
} | |
}; | |
// 1 case type: | |
// template<class Args, int Case1> | |
// class | |
// lambda_functor_base< | |
// action< | |
// 2, | |
// return_void_action<switch_action<detail::case_label<Case1> > > | |
// >, | |
// Args | |
// > | |
// { | |
// Args args; | |
// public: | |
// explicit lambda_functor_base(const Args& a) : args(a) {} | |
// template<class RET, class A, class B, class C> | |
// 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 Args> | |
// class | |
// lambda_functor_base< | |
// action< | |
// 2, | |
// return_void_action<switch_action<detail::default_label> > | |
// >, | |
// Args | |
// > | |
// { | |
// Args args; | |
// public: | |
// explicit lambda_functor_base(const Args& a) : args(a) {} | |
// | |
// template<class RET, class A, class B, class C> | |
// 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 Args, int Case1, int Case2> | |
// class | |
// lambda_functor_base< | |
// action<3, | |
// return_void_action< | |
// switch_action< | |
// detail::case_label<Case1>, | |
// detail::case_label<Case2> | |
// > | |
// > | |
// >, | |
// Args | |
// > | |
// { | |
// Args args; | |
// public: | |
// explicit lambda_functor_base(const Args& a) : args(a) {} | |
// template<class RET, class A, class B, class C> | |
// 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 Args, int Case1> | |
// class | |
// lambda_functor_base< | |
// action<3, | |
// return_void_action< | |
// switch_action< | |
// detail::case_label<Case1>, | |
// detail::default_label | |
// > | |
// > | |
// >, | |
// Args | |
// > | |
// { | |
// Args args; | |
// public: | |
// explicit lambda_functor_base(const Args& a) : args(a) {} | |
// template<class RET, class A, class B, class C> | |
// 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<BOOST_PP_INC(N)>(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 Args, BOOST_LAMBDA_A_I_LIST(N, int Case)> \ | |
class \ | |
lambda_functor_base< \ | |
switch_action<BOOST_PP_INC(N), \ | |
BOOST_LAMBDA_A_I_B_LIST(N, detail::case_label<Case,>) \ | |
>, \ | |
Args \ | |
> \ | |
{ \ | |
public: \ | |
Args args; \ | |
template <class SigArgs> struct sig { typedef void type; }; \ | |
public: \ | |
explicit lambda_functor_base(const Args& a) : args(a) {} \ | |
\ | |
template<class RET, CALL_TEMPLATE_ARGS> \ | |
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_INC(N), \ | |
BOOST_LAMBDA_A_I_B_LIST(BOOST_PP_DEC(N), \ | |
detail::case_label<Case, >) \ | |
BOOST_PP_COMMA_IF(BOOST_PP_DEC(N)) \ | |
detail::default_label \ | |
>, \ | |
Args \ | |
> \ | |
{ \ | |
public: \ | |
Args args; \ | |
template <class SigArgs> struct sig { typedef void type; }; \ | |
public: \ | |
explicit lambda_functor_base(const Args& a) : args(a) {} \ | |
\ | |
template<class RET, CALL_TEMPLATE_ARGS> \ | |
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<N>(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 <class TestArg> | |
inline const | |
lambda_functor< | |
lambda_functor_base< | |
switch_action<1>, | |
tuple<lambda_functor<TestArg> > | |
> | |
> | |
switch_statement(const lambda_functor<TestArg>& a1) { | |
return | |
lambda_functor_base< | |
switch_action<1>, | |
tuple< lambda_functor<TestArg> > | |
> | |
( tuple<lambda_functor<TestArg> >(a1)); | |
} | |
#define HELPER(z, N, FOO) \ | |
BOOST_PP_COMMA_IF(N) \ | |
BOOST_PP_CAT( \ | |
const tagged_lambda_functor<detail::switch_case_tag<TagData, \ | |
N>) \ | |
BOOST_PP_COMMA() Arg##N>& a##N | |
#define HELPER_LIST(N) BOOST_PP_REPEAT(N, HELPER, FOO) | |
#define BOOST_LAMBDA_SWITCH_STATEMENT(N) \ | |
template <class TestArg, \ | |
BOOST_LAMBDA_A_I_LIST(N, class TagData), \ | |
BOOST_LAMBDA_A_I_LIST(N, class Arg)> \ | |
inline const \ | |
lambda_functor< \ | |
lambda_functor_base< \ | |
switch_action<BOOST_PP_INC(N), \ | |
BOOST_LAMBDA_A_I_LIST(N, TagData) \ | |
>, \ | |
tuple<lambda_functor<TestArg>, BOOST_LAMBDA_A_I_LIST(N, Arg)> \ | |
> \ | |
> \ | |
switch_statement( \ | |
const lambda_functor<TestArg>& ta, \ | |
HELPER_LIST(N) \ | |
) \ | |
{ \ | |
return \ | |
lambda_functor_base< \ | |
switch_action<BOOST_PP_INC(N), \ | |
BOOST_LAMBDA_A_I_LIST(N, TagData) \ | |
>, \ | |
tuple<lambda_functor<TestArg>, BOOST_LAMBDA_A_I_LIST(N, Arg)> \ | |
> \ | |
( tuple<lambda_functor<TestArg>, 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 | |