source: NonGTP/Boost/boost/lambda/switch.hpp @ 857

Revision 857, 16.6 KB checked in by igarcia, 19 years ago (diff)
Line 
1// Boost Lambda Library -- switch.hpp -----------------------------------
2//
3// Copyright (C) 2000 Gary Powell (powellg@amazon.com)
4// Copyright (C) 1999, 2000 Jaakko Järvi (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
469
470  // up to 9 cases supported (counting default:)
471BOOST_PP_REPEAT_2ND(9,BOOST_LAMBDA_SWITCH_HELPER,FOO)
472BOOST_PP_REPEAT_2ND(9,BOOST_LAMBDA_SWITCH_STATEMENT_HELPER,FOO)
473
474
475} // namespace lambda
476} // namespace boost
477
478
479#undef HELPER
480#undef HELPER_LIST
481
482#undef BOOST_LAMBDA_SWITCH_HELPER
483#undef BOOST_LAMBDA_SWITCH
484#undef BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE
485#undef BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE
486
487#undef BOOST_LAMBDA_SWITCH_CASE_BLOCK
488#undef BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST
489
490#undef BOOST_LAMBDA_SWITCH_STATEMENT
491#undef BOOST_LAMBDA_SWITCH_STATEMENT_HELPER
492
493
494
495#endif
496
497
498
499
500
501
502
Note: See TracBrowser for help on using the repository browser.