1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
11 #ifndef BOOST_COMPUTE_CLOSURE_HPP
12 #define BOOST_COMPUTE_CLOSURE_HPP
17 #include <boost/config.hpp>
18 #include <boost/fusion/adapted/boost_tuple.hpp>
19 #include <boost/fusion/algorithm/iteration/for_each.hpp>
20 #include <boost/mpl/for_each.hpp>
21 #include <boost/mpl/transform.hpp>
22 #include <boost/typeof/typeof.hpp>
23 #include <boost/static_assert.hpp>
24 #include <boost/algorithm/string.hpp>
25 #include <boost/tuple/tuple.hpp>
26 #include <boost/type_traits/function_traits.hpp>
28 #include <boost/compute/cl.hpp>
29 #include <boost/compute/function.hpp>
30 #include <boost/compute/type_traits/type_name.hpp>
31 #include <boost/compute/type_traits/detail/capture_traits.hpp>
37 template<class ResultType, class ArgTuple, class CaptureTuple>
41 typedef ResultType result_type;
43 BOOST_STATIC_CONSTANT(
44 size_t, arity = boost::tuples::length<ArgTuple>::value
47 invoked_closure(const std::string &name,
48 const std::string &source,
49 const std::map<std::string, std::string> &definitions,
51 const CaptureTuple &capture)
54 m_definitions(definitions),
60 std::string name() const
65 std::string source() const
70 const std::map<std::string, std::string>& definitions() const
75 const ArgTuple& args() const
80 const CaptureTuple& capture() const
88 std::map<std::string, std::string> m_definitions;
90 CaptureTuple m_capture;
93 } // end detail namespace
96 template<class Signature, class CaptureTuple>
101 boost::function_traits<Signature>::result_type result_type;
103 BOOST_STATIC_CONSTANT(
104 size_t, arity = boost::function_traits<Signature>::arity
107 closure(const std::string &name,
108 const CaptureTuple &capture,
109 const std::string &source)
120 std::string name() const
126 std::string source() const
132 void define(std::string name, std::string value = std::string())
134 m_definitions[name] = value;
138 detail::invoked_closure<result_type, boost::tuple<>, CaptureTuple>
141 BOOST_STATIC_ASSERT_MSG(
143 "Non-nullary closure function invoked with zero arguments"
146 return detail::invoked_closure<result_type, boost::tuple<>, CaptureTuple>(
147 m_name, m_source, m_definitions, boost::make_tuple(), m_capture
153 detail::invoked_closure<result_type, boost::tuple<Arg1>, CaptureTuple>
154 operator()(const Arg1 &arg1) const
156 BOOST_STATIC_ASSERT_MSG(
158 "Non-unary closure function invoked with one argument"
161 return detail::invoked_closure<result_type, boost::tuple<Arg1>, CaptureTuple>(
162 m_name, m_source, m_definitions, boost::make_tuple(arg1), m_capture
167 template<class Arg1, class Arg2>
168 detail::invoked_closure<result_type, boost::tuple<Arg1, Arg2>, CaptureTuple>
169 operator()(const Arg1 &arg1, const Arg2 &arg2) const
171 BOOST_STATIC_ASSERT_MSG(
173 "Non-binary closure function invoked with two arguments"
176 return detail::invoked_closure<result_type, boost::tuple<Arg1, Arg2>, CaptureTuple>(
177 m_name, m_source, m_definitions, boost::make_tuple(arg1, arg2), m_capture
182 template<class Arg1, class Arg2, class Arg3>
183 detail::invoked_closure<result_type, boost::tuple<Arg1, Arg2, Arg3>, CaptureTuple>
184 operator()(const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) const
186 BOOST_STATIC_ASSERT_MSG(
188 "Non-ternary closure function invoked with three arguments"
191 return detail::invoked_closure<result_type, boost::tuple<Arg1, Arg2, Arg3>, CaptureTuple>(
192 m_name, m_source, m_definitions, boost::make_tuple(arg1, arg2, arg3), m_capture
198 std::string m_source;
199 std::map<std::string, std::string> m_definitions;
200 CaptureTuple m_capture;
205 struct closure_signature_argument_inserter
207 closure_signature_argument_inserter(std::stringstream &s_,
208 const char *capture_string,
215 size_t capture_string_length = std::strlen(capture_string);
216 BOOST_ASSERT(capture_string[0] == '(' &&
217 capture_string[capture_string_length-1] == ')');
218 std::string capture_string_(capture_string + 1, capture_string_length - 2);
219 boost::split(m_capture_names, capture_string_ , boost::is_any_of(","));
223 void operator()(const T&) const
225 BOOST_ASSERT(n < m_capture_names.size());
227 // get captured variable name
228 std::string variable_name = m_capture_names[n];
230 // remove leading and trailing whitespace from variable name
231 boost::trim(variable_name);
233 s << capture_traits<T>::type_name() << " " << variable_name;
242 std::vector<std::string> m_capture_names;
243 std::stringstream &s;
246 template<class Signature, class CaptureTuple>
248 make_closure_declaration(const char *name,
249 const char *arguments,
250 const CaptureTuple &capture_tuple,
251 const char *capture_string)
254 boost::function_traits<Signature>::result_type result_type;
256 boost::function_types::parameter_types<Signature>::type parameter_types;
258 mpl::size<parameter_types>::type arity_type;
261 s << "inline " << type_name<result_type>() << " " << name;
264 // insert function arguments
265 signature_argument_inserter i(s, arguments, arity_type::value);
267 typename mpl::transform<parameter_types, boost::add_pointer<mpl::_1>
271 // insert capture arguments
272 closure_signature_argument_inserter j(
273 s, capture_string, boost::tuples::length<CaptureTuple>::value
275 fusion::for_each(capture_tuple, j);
281 // used by the BOOST_COMPUTE_CLOSURE() macro to create a closure
282 // function with the given signature, name, capture, and source.
283 template<class Signature, class CaptureTuple>
284 inline closure<Signature, CaptureTuple>
285 make_closure_impl(const char *name,
286 const char *arguments,
287 const CaptureTuple &capture,
288 const char *capture_string,
289 const std::string &source)
292 s << make_closure_declaration<Signature>(name, arguments, capture, capture_string);
295 return closure<Signature, CaptureTuple>(name, capture, s.str());
298 } // end detail namespace
299 } // end compute namespace
300 } // end boost namespace
302 /// Creates a closure function object with \p name and \p source.
304 /// \param return_type The return type for the function.
305 /// \param name The name of the function.
306 /// \param arguments A list of arguments for the function.
307 /// \param capture A list of variables to capture.
308 /// \param source The OpenCL C source code for the function.
310 /// For example, to create a function which checks if a 2D point is
311 /// contained in a circle of a given radius:
313 /// // radius variable declared in C++
314 /// float radius = 1.5f;
316 /// // create a closure function which returns true if the 2D point
317 /// // argument is contained within a circle of the given radius
318 /// BOOST_COMPUTE_CLOSURE(bool, is_in_circle, (const float2_ p), (radius),
320 /// return sqrt(p.x*p.x + p.y*p.y) < radius;
323 /// // vector of 2D points
324 /// boost::compute::vector<float2_> points = ...
326 /// // count number of points in the circle
327 /// size_t count = boost::compute::count_if(
328 /// points.begin(), points.end(), is_in_circle, queue
332 /// \see BOOST_COMPUTE_FUNCTION()
333 #ifdef BOOST_COMPUTE_DOXYGEN_INVOKED
334 #define BOOST_COMPUTE_CLOSURE(return_type, name, arguments, capture, source)
336 #define BOOST_COMPUTE_CLOSURE(return_type, name, arguments, capture, ...) \
337 ::boost::compute::closure< \
338 return_type arguments, BOOST_TYPEOF(boost::tie capture) \
340 ::boost::compute::detail::make_closure_impl< \
341 return_type arguments \
343 #name, #arguments, boost::tie capture, #capture, #__VA_ARGS__ \
347 #endif // BOOST_COMPUTE_CLOSURE_HPP