EVOLUTION-MANAGER
Edit File: context.hpp
//---------------------------------------------------------------------------// // 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