2
0
mirror of https://github.com/boostorg/lambda.git synced 2026-01-25 06:12:27 +00:00
Files
lambda/include/boost/lambda/detail/lambda_functors.hpp
2002-03-21 22:45:48 +00:00

652 lines
20 KiB
C++

// Boost Lambda Library - lambda_functors.hpp -------------------------------
// Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
//
// Permission to copy, use, sell and distribute this software is granted
// provided this copyright notice appears in all copies.
// Permission to modify the code and to distribute modified code is granted
// provided this copyright notice appears in all copies, and a notice
// that the code was modified is included with the copyright notice.
//
// This software is provided "as is" without express or implied warranty,
// and with no claim as to its suitability for any purpose.
//
// For more information, see http://www.boost.org
// ------------------------------------------------
#ifndef BOOST_LAMBDA_LAMBDA_FUNCTORS_HPP
#define BOOST_LAMBDA_LAMBDA_FUNCTORS_HPP
namespace boost {
namespace lambda {
// -- lambda_functor --------------------------------------------
// --------------------------------------------------------------
//inline const null_type const_null_type() { return null_type(); }
namespace detail {
namespace {
static const null_type constant_null_type = null_type();
} // unnamed
} // detail
#define const_null_type() detail::constant_null_type
#if defined BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
#error "Multiple defines of BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT"
#endif
#define BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT\
template<class A>\
const lambda_functor<lambda_functor_args<\
action<2, other_action<assignment_action> >,\
boost::tuple<lambda_functor, \
typename const_copy_argument <const A>::type>,\
combine_arities<lambda_functor,A>::value> >\
operator=(const A& a) const { \
return lambda_functor<lambda_functor_args<\
action<2, other_action<assignment_action> >,\
boost::tuple<lambda_functor, \
typename const_copy_argument <const A>::type>,\
combine_arities<lambda_functor,A>::value> >\
( boost::tuple<lambda_functor, \
typename const_copy_argument <const A>::type>(*this, a) );\
}\
\
#if defined BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
#error "Multiple defines of BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT"
#endif
#define BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT\
template<class A>\
const lambda_functor<lambda_functor_args<\
action<2, other_action<subscript_action> >,\
boost::tuple<lambda_functor, \
typename const_copy_argument <const A>::type>,\
combine_arities<lambda_functor,A>::value> >\
operator[](const A& a) const { \
return lambda_functor<lambda_functor_args<\
action<2, other_action<subscript_action> >,\
boost::tuple<lambda_functor, \
typename const_copy_argument <const A>::type>,\
combine_arities<lambda_functor,A>::value> >\
( boost::tuple<lambda_functor, \
typename const_copy_argument <const A>::type>(*this, a ) );\
}\
\
// -- free variables types --------------------------------------------------
template <int I> class placeholder {};
typedef const lambda_functor<placeholder<FIRST> > placeholder1_type;
typedef const lambda_functor<placeholder<SECOND> > placeholder2_type;
typedef const lambda_functor<placeholder<THIRD> > placeholder3_type;
// free variables are lambda_functors. This is to allow uniform handling with
// other lambda_functors.
// -------------------------------------------------------------------
// template <int I>
// class lambda_functor<placeholder<I> > {
// public:
// lambda_functor() {}
// // (do nothing) bug in gcc 2.95.2 for const template objects.
// BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
// BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
// };
// covers _E, does not define (), cause it will only be called
// inside of other lambda functors.
template <int I>
class lambda_functor<placeholder<I> > {
public:
lambda_functor() {}
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
template<>
class lambda_functor<placeholder<FIRST> > {
public:
lambda_functor() {}
template <class A>
A& operator()(A& a) const { return a; }
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
template<>
class lambda_functor<placeholder<SECOND> > {
public:
lambda_functor() {}
template <class A, class B>
B& operator()(A&, B& b) const { return b; }
// currying call: creates another lambda functor
template<class A>
placeholder1_type
operator()(A&) const { return _1; }
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
template<>
class lambda_functor<placeholder<THIRD> > {
public:
lambda_functor() {}
template <class A, class B, class C>
C& operator()(A&, B&, C& c) const { return c; }
// currying calls: create another lambda functor
template<class A>
placeholder2_type
operator()(A&) const { return _2; }
template<class A, class B>
placeholder1_type
operator()(A&, B&) const { return _1; }
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
namespace detail {
// helpers
template <class T> struct identity { typedef T type; };
// take the Nth element in the tuple, or null_type if tuple is not
// long enough
template <int N, class T>
struct element_or_null_type {
typedef typename
detail::IF_type<
(N < boost::tuples::length<T>::value),
boost::tuples::element<N, T>,
identity<null_type>
>::type type;
};
// Lambda functors all provide the sig member template for
// querying their return type.
// these type mappings implement the tools for that deduction
//type mapping to compute the new lambda functor resulting from a curried
// call.
template<class LF, int Args_expected, class SigArgs>
struct curry_sig {
// First arg in SigArgs is the lambda functor type, that's why the -1
BOOST_STATIC_CONSTANT(int, acount = boost::tuples::length<SigArgs>::value-1);
// currying is only supported for 2- and 3-ary lambda functors, and
// must be called by 1 or 2 arguments.
// acount 1 or 2, dig_arity<LF>::value SECOND or THIRD
typedef typename detail::element_or_null_type<1, SigArgs>::type el_1;
typedef typename detail::element_or_null_type<2, SigArgs>::type el_2;
typedef lambda_functor<
lambda_functor_args<
action<Args_expected + 1, curry_action<acount> >,
// remove_const_refernce takes care that const null_type will
// be null_type, that arrays are always stored as const refs,
// that nonconst refs remain nonconst refs, and everything else goes
// to const copy.
tuple<
LF,
typename detail::remove_const_reference<el_1>::type,
typename detail::remove_const_reference<el_2>::type
>,
detail::reduce_arity<dig_arity<LF>::value, acount>::value
>
> type;
};
// enter the normal return type deduction
template <class LF, class SigArgs>
struct eval_sig
{
typedef typename
return_type<
LF,
open_args<
typename detail::element_or_null_type<1, SigArgs>::type,
typename detail::element_or_null_type<2, SigArgs>::type,
typename detail::element_or_null_type<3, SigArgs>::type
>
>::type type;
};
// either a normal evaluation, or a curried call
template <class LF, int Args_expected, class SigArgs>
struct lambda_functor_sig
{
typedef typename
detail::IF_type<
(boost::tuples::length<SigArgs>::value - 1 < Args_expected),
detail::curry_sig<LF, Args_expected, SigArgs>,
detail::eval_sig<LF, SigArgs>
>::type type;
};
} // end detail
// -- lambda_functor NONE ------------------------------------------------
template <class Action, class Args>
class lambda_functor<lambda_functor_args<Action, Args, NONE> >
: public lambda_functor_base<Action, Args>, public has_sig
{
public:
typedef lambda_functor_base<Action, Args> inherited;
explicit lambda_functor(const Args& args)
: inherited(args) {}
// lambda functors can be copied, if arity and action are the same
// and Args tuples are copyable
template <class Args2> lambda_functor
(const lambda_functor<lambda_functor_args<Action, Args2, NONE> >& f)
: inherited(f.args) {}
template <class SigArgs> struct sig {
typedef typename
detail::lambda_functor_sig<lambda_functor, 0, SigArgs>::type type;
};
typename return_type<
lambda_functor,
open_args<null_type, null_type, null_type>
>::type
operator()() const {
return inherited::template
call<
typename return_type<
lambda_functor,
open_args<null_type, null_type, null_type> >::type
>(const_null_type(), const_null_type(), const_null_type());
}
template<class RET>
RET ret_call() const {
return inherited:: template call<RET>(const_null_type(),
const_null_type(),
const_null_type());
}
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
// -- lambda_functor FIRST -------------------------------------------------
template <class Action, class Args>
class lambda_functor<lambda_functor_args<Action, Args, FIRST> >
: public lambda_functor_base<Action, Args>
{
public:
typedef lambda_functor_base<Action, Args> inherited;
explicit lambda_functor(const Args& args)
: inherited(args) {}
// lambda functors can be copied, if arity and action are the same
// and Args tuples copyable
template <class Args2> lambda_functor
(const lambda_functor<lambda_functor_args<Action, Args2, FIRST> >& f)
: inherited(f.args) {}
template <class SigArgs> struct sig {
typedef typename
detail::lambda_functor_sig<lambda_functor, 1, SigArgs>::type type;
};
template<class A>
typename
return_type<lambda_functor, open_args<A&, null_type, null_type> >::type
operator()(A& a) const
{
return inherited::template call<
typename return_type<
lambda_functor, open_args<A&, null_type, null_type>
>::type
>(a, const_null_type(), const_null_type());
}
template<class RET, class A>
RET ret_call(A& a) const
{
return inherited:: template call<RET>(a, const_null_type(), const_null_type());
}
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
// -- lambda_functor SECOND -------------------------------------------------
template <class Action, class Args>
class lambda_functor<lambda_functor_args<Action, Args, SECOND> >
: public lambda_functor_base<Action, Args>, public has_sig
{
public:
typedef lambda_functor_base<Action, Args> inherited;
explicit lambda_functor(const Args& args)
: inherited(args) {}
// lambda functors can be copied, if arity and action are the same
// and Args tuples copyable
template <class Args2> lambda_functor
(const lambda_functor<lambda_functor_args<Action, Args2, SECOND> >& f)
: inherited(f.args) {}
template <class SigArgs> struct sig {
typedef typename
detail::lambda_functor_sig<lambda_functor, 2, SigArgs>::type type;
};
template<class A, class B>
typename return_type<lambda_functor, open_args<A&, B&, null_type> >::type
operator()(A& a, B& b) const
{
return inherited::template call<
typename return_type<
lambda_functor, open_args<A&, B&, null_type>
>::type>(a, b, const_null_type());
}
// currying call: creates another lambda functor
template<class A>
typename sig<tuple<const lambda_functor&, A&> >::type
operator()(A& a) const
{
return
typename sig<tuple<const lambda_functor&, A&> >::type
(
tuple<lambda_functor,
typename detail::remove_const_reference<A&>::type>(*this, a)
);
}
template<class RET, class A, class B>
RET ret_call(A& a, B& b) const {
return inherited::template call<RET>(a, b, const_null_type());
}
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
// -- lambda_functor THIRD -------------------------------------------------
template <class Action, class Args>
class lambda_functor<lambda_functor_args<Action, Args, THIRD> > : public lambda_functor_base<Action, Args>, public has_sig
{
public:
typedef lambda_functor_base<Action, Args> inherited;
explicit lambda_functor(const Args& args)
: inherited(args) {}
// lambda functors can be copied, if arity and action are the same
// and Args tuples copyable
template <class Args2> lambda_functor
(const lambda_functor<lambda_functor_args<Action, Args2, THIRD> >& f)
: inherited(f.args) {}
template <class SigArgs> struct sig {
typedef typename
detail::lambda_functor_sig<lambda_functor, 3, SigArgs>::type type;
};
template<class A, class B, class C>
typename return_type<lambda_functor, open_args<A&, B&, C&> >::type
operator()(A& a, B& b, C& c) const
{
return inherited::template call<
typename return_type<lambda_functor, open_args<A&, B&, C&>
>::type>(a, b, c);
}
template<class RET, class A, class B, class C>
RET ret_call(A& a, B& b, C& c) const {
return inherited::template call<RET>(a, b, c);
}
// currying call, one argument still missing
template<class A, class B>
typename sig<tuple<const lambda_functor&, A&, B&> >::type
operator()(A& a, B& b) const
{
return
typename sig<tuple<const lambda_functor&, A&, B&> >::type
( tuple<
lambda_functor,
typename detail::remove_const_reference<A&>::type,
typename detail::remove_const_reference<B&>::type
> (*this, a, b)
);
}
// currying call, two arguments still missing
// The return type is:
// lambda_functor<
// lambda_functor_args<
// action<4, curry_action<1> >,
// detail::bind_tuple_mapper<lambda_functor, const A>::type,
// SECOND
// >
// >
template<class A>
typename sig<tuple<const lambda_functor&, A&> >::type
operator()(A& a) const
{
return
typename sig<tuple<const lambda_functor&, A&> >::type
(
tuple<lambda_functor, typename detail::remove_const_reference<A&>::type>(*this, a)
);
}
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
// -- lambda_functor (Arbitrary Code) ---------------------------------------
// matches any arity code with EXCEPTION or RETHROW bits on
// This specialisation is only instantiated if delayed exception
// handling is used. See exceptions.hpp.
// ----------------------------------------------------------
template <class Action, class Args, int Code>
class lambda_functor<lambda_functor_args<Action, Args, Code> >
: public lambda_functor_base<Action, Args>
{
public:
typedef lambda_functor_base<Action, Args> inherited;
explicit lambda_functor(const Args& args)
: inherited(args) {}
// lambda functors can be copied, if arity and action are the same
// and Args tuples copyable
template <class Args2> lambda_functor
(const lambda_functor<lambda_functor_args<Action, Args2, Code> >& f)
: inherited(f.args) {}
// No operator() for this, since this lambda_functor can only be used
// in a catch_exception or catch_all
template<class RET, class A, class B, class C>
RET ret_call(A& a, B& b, C& c) const
{
return inherited::template call<RET>(a, b, c);
}
};
// any lambda functor can be turned into a const_incorrect_lambda_functor
// The operator() takes arguments as consts and then casts constness
// away. So this breaks const correctness!!! but is a necessary workaround
// in some cases due to language limitations.
// Note, that this is not a lambda_functor anymore, so it can not be used
// as a sub lambda expression.
template <class Arg>
struct const_incorrect_lambda_functor
: private lambda_functor<Arg> {
public:
BOOST_STATIC_ASSERT(dig_arity<Arg>::value <= THIRD);
// only allowed for normal lambda functions, not EXCEPTION ones
typedef lambda_functor<Arg> inherited;
explicit const_incorrect_lambda_functor(const lambda_functor<Arg>& lf)
: inherited(lf.args) {}
template <class SigArgs> struct sig {
typedef typename
::boost::lambda::lambda_functor<Arg>::template sig<SigArgs>::type type;
};
typename sig<tuple<const lambda_functor<Arg>& > >::type
operator()() const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>& > >::type>();
}
template<class A>
typename sig<tuple<const lambda_functor<Arg>&, A&> >::type
operator()(const A& a) const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, A&> >::type >(const_cast<A&>(a));
}
template<class A, class B>
typename sig<tuple<const lambda_functor<Arg>&, A&, B&> >::type
operator()(const A& a, const B& b) const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, A&, B&> >::type >(const_cast<A&>(a), const_cast<B&>(b));
}
template<class A, class B, class C>
typename sig<tuple<const lambda_functor<Arg>&, A&, B&, C&> >::type
operator()(const A& a, const B& b, const C& c) const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, A&, B&, C&> >::type>(const_cast<A&>(a), const_cast<B&>(b), const_cast<C&>(c));
}
};
// ------------------------------------------------------------------------
// any lambda functor can be turned into a const_parameter_lambda_functor
// The operator() takes arguments as const.
// This is useful if lambda functors are called with non-const rvalues.
// Note, that this is not a lambda_functor anymore, so it can not be used
// as a sub lambda expression.
template <class Arg>
struct const_parameter_lambda_functor
: private lambda_functor<Arg> {
public:
BOOST_STATIC_ASSERT(dig_arity<Arg>::value <= THIRD);
// only allowed for normal lambda functions, not EXCEPTION ones
typedef lambda_functor<Arg> inherited;
explicit const_parameter_lambda_functor(const lambda_functor<Arg>& lf)
: inherited(lf.args) {}
template <class SigArgs> struct sig {
typedef typename
::boost::lambda::lambda_functor<Arg>::template sig<SigArgs>::type type;
};
// This is provided just for completeness; no arguments, no constness
// problems.
typename sig<tuple<const lambda_functor<Arg>& > >::type
operator()() const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>& > >::type>();
}
template<class A>
typename sig<tuple<const lambda_functor<Arg>&, const A&> >::type
operator()(const A& a) const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, const A&> >::type >(a);
}
template<class A, class B>
typename sig<tuple<const lambda_functor<Arg>&, const A&, const B&> >::type
operator()(const A& a, const B& b) const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, const A&, const B&> >::type >(a, b);
}
template<class A, class B, class C>
typename sig<tuple<const lambda_functor<Arg>&, const A&, const B&, const C&> >::type
operator()(const A& a, const B& b, const C& c) const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, const A&, const B&, const C&> >::type>(a, b, c);
}
};
// Tagged lambda_functor -------------
// This is a generic class for special types of lambda functors,
// e.g. certain parameters of switch_statement must be case_statements,
// rather than arbitrary lambda functors
template<class Tag, class LambdaFunctor>
class tagged_lambda_functor;
template<class Tag, class Args>
class tagged_lambda_functor<Tag, lambda_functor<Args> >
: public lambda_functor<Args>
{
public:
template<class T>
tagged_lambda_functor(const lambda_functor<T>& a)
: lambda_functor<Args>(a) {}
// only works for the no body case.
explicit tagged_lambda_functor() : lambda_functor<Args>( null_type() ) {}
};
#undef BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
#undef BOOST_LAMBDA_LAMBDA_FUNCTOR_ADDRESSOF
#undef BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
} // namespace lambda
} // namespace boost
#endif