File indexing completed on 2025-01-18 09:30:04
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_COMPUTE_CLOSURE_HPP
0012 #define BOOST_COMPUTE_CLOSURE_HPP
0013
0014 #include <string>
0015 #include <sstream>
0016
0017 #include <boost/config.hpp>
0018 #include <boost/fusion/adapted/boost_tuple.hpp>
0019 #include <boost/fusion/algorithm/iteration/for_each.hpp>
0020 #include <boost/mpl/for_each.hpp>
0021 #include <boost/mpl/transform.hpp>
0022 #include <boost/typeof/typeof.hpp>
0023 #include <boost/static_assert.hpp>
0024 #include <boost/algorithm/string.hpp>
0025 #include <boost/tuple/tuple.hpp>
0026 #include <boost/type_traits/function_traits.hpp>
0027
0028 #include <boost/compute/cl.hpp>
0029 #include <boost/compute/function.hpp>
0030 #include <boost/compute/type_traits/type_name.hpp>
0031 #include <boost/compute/type_traits/detail/capture_traits.hpp>
0032
0033 namespace boost {
0034 namespace compute {
0035 namespace detail {
0036
0037 template<class ResultType, class ArgTuple, class CaptureTuple>
0038 class invoked_closure
0039 {
0040 public:
0041 typedef ResultType result_type;
0042
0043 BOOST_STATIC_CONSTANT(
0044 size_t, arity = boost::tuples::length<ArgTuple>::value
0045 );
0046
0047 invoked_closure(const std::string &name,
0048 const std::string &source,
0049 const std::map<std::string, std::string> &definitions,
0050 const ArgTuple &args,
0051 const CaptureTuple &capture)
0052 : m_name(name),
0053 m_source(source),
0054 m_definitions(definitions),
0055 m_args(args),
0056 m_capture(capture)
0057 {
0058 }
0059
0060 std::string name() const
0061 {
0062 return m_name;
0063 }
0064
0065 std::string source() const
0066 {
0067 return m_source;
0068 }
0069
0070 const std::map<std::string, std::string>& definitions() const
0071 {
0072 return m_definitions;
0073 }
0074
0075 const ArgTuple& args() const
0076 {
0077 return m_args;
0078 }
0079
0080 const CaptureTuple& capture() const
0081 {
0082 return m_capture;
0083 }
0084
0085 private:
0086 std::string m_name;
0087 std::string m_source;
0088 std::map<std::string, std::string> m_definitions;
0089 ArgTuple m_args;
0090 CaptureTuple m_capture;
0091 };
0092
0093 }
0094
0095
0096 template<class Signature, class CaptureTuple>
0097 class closure
0098 {
0099 public:
0100 typedef typename
0101 boost::function_traits<Signature>::result_type result_type;
0102
0103 BOOST_STATIC_CONSTANT(
0104 size_t, arity = boost::function_traits<Signature>::arity
0105 );
0106
0107 closure(const std::string &name,
0108 const CaptureTuple &capture,
0109 const std::string &source)
0110 : m_name(name),
0111 m_source(source),
0112 m_capture(capture)
0113 {
0114 }
0115
0116 ~closure()
0117 {
0118 }
0119
0120 std::string name() const
0121 {
0122 return m_name;
0123 }
0124
0125
0126 std::string source() const
0127 {
0128 return m_source;
0129 }
0130
0131
0132 void define(std::string name, std::string value = std::string())
0133 {
0134 m_definitions[name] = value;
0135 }
0136
0137
0138 detail::invoked_closure<result_type, boost::tuple<>, CaptureTuple>
0139 operator()() const
0140 {
0141 BOOST_STATIC_ASSERT_MSG(
0142 arity == 0,
0143 "Non-nullary closure function invoked with zero arguments"
0144 );
0145
0146 return detail::invoked_closure<result_type, boost::tuple<>, CaptureTuple>(
0147 m_name, m_source, m_definitions, boost::make_tuple(), m_capture
0148 );
0149 }
0150
0151
0152 template<class Arg1>
0153 detail::invoked_closure<result_type, boost::tuple<Arg1>, CaptureTuple>
0154 operator()(const Arg1 &arg1) const
0155 {
0156 BOOST_STATIC_ASSERT_MSG(
0157 arity == 1,
0158 "Non-unary closure function invoked with one argument"
0159 );
0160
0161 return detail::invoked_closure<result_type, boost::tuple<Arg1>, CaptureTuple>(
0162 m_name, m_source, m_definitions, boost::make_tuple(arg1), m_capture
0163 );
0164 }
0165
0166
0167 template<class Arg1, class Arg2>
0168 detail::invoked_closure<result_type, boost::tuple<Arg1, Arg2>, CaptureTuple>
0169 operator()(const Arg1 &arg1, const Arg2 &arg2) const
0170 {
0171 BOOST_STATIC_ASSERT_MSG(
0172 arity == 2,
0173 "Non-binary closure function invoked with two arguments"
0174 );
0175
0176 return detail::invoked_closure<result_type, boost::tuple<Arg1, Arg2>, CaptureTuple>(
0177 m_name, m_source, m_definitions, boost::make_tuple(arg1, arg2), m_capture
0178 );
0179 }
0180
0181
0182 template<class Arg1, class Arg2, class Arg3>
0183 detail::invoked_closure<result_type, boost::tuple<Arg1, Arg2, Arg3>, CaptureTuple>
0184 operator()(const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) const
0185 {
0186 BOOST_STATIC_ASSERT_MSG(
0187 arity == 3,
0188 "Non-ternary closure function invoked with three arguments"
0189 );
0190
0191 return detail::invoked_closure<result_type, boost::tuple<Arg1, Arg2, Arg3>, CaptureTuple>(
0192 m_name, m_source, m_definitions, boost::make_tuple(arg1, arg2, arg3), m_capture
0193 );
0194 }
0195
0196 private:
0197 std::string m_name;
0198 std::string m_source;
0199 std::map<std::string, std::string> m_definitions;
0200 CaptureTuple m_capture;
0201 };
0202
0203 namespace detail {
0204
0205 struct closure_signature_argument_inserter
0206 {
0207 closure_signature_argument_inserter(std::stringstream &s_,
0208 const char *capture_string,
0209 size_t last)
0210 : s(s_)
0211 {
0212 n = 0;
0213 m_last = last;
0214
0215 size_t capture_string_length = std::strlen(capture_string);
0216 BOOST_ASSERT(capture_string[0] == '(' &&
0217 capture_string[capture_string_length-1] == ')');
0218 std::string capture_string_(capture_string + 1, capture_string_length - 2);
0219 boost::split(m_capture_names, capture_string_ , boost::is_any_of(","));
0220 }
0221
0222 template<class T>
0223 void operator()(const T&) const
0224 {
0225 BOOST_ASSERT(n < m_capture_names.size());
0226
0227
0228 std::string variable_name = m_capture_names[n];
0229
0230
0231 boost::trim(variable_name);
0232
0233 s << capture_traits<T>::type_name() << " " << variable_name;
0234 if(n+1 < m_last){
0235 s << ", ";
0236 }
0237 n++;
0238 }
0239
0240 mutable size_t n;
0241 size_t m_last;
0242 std::vector<std::string> m_capture_names;
0243 std::stringstream &s;
0244 };
0245
0246 template<class Signature, class CaptureTuple>
0247 inline std::string
0248 make_closure_declaration(const char *name,
0249 const char *arguments,
0250 const CaptureTuple &capture_tuple,
0251 const char *capture_string)
0252 {
0253 typedef typename
0254 boost::function_traits<Signature>::result_type result_type;
0255 typedef typename
0256 boost::function_types::parameter_types<Signature>::type parameter_types;
0257 typedef typename
0258 mpl::size<parameter_types>::type arity_type;
0259
0260 std::stringstream s;
0261 s << "inline " << type_name<result_type>() << " " << name;
0262 s << "(";
0263
0264
0265 signature_argument_inserter i(s, arguments, arity_type::value);
0266 mpl::for_each<
0267 typename mpl::transform<parameter_types, boost::add_pointer<mpl::_1>
0268 >::type>(i);
0269 s << ", ";
0270
0271
0272 closure_signature_argument_inserter j(
0273 s, capture_string, boost::tuples::length<CaptureTuple>::value
0274 );
0275 fusion::for_each(capture_tuple, j);
0276
0277 s << ")";
0278 return s.str();
0279 }
0280
0281
0282
0283 template<class Signature, class CaptureTuple>
0284 inline closure<Signature, CaptureTuple>
0285 make_closure_impl(const char *name,
0286 const char *arguments,
0287 const CaptureTuple &capture,
0288 const char *capture_string,
0289 const std::string &source)
0290 {
0291 std::stringstream s;
0292 s << make_closure_declaration<Signature>(name, arguments, capture, capture_string);
0293 s << source;
0294
0295 return closure<Signature, CaptureTuple>(name, capture, s.str());
0296 }
0297
0298 }
0299 }
0300 }
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333 #ifdef BOOST_COMPUTE_DOXYGEN_INVOKED
0334 #define BOOST_COMPUTE_CLOSURE(return_type, name, arguments, capture, source)
0335 #else
0336 #define BOOST_COMPUTE_CLOSURE(return_type, name, arguments, capture, ...) \
0337 ::boost::compute::closure< \
0338 return_type arguments, BOOST_TYPEOF(boost::tie capture) \
0339 > name = \
0340 ::boost::compute::detail::make_closure_impl< \
0341 return_type arguments \
0342 >( \
0343 #name, #arguments, boost::tie capture, #capture, #__VA_ARGS__ \
0344 )
0345 #endif
0346
0347 #endif