5#ifndef __eigenpy_user_type_hpp__ 6#define __eigenpy_user_type_hpp__ 10#include "eigenpy/fwd.hpp" 11#include "eigenpy/numpy-type.hpp" 12#include "eigenpy/register.hpp" 17template <
typename From,
typename To>
19 static To run(
const From& from) {
20#pragma GCC diagnostic push 21#pragma GCC diagnostic ignored "-Wconversion" 22#pragma GCC diagnostic ignored "-Wfloat-conversion" 23 return static_cast<To
>(from);
24#pragma GCC diagnostic pop 30template <
typename From,
typename To>
31static void cast(
void* from_,
void* to_, npy_intp n,
void* ,
34 const From* from =
static_cast<From*
>(from_);
35 To* to =
static_cast<To*
>(to_);
36 for (npy_intp i = 0; i < n; i++) {
37 to[i] = eigenpy::cast<From, To>::run(from[i]);
53 static PyObject* run(
void* data,
void* ) {
55 T* elt_ptr =
static_cast<T*
>(data);
56 bp::object m(boost::ref(*elt_ptr));
62template <typename T, int type_code = NumpyEquivalentType<T>::type_code>
63struct SpecialMethods {
64 inline static void copyswap(
void* ,
void* ,
int ,
66 inline static PyObject* getitem(
void* ,
68 inline static int setitem(PyObject* ,
void* ,
70 inline static void copyswapn(
void* ,
long ,
void* ,
73 inline static npy_bool nonzero(
75 inline static void dotfunc(
void* , npy_intp ,
void* ,
76 npy_intp ,
void* , npy_intp ,
78 inline static int fill(
void* data_, npy_intp length,
void* arr);
79 inline static int fillwithscalar(
void* buffer_, npy_intp length,
void* value,
90 enum { value = offsetof(Data, v) };
94struct SpecialMethods<T, NPY_USERDEF> {
95 static void copyswap(
void* dst,
void* src,
int swap,
void* ) {
98 T& t1 = *
static_cast<T*
>(dst);
99 T& t2 = *
static_cast<T*
>(src);
104 T& t1 = *
static_cast<T*
>(dst);
105 T& t2 = *
static_cast<T*
>(src);
110 static PyObject* getitem(
void* ip,
void* ap) {
111 return eigenpy::internal::getitem<T>::run(ip, ap);
129 inline static int setitem(PyObject* src_obj,
void* dest_ptr,
void* array) {
132 eigenpy::Exception(
"Cannot retrieve the type stored in the array.");
136 PyArrayObject* py_array =
static_cast<PyArrayObject*
>(array);
137 PyArray_Descr* descr = PyArray_DTYPE(py_array);
138 PyTypeObject* array_scalar_type = descr->typeobj;
139 PyTypeObject* src_obj_type = Py_TYPE(src_obj);
141 T& dest = *
static_cast<T*
>(dest_ptr);
142 if (array_scalar_type != src_obj_type) {
143 long long src_value = PyLong_AsLongLong(src_obj);
144 if (src_value == -1 && PyErr_Occurred()) {
145 std::stringstream ss;
146 ss <<
"The input type is of wrong type. ";
147 ss <<
"The expected type is " << bp::type_info(
typeid(T)).name()
149 eigenpy::Exception(ss.str());
156 bp::extract<T&> extract_src_obj(src_obj);
157 if (!extract_src_obj.check()) {
158 std::cout <<
"if (!extract_src_obj.check())" << std::endl;
159 std::stringstream ss;
160 ss <<
"The input type is of wrong type. ";
161 ss <<
"The expected type is " << bp::type_info(
typeid(T)).name()
163 eigenpy::Exception(ss.str());
167 const T& src = extract_src_obj();
168 T& dest = *
static_cast<T*
>(dest_ptr);
175 inline static void copyswapn(
void* dst,
long dstride,
void* src,
long sstride,
176 long n,
int swap,
void* array) {
179 char* dstptr =
static_cast<char*
>(dst);
180 char* srcptr =
static_cast<char*
>(src);
182 PyArrayObject* py_array =
static_cast<PyArrayObject*
>(array);
183 PyArray_CopySwapFunc* copyswap =
184 PyDataType_GetArrFuncs(PyArray_DESCR(py_array))->copyswap;
186 for (npy_intp i = 0; i < n; i++) {
187 copyswap(dstptr, srcptr, swap, array);
193 inline static npy_bool nonzero(
void* ip,
void* array) {
195 static const T ZeroValue = T(0);
196 PyArrayObject* py_array =
static_cast<PyArrayObject*
>(array);
197 if (py_array == NULL || PyArray_ISBEHAVED_RO(py_array)) {
198 const T& value = *
static_cast<T*
>(ip);
199 return (npy_bool)(value != ZeroValue);
202 PyDataType_GetArrFuncs(PyArray_DESCR(py_array))
203 ->copyswap(&tmp_value, ip, PyArray_ISBYTESWAPPED(py_array), array);
204 return (npy_bool)(tmp_value != ZeroValue);
208 inline static void dotfunc(
void* ip0_, npy_intp is0,
void* ip1_, npy_intp is1,
209 void* op, npy_intp n,
void* ) {
211 typedef Eigen::Matrix<T, Eigen::Dynamic, 1> VectorT;
212 typedef Eigen::InnerStride<Eigen::Dynamic> InputStride;
213 typedef const Eigen::Map<const VectorT, 0, InputStride> ConstMapType;
215 ConstMapType v0(
static_cast<T*
>(ip0_), n,
216 InputStride(is0 / (Eigen::DenseIndex)
sizeof(T))),
217 v1(
static_cast<T*
>(ip1_), n,
218 InputStride(is1 / (Eigen::DenseIndex)
sizeof(T)));
220 *
static_cast<T*
>(op) = v0.dot(v1);
223 inline static int fillwithscalar(
void* buffer_, npy_intp length,
void* value,
226 T r = *
static_cast<T*
>(value);
227 T* buffer =
static_cast<T*
>(buffer_);
229 for (i = 0; i < length; i++) {
235 static int fill(
void* data_, npy_intp length,
void* ) {
237 T* data =
static_cast<T*
>(data_);
238 const T delta = data[1] - data[0];
241 for (i = 2; i < length; i++) {
252template <
typename From,
typename To>
253bool registerCast(
const bool safe) {
254 PyArray_Descr* from_array_descr = Register::getPyArrayDescr<From>();
258 int to_typenum = Register::getTypeCode<To>();
259 assert(to_typenum >= 0 &&
"to_typenum is not valid");
260 assert(from_array_descr != NULL &&
"from_array_descr is not valid");
269 if (call_PyArray_RegisterCastFunc(from_array_descr, to_typenum,
270 static_cast<PyArray_VectorUnaryFunc*
>(
271 &eigenpy::internal::cast<From, To>)) <
273 std::stringstream ss;
274 ss <<
"PyArray_RegisterCastFunc of the cast from " 275 << bp::type_info(
typeid(From)).name() <<
" to " 276 << bp::type_info(
typeid(To)).name() <<
" has failed.";
277 eigenpy::Exception(ss.str());
281 if (safe && call_PyArray_RegisterCanCast(from_array_descr, to_typenum,
283 std::stringstream ss;
284 ss <<
"PyArray_RegisterCanCast of the cast from " 285 << bp::type_info(
typeid(From)).name() <<
" to " 286 << bp::type_info(
typeid(To)).name() <<
" has failed.";
287 eigenpy::Exception(ss.str());
299 bp::type_info
type = bp::type_id<T>();
300 const bp::converter::registration* registration =
301 bp::converter::registry::query(
type);
309 bp::handle<PyTypeObject> handle(
310 bp::borrowed(registration->get_class_object()));
311 return bp::object(handle);
314template <
typename Scalar>
315int registerNewType(PyTypeObject* py_type_ptr = NULL) {
318 if (isNumpyNativeType<Scalar>())
319 return NumpyEquivalentType<Scalar>::type_code;
322 if (py_type_ptr == NULL) {
323 py_type_ptr = Register::getPyType<Scalar>();
326 if (Register::isRegistered(py_type_ptr))
327 return Register::getTypeCode(
330 PyArray_GetItemFunc* getitem = &internal::SpecialMethods<Scalar>::getitem;
331 PyArray_SetItemFunc* setitem = &internal::SpecialMethods<Scalar>::setitem;
332 PyArray_NonzeroFunc* nonzero = &internal::SpecialMethods<Scalar>::nonzero;
333 PyArray_CopySwapFunc* copyswap = &internal::SpecialMethods<Scalar>::copyswap;
334 PyArray_CopySwapNFunc* copyswapn =
reinterpret_cast<PyArray_CopySwapNFunc*
>(
335 &internal::SpecialMethods<Scalar>::copyswapn);
336 PyArray_DotFunc* dotfunc = &internal::SpecialMethods<Scalar>::dotfunc;
337 PyArray_FillFunc* fill = &internal::SpecialMethods<Scalar>::fill;
338 PyArray_FillWithScalarFunc* fillwithscalar =
339 &internal::SpecialMethods<Scalar>::fillwithscalar;
341 int code = Register::registerNewType(
342 py_type_ptr, &
typeid(Scalar),
sizeof(Scalar),
343 internal::OffsetOf<Scalar>::value, getitem, setitem, nonzero, copyswap,
344 copyswapn, dotfunc, fill, fillwithscalar);
346 call_PyArray_RegisterCanCast(call_PyArray_DescrFromType(NPY_OBJECT), code,
boost::python::object getInstanceClass()
Get the class object for a wrapped type that has been exposed through Boost.Python.
Default cast algo to cast a From to To. Can be specialized for any types.