File indexing completed on 2025-01-18 09:30:02
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_COMPUTE_LAMBDA_CONTEXT_HPP
0012 #define BOOST_COMPUTE_LAMBDA_CONTEXT_HPP
0013
0014 #include <boost/proto/core.hpp>
0015 #include <boost/proto/context.hpp>
0016 #include <boost/type_traits.hpp>
0017 #include <boost/preprocessor/repetition.hpp>
0018
0019 #include <boost/compute/config.hpp>
0020 #include <boost/compute/function.hpp>
0021 #include <boost/compute/lambda/result_of.hpp>
0022 #include <boost/compute/lambda/functional.hpp>
0023 #include <boost/compute/type_traits/result_of.hpp>
0024 #include <boost/compute/type_traits/type_name.hpp>
0025 #include <boost/compute/detail/meta_kernel.hpp>
0026
0027 namespace boost {
0028 namespace compute {
0029 namespace lambda {
0030
0031 namespace mpl = boost::mpl;
0032 namespace proto = boost::proto;
0033
0034 #define BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(tag, op) \
0035 template<class LHS, class RHS> \
0036 void operator()(tag, const LHS &lhs, const RHS &rhs) \
0037 { \
0038 if(proto::arity_of<LHS>::value > 0){ \
0039 stream << '('; \
0040 proto::eval(lhs, *this); \
0041 stream << ')'; \
0042 } \
0043 else { \
0044 proto::eval(lhs, *this); \
0045 } \
0046 \
0047 stream << op; \
0048 \
0049 if(proto::arity_of<RHS>::value > 0){ \
0050 stream << '('; \
0051 proto::eval(rhs, *this); \
0052 stream << ')'; \
0053 } \
0054 else { \
0055 proto::eval(rhs, *this); \
0056 } \
0057 }
0058
0059
0060 template<class Args>
0061 struct context : proto::callable_context<context<Args> >
0062 {
0063 typedef void result_type;
0064 typedef Args args_tuple;
0065
0066
0067 context(boost::compute::detail::meta_kernel &kernel, const Args &args_)
0068 : stream(kernel),
0069 args(args_)
0070 {
0071 }
0072
0073
0074 template<class T>
0075 void operator()(proto::tag::terminal, const T &x)
0076 {
0077
0078 stream << stream.lit(x);
0079 }
0080
0081 void operator()(proto::tag::terminal, const uchar_ &x)
0082 {
0083 stream << "(uchar)(" << stream.lit(uint_(x)) << "u)";
0084 }
0085
0086 void operator()(proto::tag::terminal, const char_ &x)
0087 {
0088 stream << "(char)(" << stream.lit(int_(x)) << ")";
0089 }
0090
0091 void operator()(proto::tag::terminal, const ushort_ &x)
0092 {
0093 stream << "(ushort)(" << stream.lit(x) << "u)";
0094 }
0095
0096 void operator()(proto::tag::terminal, const short_ &x)
0097 {
0098 stream << "(short)(" << stream.lit(x) << ")";
0099 }
0100
0101 void operator()(proto::tag::terminal, const uint_ &x)
0102 {
0103 stream << "(" << stream.lit(x) << "u)";
0104 }
0105
0106 void operator()(proto::tag::terminal, const ulong_ &x)
0107 {
0108 stream << "(" << stream.lit(x) << "ul)";
0109 }
0110
0111 void operator()(proto::tag::terminal, const long_ &x)
0112 {
0113 stream << "(" << stream.lit(x) << "l)";
0114 }
0115
0116
0117 template<int I>
0118 void operator()(proto::tag::terminal, placeholder<I>)
0119 {
0120 stream << boost::get<I>(args);
0121 }
0122
0123
0124 #define BOOST_COMPUTE_LAMBDA_CONTEXT_FUNCTION_ARG(z, n, unused) \
0125 BOOST_PP_COMMA_IF(n) BOOST_PP_CAT(const Arg, n) BOOST_PP_CAT(&arg, n)
0126
0127 #define BOOST_COMPUTE_LAMBDA_CONTEXT_FUNCTION(z, n, unused) \
0128 template<class F, BOOST_PP_ENUM_PARAMS(n, class Arg)> \
0129 void operator()( \
0130 proto::tag::function, \
0131 const F &function, \
0132 BOOST_PP_REPEAT(n, BOOST_COMPUTE_LAMBDA_CONTEXT_FUNCTION_ARG, ~) \
0133 ) \
0134 { \
0135 proto::value(function).apply(*this, BOOST_PP_ENUM_PARAMS(n, arg)); \
0136 }
0137
0138 BOOST_PP_REPEAT_FROM_TO(1, BOOST_COMPUTE_MAX_ARITY, BOOST_COMPUTE_LAMBDA_CONTEXT_FUNCTION, ~)
0139
0140 #undef BOOST_COMPUTE_LAMBDA_CONTEXT_FUNCTION
0141
0142
0143 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::plus, '+')
0144 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::minus, '-')
0145 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::multiplies, '*')
0146 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::divides, '/')
0147 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::modulus, '%')
0148 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::less, '<')
0149 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::greater, '>')
0150 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::less_equal, "<=")
0151 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::greater_equal, ">=")
0152 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::equal_to, "==")
0153 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::not_equal_to, "!=")
0154 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::logical_and, "&&")
0155 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::logical_or, "||")
0156 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::bitwise_and, '&')
0157 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::bitwise_or, '|')
0158 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::bitwise_xor, '^')
0159 BOOST_COMPUTE_LAMBDA_CONTEXT_DEFINE_BINARY_OPERATOR(proto::tag::assign, '=')
0160
0161
0162 template<class LHS, class RHS>
0163 void operator()(proto::tag::subscript, const LHS &lhs, const RHS &rhs)
0164 {
0165 proto::eval(lhs, *this);
0166 stream << '[';
0167 proto::eval(rhs, *this);
0168 stream << ']';
0169 }
0170
0171
0172 template<class Pred, class Arg1, class Arg2>
0173 void operator()(proto::tag::if_else_, const Pred &p, const Arg1 &x, const Arg2 &y)
0174 {
0175 proto::eval(p, *this);
0176 stream << '?';
0177 proto::eval(x, *this);
0178 stream << ':';
0179 proto::eval(y, *this);
0180 }
0181
0182 boost::compute::detail::meta_kernel &stream;
0183 Args args;
0184 };
0185
0186 namespace detail {
0187
0188 template<class Expr, class Arg>
0189 struct invoked_unary_expression
0190 {
0191 typedef typename ::boost::compute::result_of<Expr(Arg)>::type result_type;
0192
0193 invoked_unary_expression(const Expr &expr, const Arg &arg)
0194 : m_expr(expr),
0195 m_arg(arg)
0196 {
0197 }
0198
0199 Expr m_expr;
0200 Arg m_arg;
0201 };
0202
0203 template<class Expr, class Arg>
0204 boost::compute::detail::meta_kernel&
0205 operator<<(boost::compute::detail::meta_kernel &kernel,
0206 const invoked_unary_expression<Expr, Arg> &expr)
0207 {
0208 context<boost::tuple<Arg> > ctx(kernel, boost::make_tuple(expr.m_arg));
0209 proto::eval(expr.m_expr, ctx);
0210
0211 return kernel;
0212 }
0213
0214 template<class Expr, class Arg1, class Arg2>
0215 struct invoked_binary_expression
0216 {
0217 typedef typename ::boost::compute::result_of<Expr(Arg1, Arg2)>::type result_type;
0218
0219 invoked_binary_expression(const Expr &expr,
0220 const Arg1 &arg1,
0221 const Arg2 &arg2)
0222 : m_expr(expr),
0223 m_arg1(arg1),
0224 m_arg2(arg2)
0225 {
0226 }
0227
0228 Expr m_expr;
0229 Arg1 m_arg1;
0230 Arg2 m_arg2;
0231 };
0232
0233 template<class Expr, class Arg1, class Arg2>
0234 boost::compute::detail::meta_kernel&
0235 operator<<(boost::compute::detail::meta_kernel &kernel,
0236 const invoked_binary_expression<Expr, Arg1, Arg2> &expr)
0237 {
0238 context<boost::tuple<Arg1, Arg2> > ctx(
0239 kernel,
0240 boost::make_tuple(expr.m_arg1, expr.m_arg2)
0241 );
0242 proto::eval(expr.m_expr, ctx);
0243
0244 return kernel;
0245 }
0246
0247 }
0248
0249
0250 struct domain;
0251
0252
0253 template<class Expr>
0254 struct expression : proto::extends<Expr, expression<Expr>, domain>
0255 {
0256 typedef proto::extends<Expr, expression<Expr>, domain> base_type;
0257
0258 BOOST_PROTO_EXTENDS_USING_ASSIGN(expression)
0259
0260 expression(const Expr &expr = Expr())
0261 : base_type(expr)
0262 {
0263 }
0264
0265
0266 template<class Signature>
0267 struct result
0268 {
0269 };
0270
0271 template<class This>
0272 struct result<This()>
0273 {
0274 typedef
0275 typename ::boost::compute::lambda::result_of<Expr>::type type;
0276 };
0277
0278 template<class This, class Arg>
0279 struct result<This(Arg)>
0280 {
0281 typedef
0282 typename ::boost::compute::lambda::result_of<
0283 Expr,
0284 typename boost::tuple<Arg>
0285 >::type type;
0286 };
0287
0288 template<class This, class Arg1, class Arg2>
0289 struct result<This(Arg1, Arg2)>
0290 {
0291 typedef typename
0292 ::boost::compute::lambda::result_of<
0293 Expr,
0294 typename boost::tuple<Arg1, Arg2>
0295 >::type type;
0296 };
0297
0298 template<class Arg>
0299 detail::invoked_unary_expression<expression<Expr>, Arg>
0300 operator()(const Arg &x) const
0301 {
0302 return detail::invoked_unary_expression<expression<Expr>, Arg>(*this, x);
0303 }
0304
0305 template<class Arg1, class Arg2>
0306 detail::invoked_binary_expression<expression<Expr>, Arg1, Arg2>
0307 operator()(const Arg1 &x, const Arg2 &y) const
0308 {
0309 return detail::invoked_binary_expression<
0310 expression<Expr>,
0311 Arg1,
0312 Arg2
0313 >(*this, x, y);
0314 }
0315
0316
0317 template<class R, class A1>
0318 operator function<R(A1)>() const
0319 {
0320 using ::boost::compute::detail::meta_kernel;
0321
0322 std::stringstream source;
0323
0324 ::boost::compute::detail::meta_kernel_variable<A1> arg1("x");
0325
0326 source << "inline " << type_name<R>() << " lambda"
0327 << ::boost::compute::detail::generate_argument_list<R(A1)>('x')
0328 << "{\n"
0329 << " return " << meta_kernel::expr_to_string((*this)(arg1)) << ";\n"
0330 << "}\n";
0331
0332 return make_function_from_source<R(A1)>("lambda", source.str());
0333 }
0334
0335 template<class R, class A1, class A2>
0336 operator function<R(A1, A2)>() const
0337 {
0338 using ::boost::compute::detail::meta_kernel;
0339
0340 std::stringstream source;
0341
0342 ::boost::compute::detail::meta_kernel_variable<A1> arg1("x");
0343 ::boost::compute::detail::meta_kernel_variable<A1> arg2("y");
0344
0345 source << "inline " << type_name<R>() << " lambda"
0346 << ::boost::compute::detail::generate_argument_list<R(A1, A2)>('x')
0347 << "{\n"
0348 << " return " << meta_kernel::expr_to_string((*this)(arg1, arg2)) << ";\n"
0349 << "}\n";
0350
0351 return make_function_from_source<R(A1, A2)>("lambda", source.str());
0352 }
0353 };
0354
0355
0356 struct domain : proto::domain<proto::generator<expression> >
0357 {
0358 };
0359
0360 }
0361 }
0362 }
0363
0364 #endif