Update contrib.
     1 // Boost Lambda Library -- if.hpp ------------------------------------------
 
     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
 
     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)
 
    11 // For more information, see www.boost.org
 
    13 // --------------------------------------------------------------------------
 
    15 #if !defined(BOOST_LAMBDA_IF_HPP)
 
    16 #define BOOST_LAMBDA_IF_HPP
 
    18 #include "boost/lambda/core.hpp"
 
    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"
 
    27 // -- if control construct actions ----------------------
 
    29 class ifthen_action {};
 
    30 class ifthenelse_action {};
 
    31 class ifthenelsereturn_action {};
 
    33 // Specialization for if_then.
 
    36 lambda_functor_base<ifthen_action, Args> {
 
    39   template <class T> struct sig { typedef void type; };
 
    41   explicit lambda_functor_base(const Args& a) : args(a) {}
 
    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); 
 
    51 template <class Arg1, class Arg2>
 
    56     tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
 
    59 if_then(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
 
    63       tuple<lambda_functor<Arg1>, lambda_functor<Arg2> > 
 
    65     ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
 
    69 // Specialization for if_then_else.
 
    72 lambda_functor_base<ifthenelse_action, Args> {
 
    75   template <class T> struct sig { typedef void type; };
 
    77   explicit lambda_functor_base(const Args& a) : args(a) {}
 
    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); 
 
    84       detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
 
    92 template <class Arg1, class Arg2, class Arg3>
 
    97     tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
 
   100 if_then_else(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2, 
 
   101              const lambda_functor<Arg3>& a3) {
 
   105       tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
 
   107     (tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
 
   111 // Our version of operator?:()
 
   113 template <class Arg1, class Arg2, class Arg3>
 
   117       other_action<ifthenelsereturn_action>, 
 
   118       tuple<lambda_functor<Arg1>,
 
   119           typename const_copy_argument<Arg2>::type,
 
   120           typename const_copy_argument<Arg3>::type>
 
   123 if_then_else_return(const lambda_functor<Arg1>& a1, 
 
   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) );
 
   139 // return type specialization for conditional expression begins -----------
 
   140 // start reading below and move upwards
 
   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;
 
   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> {
 
   151     detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
 
   152   // ambiguous type in conditional expression
 
   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> {
 
   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> {
 
   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> {
 
   173 // neither can be converted. Then we drop the potential references, and
 
   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 ?
 
   185        return_type_2_ifthenelsereturn<
 
   187          boost::is_convertible<plainA,plainB>::value, 
 
   188          boost::is_convertible<plainB,plainA>::value,
 
   189          boost::is_same<plainA,plainB>::value,
 
   195 template<class A, class B>
 
   196 struct return_type_2_ifthenelsereturn<2, false, false, false, A, B> {
 
   198     detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
 
   199   // types_do_not_match_in_conditional_expression 
 
   204 // PHASE 5: now we know that types are not arithmetic.
 
   205 template<class A, class B>
 
   206 struct non_numeric_types {
 
   208     return_type_2_ifthenelsereturn<
 
   210       is_convertible<A,B>::value, 
 
   211       is_convertible<B,A>::value, 
 
   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 {
 
   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
 
   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; 
 
   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;
 
   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;
 
   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;
 
   252 // PHASE 3 : Are the types same?
 
   253 // No, check if they are arithmetic or not
 
   254 template <class A, class B>
 
   256   typedef typename detail::remove_reference_and_cv<A>::type plainA;
 
   257   typedef typename detail::remove_reference_and_cv<B>::type plainB;
 
   261       detail::promote_code<plainA>::value, 
 
   262       detail::promote_code<plainB>::value, 
 
   267 template <class A> struct same_or_not<A, A> {
 
   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> { 
 
   277   typedef typename detail::array_to_pointer<A>::type A1;
 
   278   typedef typename detail::array_to_pointer<B>::type B1;
 
   281     boost::add_const<typename detail::same_or_not<A1, B1>::type>::type type;
 
   284 // PHASE 1 : Deduction is based on the second and third operand
 
   287 // return type specialization for conditional expression ends -----------
 
   290 // Specialization of lambda_functor_base for if_then_else_return.
 
   293 lambda_functor_base<other_action<ifthenelsereturn_action>, Args> {
 
   297   template <class SigArgs> struct sig {
 
   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;
 
   302     typedef typename return_type_2<
 
   303       other_action<ifthenelsereturn_action>, ret1, ret2
 
   308   explicit lambda_functor_base(const Args& a) : args(a) {}
 
   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) 
 
   315        detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
 
   319   // The code below is from Joel de Guzman, some name changes etc. 
 
   322 ///////////////////////////////////////////////////////////////////////////////
 
   324 //  if_then_else_composite
 
   326 //      This composite has two (2) forms:
 
   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
 
   351 ///////////////////////////////////////////////////////////////////////////////
 
   352 template <typename CondT, typename ThenT, typename ElseT>
 
   353 struct if_then_else_composite {
 
   355     typedef if_then_else_composite<CondT, ThenT, ElseT> self_t;
 
   357     template <class SigArgs>
 
   358     struct sig { typedef void type; };
 
   360     if_then_else_composite(
 
   364     :   cond(cond_), then(then_), else_(else__) {}
 
   366     template <class Ret, CALL_TEMPLATE_ARGS>
 
   367     Ret call(CALL_FORMAL_ARGS) const
 
   369         if (cond.internal_call(CALL_ACTUAL_ARGS))
 
   370             then.internal_call(CALL_ACTUAL_ARGS);
 
   372             else_.internal_call(CALL_ACTUAL_ARGS);
 
   375     CondT cond; ThenT then; ElseT else_; //  lambda_functors
 
   378 //////////////////////////////////
 
   379 template <typename CondT, typename ThenT>
 
   382     else_gen(CondT const& cond_, ThenT const& then_)
 
   383     :   cond(cond_), then(then_) {}
 
   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_)
 
   390         typedef if_then_else_composite<CondT, ThenT,
 
   391             typename as_lambda_functor<ElseT>::type>
 
   394         return result(cond, then, to_lambda_functor(else_));
 
   397     CondT cond; ThenT then;
 
   400 //////////////////////////////////
 
   401 template <typename CondT, typename ThenT>
 
   402 struct if_then_composite {
 
   404     template <class SigArgs>
 
   405     struct sig { typedef void type; };
 
   407     if_then_composite(CondT const& cond_, ThenT const& then_)
 
   408     :   cond(cond_), then(then_), else_(cond, then) {}
 
   410     template <class Ret, CALL_TEMPLATE_ARGS>
 
   411     Ret call(CALL_FORMAL_ARGS) const
 
   413       if (cond.internal_call(CALL_ACTUAL_ARGS))
 
   414             then.internal_call(CALL_ACTUAL_ARGS);
 
   417     CondT cond; ThenT then; //  lambda_functors
 
   418     else_gen<CondT, ThenT> else_;
 
   421 //////////////////////////////////
 
   422 template <typename CondT>
 
   425     if_gen(CondT const& cond_)
 
   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
 
   434         typedef if_then_composite<
 
   435             typename as_lambda_functor<CondT>::type,
 
   436             typename as_lambda_functor<ThenT>::type>
 
   440             to_lambda_functor(cond),
 
   441             to_lambda_functor(then));
 
   447 //////////////////////////////////
 
   448 template <typename CondT>
 
   450 if_(CondT const& cond)
 
   452     return if_gen<CondT>(cond);
 
   460 #endif // BOOST_LAMBDA_IF_HPP