509 lines
17 KiB
C++
509 lines
17 KiB
C++
// 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|