Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //---------------------------------------------------------------------------//
0002 // Copyright (c) 2013-2014 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_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 } // end detail namespace
0094 
0095 /// \internal_
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     /// \internal_
0126     std::string source() const
0127     {
0128         return m_source;
0129     }
0130 
0131     /// \internal_
0132     void define(std::string name, std::string value = std::string())
0133     {
0134         m_definitions[name] = value;
0135     }
0136 
0137     /// \internal_
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     /// \internal_
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     /// \internal_
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     /// \internal_
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         // get captured variable name
0228         std::string variable_name = m_capture_names[n];
0229 
0230         // remove leading and trailing whitespace from variable name
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     // insert function arguments
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     // insert capture arguments
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 // used by the BOOST_COMPUTE_CLOSURE() macro to create a closure
0282 // function with the given signature, name, capture, and source.
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 } // end detail namespace
0299 } // end compute namespace
0300 } // end boost namespace
0301 
0302 /// Creates a closure function object with \p name and \p source.
0303 ///
0304 /// \param return_type The return type for the function.
0305 /// \param name The name of the function.
0306 /// \param arguments A list of arguments for the function.
0307 /// \param capture A list of variables to capture.
0308 /// \param source The OpenCL C source code for the function.
0309 ///
0310 /// For example, to create a function which checks if a 2D point is
0311 /// contained in a circle of a given radius:
0312 /// \code
0313 /// // radius variable declared in C++
0314 /// float radius = 1.5f;
0315 ///
0316 /// // create a closure function which returns true if the 2D point
0317 /// // argument is contained within a circle of the given radius
0318 /// BOOST_COMPUTE_CLOSURE(bool, is_in_circle, (const float2_ p), (radius),
0319 /// {
0320 ///     return sqrt(p.x*p.x + p.y*p.y) < radius;
0321 /// });
0322 ///
0323 /// // vector of 2D points
0324 /// boost::compute::vector<float2_> points = ...
0325 ///
0326 /// // count number of points in the circle
0327 /// size_t count = boost::compute::count_if(
0328 ///     points.begin(), points.end(), is_in_circle, queue
0329 /// );
0330 /// \endcode
0331 ///
0332 /// \see BOOST_COMPUTE_FUNCTION()
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 // BOOST_COMPUTE_CLOSURE_HPP