struct.hpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. // See http://boostorg.github.com/compute for more information.
  9. //---------------------------------------------------------------------------//
  10. #ifndef BOOST_COMPUTE_TYPES_STRUCT_HPP
  11. #define BOOST_COMPUTE_TYPES_STRUCT_HPP
  12. #include <sstream>
  13. #include <boost/static_assert.hpp>
  14. #include <boost/preprocessor/expr_if.hpp>
  15. #include <boost/preprocessor/stringize.hpp>
  16. #include <boost/preprocessor/seq/fold_left.hpp>
  17. #include <boost/preprocessor/seq/for_each.hpp>
  18. #include <boost/preprocessor/seq/transform.hpp>
  19. #include <boost/compute/type_traits/type_definition.hpp>
  20. #include <boost/compute/type_traits/type_name.hpp>
  21. #include <boost/compute/detail/meta_kernel.hpp>
  22. #include <boost/compute/detail/variadic_macros.hpp>
  23. namespace boost {
  24. namespace compute {
  25. namespace detail {
  26. template<class Struct, class T>
  27. inline std::string adapt_struct_insert_member(T Struct::*, const char *name)
  28. {
  29. std::stringstream s;
  30. s << " " << type_name<T>() << " " << name << ";\n";
  31. return s.str();
  32. }
  33. template<class Struct, class T, int N>
  34. inline std::string adapt_struct_insert_member(T (Struct::*)[N], const char *name)
  35. {
  36. std::stringstream s;
  37. s << " " << type_name<T>() << " " << name << "[" << N << "]" << ";\n";
  38. return s.str();
  39. }
  40. } // end detail namespace
  41. } // end compute namespace
  42. } // end boost namespace
  43. /// \internal_
  44. #define BOOST_COMPUTE_DETAIL_ADAPT_STRUCT_INSERT_MEMBER(r, type, member) \
  45. << ::boost::compute::detail::adapt_struct_insert_member( \
  46. &type::member, BOOST_PP_STRINGIZE(member) \
  47. )
  48. /// \internal_
  49. #define BOOST_COMPUTE_DETAIL_ADAPT_STRUCT_STREAM_MEMBER(r, data, i, elem) \
  50. BOOST_PP_EXPR_IF(i, << ", ") << data.elem
  51. /// \internal_
  52. #define BOOST_COMPUTE_DETAIL_STRUCT_MEMBER_SIZE(s, struct_, member_) \
  53. sizeof(((struct_ *)0)->member_)
  54. /// \internal_
  55. #define BOOST_COMPUTE_DETAIL_STRUCT_MEMBER_SIZE_ADD(s, x, y) (x+y)
  56. /// \internal_
  57. #define BOOST_COMPUTE_DETAIL_STRUCT_MEMBER_SIZE_SUM(struct_, members_) \
  58. BOOST_PP_SEQ_FOLD_LEFT( \
  59. BOOST_COMPUTE_DETAIL_STRUCT_MEMBER_SIZE_ADD, \
  60. 0, \
  61. BOOST_PP_SEQ_TRANSFORM( \
  62. BOOST_COMPUTE_DETAIL_STRUCT_MEMBER_SIZE, struct_, members_ \
  63. ) \
  64. )
  65. /// \internal_
  66. ///
  67. /// Returns true if struct_ contains no internal padding bytes (i.e. it is
  68. /// packed). members_ is a sequence of the names of the struct members.
  69. #define BOOST_COMPUTE_DETAIL_STRUCT_IS_PACKED(struct_, members_) \
  70. (sizeof(struct_) == BOOST_COMPUTE_DETAIL_STRUCT_MEMBER_SIZE_SUM(struct_, members_))
  71. /// The BOOST_COMPUTE_ADAPT_STRUCT() macro makes a C++ struct/class available
  72. /// to OpenCL kernels.
  73. ///
  74. /// \param type The C++ type.
  75. /// \param name The OpenCL name.
  76. /// \param members A tuple of the struct's members.
  77. ///
  78. /// For example, to adapt a 2D particle struct with position (x, y) and
  79. /// velocity (dx, dy):
  80. /// \code
  81. /// // c++ struct definition
  82. /// struct Particle
  83. /// {
  84. /// float x, y;
  85. /// float dx, dy;
  86. /// };
  87. ///
  88. /// // adapt struct for OpenCL
  89. /// BOOST_COMPUTE_ADAPT_STRUCT(Particle, Particle, (x, y, dx, dy))
  90. /// \endcode
  91. ///
  92. /// After adapting the struct it can be used in Boost.Compute containers
  93. /// and with Boost.Compute algorithms:
  94. /// \code
  95. /// // create vector of particles
  96. /// boost::compute::vector<Particle> particles = ...
  97. ///
  98. /// // function to compare particles by their x-coordinate
  99. /// BOOST_COMPUTE_FUNCTION(bool, sort_by_x, (Particle a, Particle b),
  100. /// {
  101. /// return a.x < b.x;
  102. /// });
  103. ///
  104. /// // sort particles by their x-coordinate
  105. /// boost::compute::sort(
  106. /// particles.begin(), particles.end(), sort_by_x, queue
  107. /// );
  108. /// \endcode
  109. ///
  110. /// Due to differences in struct padding between the host compiler and the
  111. /// device compiler, the \c BOOST_COMPUTE_ADAPT_STRUCT() macro requires that
  112. /// the adapted struct is packed (i.e. no padding bytes between members).
  113. ///
  114. /// \see type_name()
  115. #define BOOST_COMPUTE_ADAPT_STRUCT(type, name, members) \
  116. BOOST_STATIC_ASSERT_MSG( \
  117. BOOST_COMPUTE_DETAIL_STRUCT_IS_PACKED(type, BOOST_COMPUTE_PP_TUPLE_TO_SEQ(members)), \
  118. "BOOST_COMPUTE_ADAPT_STRUCT() does not support structs with internal padding." \
  119. ); \
  120. BOOST_COMPUTE_TYPE_NAME(type, name) \
  121. namespace boost { namespace compute { \
  122. template<> \
  123. inline std::string type_definition<type>() \
  124. { \
  125. std::stringstream declaration; \
  126. declaration << "typedef struct __attribute__((packed)) {\n" \
  127. BOOST_PP_SEQ_FOR_EACH( \
  128. BOOST_COMPUTE_DETAIL_ADAPT_STRUCT_INSERT_MEMBER, \
  129. type, \
  130. BOOST_COMPUTE_PP_TUPLE_TO_SEQ(members) \
  131. ) \
  132. << "} " << type_name<type>() << ";\n"; \
  133. return declaration.str(); \
  134. } \
  135. namespace detail { \
  136. template<> \
  137. struct inject_type_impl<type> \
  138. { \
  139. void operator()(meta_kernel &kernel) \
  140. { \
  141. kernel.add_type_declaration<type>(type_definition<type>()); \
  142. } \
  143. }; \
  144. inline meta_kernel& operator<<(meta_kernel &k, type s) \
  145. { \
  146. return k << "(" << #name << "){" \
  147. BOOST_PP_SEQ_FOR_EACH_I( \
  148. BOOST_COMPUTE_DETAIL_ADAPT_STRUCT_STREAM_MEMBER, \
  149. s, \
  150. BOOST_COMPUTE_PP_TUPLE_TO_SEQ(members) \
  151. ) \
  152. << "}"; \
  153. } \
  154. }}}
  155. #endif // BOOST_COMPUTE_TYPES_STRUCT_HPP