// Boost Lambda Library -- switch.hpp -----------------------------------

//

// Copyright (C) 2000 Gary Powell (powellg@amazon.com)

// Copyright (C) 1999, 2000 Jaakko Järvi (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))







  // 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)





} // 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















