174 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			174 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | //---------------------------------------------------------------------------// | ||
|  | // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> | ||
|  | // | ||
|  | // 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 <sstream> | ||
|  | 
 | ||
|  | #include <boost/static_assert.hpp> | ||
|  | 
 | ||
|  | #include <boost/preprocessor/expr_if.hpp> | ||
|  | #include <boost/preprocessor/stringize.hpp> | ||
|  | #include <boost/preprocessor/seq/fold_left.hpp> | ||
|  | #include <boost/preprocessor/seq/for_each.hpp> | ||
|  | #include <boost/preprocessor/seq/transform.hpp> | ||
|  | 
 | ||
|  | #include <boost/compute/type_traits/type_definition.hpp> | ||
|  | #include <boost/compute/type_traits/type_name.hpp> | ||
|  | #include <boost/compute/detail/meta_kernel.hpp> | ||
|  | #include <boost/compute/detail/variadic_macros.hpp> | ||
|  | 
 | ||
|  | namespace boost { | ||
|  | namespace compute { | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | template<class Struct, class T> | ||
|  | inline std::string adapt_struct_insert_member(T Struct::*, const char *name) | ||
|  | { | ||
|  |     std::stringstream s; | ||
|  |     s << "    " << type_name<T>() << " " << name << ";\n"; | ||
|  |     return s.str(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | template<class Struct, class T, int N> | ||
|  | inline std::string adapt_struct_insert_member(T (Struct::*)[N], const char *name) | ||
|  | { | ||
|  |     std::stringstream s; | ||
|  |     s << "    " << type_name<T>() << " " << 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<Particle> 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<type>() \ | ||
|  |     { \ | ||
|  |         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<type>() << ";\n"; \ | ||
|  |         return declaration.str(); \ | ||
|  |     } \ | ||
|  |     namespace detail { \ | ||
|  |     template<> \ | ||
|  |     struct inject_type_impl<type> \ | ||
|  |     { \ | ||
|  |         void operator()(meta_kernel &kernel) \ | ||
|  |         { \ | ||
|  |             kernel.add_type_declaration<type>(type_definition<type>()); \ | ||
|  |         } \ | ||
|  |     }; \ | ||
|  |     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 |