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
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 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
463