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
|