Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:02

0001 //---------------------------------------------------------------------------//
0002 // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
0003 //
0004 // Distributed under the Boost Software License, Version 1.0
0005 // See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt
0007 //
0008 // See http://boostorg.github.com/compute for more information.
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 // lambda expression context
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     // create a lambda context for kernel with args
0067     context(boost::compute::detail::meta_kernel &kernel, const Args &args_)
0068         : stream(kernel),
0069           args(args_)
0070     {
0071     }
0072 
0073     // handle terminals
0074     template<class T>
0075     void operator()(proto::tag::terminal, const T &x)
0076     {
0077         // terminal values in lambda expressions are always literals
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     // handle placeholders
0117     template<int I>
0118     void operator()(proto::tag::terminal, placeholder<I>)
0119     {
0120         stream << boost::get<I>(args);
0121     }
0122 
0123     // handle functions
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     // operators
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     // subscript operator
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     // ternary conditional operator
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 } // end detail namespace
0248 
0249 // forward declare domain
0250 struct domain;
0251 
0252 // lambda expression wrapper
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     // result_of protocol
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     // function<> conversion operator
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 // lambda expression domain
0356 struct domain : proto::domain<proto::generator<expression> >
0357 {
0358 };
0359 
0360 } // end lambda namespace
0361 } // end compute namespace
0362 } // end boost namespace
0363 
0364 #endif // BOOST_COMPUTE_LAMBDA_CONTEXT_HPP