File indexing completed on 2025-01-18 09:30:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_COMPUTE_FUNCTION_HPP
0012 #define BOOST_COMPUTE_FUNCTION_HPP
0013
0014 #include <map>
0015 #include <string>
0016 #include <sstream>
0017 #include <vector>
0018
0019 #include <boost/assert.hpp>
0020 #include <boost/config.hpp>
0021 #include <boost/function_types/parameter_types.hpp>
0022 #include <boost/preprocessor/repetition.hpp>
0023 #include <boost/mpl/for_each.hpp>
0024 #include <boost/mpl/size.hpp>
0025 #include <boost/mpl/transform.hpp>
0026 #include <boost/static_assert.hpp>
0027 #include <boost/tuple/tuple.hpp>
0028 #include <boost/type_traits/add_pointer.hpp>
0029 #include <boost/type_traits/function_traits.hpp>
0030
0031 #include <boost/compute/cl.hpp>
0032 #include <boost/compute/config.hpp>
0033 #include <boost/compute/type_traits/type_name.hpp>
0034
0035 namespace boost {
0036 namespace compute {
0037 namespace detail {
0038
0039 template<class ResultType, class ArgTuple>
0040 class invoked_function
0041 {
0042 public:
0043 typedef ResultType result_type;
0044
0045 BOOST_STATIC_CONSTANT(
0046 size_t, arity = boost::tuples::length<ArgTuple>::value
0047 );
0048
0049 invoked_function(const std::string &name,
0050 const std::string &source)
0051 : m_name(name),
0052 m_source(source)
0053 {
0054 }
0055
0056 invoked_function(const std::string &name,
0057 const std::string &source,
0058 const std::map<std::string, std::string> &definitions)
0059 : m_name(name),
0060 m_source(source),
0061 m_definitions(definitions)
0062 {
0063 }
0064
0065 invoked_function(const std::string &name,
0066 const std::string &source,
0067 const ArgTuple &args)
0068 : m_name(name),
0069 m_source(source),
0070 m_args(args)
0071 {
0072 }
0073
0074 invoked_function(const std::string &name,
0075 const std::string &source,
0076 const std::map<std::string, std::string> &definitions,
0077 const ArgTuple &args)
0078 : m_name(name),
0079 m_source(source),
0080 m_definitions(definitions),
0081 m_args(args)
0082 {
0083 }
0084
0085 std::string name() const
0086 {
0087 return m_name;
0088 }
0089
0090 std::string source() const
0091 {
0092 return m_source;
0093 }
0094
0095 const std::map<std::string, std::string>& definitions() const
0096 {
0097 return m_definitions;
0098 }
0099
0100 const ArgTuple& args() const
0101 {
0102 return m_args;
0103 }
0104
0105 private:
0106 std::string m_name;
0107 std::string m_source;
0108 std::map<std::string, std::string> m_definitions;
0109 ArgTuple m_args;
0110 };
0111
0112 }
0113
0114
0115
0116 template<class Signature>
0117 class function
0118 {
0119 public:
0120
0121 typedef typename
0122 boost::function_traits<Signature>::result_type result_type;
0123
0124
0125 BOOST_STATIC_CONSTANT(
0126 size_t, arity = boost::function_traits<Signature>::arity
0127 );
0128
0129
0130 typedef Signature signature;
0131
0132
0133 function(const std::string &name)
0134 : m_name(name)
0135 {
0136 }
0137
0138
0139 ~function()
0140 {
0141 }
0142
0143
0144 std::string name() const
0145 {
0146 return m_name;
0147 }
0148
0149
0150 void set_source(const std::string &source)
0151 {
0152 m_source = source;
0153 }
0154
0155
0156 std::string source() const
0157 {
0158 return m_source;
0159 }
0160
0161
0162 void define(std::string name, std::string value = std::string())
0163 {
0164 m_definitions[name] = value;
0165 }
0166
0167 bool operator==(const function<Signature>& other) const
0168 {
0169 return
0170 (m_name == other.m_name)
0171 && (m_definitions == other.m_definitions)
0172 && (m_source == other.m_source);
0173 }
0174
0175 bool operator!=(const function<Signature>& other) const
0176 {
0177 return !(*this == other);
0178 }
0179
0180
0181 detail::invoked_function<result_type, boost::tuple<> >
0182 operator()() const
0183 {
0184 BOOST_STATIC_ASSERT_MSG(
0185 arity == 0,
0186 "Non-nullary function invoked with zero arguments"
0187 );
0188
0189 return detail::invoked_function<result_type, boost::tuple<> >(
0190 m_name, m_source, m_definitions
0191 );
0192 }
0193
0194
0195 template<class Arg1>
0196 detail::invoked_function<result_type, boost::tuple<Arg1> >
0197 operator()(const Arg1 &arg1) const
0198 {
0199 BOOST_STATIC_ASSERT_MSG(
0200 arity == 1,
0201 "Non-unary function invoked one argument"
0202 );
0203
0204 return detail::invoked_function<result_type, boost::tuple<Arg1> >(
0205 m_name, m_source, m_definitions, boost::make_tuple(arg1)
0206 );
0207 }
0208
0209
0210 template<class Arg1, class Arg2>
0211 detail::invoked_function<result_type, boost::tuple<Arg1, Arg2> >
0212 operator()(const Arg1 &arg1, const Arg2 &arg2) const
0213 {
0214 BOOST_STATIC_ASSERT_MSG(
0215 arity == 2,
0216 "Non-binary function invoked with two arguments"
0217 );
0218
0219 return detail::invoked_function<result_type, boost::tuple<Arg1, Arg2> >(
0220 m_name, m_source, m_definitions, boost::make_tuple(arg1, arg2)
0221 );
0222 }
0223
0224
0225 template<class Arg1, class Arg2, class Arg3>
0226 detail::invoked_function<result_type, boost::tuple<Arg1, Arg2, Arg3> >
0227 operator()(const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) const
0228 {
0229 BOOST_STATIC_ASSERT_MSG(
0230 arity == 3,
0231 "Non-ternary function invoked with three arguments"
0232 );
0233
0234 return detail::invoked_function<result_type, boost::tuple<Arg1, Arg2, Arg3> >(
0235 m_name, m_source, m_definitions, boost::make_tuple(arg1, arg2, arg3)
0236 );
0237 }
0238
0239 private:
0240 std::string m_name;
0241 std::string m_source;
0242 std::map<std::string, std::string> m_definitions;
0243 };
0244
0245
0246
0247
0248
0249
0250
0251 template<class Signature>
0252 inline function<Signature>
0253 make_function_from_source(const std::string &name, const std::string &source)
0254 {
0255 function<Signature> f(name);
0256 f.set_source(source);
0257 return f;
0258 }
0259
0260 namespace detail {
0261
0262
0263
0264
0265 inline std::vector<std::string> parse_argument_names(const char *arguments)
0266 {
0267 BOOST_ASSERT_MSG(
0268 arguments[0] == '(' && arguments[std::strlen(arguments)-1] == ')',
0269 "Arguments should start and end with parentheses"
0270 );
0271
0272 std::vector<std::string> args;
0273
0274 size_t last_space = 0;
0275 size_t skip_comma = 0;
0276 for(size_t i = 1; i < std::strlen(arguments) - 2; i++){
0277 const char c = arguments[i];
0278
0279 if(c == ' '){
0280 last_space = i;
0281 }
0282 else if(c == ',' && !skip_comma){
0283 std::string name(
0284 arguments + last_space + 1, i - last_space - 1
0285 );
0286 args.push_back(name);
0287 }
0288 else if(c == '<'){
0289 skip_comma++;
0290 }
0291 else if(c == '>'){
0292 skip_comma--;
0293 }
0294 }
0295
0296 std::string last_argument(
0297 arguments + last_space + 1, std::strlen(arguments) - last_space - 2
0298 );
0299 args.push_back(last_argument);
0300
0301 return args;
0302 }
0303
0304 struct signature_argument_inserter
0305 {
0306 signature_argument_inserter(std::stringstream &s_, const char *arguments, size_t last)
0307 : s(s_)
0308 {
0309 n = 0;
0310 m_last = last;
0311
0312 m_argument_names = parse_argument_names(arguments);
0313
0314 BOOST_ASSERT_MSG(
0315 m_argument_names.size() == last,
0316 "Wrong number of arguments"
0317 );
0318 }
0319
0320 template<class T>
0321 void operator()(const T*)
0322 {
0323 s << type_name<T>() << " " << m_argument_names[n];
0324 if(n+1 < m_last){
0325 s << ", ";
0326 }
0327 n++;
0328 }
0329
0330 size_t n;
0331 size_t m_last;
0332 std::stringstream &s;
0333 std::vector<std::string> m_argument_names;
0334 };
0335
0336 template<class Signature>
0337 inline std::string make_function_declaration(const char *name, const char *arguments)
0338 {
0339 typedef typename
0340 boost::function_traits<Signature>::result_type result_type;
0341 typedef typename
0342 boost::function_types::parameter_types<Signature>::type parameter_types;
0343 typedef typename
0344 mpl::size<parameter_types>::type arity_type;
0345
0346 std::stringstream s;
0347 s << "inline " << type_name<result_type>() << " " << name;
0348 s << "(";
0349
0350 if(arity_type::value > 0){
0351 signature_argument_inserter i(s, arguments, arity_type::value);
0352 mpl::for_each<
0353 typename mpl::transform<parameter_types, boost::add_pointer<mpl::_1>
0354 >::type>(i);
0355 }
0356
0357 s << ")";
0358 return s.str();
0359 }
0360
0361 struct argument_list_inserter
0362 {
0363 argument_list_inserter(std::stringstream &s_, const char first, size_t last)
0364 : s(s_)
0365 {
0366 n = 0;
0367 m_last = last;
0368 m_name = first;
0369 }
0370
0371 template<class T>
0372 void operator()(const T*)
0373 {
0374 s << type_name<T>() << " " << m_name++;
0375 if(n+1 < m_last){
0376 s << ", ";
0377 }
0378 n++;
0379 }
0380
0381 size_t n;
0382 size_t m_last;
0383 char m_name;
0384 std::stringstream &s;
0385 };
0386
0387 template<class Signature>
0388 inline std::string generate_argument_list(const char first = 'a')
0389 {
0390 typedef typename
0391 boost::function_types::parameter_types<Signature>::type parameter_types;
0392 typedef typename
0393 mpl::size<parameter_types>::type arity_type;
0394
0395 std::stringstream s;
0396 s << '(';
0397
0398 if(arity_type::value > 0){
0399 argument_list_inserter i(s, first, arity_type::value);
0400 mpl::for_each<
0401 typename mpl::transform<parameter_types, boost::add_pointer<mpl::_1>
0402 >::type>(i);
0403 }
0404
0405 s << ')';
0406 return s.str();
0407 }
0408
0409
0410
0411 template<class Signature>
0412 inline function<Signature>
0413 make_function_impl(const char *name, const char *arguments, const char *source)
0414 {
0415 std::stringstream s;
0416 s << make_function_declaration<Signature>(name, arguments);
0417 s << source;
0418
0419 return make_function_from_source<Signature>(name, s.str());
0420 }
0421
0422 }
0423 }
0424 }
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457 #ifdef BOOST_COMPUTE_DOXYGEN_INVOKED
0458 #define BOOST_COMPUTE_FUNCTION(return_type, name, arguments, source)
0459 #else
0460 #define BOOST_COMPUTE_FUNCTION(return_type, name, arguments, ...) \
0461 ::boost::compute::function<return_type arguments> name = \
0462 ::boost::compute::detail::make_function_impl<return_type arguments>( \
0463 #name, #arguments, #__VA_ARGS__ \
0464 )
0465 #endif
0466
0467 #endif