123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- //---------------------------------------------------------------------------//
- // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.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
- //
- // See http://boostorg.github.com/compute for more information.
- //---------------------------------------------------------------------------//
- #ifndef BOOST_COMPUTE_LAMBDA_CONTEXT_HPP
- #define BOOST_COMPUTE_LAMBDA_CONTEXT_HPP
- #include <boost/proto/core.hpp>
- #include <boost/proto/context.hpp>
- #include <boost/type_traits.hpp>
- #include <boost/preprocessor/repetition.hpp>
- #include <boost/compute/config.hpp>
- #include <boost/compute/function.hpp>
- #include <boost/compute/lambda/result_of.hpp>
- #include <boost/compute/lambda/functional.hpp>
- #include <boost/compute/type_traits/result_of.hpp>
- #include <boost/compute/type_traits/type_name.hpp>
- #include <boost/compute/detail/meta_kernel.hpp>
- namespace boost {
- namespace compute {
- namespace lambda {
- namespace mpl = boost::mpl;
- namespace proto = boost::proto;
- #define BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(tag, op) \
- template<class LHS, class RHS> \
- void operator()(tag, const LHS &lhs, const RHS &rhs) \
- { \
- if(proto::arity_of<LHS>::value > 0){ \
- stream << '('; \
- proto::eval(lhs, *this); \
- stream << ')'; \
- } \
- else { \
- proto::eval(lhs, *this); \
- } \
- \
- stream << op; \
- \
- if(proto::arity_of<RHS>::value > 0){ \
- stream << '('; \
- proto::eval(rhs, *this); \
- stream << ')'; \
- } \
- else { \
- proto::eval(rhs, *this); \
- } \
- }
- // lambda expression context
- template<class Args>
- struct context : proto::callable_context<context<Args> >
- {
- typedef void result_type;
- typedef Args args_tuple;
- // create a lambda context for kernel with args
- context(boost::compute::detail::meta_kernel &kernel, const Args &args_)
- : stream(kernel),
- args(args_)
- {
- }
- // handle terminals
- template<class T>
- void operator()(proto::tag::terminal, const T &x)
- {
- // terminal values in lambda expressions are always literals
- stream << stream.lit(x);
- }
- void operator()(proto::tag::terminal, const uchar_ &x)
- {
- stream << "(uchar)(" << stream.lit(uint_(x)) << "u)";
- }
- void operator()(proto::tag::terminal, const char_ &x)
- {
- stream << "(char)(" << stream.lit(int_(x)) << ")";
- }
- void operator()(proto::tag::terminal, const ushort_ &x)
- {
- stream << "(ushort)(" << stream.lit(x) << "u)";
- }
- void operator()(proto::tag::terminal, const short_ &x)
- {
- stream << "(short)(" << stream.lit(x) << ")";
- }
- void operator()(proto::tag::terminal, const uint_ &x)
- {
- stream << "(" << stream.lit(x) << "u)";
- }
- void operator()(proto::tag::terminal, const ulong_ &x)
- {
- stream << "(" << stream.lit(x) << "ul)";
- }
- void operator()(proto::tag::terminal, const long_ &x)
- {
- stream << "(" << stream.lit(x) << "l)";
- }
- // handle placeholders
- template<int I>
- void operator()(proto::tag::terminal, placeholder<I>)
- {
- stream << boost::get<I>(args);
- }
- // handle functions
- #define BOOST_COMPUTE_LAMBDA_CONTEXT_FUNCTION_ARG(z, n, unused) \
- BOOST_PP_COMMA_IF(n) BOOST_PP_CAT(const Arg, n) BOOST_PP_CAT(&arg, n)
- #define BOOST_COMPUTE_LAMBDA_CONTEXT_FUNCTION(z, n, unused) \
- template<class F, BOOST_PP_ENUM_PARAMS(n, class Arg)> \
- void operator()( \
- proto::tag::function, \
- const F &function, \
- BOOST_PP_REPEAT(n, BOOST_COMPUTE_LAMBDA_CONTEXT_FUNCTION_ARG, ~) \
- ) \
- { \
- proto::value(function).apply(*this, BOOST_PP_ENUM_PARAMS(n, arg)); \
- }
- BOOST_PP_REPEAT_FROM_TO(1, BOOST_COMPUTE_MAX_ARITY, BOOST_COMPUTE_LAMBDA_CONTEXT_FUNCTION, ~)
- #undef BOOST_COMPUTE_LAMBDA_CONTEXT_FUNCTION
- // operators
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::plus, '+')
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::minus, '-')
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::multiplies, '*')
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::divides, '/')
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::modulus, '%')
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::less, '<')
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::greater, '>')
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::less_equal, "<=")
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::greater_equal, ">=")
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::equal_to, "==")
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::not_equal_to, "!=")
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::logical_and, "&&")
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::logical_or, "||")
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::bitwise_and, '&')
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::bitwise_or, '|')
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::bitwise_xor, '^')
- BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::assign, '=')
- // subscript operator
- template<class LHS, class RHS>
- void operator()(proto::tag::subscript, const LHS &lhs, const RHS &rhs)
- {
- proto::eval(lhs, *this);
- stream << '[';
- proto::eval(rhs, *this);
- stream << ']';
- }
- // ternary conditional operator
- template<class Pred, class Arg1, class Arg2>
- void operator()(proto::tag::if_else_, const Pred &p, const Arg1 &x, const Arg2 &y)
- {
- proto::eval(p, *this);
- stream << '?';
- proto::eval(x, *this);
- stream << ':';
- proto::eval(y, *this);
- }
- boost::compute::detail::meta_kernel &stream;
- Args args;
- };
- namespace detail {
- template<class Expr, class Arg>
- struct invoked_unary_expression
- {
- typedef typename ::boost::compute::result_of<Expr(Arg)>::type result_type;
- invoked_unary_expression(const Expr &expr, const Arg &arg)
- : m_expr(expr),
- m_arg(arg)
- {
- }
- Expr m_expr;
- Arg m_arg;
- };
- template<class Expr, class Arg>
- boost::compute::detail::meta_kernel&
- operator<<(boost::compute::detail::meta_kernel &kernel,
- const invoked_unary_expression<Expr, Arg> &expr)
- {
- context<boost::tuple<Arg> > ctx(kernel, boost::make_tuple(expr.m_arg));
- proto::eval(expr.m_expr, ctx);
- return kernel;
- }
- template<class Expr, class Arg1, class Arg2>
- struct invoked_binary_expression
- {
- typedef typename ::boost::compute::result_of<Expr(Arg1, Arg2)>::type result_type;
- invoked_binary_expression(const Expr &expr,
- const Arg1 &arg1,
- const Arg2 &arg2)
- : m_expr(expr),
- m_arg1(arg1),
- m_arg2(arg2)
- {
- }
- Expr m_expr;
- Arg1 m_arg1;
- Arg2 m_arg2;
- };
- template<class Expr, class Arg1, class Arg2>
- boost::compute::detail::meta_kernel&
- operator<<(boost::compute::detail::meta_kernel &kernel,
- const invoked_binary_expression<Expr, Arg1, Arg2> &expr)
- {
- context<boost::tuple<Arg1, Arg2> > ctx(
- kernel,
- boost::make_tuple(expr.m_arg1, expr.m_arg2)
- );
- proto::eval(expr.m_expr, ctx);
- return kernel;
- }
- } // end detail namespace
- // forward declare domain
- struct domain;
- // lambda expression wrapper
- template<class Expr>
- struct expression : proto::extends<Expr, expression<Expr>, domain>
- {
- typedef proto::extends<Expr, expression<Expr>, domain> base_type;
- BOOST_PROTO_EXTENDS_USING_ASSIGN(expression)
- expression(const Expr &expr = Expr())
- : base_type(expr)
- {
- }
- // result_of protocol
- template<class Signature>
- struct result
- {
- };
- template<class This>
- struct result<This()>
- {
- typedef
- typename ::boost::compute::lambda::result_of<Expr>::type type;
- };
- template<class This, class Arg>
- struct result<This(Arg)>
- {
- typedef
- typename ::boost::compute::lambda::result_of<
- Expr,
- typename boost::tuple<Arg>
- >::type type;
- };
- template<class This, class Arg1, class Arg2>
- struct result<This(Arg1, Arg2)>
- {
- typedef typename
- ::boost::compute::lambda::result_of<
- Expr,
- typename boost::tuple<Arg1, Arg2>
- >::type type;
- };
- template<class Arg>
- detail::invoked_unary_expression<expression<Expr>, Arg>
- operator()(const Arg &x) const
- {
- return detail::invoked_unary_expression<expression<Expr>, Arg>(*this, x);
- }
- template<class Arg1, class Arg2>
- detail::invoked_binary_expression<expression<Expr>, Arg1, Arg2>
- operator()(const Arg1 &x, const Arg2 &y) const
- {
- return detail::invoked_binary_expression<
- expression<Expr>,
- Arg1,
- Arg2
- >(*this, x, y);
- }
- // function<> conversion operator
- template<class R, class A1>
- operator function<R(A1)>() const
- {
- using ::boost::compute::detail::meta_kernel;
- std::stringstream source;
- ::boost::compute::detail::meta_kernel_variable<A1> arg1("x");
- source << "inline " << type_name<R>() << " lambda"
- << ::boost::compute::detail::generate_argument_list<R(A1)>('x')
- << "{\n"
- << " return " << meta_kernel::expr_to_string((*this)(arg1)) << ";\n"
- << "}\n";
- return make_function_from_source<R(A1)>("lambda", source.str());
- }
- template<class R, class A1, class A2>
- operator function<R(A1, A2)>() const
- {
- using ::boost::compute::detail::meta_kernel;
- std::stringstream source;
- ::boost::compute::detail::meta_kernel_variable<A1> arg1("x");
- ::boost::compute::detail::meta_kernel_variable<A1> arg2("y");
- source << "inline " << type_name<R>() << " lambda"
- << ::boost::compute::detail::generate_argument_list<R(A1, A2)>('x')
- << "{\n"
- << " return " << meta_kernel::expr_to_string((*this)(arg1, arg2)) << ";\n"
- << "}\n";
- return make_function_from_source<R(A1, A2)>("lambda", source.str());
- }
- };
- // lambda expression domain
- struct domain : proto::domain<proto::generator<expression> >
- {
- };
- } // end lambda namespace
- } // end compute namespace
- } // end boost namespace
- #endif // BOOST_COMPUTE_LAMBDA_CONTEXT_HPP
|