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

Revision 857, 13.5 KB checked in by igarcia, 18 years ago (diff)
Line 
1// Boost Lambda Library -- if.hpp ------------------------------------------
2
3// Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
4// Copyright (C) 2000 Gary Powell (powellg@amazon.com)
5// Copyright (C) 2001-2002 Joel de Guzman
6//
7// Distributed under the Boost Software License, Version 1.0. (See
8// accompanying file LICENSE_1_0.txt or copy at
9// http://www.boost.org/LICENSE_1_0.txt)
10//
11// For more information, see www.boost.org
12
13// --------------------------------------------------------------------------
14
15#if !defined(BOOST_LAMBDA_IF_HPP)
16#define BOOST_LAMBDA_IF_HPP
17
18#include "boost/lambda/core.hpp"
19
20// Arithmetic type promotion needed for if_then_else_return
21#include "boost/lambda/detail/operator_actions.hpp"
22#include "boost/lambda/detail/operator_return_type_traits.hpp"
23
24namespace boost {
25namespace lambda {
26
27// -- if control construct actions ----------------------
28
29class ifthen_action {};
30class ifthenelse_action {};
31class ifthenelsereturn_action {};
32
33// Specialization for if_then.
34template<class Args>
35class
36lambda_functor_base<ifthen_action, Args> {
37public:
38  Args args;
39  template <class T> struct sig { typedef void type; };
40public:
41  explicit lambda_functor_base(const Args& a) : args(a) {}
42
43  template<class RET, CALL_TEMPLATE_ARGS>
44  RET call(CALL_FORMAL_ARGS) const {
45    if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
46      detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
47  }
48};
49
50// If Then
51template <class Arg1, class Arg2>
52inline const
53lambda_functor<
54  lambda_functor_base<
55    ifthen_action,
56    tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
57  >
58>
59if_then(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
60  return
61    lambda_functor_base<
62      ifthen_action,
63      tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
64    >
65    ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
66}
67
68
69// Specialization for if_then_else.
70template<class Args>
71class
72lambda_functor_base<ifthenelse_action, Args> {
73public:
74  Args args;
75  template <class T> struct sig { typedef void type; };
76public:
77  explicit lambda_functor_base(const Args& a) : args(a) {}
78
79  template<class RET, CALL_TEMPLATE_ARGS>
80  RET call(CALL_FORMAL_ARGS) const {
81    if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
82      detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
83    else
84      detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
85  }
86};
87
88
89
90// If then else
91
92template <class Arg1, class Arg2, class Arg3>
93inline const
94lambda_functor<
95  lambda_functor_base<
96    ifthenelse_action,
97    tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
98  >
99>
100if_then_else(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
101             const lambda_functor<Arg3>& a3) {
102  return
103    lambda_functor_base<
104      ifthenelse_action,
105      tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
106    >
107    (tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
108       (a1, a2, a3) );
109}
110
111// Our version of operator?:()
112
113template <class Arg1, class Arg2, class Arg3>
114inline const
115  lambda_functor<
116    lambda_functor_base<
117      other_action<ifthenelsereturn_action>,
118      tuple<lambda_functor<Arg1>,
119          typename const_copy_argument<Arg2>::type,
120          typename const_copy_argument<Arg3>::type>
121  >
122>
123if_then_else_return(const lambda_functor<Arg1>& a1,
124                    const Arg2 & a2,
125                    const Arg3 & a3) {
126  return
127      lambda_functor_base<
128        other_action<ifthenelsereturn_action>,
129        tuple<lambda_functor<Arg1>,
130              typename const_copy_argument<Arg2>::type,
131              typename const_copy_argument<Arg3>::type>
132      > ( tuple<lambda_functor<Arg1>,
133              typename const_copy_argument<Arg2>::type,
134              typename const_copy_argument<Arg3>::type> (a1, a2, a3) );
135}
136
137namespace detail {
138
139// return type specialization for conditional expression begins -----------
140// start reading below and move upwards
141
142// PHASE 6:1
143// check if A is conbertible to B and B to A
144template<int Phase, bool AtoB, bool BtoA, bool SameType, class A, class B>
145struct return_type_2_ifthenelsereturn;
146
147// if A can be converted to B and vice versa -> ambiguous
148template<int Phase, class A, class B>
149struct return_type_2_ifthenelsereturn<Phase, true, true, false, A, B> {
150  typedef
151    detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
152  // ambiguous type in conditional expression
153};
154// if A can be converted to B and vice versa and are of same type
155template<int Phase, class A, class B>
156struct return_type_2_ifthenelsereturn<Phase, true, true, true, A, B> {
157  typedef A type;
158};
159
160
161// A can be converted to B
162template<int Phase, class A, class B>
163struct return_type_2_ifthenelsereturn<Phase, true, false, false, A, B> {
164  typedef B type;
165};
166
167// B can be converted to A
168template<int Phase, class A, class B>
169struct return_type_2_ifthenelsereturn<Phase, false, true, false, A, B> {
170  typedef A type;
171};
172
173// neither can be converted. Then we drop the potential references, and
174// try again
175template<class A, class B>
176struct return_type_2_ifthenelsereturn<1, false, false, false, A, B> {
177  // it is safe to add const, since the result will be an rvalue and thus
178  // const anyway. The const are needed eg. if the types
179  // are 'const int*' and 'void *'. The remaining type should be 'const void*'
180  typedef const typename boost::remove_reference<A>::type plainA;
181  typedef const typename boost::remove_reference<B>::type plainB;
182  // TODO: Add support for volatile ?
183
184  typedef typename
185       return_type_2_ifthenelsereturn<
186         2,
187         boost::is_convertible<plainA,plainB>::value,
188         boost::is_convertible<plainB,plainA>::value,
189         boost::is_same<plainA,plainB>::value,
190         plainA,
191         plainB>::type type;
192};
193
194// PHASE 6:2
195template<class A, class B>
196struct return_type_2_ifthenelsereturn<2, false, false, false, A, B> {
197  typedef
198    detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
199  // types_do_not_match_in_conditional_expression
200};
201
202
203
204// PHASE 5: now we know that types are not arithmetic.
205template<class A, class B>
206struct non_numeric_types {
207  typedef typename
208    return_type_2_ifthenelsereturn<
209      1, // phase 1
210      is_convertible<A,B>::value,
211      is_convertible<B,A>::value,
212      is_same<A,B>::value,
213      A,
214      B>::type type;
215};
216
217// PHASE 4 :
218// the base case covers arithmetic types with differing promote codes
219// use the type deduction of arithmetic_actions
220template<int CodeA, int CodeB, class A, class B>
221struct arithmetic_or_not {
222  typedef typename
223    return_type_2<arithmetic_action<plus_action>, A, B>::type type;
224  // plus_action is just a random pick, has to be a concrete instance
225};
226
227// this case covers the case of artihmetic types with the same promote codes.
228// non numeric deduction is used since e.g. integral promotion is not
229// performed with operator ?:
230template<int CodeA, class A, class B>
231struct arithmetic_or_not<CodeA, CodeA, A, B> {
232  typedef typename non_numeric_types<A, B>::type type;
233};
234
235// if either A or B has promote code -1 it is not an arithmetic type
236template<class A, class B>
237struct arithmetic_or_not <-1, -1, A, B> {
238  typedef typename non_numeric_types<A, B>::type type;
239};
240template<int CodeB, class A, class B>
241struct arithmetic_or_not <-1, CodeB, A, B> {
242  typedef typename non_numeric_types<A, B>::type type;
243};
244template<int CodeA, class A, class B>
245struct arithmetic_or_not <CodeA, -1, A, B> {
246  typedef typename non_numeric_types<A, B>::type type;
247};
248
249
250
251
252// PHASE 3 : Are the types same?
253// No, check if they are arithmetic or not
254template <class A, class B>
255struct same_or_not {
256  typedef typename detail::remove_reference_and_cv<A>::type plainA;
257  typedef typename detail::remove_reference_and_cv<B>::type plainB;
258
259  typedef typename
260    arithmetic_or_not<
261      detail::promote_code<plainA>::value,
262      detail::promote_code<plainB>::value,
263      A,
264      B>::type type;
265};
266// Yes, clear.
267template <class A> struct same_or_not<A, A> {
268  typedef A type;
269};
270
271} // detail
272
273// PHASE 2 : Perform first the potential array_to_pointer conversion
274template<class A, class B>
275struct return_type_2<other_action<ifthenelsereturn_action>, A, B> {
276
277  typedef typename detail::array_to_pointer<A>::type A1;
278  typedef typename detail::array_to_pointer<B>::type B1;
279
280  typedef typename
281    boost::add_const<typename detail::same_or_not<A1, B1>::type>::type type;
282};
283
284// PHASE 1 : Deduction is based on the second and third operand
285
286
287// return type specialization for conditional expression ends -----------
288
289
290// Specialization of lambda_functor_base for if_then_else_return.
291template<class Args>
292class
293lambda_functor_base<other_action<ifthenelsereturn_action>, Args> {
294public:
295  Args args;
296
297  template <class SigArgs> struct sig {
298  private:
299    typedef typename detail::nth_return_type_sig<1, Args, SigArgs>::type ret1;
300    typedef typename detail::nth_return_type_sig<2, Args, SigArgs>::type ret2;
301  public:
302    typedef typename return_type_2<
303      other_action<ifthenelsereturn_action>, ret1, ret2
304    >::type type;
305  };
306
307public:
308  explicit lambda_functor_base(const Args& a) : args(a) {}
309
310  template<class RET, CALL_TEMPLATE_ARGS>
311  RET call(CALL_FORMAL_ARGS) const {
312    return (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) ?
313       detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS)
314    :
315       detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
316  }
317};
318
319  // The code below is from Joel de Guzman, some name changes etc.
320  // has been made.
321
322///////////////////////////////////////////////////////////////////////////////
323//
324//  if_then_else_composite
325//
326//      This composite has two (2) forms:
327//
328//          if_(condition)
329//          [
330//              statement
331//          ]
332//
333//      and
334//
335//          if_(condition)
336//          [
337//              true_statement
338//          ]
339//          .else_
340//          [
341//              false_statement
342//          ]
343//
344//      where condition is an lambda_functor that evaluates to bool. If condition
345//      is true, the true_statement (again an lambda_functor) is executed
346//      otherwise, the false_statement (another lambda_functor) is executed. The
347//      result type of this is void. Note the trailing underscore after
348//      if_ and the the leading dot and the trailing underscore before
349//      and after .else_.
350//
351///////////////////////////////////////////////////////////////////////////////
352template <typename CondT, typename ThenT, typename ElseT>
353struct if_then_else_composite {
354
355    typedef if_then_else_composite<CondT, ThenT, ElseT> self_t;
356
357    template <class SigArgs>
358    struct sig { typedef void type; };
359
360    if_then_else_composite(
361        CondT const& cond_,
362        ThenT const& then_,
363        ElseT const& else__)
364    :   cond(cond_), then(then_), else_(else__) {}
365
366    template <class Ret, CALL_TEMPLATE_ARGS>
367    Ret call(CALL_FORMAL_ARGS) const
368    {
369        if (cond.internal_call(CALL_ACTUAL_ARGS))
370            then.internal_call(CALL_ACTUAL_ARGS);
371        else
372            else_.internal_call(CALL_ACTUAL_ARGS);
373    }
374
375    CondT cond; ThenT then; ElseT else_; //  lambda_functors
376};
377
378//////////////////////////////////
379template <typename CondT, typename ThenT>
380struct else_gen {
381
382    else_gen(CondT const& cond_, ThenT const& then_)
383    :   cond(cond_), then(then_) {}
384
385    template <typename ElseT>
386    lambda_functor<if_then_else_composite<CondT, ThenT,
387        typename as_lambda_functor<ElseT>::type> >
388    operator[](ElseT const& else_)
389    {
390        typedef if_then_else_composite<CondT, ThenT,
391            typename as_lambda_functor<ElseT>::type>
392        result;
393
394        return result(cond, then, to_lambda_functor(else_));
395    }
396
397    CondT cond; ThenT then;
398};
399
400//////////////////////////////////
401template <typename CondT, typename ThenT>
402struct if_then_composite {
403
404    template <class SigArgs>
405    struct sig { typedef void type; };
406
407    if_then_composite(CondT const& cond_, ThenT const& then_)
408    :   cond(cond_), then(then_), else_(cond, then) {}
409
410    template <class Ret, CALL_TEMPLATE_ARGS>
411    Ret call(CALL_FORMAL_ARGS) const
412    {
413      if (cond.internal_call(CALL_ACTUAL_ARGS))
414            then.internal_call(CALL_ACTUAL_ARGS);
415    }
416
417    CondT cond; ThenT then; //  lambda_functors
418    else_gen<CondT, ThenT> else_;
419};
420
421//////////////////////////////////
422template <typename CondT>
423struct if_gen {
424
425    if_gen(CondT const& cond_)
426    :   cond(cond_) {}
427
428    template <typename ThenT>
429    lambda_functor<if_then_composite<
430        typename as_lambda_functor<CondT>::type,
431        typename as_lambda_functor<ThenT>::type> >
432    operator[](ThenT const& then) const
433    {
434        typedef if_then_composite<
435            typename as_lambda_functor<CondT>::type,
436            typename as_lambda_functor<ThenT>::type>
437        result;
438
439        return result(
440            to_lambda_functor(cond),
441            to_lambda_functor(then));
442    }
443
444    CondT cond;
445};
446
447//////////////////////////////////
448template <typename CondT>
449inline if_gen<CondT>
450if_(CondT const& cond)
451{
452    return if_gen<CondT>(cond);
453}
454
455
456
457} // lambda
458} // boost
459
460#endif // BOOST_LAMBDA_IF_HPP
461
462
Note: See TracBrowser for help on using the repository browser.