//---------------------------------------------------------------------------// // Copyright (c) 2013-2014 Kyle Lutz // // Distributed under the Boost Software License, Version 1.0 // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt // // See http://boostorg.github.com/compute for more information. //---------------------------------------------------------------------------// #ifndef BOOST_COMPUTE_TYPES_STRUCT_HPP #define BOOST_COMPUTE_TYPES_STRUCT_HPP #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace compute { namespace detail { template inline std::string adapt_struct_insert_member(T Struct::*, const char *name) { std::stringstream s; s << " " << type_name() << " " << name << ";\n"; return s.str(); } template inline std::string adapt_struct_insert_member(T (Struct::*)[N], const char *name) { std::stringstream s; s << " " << type_name() << " " << name << "[" << N << "]" << ";\n"; return s.str(); } } // end detail namespace } // end compute namespace } // end boost namespace /// \internal_ #define BOOST_COMPUTE_DETAIL_ADAPT_STRUCT_INSERT_MEMBER(r, type, member) \ << ::boost::compute::detail::adapt_struct_insert_member( \ &type::member, BOOST_PP_STRINGIZE(member) \ ) /// \internal_ #define BOOST_COMPUTE_DETAIL_ADAPT_STRUCT_STREAM_MEMBER(r, data, i, elem) \ BOOST_PP_EXPR_IF(i, << ", ") << data.elem /// \internal_ #define BOOST_COMPUTE_DETAIL_STRUCT_MEMBER_SIZE(s, struct_, member_) \ sizeof(((struct_ *)0)->member_) /// \internal_ #define BOOST_COMPUTE_DETAIL_STRUCT_MEMBER_SIZE_ADD(s, x, y) (x+y) /// \internal_ #define BOOST_COMPUTE_DETAIL_STRUCT_MEMBER_SIZE_SUM(struct_, members_) \ BOOST_PP_SEQ_FOLD_LEFT( \ BOOST_COMPUTE_DETAIL_STRUCT_MEMBER_SIZE_ADD, \ 0, \ BOOST_PP_SEQ_TRANSFORM( \ BOOST_COMPUTE_DETAIL_STRUCT_MEMBER_SIZE, struct_, members_ \ ) \ ) /// \internal_ /// /// Returns true if struct_ contains no internal padding bytes (i.e. it is /// packed). members_ is a sequence of the names of the struct members. #define BOOST_COMPUTE_DETAIL_STRUCT_IS_PACKED(struct_, members_) \ (sizeof(struct_) == BOOST_COMPUTE_DETAIL_STRUCT_MEMBER_SIZE_SUM(struct_, members_)) /// The BOOST_COMPUTE_ADAPT_STRUCT() macro makes a C++ struct/class available /// to OpenCL kernels. /// /// \param type The C++ type. /// \param name The OpenCL name. /// \param members A tuple of the struct's members. /// /// For example, to adapt a 2D particle struct with position (x, y) and /// velocity (dx, dy): /// \code /// // c++ struct definition /// struct Particle /// { /// float x, y; /// float dx, dy; /// }; /// /// // adapt struct for OpenCL /// BOOST_COMPUTE_ADAPT_STRUCT(Particle, Particle, (x, y, dx, dy)) /// \endcode /// /// After adapting the struct it can be used in Boost.Compute containers /// and with Boost.Compute algorithms: /// \code /// // create vector of particles /// boost::compute::vector particles = ... /// /// // function to compare particles by their x-coordinate /// BOOST_COMPUTE_FUNCTION(bool, sort_by_x, (Particle a, Particle b), /// { /// return a.x < b.x; /// }); /// /// // sort particles by their x-coordinate /// boost::compute::sort( /// particles.begin(), particles.end(), sort_by_x, queue /// ); /// \endcode /// /// Due to differences in struct padding between the host compiler and the /// device compiler, the \c BOOST_COMPUTE_ADAPT_STRUCT() macro requires that /// the adapted struct is packed (i.e. no padding bytes between members). /// /// \see type_name() #define BOOST_COMPUTE_ADAPT_STRUCT(type, name, members) \ BOOST_STATIC_ASSERT_MSG( \ BOOST_COMPUTE_DETAIL_STRUCT_IS_PACKED(type, BOOST_COMPUTE_PP_TUPLE_TO_SEQ(members)), \ "BOOST_COMPUTE_ADAPT_STRUCT() does not support structs with internal padding." \ ); \ BOOST_COMPUTE_TYPE_NAME(type, name) \ namespace boost { namespace compute { \ template<> \ inline std::string type_definition() \ { \ std::stringstream declaration; \ declaration << "typedef struct __attribute__((packed)) {\n" \ BOOST_PP_SEQ_FOR_EACH( \ BOOST_COMPUTE_DETAIL_ADAPT_STRUCT_INSERT_MEMBER, \ type, \ BOOST_COMPUTE_PP_TUPLE_TO_SEQ(members) \ ) \ << "} " << type_name() << ";\n"; \ return declaration.str(); \ } \ namespace detail { \ template<> \ struct inject_type_impl \ { \ void operator()(meta_kernel &kernel) \ { \ kernel.add_type_declaration(type_definition()); \ } \ }; \ inline meta_kernel& operator<<(meta_kernel &k, type s) \ { \ return k << "(" << #name << "){" \ BOOST_PP_SEQ_FOR_EACH_I( \ BOOST_COMPUTE_DETAIL_ADAPT_STRUCT_STREAM_MEMBER, \ s, \ BOOST_COMPUTE_PP_TUPLE_TO_SEQ(members) \ ) \ << "}"; \ } \ }}} #endif // BOOST_COMPUTE_TYPES_STRUCT_HPP