170 lines
5.2 KiB
C++
170 lines
5.2 KiB
C++
/*
|
|
* Copyright 2023 INRIA
|
|
*/
|
|
|
|
#ifndef __eigenpy_alignment_hpp__
|
|
#define __eigenpy_alignment_hpp__
|
|
|
|
#include <boost/python/detail/referent_storage.hpp>
|
|
#include <boost/python/converter/arg_from_python.hpp>
|
|
#include <boost/python/converter/rvalue_from_python_data.hpp>
|
|
#include <boost/type_traits/aligned_storage.hpp>
|
|
#include <eigenpy/utils/is-aligned.hpp>
|
|
|
|
namespace eigenpy {
|
|
|
|
template <std::size_t size, std::size_t alignment = EIGENPY_DEFAULT_ALIGN_BYTES>
|
|
struct aligned_storage {
|
|
union type {
|
|
typename ::boost::aligned_storage<size, alignment>::type data;
|
|
char bytes[size];
|
|
};
|
|
};
|
|
|
|
template <class Data>
|
|
struct aligned_instance {
|
|
PyObject_VAR_HEAD PyObject *dict;
|
|
PyObject *weakrefs;
|
|
boost::python::instance_holder *objects;
|
|
|
|
typename aligned_storage<sizeof(Data)>::type storage;
|
|
};
|
|
|
|
inline void *aligned_malloc(
|
|
std::size_t size, std::size_t alignment = EIGENPY_DEFAULT_ALIGN_BYTES) {
|
|
void *original = std::malloc(size + alignment);
|
|
if (original == 0) return 0;
|
|
if (is_aligned(original, alignment)) return original;
|
|
void *aligned =
|
|
reinterpret_cast<void *>((reinterpret_cast<std::size_t>(original) &
|
|
~(std::size_t(alignment - 1))) +
|
|
alignment);
|
|
*(reinterpret_cast<void **>(aligned) - 1) = original;
|
|
return aligned;
|
|
}
|
|
|
|
} // namespace eigenpy
|
|
|
|
namespace boost {
|
|
namespace python {
|
|
namespace detail {
|
|
|
|
template <typename Scalar, int Rows, int Cols, int Options, int MaxRows,
|
|
int MaxCols>
|
|
struct referent_storage<
|
|
Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> &> {
|
|
typedef Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> T;
|
|
typedef
|
|
typename eigenpy::aligned_storage<referent_size<T &>::value>::type type;
|
|
};
|
|
|
|
template <typename Scalar, int Rows, int Cols, int Options, int MaxRows,
|
|
int MaxCols>
|
|
struct referent_storage<
|
|
const Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> &> {
|
|
typedef Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> T;
|
|
typedef
|
|
typename eigenpy::aligned_storage<referent_size<T &>::value>::type type;
|
|
};
|
|
|
|
#ifdef EIGENPY_WITH_TENSOR_SUPPORT
|
|
template <typename Scalar, int Rank, int Options, typename IndexType>
|
|
struct referent_storage<Eigen::Tensor<Scalar, Rank, Options, IndexType> &> {
|
|
typedef Eigen::Tensor<Scalar, Rank, Options, IndexType> T;
|
|
typedef
|
|
typename eigenpy::aligned_storage<referent_size<T &>::value>::type type;
|
|
};
|
|
|
|
template <typename Scalar, int Rank, int Options, typename IndexType>
|
|
struct referent_storage<
|
|
const Eigen::Tensor<Scalar, Rank, Options, IndexType> &> {
|
|
typedef Eigen::Tensor<Scalar, Rank, Options, IndexType> T;
|
|
typedef
|
|
typename eigenpy::aligned_storage<referent_size<T &>::value>::type type;
|
|
};
|
|
#endif
|
|
|
|
template <typename Scalar, int Options>
|
|
struct referent_storage<Eigen::Quaternion<Scalar, Options> &> {
|
|
typedef Eigen::Quaternion<Scalar, Options> T;
|
|
typedef
|
|
typename eigenpy::aligned_storage<referent_size<T &>::value>::type type;
|
|
};
|
|
|
|
template <typename Scalar, int Options>
|
|
struct referent_storage<const Eigen::Quaternion<Scalar, Options> &> {
|
|
typedef Eigen::Quaternion<Scalar, Options> T;
|
|
typedef
|
|
typename eigenpy::aligned_storage<referent_size<T &>::value>::type type;
|
|
};
|
|
|
|
} // namespace detail
|
|
} // namespace python
|
|
} // namespace boost
|
|
|
|
namespace boost {
|
|
namespace python {
|
|
namespace objects {
|
|
|
|
// Force alignment of instance with value_holder
|
|
template <typename Derived>
|
|
struct instance<value_holder<Derived> >
|
|
: ::eigenpy::aligned_instance<value_holder<Derived> > {};
|
|
|
|
} // namespace objects
|
|
} // namespace python
|
|
} // namespace boost
|
|
|
|
namespace eigenpy {
|
|
|
|
template <class T>
|
|
struct call_destructor {
|
|
static void run(void *bytes) {
|
|
typedef typename boost::remove_const<
|
|
typename boost::remove_reference<T>::type>::type T_;
|
|
static_cast<T_ *>((void *)bytes)->~T_();
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
struct rvalue_from_python_data
|
|
: ::boost::python::converter::rvalue_from_python_storage<T> {
|
|
#if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) && \
|
|
(!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) && \
|
|
(!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) && \
|
|
!defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing \
|
|
this */
|
|
// This must always be a POD struct with m_data its first member.
|
|
BOOST_STATIC_ASSERT(
|
|
BOOST_PYTHON_OFFSETOF(
|
|
::boost::python::converter::rvalue_from_python_storage<T>, stage1) ==
|
|
0);
|
|
#endif
|
|
|
|
// The usual constructor
|
|
rvalue_from_python_data(
|
|
::boost::python::converter::rvalue_from_python_stage1_data const
|
|
&_stage1) {
|
|
this->stage1 = _stage1;
|
|
}
|
|
|
|
// This constructor just sets m_convertible -- used by
|
|
// implicitly_convertible<> to perform the final step of the
|
|
// conversion, where the construct() function is already known.
|
|
rvalue_from_python_data(void *convertible) {
|
|
this->stage1.convertible = convertible;
|
|
}
|
|
|
|
// Destroys any object constructed in the storage.
|
|
~rvalue_from_python_data() {
|
|
if (this->stage1.convertible == this->storage.bytes) {
|
|
void *storage = reinterpret_cast<void *>(this->storage.bytes);
|
|
call_destructor<T>::run(storage);
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace eigenpy
|
|
|
|
#endif // __eigenpy_alignment_hpp__
|