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
24namespace boost {
25namespace lambda {
26
27// Switch actions
28template <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>
33struct switch_action {};
34
35
36namespace detail {
37
38 // templates to represent special lambda functors for the cases in
39 // switch statements
40
41template <int Value> struct case_label {};
42struct default_label {};
43
44template<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
57template <int CaseValue, class Arg>
58inline const
59tagged_lambda_functor<
60 detail::switch_case_tag<detail::case_label<CaseValue> >,
61 lambda_functor<Arg>
62>
63case_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.
72template <int CaseValue>
73inline const
74tagged_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>
83case_statement() {
84return
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
97template <class Arg>
98inline const
99tagged_lambda_functor<
100 detail::switch_case_tag<detail::default_label>,
101 lambda_functor<Arg>
102>
103default_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.
112inline const
113tagged_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>
122default_statement() {
123return
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.
135template<class Args>
136class
137lambda_functor_base<
138 switch_action<1>,
139 Args
140>
141{
142public:
143 Args args;
144 template <class SigArgs> struct sig { typedef void type; };
145public:
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) \
286BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(A,i)
287
288#define BOOST_LAMBDA_A_I_B(z, i, T) \
289BOOST_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) \
292BOOST_PP_REPEAT(i,BOOST_LAMBDA_A_I, A)
293
294#define BOOST_LAMBDA_A_I_B_LIST(i, A, B) \
295BOOST_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) \
305BOOST_PP_REPEAT(N, BOOST_LAMBDA_SWITCH_CASE_BLOCK, FOO)
306// 2 case type:
307
308#define BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE(N) \
309template<class Args, BOOST_LAMBDA_A_I_LIST(N, int Case)> \
310class \
311lambda_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{ \
318public: \
319 Args args; \
320 template <class SigArgs> struct sig { typedef void type; }; \
321public: \
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) \
336template< \
337 class Args BOOST_PP_COMMA_IF(BOOST_PP_DEC(N)) \
338 BOOST_LAMBDA_A_I_LIST(BOOST_PP_DEC(N), int Case) \
339> \
340class \
341lambda_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{ \
351public: \
352 Args args; \
353 template <class SigArgs> struct sig { typedef void type; }; \
354public: \
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
377inline const
378lambda_functor<
379 lambda_functor_base<
380 do_nothing_action,
381 null_type
382 >
383>
384switch_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
394template <class TestArg>
395inline const
396lambda_functor<
397 lambda_functor_base<
398 switch_action<1>,
399 tuple<lambda_functor<TestArg> >
400 >
401>
402switch_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) \
413BOOST_PP_COMMA_IF(N) \
414BOOST_PP_CAT( \
415 const tagged_lambda_functor<detail::switch_case_tag<TagData, \
416 N>) \
417BOOST_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) \
423template <class TestArg, \
424 BOOST_LAMBDA_A_I_LIST(N, class TagData), \
425 BOOST_LAMBDA_A_I_LIST(N, class Arg)> \
426inline const \
427lambda_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> \
435switch_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) \
457BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE(N) \
458BOOST_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) \
462BOOST_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) \
466BOOST_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:)
474BOOST_PP_REPEAT_2ND(9,BOOST_LAMBDA_SWITCH_HELPER,FOO)
475BOOST_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