Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / lambda / if.hpp
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:
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 >
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:
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 >
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 >
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:
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
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 //////////////////////////////////
379 template <typename CondT, typename ThenT>
380 struct 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 //////////////////////////////////
401 template <typename CondT, typename ThenT>
402 struct 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 //////////////////////////////////
422 template <typename CondT>
423 struct 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 //////////////////////////////////
448 template <typename CondT>
449 inline if_gen<CondT>
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