Back to home page

EIC code displayed by LXR

 
 

    


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

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_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 } // end detail namespace
0113 
0114 /// \class function
0115 /// \brief A function object.
0116 template<class Signature>
0117 class function
0118 {
0119 public:
0120     /// \internal_
0121     typedef typename
0122         boost::function_traits<Signature>::result_type result_type;
0123 
0124     /// \internal_
0125     BOOST_STATIC_CONSTANT(
0126         size_t, arity = boost::function_traits<Signature>::arity
0127     );
0128 
0129     /// \internal_
0130     typedef Signature signature;
0131 
0132     /// Creates a new function object with \p name.
0133     function(const std::string &name)
0134         : m_name(name)
0135     {
0136     }
0137 
0138     /// Destroys the function object.
0139     ~function()
0140     {
0141     }
0142 
0143     /// \internal_
0144     std::string name() const
0145     {
0146         return m_name;
0147     }
0148 
0149     /// \internal_
0150     void set_source(const std::string &source)
0151     {
0152         m_source = source;
0153     }
0154 
0155     /// \internal_
0156     std::string source() const
0157     {
0158         return m_source;
0159     }
0160 
0161     /// \internal_
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     /// \internal_
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     /// \internal_
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     /// \internal_
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     /// \internal_
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 /// Creates a function object given its \p name and \p source.
0246 ///
0247 /// \param name The function name.
0248 /// \param source The function source code.
0249 ///
0250 /// \see BOOST_COMPUTE_FUNCTION()
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 // given a string containing the arguments declaration for a function
0263 // like: "(int a, const float b)", returns a vector containing the name
0264 // of each argument (e.g. ["a", "b"]).
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 // used by the BOOST_COMPUTE_FUNCTION() macro to create a function
0410 // with the given signature, name, arguments, and source.
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 } // end detail namespace
0423 } // end compute namespace
0424 } // end boost namespace
0425 
0426 /// Creates a function object with \p name and \p source.
0427 ///
0428 /// \param return_type The return type for the function.
0429 /// \param name The name of the function.
0430 /// \param arguments A list of arguments for the function.
0431 /// \param source The OpenCL C source code for the function.
0432 ///
0433 /// The function declaration and signature are automatically created using
0434 /// the \p return_type, \p name, and \p arguments macro parameters.
0435 ///
0436 /// The source code for the function is interpreted as OpenCL C99 source code
0437 /// which is stringified and passed to the OpenCL compiler when the function
0438 /// is invoked.
0439 ///
0440 /// For example, to create a function which squares a number:
0441 /// \code
0442 /// BOOST_COMPUTE_FUNCTION(float, square, (float x),
0443 /// {
0444 ///     return x * x;
0445 /// });
0446 /// \endcode
0447 ///
0448 /// And to create a function which sums two numbers:
0449 /// \code
0450 /// BOOST_COMPUTE_FUNCTION(int, sum_two, (int x, int y),
0451 /// {
0452 ///     return x + y;
0453 /// });
0454 /// \endcode
0455 ///
0456 /// \see BOOST_COMPUTE_CLOSURE()
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 // BOOST_COMPUTE_FUNCTION_HPP