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
 | 
