os/ossrv/ossrv_pub/boost_apis/boost/lambda/if.hpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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