blob: 56f80ace28236ac588b4826e1307e753624cbceb [file] [log] [blame]
// Boost Lambda Library -- control_structures_impl.hpp ---------------------
// Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi)
// Copyright (C) 2000 Gary Powell (powellg@amazon.com)
//
// 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_CONTROL_CONSTRUCTS_HPP)
#define BOOST_LAMBDA_CONTROL_CONSTRUCTS_HPP
namespace boost {
namespace lambda {
// -- void return control actions ----------------------
class forloop_action {};
class forloop_no_body_action {};
class ifthen_action {};
class ifthenelse_action {};
class whileloop_action {};
class whileloop_no_body_action {};
class dowhileloop_action {};
class dowhileloop_no_body_action {};
// -- nonvoid return control actions ----------------------
class ifthenelsereturn_action {};
// For loop
template <class Arg1, class Arg2, class Arg3, class Arg4>
inline const
lambda_functor<
lambda_functor_base<
forloop_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
lambda_functor<Arg3>, lambda_functor<Arg4> >
>
>
for_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
const lambda_functor<Arg3>& a3, const lambda_functor<Arg4>& a4) {
return
lambda_functor_base<
forloop_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
lambda_functor<Arg3>, lambda_functor<Arg4> >
>
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
lambda_functor<Arg3>, lambda_functor<Arg4> >(a1, a2, a3, a4)
);
}
// No body case.
template <class Arg1, class Arg2, class Arg3>
inline const
lambda_functor<
lambda_functor_base<
forloop_no_body_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
>
>
for_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
const lambda_functor<Arg3>& a3) {
return
lambda_functor_base<
forloop_no_body_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
lambda_functor<Arg3> >
>
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
lambda_functor<Arg3> >(a1, a2, a3) );
}
// While loop
template <class Arg1, class Arg2>
inline const
lambda_functor<
lambda_functor_base<
whileloop_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
>
>
while_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
return
lambda_functor_base<
whileloop_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
>
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
}
// No body case.
template <class Arg1>
inline const
lambda_functor<
lambda_functor_base<
whileloop_no_body_action,
tuple<lambda_functor<Arg1> >
>
>
while_loop(const lambda_functor<Arg1>& a1) {
return
lambda_functor_base<
whileloop_no_body_action,
tuple<lambda_functor<Arg1> >
>
( tuple<lambda_functor<Arg1> >(a1) );
}
// Do While loop
template <class Arg1, class Arg2>
inline const
lambda_functor<
lambda_functor_base<
dowhileloop_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
>
>
do_while_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
return
lambda_functor_base<
dowhileloop_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
>
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
}
// No body case.
template <class Arg1>
inline const
lambda_functor<
lambda_functor_base<
dowhileloop_no_body_action,
tuple<lambda_functor<Arg1> >
>
>
do_while_loop(const lambda_functor<Arg1>& a1) {
return
lambda_functor_base<
dowhileloop_no_body_action,
tuple<lambda_functor<Arg1> >
>
( tuple<lambda_functor<Arg1> >(a1));
}
// 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) );
}
// 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 -----------
// Control loop lambda_functor_base specializations.
// Specialization for for_loop.
template<class Args>
class
lambda_functor_base<forloop_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 {
for(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))
detail::select(boost::tuples::get<3>(args), CALL_ACTUAL_ARGS);
}
};
// No body case
template<class Args>
class
lambda_functor_base<forloop_no_body_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 {
for(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)) {}
}
};
// Specialization for while_loop.
template<class Args>
class
lambda_functor_base<whileloop_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 {
while(detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
}
};
// No body case
template<class Args>
class
lambda_functor_base<whileloop_no_body_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 {
while(detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) {}
}
};
// Specialization for do_while_loop.
// Note that the first argument is the condition.
template<class Args>
class
lambda_functor_base<dowhileloop_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 {
do {
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
} while (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) );
}
};
// No body case
template<class Args>
class
lambda_functor_base<dowhileloop_no_body_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 {
do {} while (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) );
}
};
// 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);
}
};
// 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);
}
};
// 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);
}
};
} // lambda
} // boost
#endif // BOOST_LAMBDA_CONTROL_CONSTRUCTS_HPP