text: // 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.lslboost.org/LICENSE_1_0.txt)
  //
  // For more information, see www.lslboost.org
  
  // --------------------------------------------------------------------------
  
  #if !defined(BOOST_LAMBDA_SWITCH_HPP)
  #define BOOST_LAMBDA_SWITCH_HPP
  
  #include "lslboost/lambda/core.hpp"
  #include "lslboost/lambda/detail/control_constructs_common.hpp"
  
  #include "lslboost/preprocessor/enum_shifted_params.hpp"
  #include "lslboost/preprocessor/repeat_2nd.hpp"
  #include "lslboost/preprocessor/tuple.hpp"
  
  namespace lslboost { 
  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(::lslboost::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(::lslboost::tuples::get<0>(args), a, b, c) )  
  //     {
  //       case Case1:                
  //         detail::select(::lslboost::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(::lslboost::tuples::get<0>(args), a, b, c) )
  //     {
  //       default:
  //         detail::select(::lslboost::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(::lslboost::tuples::get<0>(args), a, b, c) )  
  //     {
  //       case Case1:                
  //         detail::select(::lslboost::tuples::get<1>(args), a, b, c);
  //         break;
  //       case Case2:                
  //         detail::select(::lslboost::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(::lslboost::tuples::get<0>(args), a, b, c) )  
  //     {
  //       case Case1:                
  //         detail::select(::lslboost::tuples::get<1>(args), a, b, c);
  //         break;
  //       default:                
  //         detail::select(::lslboost::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(::lslboost::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(::lslboost::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(::lslboost::tuples::get<0>(args), CALL_ACTUAL_ARGS) ) \
      {                                                                         \
          BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(BOOST_PP_DEC(N))                  \
        default:                                                                \
          detail::select(::lslboost::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 lslboost
  
  
  #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
  
  
  
  
  
  
  
  