switch.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. // Boost Lambda Library -- switch.hpp -----------------------------------
  2. //
  3. // Copyright (C) 2000 Gary Powell ([email protected])
  4. // Copyright (C) 1999, 2000 Jaakko Jarvi ([email protected])
  5. //
  6. // Distributed under the Boost Software License, Version 1.0. (See
  7. // accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. // For more information, see www.boost.org
  11. // --------------------------------------------------------------------------
  12. #if !defined(BOOST_LAMBDA_SWITCH_HPP)
  13. #define BOOST_LAMBDA_SWITCH_HPP
  14. #include "boost/lambda/core.hpp"
  15. #include "boost/lambda/detail/control_constructs_common.hpp"
  16. #include "boost/preprocessor/enum_shifted_params.hpp"
  17. #include "boost/preprocessor/repeat_2nd.hpp"
  18. #include "boost/preprocessor/tuple.hpp"
  19. namespace boost {
  20. namespace lambda {
  21. // Switch actions
  22. template <int N, class Switch1 = null_type, class Switch2 = null_type,
  23. class Switch3 = null_type, class Switch4 = null_type,
  24. class Switch5 = null_type, class Switch6 = null_type,
  25. class Switch7 = null_type, class Switch8 = null_type,
  26. class Switch9 = null_type>
  27. struct switch_action {};
  28. namespace detail {
  29. // templates to represent special lambda functors for the cases in
  30. // switch statements
  31. template <int Value> struct case_label {};
  32. struct default_label {};
  33. template<class Type> struct switch_case_tag {};
  34. // a normal case is represented as:
  35. // tagged_lambda_functor<switch_case_tag<case_label<N> > >, LambdaFunctor>
  36. // the default case as:
  37. // tagged_lambda_functor<switch_case_tag<default_label> >, LambdaFunctor>
  38. } // end detail
  39. /// create switch_case_tag tagged_lambda_functors
  40. template <int CaseValue, class Arg>
  41. inline const
  42. tagged_lambda_functor<
  43. detail::switch_case_tag<detail::case_label<CaseValue> >,
  44. lambda_functor<Arg>
  45. >
  46. case_statement(const lambda_functor<Arg>& a) {
  47. return
  48. tagged_lambda_functor<
  49. detail::switch_case_tag<detail::case_label<CaseValue> >,
  50. lambda_functor<Arg>
  51. >(a);
  52. }
  53. // No case body case.
  54. template <int CaseValue>
  55. inline const
  56. tagged_lambda_functor<
  57. detail::switch_case_tag<detail::case_label<CaseValue> >,
  58. lambda_functor<
  59. lambda_functor_base<
  60. do_nothing_action,
  61. null_type
  62. >
  63. >
  64. >
  65. case_statement() {
  66. return
  67. tagged_lambda_functor<
  68. detail::switch_case_tag<detail::case_label<CaseValue> >,
  69. lambda_functor<
  70. lambda_functor_base<
  71. do_nothing_action,
  72. null_type
  73. >
  74. >
  75. > () ;
  76. }
  77. // default label
  78. template <class Arg>
  79. inline const
  80. tagged_lambda_functor<
  81. detail::switch_case_tag<detail::default_label>,
  82. lambda_functor<Arg>
  83. >
  84. default_statement(const lambda_functor<Arg>& a) {
  85. return
  86. tagged_lambda_functor<
  87. detail::switch_case_tag<detail::default_label>,
  88. lambda_functor<Arg>
  89. >(a);
  90. }
  91. // default lable, no case body case.
  92. inline const
  93. tagged_lambda_functor<
  94. detail::switch_case_tag<detail::default_label>,
  95. lambda_functor<
  96. lambda_functor_base<
  97. do_nothing_action,
  98. null_type
  99. >
  100. >
  101. >
  102. default_statement() {
  103. return
  104. lambda_functor_base<
  105. do_nothing_action,
  106. null_type
  107. > () ;
  108. }
  109. // Specializations for lambda_functor_base of case_statement -----------------
  110. // 0 case type:
  111. // useless (just the condition part) but provided for completeness.
  112. template<class Args>
  113. class
  114. lambda_functor_base<
  115. switch_action<1>,
  116. Args
  117. >
  118. {
  119. public:
  120. Args args;
  121. template <class SigArgs> struct sig { typedef void type; };
  122. public:
  123. explicit lambda_functor_base(const Args& a) : args(a) {}
  124. template<class RET, CALL_TEMPLATE_ARGS>
  125. RET call(CALL_FORMAL_ARGS) const {
  126. detail::select(::boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
  127. }
  128. };
  129. // 1 case type:
  130. // template<class Args, int Case1>
  131. // class
  132. // lambda_functor_base<
  133. // action<
  134. // 2,
  135. // return_void_action<switch_action<detail::case_label<Case1> > >
  136. // >,
  137. // Args
  138. // >
  139. // {
  140. // Args args;
  141. // public:
  142. // explicit lambda_functor_base(const Args& a) : args(a) {}
  143. // template<class RET, class A, class B, class C>
  144. // RET call(A& a, B& b, C& c) const {
  145. // switch( detail::select(::boost::tuples::get<0>(args), a, b, c) )
  146. // {
  147. // case Case1:
  148. // detail::select(::boost::tuples::get<1>(args), a, b, c);
  149. // break;
  150. // }
  151. // }
  152. // };
  153. // switch with default being the sole label - doesn't make much sense but
  154. // it is there for completeness
  155. // template<class Args>
  156. // class
  157. // lambda_functor_base<
  158. // action<
  159. // 2,
  160. // return_void_action<switch_action<detail::default_label> >
  161. // >,
  162. // Args
  163. // >
  164. // {
  165. // Args args;
  166. // public:
  167. // explicit lambda_functor_base(const Args& a) : args(a) {}
  168. //
  169. // template<class RET, class A, class B, class C>
  170. // RET call(A& a, B& b, C& c) const {
  171. // switch( detail::select(::boost::tuples::get<0>(args), a, b, c) )
  172. // {
  173. // default:
  174. // detail::select(::boost::tuples::get<1>(args), a, b, c);
  175. // break;
  176. // }
  177. // }
  178. // };
  179. // // 2 case type:
  180. // The different specializations are generated with Vesa Karvonen's
  181. // preprocessor library.
  182. // This is just a comment to show what the generated classes look like
  183. // template<class Args, int Case1, int Case2>
  184. // class
  185. // lambda_functor_base<
  186. // action<3,
  187. // return_void_action<
  188. // switch_action<
  189. // detail::case_label<Case1>,
  190. // detail::case_label<Case2>
  191. // >
  192. // >
  193. // >,
  194. // Args
  195. // >
  196. // {
  197. // Args args;
  198. // public:
  199. // explicit lambda_functor_base(const Args& a) : args(a) {}
  200. // template<class RET, class A, class B, class C>
  201. // RET call(A& a, B& b, C& c) const {
  202. // switch( detail::select(::boost::tuples::get<0>(args), a, b, c) )
  203. // {
  204. // case Case1:
  205. // detail::select(::boost::tuples::get<1>(args), a, b, c);
  206. // break;
  207. // case Case2:
  208. // detail::select(::boost::tuples::get<2>(args), a, b, c);
  209. // break;
  210. // }
  211. // }
  212. // };
  213. // template<class Args, int Case1>
  214. // class
  215. // lambda_functor_base<
  216. // action<3,
  217. // return_void_action<
  218. // switch_action<
  219. // detail::case_label<Case1>,
  220. // detail::default_label
  221. // >
  222. // >
  223. // >,
  224. // Args
  225. // >
  226. // {
  227. // Args args;
  228. // public:
  229. // explicit lambda_functor_base(const Args& a) : args(a) {}
  230. // template<class RET, class A, class B, class C>
  231. // RET call(A& a, B& b, C& c) const {
  232. // switch( detail::select(::boost::tuples::get<0>(args), a, b, c) )
  233. // {
  234. // case Case1:
  235. // detail::select(::boost::tuples::get<1>(args), a, b, c);
  236. // break;
  237. // default:
  238. // detail::select(::boost::tuples::get<2>(args), a, b, c);
  239. // break;
  240. // }
  241. // }
  242. // };
  243. // -------------------------
  244. // Some helper preprocessor macros ---------------------------------
  245. // BOOST_LAMBDA_A_I_LIST(N, X) is a list of form X0, X1, ..., XN
  246. // BOOST_LAMBDA_A_I_B_LIST(N, X, Y) is a list of form X0 Y, X1 Y, ..., XN Y
  247. #define BOOST_LAMBDA_A_I(z, i, A) \
  248. BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(A,i)
  249. #define BOOST_LAMBDA_A_I_B(z, i, T) \
  250. BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2,0,T),i) BOOST_PP_TUPLE_ELEM(2,1,T)
  251. #define BOOST_LAMBDA_A_I_LIST(i, A) \
  252. BOOST_PP_REPEAT(i,BOOST_LAMBDA_A_I, A)
  253. #define BOOST_LAMBDA_A_I_B_LIST(i, A, B) \
  254. BOOST_PP_REPEAT(i,BOOST_LAMBDA_A_I_B, (A,B))
  255. // Switch related macros -------------------------------------------
  256. #define BOOST_LAMBDA_SWITCH_CASE_BLOCK(z, N, A) \
  257. case Case##N: \
  258. detail::select(::boost::tuples::get<BOOST_PP_INC(N)>(args), CALL_ACTUAL_ARGS); \
  259. break;
  260. #define BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(N) \
  261. BOOST_PP_REPEAT(N, BOOST_LAMBDA_SWITCH_CASE_BLOCK, FOO)
  262. // 2 case type:
  263. #define BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE(N) \
  264. template<class Args, BOOST_LAMBDA_A_I_LIST(N, int Case)> \
  265. class \
  266. lambda_functor_base< \
  267. switch_action<BOOST_PP_INC(N), \
  268. BOOST_LAMBDA_A_I_B_LIST(N, detail::case_label<Case,>) \
  269. >, \
  270. Args \
  271. > \
  272. { \
  273. public: \
  274. Args args; \
  275. template <class SigArgs> struct sig { typedef void type; }; \
  276. public: \
  277. explicit lambda_functor_base(const Args& a) : args(a) {} \
  278. \
  279. template<class RET, CALL_TEMPLATE_ARGS> \
  280. RET call(CALL_FORMAL_ARGS) const { \
  281. switch( detail::select(::boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) ) \
  282. { \
  283. BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(N) \
  284. } \
  285. } \
  286. };
  287. #define BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE(N) \
  288. template< \
  289. class Args BOOST_PP_COMMA_IF(BOOST_PP_DEC(N)) \
  290. BOOST_LAMBDA_A_I_LIST(BOOST_PP_DEC(N), int Case) \
  291. > \
  292. class \
  293. lambda_functor_base< \
  294. switch_action<BOOST_PP_INC(N), \
  295. BOOST_LAMBDA_A_I_B_LIST(BOOST_PP_DEC(N), \
  296. detail::case_label<Case, >) \
  297. BOOST_PP_COMMA_IF(BOOST_PP_DEC(N)) \
  298. detail::default_label \
  299. >, \
  300. Args \
  301. > \
  302. { \
  303. public: \
  304. Args args; \
  305. template <class SigArgs> struct sig { typedef void type; }; \
  306. public: \
  307. explicit lambda_functor_base(const Args& a) : args(a) {} \
  308. \
  309. template<class RET, CALL_TEMPLATE_ARGS> \
  310. RET call(CALL_FORMAL_ARGS) const { \
  311. switch( detail::select(::boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) ) \
  312. { \
  313. BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(BOOST_PP_DEC(N)) \
  314. default: \
  315. detail::select(::boost::tuples::get<N>(args), CALL_ACTUAL_ARGS); \
  316. break; \
  317. } \
  318. } \
  319. };
  320. // switch_statement bind functions -------------------------------------
  321. // The zero argument case, for completeness sake
  322. inline const
  323. lambda_functor<
  324. lambda_functor_base<
  325. do_nothing_action,
  326. null_type
  327. >
  328. >
  329. switch_statement() {
  330. return
  331. lambda_functor_base<
  332. do_nothing_action,
  333. null_type
  334. >
  335. ();
  336. }
  337. // 1 argument case, this is useless as well, just the condition part
  338. template <class TestArg>
  339. inline const
  340. lambda_functor<
  341. lambda_functor_base<
  342. switch_action<1>,
  343. tuple<lambda_functor<TestArg> >
  344. >
  345. >
  346. switch_statement(const lambda_functor<TestArg>& a1) {
  347. return
  348. lambda_functor_base<
  349. switch_action<1>,
  350. tuple< lambda_functor<TestArg> >
  351. >
  352. ( tuple<lambda_functor<TestArg> >(a1));
  353. }
  354. #define HELPER(z, N, FOO) \
  355. BOOST_PP_COMMA_IF(N) \
  356. BOOST_PP_CAT( \
  357. const tagged_lambda_functor<detail::switch_case_tag<TagData, \
  358. N>) \
  359. BOOST_PP_COMMA() Arg##N>& a##N
  360. #define HELPER_LIST(N) BOOST_PP_REPEAT(N, HELPER, FOO)
  361. #define BOOST_LAMBDA_SWITCH_STATEMENT(N) \
  362. template <class TestArg, \
  363. BOOST_LAMBDA_A_I_LIST(N, class TagData), \
  364. BOOST_LAMBDA_A_I_LIST(N, class Arg)> \
  365. inline const \
  366. lambda_functor< \
  367. lambda_functor_base< \
  368. switch_action<BOOST_PP_INC(N), \
  369. BOOST_LAMBDA_A_I_LIST(N, TagData) \
  370. >, \
  371. tuple<lambda_functor<TestArg>, BOOST_LAMBDA_A_I_LIST(N, Arg)> \
  372. > \
  373. > \
  374. switch_statement( \
  375. const lambda_functor<TestArg>& ta, \
  376. HELPER_LIST(N) \
  377. ) \
  378. { \
  379. return \
  380. lambda_functor_base< \
  381. switch_action<BOOST_PP_INC(N), \
  382. BOOST_LAMBDA_A_I_LIST(N, TagData) \
  383. >, \
  384. tuple<lambda_functor<TestArg>, BOOST_LAMBDA_A_I_LIST(N, Arg)> \
  385. > \
  386. ( tuple<lambda_functor<TestArg>, BOOST_LAMBDA_A_I_LIST(N, Arg)> \
  387. (ta, BOOST_LAMBDA_A_I_LIST(N, a) )); \
  388. }
  389. // Here's the actual generation
  390. #define BOOST_LAMBDA_SWITCH(N) \
  391. BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE(N) \
  392. BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE(N)
  393. // Use this to avoid case 0, these macros work only from case 1 upwards
  394. #define BOOST_LAMBDA_SWITCH_HELPER(z, N, A) \
  395. BOOST_LAMBDA_SWITCH( BOOST_PP_INC(N) )
  396. // Use this to avoid cases 0 and 1, these macros work only from case 2 upwards
  397. #define BOOST_LAMBDA_SWITCH_STATEMENT_HELPER(z, N, A) \
  398. BOOST_LAMBDA_SWITCH_STATEMENT(BOOST_PP_INC(N))
  399. #ifdef BOOST_MSVC
  400. #pragma warning(push)
  401. #pragma warning(disable:4065)
  402. #endif
  403. // up to 9 cases supported (counting default:)
  404. BOOST_PP_REPEAT_2ND(9,BOOST_LAMBDA_SWITCH_HELPER,FOO)
  405. BOOST_PP_REPEAT_2ND(9,BOOST_LAMBDA_SWITCH_STATEMENT_HELPER,FOO)
  406. #ifdef BOOST_MSVC
  407. #pragma warning(pop)
  408. #endif
  409. } // namespace lambda
  410. } // namespace boost
  411. #undef HELPER
  412. #undef HELPER_LIST
  413. #undef BOOST_LAMBDA_SWITCH_HELPER
  414. #undef BOOST_LAMBDA_SWITCH
  415. #undef BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE
  416. #undef BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE
  417. #undef BOOST_LAMBDA_SWITCH_CASE_BLOCK
  418. #undef BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST
  419. #undef BOOST_LAMBDA_SWITCH_STATEMENT
  420. #undef BOOST_LAMBDA_SWITCH_STATEMENT_HELPER
  421. #endif