123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- //---------------------------------------------------------------------------//
- // 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
|