1 // Boost Lambda Library -- if.hpp ------------------------------------------
2 
3 // Copyright (C) 1999, 2000 Jaakko Jarvi (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 
24 namespace boost {
25 namespace lambda {
26 
27 // -- if control construct actions ----------------------
28 
29 class ifthen_action {};
30 class ifthenelse_action {};
31 class ifthenelsereturn_action {};
32 
33 // Specialization for if_then.
34 template<class Args>
35 class
36 lambda_functor_base<ifthen_action, Args> {
37 public:
38   Args args;
39   template <class T> struct sig { typedef void type; };
40 public:
lambda_functor_base(const Args & a)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
51 template <class Arg1, class Arg2>
52 inline const
53 lambda_functor<
54   lambda_functor_base<
55     ifthen_action,
56     tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
57   >
58 >
if_then(const lambda_functor<Arg1> & a1,const lambda_functor<Arg2> & a2)59 if_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.
70 template<class Args>
71 class
72 lambda_functor_base<ifthenelse_action, Args> {
73 public:
74   Args args;
75   template <class T> struct sig { typedef void type; };
76 public:
lambda_functor_base(const Args & a)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 
92 template <class Arg1, class Arg2, class Arg3>
93 inline const
94 lambda_functor<
95   lambda_functor_base<
96     ifthenelse_action,
97     tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
98   >
99 >
if_then_else(const lambda_functor<Arg1> & a1,const lambda_functor<Arg2> & a2,const lambda_functor<Arg3> & a3)100 if_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 
113 template <class Arg1, class Arg2, class Arg3>
114 inline 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 >
if_then_else_return(const lambda_functor<Arg1> & a1,const Arg2 & a2,const Arg3 & a3)123 if_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 
137 namespace 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
144 template<int Phase, bool AtoB, bool BtoA, bool SameType, class A, class B>
145 struct return_type_2_ifthenelsereturn;
146 
147 // if A can be converted to B and vice versa -> ambiguous
148 template<int Phase, class A, class B>
149 struct 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
155 template<int Phase, class A, class B>
156 struct return_type_2_ifthenelsereturn<Phase, true, true, true, A, B> {
157   typedef A type;
158 };
159 
160 
161 // A can be converted to B
162 template<int Phase, class A, class B>
163 struct return_type_2_ifthenelsereturn<Phase, true, false, false, A, B> {
164   typedef B type;
165 };
166 
167 // B can be converted to A
168 template<int Phase, class A, class B>
169 struct 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
175 template<class A, class B>
176 struct 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
195 template<class A, class B>
196 struct 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.
205 template<class A, class B>
206 struct 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
220 template<int CodeA, int CodeB, class A, class B>
221 struct 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 ?:
230 template<int CodeA, class A, class B>
231 struct 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
236 template<class A, class B>
237 struct arithmetic_or_not <-1, -1, A, B> {
238   typedef typename non_numeric_types<A, B>::type type;
239 };
240 template<int CodeB, class A, class B>
241 struct arithmetic_or_not <-1, CodeB, A, B> {
242   typedef typename non_numeric_types<A, B>::type type;
243 };
244 template<int CodeA, class A, class B>
245 struct 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
254 template <class A, class B>
255 struct 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.
267 template <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
274 template<class A, class B>
275 struct 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.
291 template<class Args>
292 class
293 lambda_functor_base<other_action<ifthenelsereturn_action>, Args> {
294 public:
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 
307 public:
lambda_functor_base(const Args & a)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 leading dot and the trailing underscore before
349 //      and after .else_.
350 //
351 ///////////////////////////////////////////////////////////////////////////////
352 template <typename CondT, typename ThenT, typename ElseT>
353 struct 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 
if_then_else_compositeboost::lambda::if_then_else_composite360     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 //////////////////////////////////
379 template <typename CondT, typename ThenT>
380 struct else_gen {
381 
else_genboost::lambda::else_gen382     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> >
operator []boost::lambda::else_gen388     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 //////////////////////////////////
401 template <typename CondT, typename ThenT>
402 struct if_then_composite {
403 
404     template <class SigArgs>
405     struct sig { typedef void type; };
406 
if_then_compositeboost::lambda::if_then_composite407     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 //////////////////////////////////
422 template <typename CondT>
423 struct if_gen {
424 
if_genboost::lambda::if_gen425     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> >
operator []boost::lambda::if_gen432     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 //////////////////////////////////
448 template <typename CondT>
449 inline if_gen<CondT>
if_(CondT const & cond)450 if_(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 
463