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