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