123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- // Boost Lambda Library -- if.hpp ------------------------------------------
- // Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi)
- // Copyright (C) 2000 Gary Powell (powellg@amazon.com)
- // Copyright (C) 2001-2002 Joel de Guzman
- //
- // Distributed under the Boost Software License, Version 1.0. (See
- // accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //
- // For more information, see www.boost.org
- // --------------------------------------------------------------------------
- #if !defined(BOOST_LAMBDA_IF_HPP)
- #define BOOST_LAMBDA_IF_HPP
- #include "boost/lambda/core.hpp"
- // Arithmetic type promotion needed for if_then_else_return
- #include "boost/lambda/detail/operator_actions.hpp"
- #include "boost/lambda/detail/operator_return_type_traits.hpp"
- namespace boost {
- namespace lambda {
- // -- if control construct actions ----------------------
- class ifthen_action {};
- class ifthenelse_action {};
- class ifthenelsereturn_action {};
- // Specialization for if_then.
- template<class Args>
- class
- lambda_functor_base<ifthen_action, Args> {
- public:
- Args args;
- template <class T> struct sig { typedef void type; };
- public:
- explicit lambda_functor_base(const Args& a) : args(a) {}
- template<class RET, CALL_TEMPLATE_ARGS>
- RET call(CALL_FORMAL_ARGS) const {
- if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
- detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
- }
- };
- // If Then
- template <class Arg1, class Arg2>
- inline const
- lambda_functor<
- lambda_functor_base<
- ifthen_action,
- tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
- >
- >
- if_then(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
- return
- lambda_functor_base<
- ifthen_action,
- tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
- >
- ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
- }
- // Specialization for if_then_else.
- template<class Args>
- class
- lambda_functor_base<ifthenelse_action, Args> {
- public:
- Args args;
- template <class T> struct sig { typedef void type; };
- public:
- explicit lambda_functor_base(const Args& a) : args(a) {}
- template<class RET, CALL_TEMPLATE_ARGS>
- RET call(CALL_FORMAL_ARGS) const {
- if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
- detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
- else
- detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
- }
- };
- // If then else
- template <class Arg1, class Arg2, class Arg3>
- inline const
- lambda_functor<
- lambda_functor_base<
- ifthenelse_action,
- tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
- >
- >
- if_then_else(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
- const lambda_functor<Arg3>& a3) {
- return
- lambda_functor_base<
- ifthenelse_action,
- tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
- >
- (tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
- (a1, a2, a3) );
- }
- // Our version of operator?:()
- template <class Arg1, class Arg2, class Arg3>
- inline const
- lambda_functor<
- lambda_functor_base<
- other_action<ifthenelsereturn_action>,
- tuple<lambda_functor<Arg1>,
- typename const_copy_argument<Arg2>::type,
- typename const_copy_argument<Arg3>::type>
- >
- >
- if_then_else_return(const lambda_functor<Arg1>& a1,
- const Arg2 & a2,
- const Arg3 & a3) {
- return
- lambda_functor_base<
- other_action<ifthenelsereturn_action>,
- tuple<lambda_functor<Arg1>,
- typename const_copy_argument<Arg2>::type,
- typename const_copy_argument<Arg3>::type>
- > ( tuple<lambda_functor<Arg1>,
- typename const_copy_argument<Arg2>::type,
- typename const_copy_argument<Arg3>::type> (a1, a2, a3) );
- }
- namespace detail {
- // return type specialization for conditional expression begins -----------
- // start reading below and move upwards
- // PHASE 6:1
- // check if A is conbertible to B and B to A
- template<int Phase, bool AtoB, bool BtoA, bool SameType, class A, class B>
- struct return_type_2_ifthenelsereturn;
- // if A can be converted to B and vice versa -> ambiguous
- template<int Phase, class A, class B>
- struct return_type_2_ifthenelsereturn<Phase, true, true, false, A, B> {
- typedef
- detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
- // ambiguous type in conditional expression
- };
- // if A can be converted to B and vice versa and are of same type
- template<int Phase, class A, class B>
- struct return_type_2_ifthenelsereturn<Phase, true, true, true, A, B> {
- typedef A type;
- };
- // A can be converted to B
- template<int Phase, class A, class B>
- struct return_type_2_ifthenelsereturn<Phase, true, false, false, A, B> {
- typedef B type;
- };
- // B can be converted to A
- template<int Phase, class A, class B>
- struct return_type_2_ifthenelsereturn<Phase, false, true, false, A, B> {
- typedef A type;
- };
- // neither can be converted. Then we drop the potential references, and
- // try again
- template<class A, class B>
- struct return_type_2_ifthenelsereturn<1, false, false, false, A, B> {
- // it is safe to add const, since the result will be an rvalue and thus
- // const anyway. The const are needed eg. if the types
- // are 'const int*' and 'void *'. The remaining type should be 'const void*'
- typedef const typename boost::remove_reference<A>::type plainA;
- typedef const typename boost::remove_reference<B>::type plainB;
- // TODO: Add support for volatile ?
- typedef typename
- return_type_2_ifthenelsereturn<
- 2,
- boost::is_convertible<plainA,plainB>::value,
- boost::is_convertible<plainB,plainA>::value,
- boost::is_same<plainA,plainB>::value,
- plainA,
- plainB>::type type;
- };
- // PHASE 6:2
- template<class A, class B>
- struct return_type_2_ifthenelsereturn<2, false, false, false, A, B> {
- typedef
- detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
- // types_do_not_match_in_conditional_expression
- };
- // PHASE 5: now we know that types are not arithmetic.
- template<class A, class B>
- struct non_numeric_types {
- typedef typename
- return_type_2_ifthenelsereturn<
- 1, // phase 1
- is_convertible<A,B>::value,
- is_convertible<B,A>::value,
- is_same<A,B>::value,
- A,
- B>::type type;
- };
- // PHASE 4 :
- // the base case covers arithmetic types with differing promote codes
- // use the type deduction of arithmetic_actions
- template<int CodeA, int CodeB, class A, class B>
- struct arithmetic_or_not {
- typedef typename
- return_type_2<arithmetic_action<plus_action>, A, B>::type type;
- // plus_action is just a random pick, has to be a concrete instance
- };
- // this case covers the case of artihmetic types with the same promote codes.
- // non numeric deduction is used since e.g. integral promotion is not
- // performed with operator ?:
- template<int CodeA, class A, class B>
- struct arithmetic_or_not<CodeA, CodeA, A, B> {
- typedef typename non_numeric_types<A, B>::type type;
- };
- // if either A or B has promote code -1 it is not an arithmetic type
- template<class A, class B>
- struct arithmetic_or_not <-1, -1, A, B> {
- typedef typename non_numeric_types<A, B>::type type;
- };
- template<int CodeB, class A, class B>
- struct arithmetic_or_not <-1, CodeB, A, B> {
- typedef typename non_numeric_types<A, B>::type type;
- };
- template<int CodeA, class A, class B>
- struct arithmetic_or_not <CodeA, -1, A, B> {
- typedef typename non_numeric_types<A, B>::type type;
- };
- // PHASE 3 : Are the types same?
- // No, check if they are arithmetic or not
- template <class A, class B>
- struct same_or_not {
- typedef typename detail::remove_reference_and_cv<A>::type plainA;
- typedef typename detail::remove_reference_and_cv<B>::type plainB;
- typedef typename
- arithmetic_or_not<
- detail::promote_code<plainA>::value,
- detail::promote_code<plainB>::value,
- A,
- B>::type type;
- };
- // Yes, clear.
- template <class A> struct same_or_not<A, A> {
- typedef A type;
- };
- } // detail
- // PHASE 2 : Perform first the potential array_to_pointer conversion
- template<class A, class B>
- struct return_type_2<other_action<ifthenelsereturn_action>, A, B> {
- typedef typename detail::array_to_pointer<A>::type A1;
- typedef typename detail::array_to_pointer<B>::type B1;
- typedef typename
- boost::add_const<typename detail::same_or_not<A1, B1>::type>::type type;
- };
- // PHASE 1 : Deduction is based on the second and third operand
- // return type specialization for conditional expression ends -----------
- // Specialization of lambda_functor_base for if_then_else_return.
- template<class Args>
- class
- lambda_functor_base<other_action<ifthenelsereturn_action>, Args> {
- public:
- Args args;
- template <class SigArgs> struct sig {
- private:
- typedef typename detail::nth_return_type_sig<1, Args, SigArgs>::type ret1;
- typedef typename detail::nth_return_type_sig<2, Args, SigArgs>::type ret2;
- public:
- typedef typename return_type_2<
- other_action<ifthenelsereturn_action>, ret1, ret2
- >::type type;
- };
- public:
- explicit lambda_functor_base(const Args& a) : args(a) {}
- template<class RET, CALL_TEMPLATE_ARGS>
- RET call(CALL_FORMAL_ARGS) const {
- return (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) ?
- detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS)
- :
- detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
- }
- };
- // The code below is from Joel de Guzman, some name changes etc.
- // has been made.
- ///////////////////////////////////////////////////////////////////////////////
- //
- // if_then_else_composite
- //
- // This composite has two (2) forms:
- //
- // if_(condition)
- // [
- // statement
- // ]
- //
- // and
- //
- // if_(condition)
- // [
- // true_statement
- // ]
- // .else_
- // [
- // false_statement
- // ]
- //
- // where condition is an lambda_functor that evaluates to bool. If condition
- // is true, the true_statement (again an lambda_functor) is executed
- // otherwise, the false_statement (another lambda_functor) is executed. The
- // result type of this is void. Note the trailing underscore after
- // if_ and the leading dot and the trailing underscore before
- // and after .else_.
- //
- ///////////////////////////////////////////////////////////////////////////////
- template <typename CondT, typename ThenT, typename ElseT>
- struct if_then_else_composite {
- typedef if_then_else_composite<CondT, ThenT, ElseT> self_t;
- template <class SigArgs>
- struct sig { typedef void type; };
- if_then_else_composite(
- CondT const& cond_,
- ThenT const& then_,
- ElseT const& else__)
- : cond(cond_), then(then_), else_(else__) {}
- template <class Ret, CALL_TEMPLATE_ARGS>
- Ret call(CALL_FORMAL_ARGS) const
- {
- if (cond.internal_call(CALL_ACTUAL_ARGS))
- then.internal_call(CALL_ACTUAL_ARGS);
- else
- else_.internal_call(CALL_ACTUAL_ARGS);
- }
- CondT cond; ThenT then; ElseT else_; // lambda_functors
- };
- //////////////////////////////////
- template <typename CondT, typename ThenT>
- struct else_gen {
- else_gen(CondT const& cond_, ThenT const& then_)
- : cond(cond_), then(then_) {}
- template <typename ElseT>
- lambda_functor<if_then_else_composite<CondT, ThenT,
- typename as_lambda_functor<ElseT>::type> >
- operator[](ElseT const& else_)
- {
- typedef if_then_else_composite<CondT, ThenT,
- typename as_lambda_functor<ElseT>::type>
- result;
- return result(cond, then, to_lambda_functor(else_));
- }
- CondT cond; ThenT then;
- };
- //////////////////////////////////
- template <typename CondT, typename ThenT>
- struct if_then_composite {
- template <class SigArgs>
- struct sig { typedef void type; };
- if_then_composite(CondT const& cond_, ThenT const& then_)
- : cond(cond_), then(then_), else_(cond, then) {}
- template <class Ret, CALL_TEMPLATE_ARGS>
- Ret call(CALL_FORMAL_ARGS) const
- {
- if (cond.internal_call(CALL_ACTUAL_ARGS))
- then.internal_call(CALL_ACTUAL_ARGS);
- }
- CondT cond; ThenT then; // lambda_functors
- else_gen<CondT, ThenT> else_;
- };
- //////////////////////////////////
- template <typename CondT>
- struct if_gen {
- if_gen(CondT const& cond_)
- : cond(cond_) {}
- template <typename ThenT>
- lambda_functor<if_then_composite<
- typename as_lambda_functor<CondT>::type,
- typename as_lambda_functor<ThenT>::type> >
- operator[](ThenT const& then) const
- {
- typedef if_then_composite<
- typename as_lambda_functor<CondT>::type,
- typename as_lambda_functor<ThenT>::type>
- result;
- return result(
- to_lambda_functor(cond),
- to_lambda_functor(then));
- }
- CondT cond;
- };
- //////////////////////////////////
- template <typename CondT>
- inline if_gen<CondT>
- if_(CondT const& cond)
- {
- return if_gen<CondT>(cond);
- }
- } // lambda
- } // boost
- #endif // BOOST_LAMBDA_IF_HPP
|