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