os/ossrv/ossrv_pub/boost_apis/boost/lambda/if.hpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Boost Lambda Library -- if.hpp ------------------------------------------
sl@0
     2
sl@0
     3
// Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
sl@0
     4
// Copyright (C) 2000 Gary Powell (powellg@amazon.com)
sl@0
     5
// Copyright (C) 2001-2002 Joel de Guzman
sl@0
     6
//
sl@0
     7
// Distributed under the Boost Software License, Version 1.0. (See
sl@0
     8
// accompanying file LICENSE_1_0.txt or copy at
sl@0
     9
// http://www.boost.org/LICENSE_1_0.txt)
sl@0
    10
//
sl@0
    11
// For more information, see www.boost.org
sl@0
    12
sl@0
    13
// --------------------------------------------------------------------------
sl@0
    14
sl@0
    15
#if !defined(BOOST_LAMBDA_IF_HPP)
sl@0
    16
#define BOOST_LAMBDA_IF_HPP
sl@0
    17
sl@0
    18
#include "boost/lambda/core.hpp"
sl@0
    19
sl@0
    20
// Arithmetic type promotion needed for if_then_else_return
sl@0
    21
#include "boost/lambda/detail/operator_actions.hpp"
sl@0
    22
#include "boost/lambda/detail/operator_return_type_traits.hpp"
sl@0
    23
sl@0
    24
namespace boost { 
sl@0
    25
namespace lambda {
sl@0
    26
sl@0
    27
// -- if control construct actions ----------------------
sl@0
    28
sl@0
    29
class ifthen_action {};
sl@0
    30
class ifthenelse_action {};
sl@0
    31
class ifthenelsereturn_action {};
sl@0
    32
sl@0
    33
// Specialization for if_then.
sl@0
    34
template<class Args>
sl@0
    35
class 
sl@0
    36
lambda_functor_base<ifthen_action, Args> {
sl@0
    37
public:
sl@0
    38
  Args args;
sl@0
    39
  template <class T> struct sig { typedef void type; };
sl@0
    40
public:
sl@0
    41
  explicit lambda_functor_base(const Args& a) : args(a) {}
sl@0
    42
sl@0
    43
  template<class RET, CALL_TEMPLATE_ARGS>
sl@0
    44
  RET call(CALL_FORMAL_ARGS) const {
sl@0
    45
    if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) 
sl@0
    46
      detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS); 
sl@0
    47
  }
sl@0
    48
};
sl@0
    49
sl@0
    50
// If Then
sl@0
    51
template <class Arg1, class Arg2>
sl@0
    52
inline const 
sl@0
    53
lambda_functor<
sl@0
    54
  lambda_functor_base<
sl@0
    55
    ifthen_action, 
sl@0
    56
    tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
sl@0
    57
  > 
sl@0
    58
>
sl@0
    59
if_then(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
sl@0
    60
  return 
sl@0
    61
    lambda_functor_base<
sl@0
    62
      ifthen_action, 
sl@0
    63
      tuple<lambda_functor<Arg1>, lambda_functor<Arg2> > 
sl@0
    64
    > 
sl@0
    65
    ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
sl@0
    66
}
sl@0
    67
sl@0
    68
sl@0
    69
// Specialization for if_then_else.
sl@0
    70
template<class Args>
sl@0
    71
class 
sl@0
    72
lambda_functor_base<ifthenelse_action, Args> {
sl@0
    73
public:
sl@0
    74
  Args args;
sl@0
    75
  template <class T> struct sig { typedef void type; };
sl@0
    76
public:
sl@0
    77
  explicit lambda_functor_base(const Args& a) : args(a) {}
sl@0
    78
sl@0
    79
  template<class RET, CALL_TEMPLATE_ARGS>
sl@0
    80
  RET call(CALL_FORMAL_ARGS) const {
sl@0
    81
    if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) 
sl@0
    82
      detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS); 
sl@0
    83
    else 
sl@0
    84
      detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
sl@0
    85
  }
sl@0
    86
};
sl@0
    87
sl@0
    88
sl@0
    89
sl@0
    90
// If then else
sl@0
    91
sl@0
    92
template <class Arg1, class Arg2, class Arg3>
sl@0
    93
inline const 
sl@0
    94
lambda_functor<
sl@0
    95
  lambda_functor_base<
sl@0
    96
    ifthenelse_action, 
sl@0
    97
    tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
sl@0
    98
  > 
sl@0
    99
>
sl@0
   100
if_then_else(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2, 
sl@0
   101
             const lambda_functor<Arg3>& a3) {
sl@0
   102
  return 
sl@0
   103
    lambda_functor_base<
sl@0
   104
      ifthenelse_action, 
sl@0
   105
      tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
sl@0
   106
    > 
sl@0
   107
    (tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
sl@0
   108
       (a1, a2, a3) );
sl@0
   109
}
sl@0
   110
sl@0
   111
// Our version of operator?:()
sl@0
   112
sl@0
   113
template <class Arg1, class Arg2, class Arg3>
sl@0
   114
inline const 
sl@0
   115
  lambda_functor<
sl@0
   116
    lambda_functor_base<
sl@0
   117
      other_action<ifthenelsereturn_action>, 
sl@0
   118
      tuple<lambda_functor<Arg1>,
sl@0
   119
          typename const_copy_argument<Arg2>::type,
sl@0
   120
          typename const_copy_argument<Arg3>::type>
sl@0
   121
  > 
sl@0
   122
>
sl@0
   123
if_then_else_return(const lambda_functor<Arg1>& a1, 
sl@0
   124
                    const Arg2 & a2, 
sl@0
   125
                    const Arg3 & a3) {
sl@0
   126
  return 
sl@0
   127
      lambda_functor_base<
sl@0
   128
        other_action<ifthenelsereturn_action>, 
sl@0
   129
        tuple<lambda_functor<Arg1>,
sl@0
   130
              typename const_copy_argument<Arg2>::type,
sl@0
   131
              typename const_copy_argument<Arg3>::type>
sl@0
   132
      > ( tuple<lambda_functor<Arg1>,
sl@0
   133
              typename const_copy_argument<Arg2>::type,
sl@0
   134
              typename const_copy_argument<Arg3>::type> (a1, a2, a3) );
sl@0
   135
}
sl@0
   136
sl@0
   137
namespace detail {
sl@0
   138
sl@0
   139
// return type specialization for conditional expression begins -----------
sl@0
   140
// start reading below and move upwards
sl@0
   141
sl@0
   142
// PHASE 6:1 
sl@0
   143
// check if A is conbertible to B and B to A
sl@0
   144
template<int Phase, bool AtoB, bool BtoA, bool SameType, class A, class B>
sl@0
   145
struct return_type_2_ifthenelsereturn;
sl@0
   146
sl@0
   147
// if A can be converted to B and vice versa -> ambiguous
sl@0
   148
template<int Phase, class A, class B>
sl@0
   149
struct return_type_2_ifthenelsereturn<Phase, true, true, false, A, B> {
sl@0
   150
  typedef 
sl@0
   151
    detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
sl@0
   152
  // ambiguous type in conditional expression
sl@0
   153
};
sl@0
   154
// if A can be converted to B and vice versa and are of same type
sl@0
   155
template<int Phase, class A, class B>
sl@0
   156
struct return_type_2_ifthenelsereturn<Phase, true, true, true, A, B> {
sl@0
   157
  typedef A type;
sl@0
   158
};
sl@0
   159
sl@0
   160
sl@0
   161
// A can be converted to B
sl@0
   162
template<int Phase, class A, class B>
sl@0
   163
struct return_type_2_ifthenelsereturn<Phase, true, false, false, A, B> {
sl@0
   164
  typedef B type;
sl@0
   165
};
sl@0
   166
sl@0
   167
// B can be converted to A
sl@0
   168
template<int Phase, class A, class B>
sl@0
   169
struct return_type_2_ifthenelsereturn<Phase, false, true, false, A, B> {
sl@0
   170
  typedef A type;
sl@0
   171
};
sl@0
   172
sl@0
   173
// neither can be converted. Then we drop the potential references, and
sl@0
   174
// try again
sl@0
   175
template<class A, class B>
sl@0
   176
struct return_type_2_ifthenelsereturn<1, false, false, false, A, B> {
sl@0
   177
  // it is safe to add const, since the result will be an rvalue and thus
sl@0
   178
  // const anyway. The const are needed eg. if the types 
sl@0
   179
  // are 'const int*' and 'void *'. The remaining type should be 'const void*'
sl@0
   180
  typedef const typename boost::remove_reference<A>::type plainA; 
sl@0
   181
  typedef const typename boost::remove_reference<B>::type plainB; 
sl@0
   182
  // TODO: Add support for volatile ?
sl@0
   183
sl@0
   184
  typedef typename
sl@0
   185
       return_type_2_ifthenelsereturn<
sl@0
   186
         2,
sl@0
   187
         boost::is_convertible<plainA,plainB>::value, 
sl@0
   188
         boost::is_convertible<plainB,plainA>::value,
sl@0
   189
         boost::is_same<plainA,plainB>::value,
sl@0
   190
         plainA, 
sl@0
   191
         plainB>::type type;
sl@0
   192
};
sl@0
   193
sl@0
   194
// PHASE 6:2
sl@0
   195
template<class A, class B>
sl@0
   196
struct return_type_2_ifthenelsereturn<2, false, false, false, A, B> {
sl@0
   197
  typedef 
sl@0
   198
    detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
sl@0
   199
  // types_do_not_match_in_conditional_expression 
sl@0
   200
};
sl@0
   201
sl@0
   202
sl@0
   203
sl@0
   204
// PHASE 5: now we know that types are not arithmetic.
sl@0
   205
template<class A, class B>
sl@0
   206
struct non_numeric_types {
sl@0
   207
  typedef typename 
sl@0
   208
    return_type_2_ifthenelsereturn<
sl@0
   209
      1, // phase 1 
sl@0
   210
      is_convertible<A,B>::value, 
sl@0
   211
      is_convertible<B,A>::value, 
sl@0
   212
      is_same<A,B>::value,
sl@0
   213
      A, 
sl@0
   214
      B>::type type;
sl@0
   215
};
sl@0
   216
sl@0
   217
// PHASE 4 : 
sl@0
   218
// the base case covers arithmetic types with differing promote codes
sl@0
   219
// use the type deduction of arithmetic_actions
sl@0
   220
template<int CodeA, int CodeB, class A, class B>
sl@0
   221
struct arithmetic_or_not {
sl@0
   222
  typedef typename
sl@0
   223
    return_type_2<arithmetic_action<plus_action>, A, B>::type type; 
sl@0
   224
  // plus_action is just a random pick, has to be a concrete instance
sl@0
   225
};
sl@0
   226
sl@0
   227
// this case covers the case of artihmetic types with the same promote codes. 
sl@0
   228
// non numeric deduction is used since e.g. integral promotion is not 
sl@0
   229
// performed with operator ?: 
sl@0
   230
template<int CodeA, class A, class B>
sl@0
   231
struct arithmetic_or_not<CodeA, CodeA, A, B> {
sl@0
   232
  typedef typename non_numeric_types<A, B>::type type; 
sl@0
   233
};
sl@0
   234
sl@0
   235
// if either A or B has promote code -1 it is not an arithmetic type
sl@0
   236
template<class A, class B>
sl@0
   237
struct arithmetic_or_not <-1, -1, A, B> {
sl@0
   238
  typedef typename non_numeric_types<A, B>::type type;
sl@0
   239
};
sl@0
   240
template<int CodeB, class A, class B>
sl@0
   241
struct arithmetic_or_not <-1, CodeB, A, B> {
sl@0
   242
  typedef typename non_numeric_types<A, B>::type type;
sl@0
   243
};
sl@0
   244
template<int CodeA, class A, class B>
sl@0
   245
struct arithmetic_or_not <CodeA, -1, A, B> {
sl@0
   246
  typedef typename non_numeric_types<A, B>::type type;
sl@0
   247
};
sl@0
   248
sl@0
   249
sl@0
   250
sl@0
   251
sl@0
   252
// PHASE 3 : Are the types same?
sl@0
   253
// No, check if they are arithmetic or not
sl@0
   254
template <class A, class B>
sl@0
   255
struct same_or_not {
sl@0
   256
  typedef typename detail::remove_reference_and_cv<A>::type plainA;
sl@0
   257
  typedef typename detail::remove_reference_and_cv<B>::type plainB;
sl@0
   258
sl@0
   259
  typedef typename 
sl@0
   260
    arithmetic_or_not<
sl@0
   261
      detail::promote_code<plainA>::value, 
sl@0
   262
      detail::promote_code<plainB>::value, 
sl@0
   263
      A, 
sl@0
   264
      B>::type type;
sl@0
   265
};
sl@0
   266
// Yes, clear.
sl@0
   267
template <class A> struct same_or_not<A, A> {
sl@0
   268
  typedef A type;
sl@0
   269
};
sl@0
   270
sl@0
   271
} // detail
sl@0
   272
sl@0
   273
// PHASE 2 : Perform first the potential array_to_pointer conversion 
sl@0
   274
template<class A, class B>
sl@0
   275
struct return_type_2<other_action<ifthenelsereturn_action>, A, B> { 
sl@0
   276
sl@0
   277
  typedef typename detail::array_to_pointer<A>::type A1;
sl@0
   278
  typedef typename detail::array_to_pointer<B>::type B1;
sl@0
   279
sl@0
   280
  typedef typename 
sl@0
   281
    boost::add_const<typename detail::same_or_not<A1, B1>::type>::type type;
sl@0
   282
};
sl@0
   283
sl@0
   284
// PHASE 1 : Deduction is based on the second and third operand
sl@0
   285
sl@0
   286
sl@0
   287
// return type specialization for conditional expression ends -----------
sl@0
   288
sl@0
   289
sl@0
   290
// Specialization of lambda_functor_base for if_then_else_return.
sl@0
   291
template<class Args>
sl@0
   292
class 
sl@0
   293
lambda_functor_base<other_action<ifthenelsereturn_action>, Args> {
sl@0
   294
public:
sl@0
   295
  Args args;
sl@0
   296
sl@0
   297
  template <class SigArgs> struct sig {
sl@0
   298
  private:
sl@0
   299
    typedef typename detail::nth_return_type_sig<1, Args, SigArgs>::type ret1;
sl@0
   300
    typedef typename detail::nth_return_type_sig<2, Args, SigArgs>::type ret2;
sl@0
   301
  public:
sl@0
   302
    typedef typename return_type_2<
sl@0
   303
      other_action<ifthenelsereturn_action>, ret1, ret2
sl@0
   304
    >::type type;
sl@0
   305
  };
sl@0
   306
sl@0
   307
public:
sl@0
   308
  explicit lambda_functor_base(const Args& a) : args(a) {}
sl@0
   309
sl@0
   310
  template<class RET, CALL_TEMPLATE_ARGS>
sl@0
   311
  RET call(CALL_FORMAL_ARGS) const {
sl@0
   312
    return (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) ?
sl@0
   313
       detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS) 
sl@0
   314
    : 
sl@0
   315
       detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
sl@0
   316
  }
sl@0
   317
};
sl@0
   318
sl@0
   319
  // The code below is from Joel de Guzman, some name changes etc. 
sl@0
   320
  // has been made.
sl@0
   321
sl@0
   322
///////////////////////////////////////////////////////////////////////////////
sl@0
   323
//
sl@0
   324
//  if_then_else_composite
sl@0
   325
//
sl@0
   326
//      This composite has two (2) forms:
sl@0
   327
//
sl@0
   328
//          if_(condition)
sl@0
   329
//          [
sl@0
   330
//              statement
sl@0
   331
//          ]
sl@0
   332
//
sl@0
   333
//      and
sl@0
   334
//
sl@0
   335
//          if_(condition)
sl@0
   336
//          [
sl@0
   337
//              true_statement
sl@0
   338
//          ]
sl@0
   339
//          .else_
sl@0
   340
//          [
sl@0
   341
//              false_statement
sl@0
   342
//          ]
sl@0
   343
//
sl@0
   344
//      where condition is an lambda_functor that evaluates to bool. If condition
sl@0
   345
//      is true, the true_statement (again an lambda_functor) is executed
sl@0
   346
//      otherwise, the false_statement (another lambda_functor) is executed. The
sl@0
   347
//      result type of this is void. Note the trailing underscore after
sl@0
   348
//      if_ and the the leading dot and the trailing underscore before
sl@0
   349
//      and after .else_.
sl@0
   350
//
sl@0
   351
///////////////////////////////////////////////////////////////////////////////
sl@0
   352
template <typename CondT, typename ThenT, typename ElseT>
sl@0
   353
struct if_then_else_composite {
sl@0
   354
sl@0
   355
    typedef if_then_else_composite<CondT, ThenT, ElseT> self_t;
sl@0
   356
sl@0
   357
    template <class SigArgs>
sl@0
   358
    struct sig { typedef void type; };
sl@0
   359
sl@0
   360
    if_then_else_composite(
sl@0
   361
        CondT const& cond_,
sl@0
   362
        ThenT const& then_,
sl@0
   363
        ElseT const& else__)
sl@0
   364
    :   cond(cond_), then(then_), else_(else__) {}
sl@0
   365
sl@0
   366
    template <class Ret, CALL_TEMPLATE_ARGS>
sl@0
   367
    Ret call(CALL_FORMAL_ARGS) const
sl@0
   368
    {
sl@0
   369
        if (cond.internal_call(CALL_ACTUAL_ARGS))
sl@0
   370
            then.internal_call(CALL_ACTUAL_ARGS);
sl@0
   371
        else
sl@0
   372
            else_.internal_call(CALL_ACTUAL_ARGS);
sl@0
   373
    }
sl@0
   374
sl@0
   375
    CondT cond; ThenT then; ElseT else_; //  lambda_functors
sl@0
   376
};
sl@0
   377
sl@0
   378
//////////////////////////////////
sl@0
   379
template <typename CondT, typename ThenT>
sl@0
   380
struct else_gen {
sl@0
   381
sl@0
   382
    else_gen(CondT const& cond_, ThenT const& then_)
sl@0
   383
    :   cond(cond_), then(then_) {}
sl@0
   384
sl@0
   385
    template <typename ElseT>
sl@0
   386
    lambda_functor<if_then_else_composite<CondT, ThenT,
sl@0
   387
        typename as_lambda_functor<ElseT>::type> >
sl@0
   388
    operator[](ElseT const& else_)
sl@0
   389
    {
sl@0
   390
        typedef if_then_else_composite<CondT, ThenT,
sl@0
   391
            typename as_lambda_functor<ElseT>::type>
sl@0
   392
        result;
sl@0
   393
sl@0
   394
        return result(cond, then, to_lambda_functor(else_));
sl@0
   395
    }
sl@0
   396
sl@0
   397
    CondT cond; ThenT then;
sl@0
   398
};
sl@0
   399
sl@0
   400
//////////////////////////////////
sl@0
   401
template <typename CondT, typename ThenT>
sl@0
   402
struct if_then_composite {
sl@0
   403
sl@0
   404
    template <class SigArgs>
sl@0
   405
    struct sig { typedef void type; };
sl@0
   406
sl@0
   407
    if_then_composite(CondT const& cond_, ThenT const& then_)
sl@0
   408
    :   cond(cond_), then(then_), else_(cond, then) {}
sl@0
   409
sl@0
   410
    template <class Ret, CALL_TEMPLATE_ARGS>
sl@0
   411
    Ret call(CALL_FORMAL_ARGS) const
sl@0
   412
    {
sl@0
   413
      if (cond.internal_call(CALL_ACTUAL_ARGS))
sl@0
   414
            then.internal_call(CALL_ACTUAL_ARGS);
sl@0
   415
    }
sl@0
   416
sl@0
   417
    CondT cond; ThenT then; //  lambda_functors
sl@0
   418
    else_gen<CondT, ThenT> else_;
sl@0
   419
};
sl@0
   420
sl@0
   421
//////////////////////////////////
sl@0
   422
template <typename CondT>
sl@0
   423
struct if_gen {
sl@0
   424
sl@0
   425
    if_gen(CondT const& cond_)
sl@0
   426
    :   cond(cond_) {}
sl@0
   427
sl@0
   428
    template <typename ThenT>
sl@0
   429
    lambda_functor<if_then_composite<
sl@0
   430
        typename as_lambda_functor<CondT>::type,
sl@0
   431
        typename as_lambda_functor<ThenT>::type> >
sl@0
   432
    operator[](ThenT const& then) const
sl@0
   433
    {
sl@0
   434
        typedef if_then_composite<
sl@0
   435
            typename as_lambda_functor<CondT>::type,
sl@0
   436
            typename as_lambda_functor<ThenT>::type>
sl@0
   437
        result;
sl@0
   438
sl@0
   439
        return result(
sl@0
   440
            to_lambda_functor(cond),
sl@0
   441
            to_lambda_functor(then));
sl@0
   442
    }
sl@0
   443
sl@0
   444
    CondT cond;
sl@0
   445
};
sl@0
   446
sl@0
   447
//////////////////////////////////
sl@0
   448
template <typename CondT>
sl@0
   449
inline if_gen<CondT>
sl@0
   450
if_(CondT const& cond)
sl@0
   451
{
sl@0
   452
    return if_gen<CondT>(cond);
sl@0
   453
}
sl@0
   454
sl@0
   455
sl@0
   456
sl@0
   457
} // lambda
sl@0
   458
} // boost
sl@0
   459
sl@0
   460
#endif // BOOST_LAMBDA_IF_HPP
sl@0
   461
sl@0
   462