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