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