user-type.hpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2020-2022 INRIA
3 //
4 
5 #ifndef __eigenpy_user_type_hpp__
6 #define __eigenpy_user_type_hpp__
7 
8 #include <iostream>
9 
10 #include "eigenpy/fwd.hpp"
11 #include "eigenpy/numpy-type.hpp"
12 #include "eigenpy/register.hpp"
13 
14 namespace eigenpy {
17 template <typename From, typename To>
18 struct cast {
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
25  }
26 };
27 
28 namespace internal {
29 
30 template <typename From, typename To>
31 static void cast(void* from_, void* to_, npy_intp n, void* /*fromarr*/,
32  void* /*toarr*/) {
33  // std::cout << "cast::run" << std::endl;
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]);
38  }
39 }
40 
41 template <typename T>
42 struct getitem {
53  static PyObject* run(void* data, void* /* arr */) {
54  // std::cout << "getitem" << std::endl;
55  T* elt_ptr = static_cast<T*>(data);
56  bp::object m(boost::ref(*elt_ptr));
57  Py_INCREF(m.ptr());
58  return m.ptr();
59  }
60 };
61 
62 template <typename T, int type_code = NumpyEquivalentType<T>::type_code>
64  inline static void copyswap(void* /*dst*/, void* /*src*/, int /*swap*/,
65  void* /*arr*/) /*{}*/;
66  inline static PyObject* getitem(void* /*ip*/,
67  void* /*ap*/) /*{ return NULL; }*/;
68  inline static int setitem(PyObject* /*op*/, void* /*ov*/,
69  void* /*ap*/) /*{ return -1; }*/;
70  inline static void copyswapn(void* /*dest*/, long /*dstride*/, void* /*src*/,
71  long /*sstride*/, long /*n*/, int /*swap*/,
72  void* /*arr*/) /*{}*/;
73  inline static npy_bool nonzero(
74  void* /*ip*/, void* /*array*/) /*{ return (npy_bool)false; }*/;
75  inline static void dotfunc(void* /*ip0_*/, npy_intp /*is0*/, void* /*ip1_*/,
76  npy_intp /*is1*/, void* /*op*/, npy_intp /*n*/,
77  void* /*arr*/);
78  inline static int fill(void* data_, npy_intp length, void* arr);
79  inline static int fillwithscalar(void* buffer_, npy_intp length, void* value,
80  void* arr);
81 };
82 
83 template <typename T>
84 struct OffsetOf {
85  struct Data {
86  char c;
87  T v;
88  };
89 
90  enum { value = offsetof(Data, v) };
91 };
92 
93 template <typename T>
94 struct SpecialMethods<T, NPY_USERDEF> {
95  static void copyswap(void* dst, void* src, int swap, void* /*arr*/) {
96  // std::cout << "copyswap" << std::endl;
97  if (src != NULL) {
98  T& t1 = *static_cast<T*>(dst);
99  T& t2 = *static_cast<T*>(src);
100  t1 = t2;
101  }
102 
103  if (swap) {
104  T& t1 = *static_cast<T*>(dst);
105  T& t2 = *static_cast<T*>(src);
106  std::swap(t1, t2);
107  }
108  }
109 
110  static PyObject* getitem(void* ip, void* ap) {
111  return eigenpy::internal::getitem<T>::run(ip, ap);
112  }
113 
120 
128 
129  inline static int setitem(PyObject* src_obj, void* dest_ptr, void* array) {
130  // std::cout << "setitem" << std::endl;
131  if (array == NULL) {
132  eigenpy::Exception("Cannot retrieve the type stored in the array.");
133  return -1;
134  }
135  PyArrayObject* py_array = static_cast<PyArrayObject*>(array);
136  PyArray_Descr* descr = PyArray_DTYPE(py_array);
137  PyTypeObject* array_scalar_type = descr->typeobj;
138  PyTypeObject* src_obj_type = Py_TYPE(src_obj);
139 
140  if (array_scalar_type != src_obj_type) {
141  std::stringstream ss;
142  ss << "The input type is of wrong type. ";
143  ss << "The expected type is " << bp::type_info(typeid(T)).name()
144  << std::endl;
145  eigenpy::Exception(ss.str());
146  return -1;
147  }
148 
149  bp::extract<T&> extract_src_obj(src_obj);
150  if (!extract_src_obj.check()) {
151  std::stringstream ss;
152  ss << "The input type is of wrong type. ";
153  ss << "The expected type is " << bp::type_info(typeid(T)).name()
154  << std::endl;
155  eigenpy::Exception(ss.str());
156  return -1;
157  }
158 
159  const T& src = extract_src_obj();
160  T& dest = *static_cast<T*>(dest_ptr);
161  dest = src;
162 
163  return 0;
164  }
165 
166  inline static void copyswapn(void* dst, long dstride, void* src, long sstride,
167  long n, int swap, void* array) {
168  // std::cout << "copyswapn" << std::endl;
169 
170  char* dstptr = static_cast<char*>(dst);
171  char* srcptr = static_cast<char*>(src);
172 
173  PyArrayObject* py_array = static_cast<PyArrayObject*>(array);
174  PyArray_CopySwapFunc* copyswap =
175  PyDataType_GetArrFuncs(PyArray_DESCR(py_array))->copyswap;
176 
177  for (npy_intp i = 0; i < n; i++) {
178  copyswap(dstptr, srcptr, swap, array);
179  dstptr += dstride;
180  srcptr += sstride;
181  }
182  }
183 
184  inline static npy_bool nonzero(void* ip, void* array) {
185  // std::cout << "nonzero" << std::endl;
186  static const T ZeroValue = T(0);
187  PyArrayObject* py_array = static_cast<PyArrayObject*>(array);
188  if (py_array == NULL || PyArray_ISBEHAVED_RO(py_array)) {
189  const T& value = *static_cast<T*>(ip);
190  return (npy_bool)(value != ZeroValue);
191  } else {
192  T tmp_value;
193  PyDataType_GetArrFuncs(PyArray_DESCR(py_array))
194  ->copyswap(&tmp_value, ip, PyArray_ISBYTESWAPPED(py_array), array);
195  return (npy_bool)(tmp_value != ZeroValue);
196  }
197  }
198 
199  inline static void dotfunc(void* ip0_, npy_intp is0, void* ip1_, npy_intp is1,
200  void* op, npy_intp n, void* /*arr*/) {
201  // std::cout << "dotfunc" << std::endl;
202  typedef Eigen::Matrix<T, Eigen::Dynamic, 1> VectorT;
203  typedef Eigen::InnerStride<Eigen::Dynamic> InputStride;
204  typedef const Eigen::Map<const VectorT, 0, InputStride> ConstMapType;
205 
206  ConstMapType v0(static_cast<T*>(ip0_), n,
207  InputStride(is0 / (Eigen::DenseIndex)sizeof(T))),
208  v1(static_cast<T*>(ip1_), n,
209  InputStride(is1 / (Eigen::DenseIndex)sizeof(T)));
210 
211  *static_cast<T*>(op) = v0.dot(v1);
212  }
213 
214  inline static int fillwithscalar(void* buffer_, npy_intp length, void* value,
215  void* /*arr*/) {
216  // std::cout << "fillwithscalar" << std::endl;
217  T r = *static_cast<T*>(value);
218  T* buffer = static_cast<T*>(buffer_);
219  npy_intp i;
220  for (i = 0; i < length; i++) {
221  buffer[i] = r;
222  }
223  return 0;
224  }
225 
226  static int fill(void* data_, npy_intp length, void* /*arr*/) {
227  // std::cout << "fill" << std::endl;
228  T* data = static_cast<T*>(data_);
229  const T delta = data[1] - data[0];
230  T r = data[1];
231  npy_intp i;
232  for (i = 2; i < length; i++) {
233  r = r + delta;
234  data[i] = r;
235  }
236  return 0;
237  }
238 
239 }; // struct SpecialMethods<T,NPY_USERDEF>
240 
241 } // namespace internal
242 
243 template <typename From, typename To>
244 bool registerCast(const bool safe) {
245  PyArray_Descr* from_array_descr = Register::getPyArrayDescr<From>();
246  // int from_typenum = Register::getTypeCode<From>();
247 
248  // PyTypeObject * to_py_type = Register::getPyType<To>();
249  int to_typenum = Register::getTypeCode<To>();
250  assert(to_typenum >= 0 && "to_typenum is not valid");
251  assert(from_array_descr != NULL && "from_array_descr is not valid");
252 
253  // std::cout << "From: " << bp::type_info(typeid(From)).name() << " " <<
254  // Register::getTypeCode<From>()
255  // << " to: " << bp::type_info(typeid(To)).name() << " " <<
256  // Register::getTypeCode<To>()
257  // << "\n to_typenum: " << to_typenum
258  // << std::endl;
259 
260  if (call_PyArray_RegisterCastFunc(from_array_descr, to_typenum,
261  static_cast<PyArray_VectorUnaryFunc*>(
262  &eigenpy::internal::cast<From, To>)) <
263  0) {
264  std::stringstream ss;
265  ss << "PyArray_RegisterCastFunc of the cast from "
266  << bp::type_info(typeid(From)).name() << " to "
267  << bp::type_info(typeid(To)).name() << " has failed.";
268  eigenpy::Exception(ss.str());
269  return false;
270  }
271 
272  if (safe && call_PyArray_RegisterCanCast(from_array_descr, to_typenum,
273  NPY_NOSCALAR) < 0) {
274  std::stringstream ss;
275  ss << "PyArray_RegisterCanCast of the cast from "
276  << bp::type_info(typeid(From)).name() << " to "
277  << bp::type_info(typeid(To)).name() << " has failed.";
278  eigenpy::Exception(ss.str());
279  return false;
280  }
281 
282  return true;
283 }
284 
287 template <typename T>
288 boost::python::object getInstanceClass() {
289  // Query into the registry for type T.
290  bp::type_info type = bp::type_id<T>();
291  const bp::converter::registration* registration =
292  bp::converter::registry::query(type);
293 
294  // If the class is not registered, return None.
295  if (!registration) {
296  // std::cerr<<"Class Not Registered. Returning Empty."<<std::endl;
297  return bp::object();
298  }
299 
300  bp::handle<PyTypeObject> handle(
301  bp::borrowed(registration->get_class_object()));
302  return bp::object(handle);
303 }
304 
305 template <typename Scalar>
306 int registerNewType(PyTypeObject* py_type_ptr = NULL) {
307  // Check whether the type is a Numpy native type.
308  // In this case, the registration is not required.
309  if (isNumpyNativeType<Scalar>())
311 
312  // Retrieve the registered type for the current Scalar
313  if (py_type_ptr == NULL) { // retrive the type from Boost.Python
314  py_type_ptr = Register::getPyType<Scalar>();
315  }
316 
317  if (Register::isRegistered(py_type_ptr))
318  return Register::getTypeCode(
319  py_type_ptr); // the type is already registered
320 
321  PyArray_GetItemFunc* getitem = &internal::SpecialMethods<Scalar>::getitem;
322  PyArray_SetItemFunc* setitem = &internal::SpecialMethods<Scalar>::setitem;
323  PyArray_NonzeroFunc* nonzero = &internal::SpecialMethods<Scalar>::nonzero;
324  PyArray_CopySwapFunc* copyswap = &internal::SpecialMethods<Scalar>::copyswap;
325  PyArray_CopySwapNFunc* copyswapn = reinterpret_cast<PyArray_CopySwapNFunc*>(
327  PyArray_DotFunc* dotfunc = &internal::SpecialMethods<Scalar>::dotfunc;
328  PyArray_FillFunc* fill = &internal::SpecialMethods<Scalar>::fill;
329  PyArray_FillWithScalarFunc* fillwithscalar =
331 
332  int code = Register::registerNewType(
333  py_type_ptr, &typeid(Scalar), sizeof(Scalar),
334  internal::OffsetOf<Scalar>::value, getitem, setitem, nonzero, copyswap,
335  copyswapn, dotfunc, fill, fillwithscalar);
336 
338  NPY_NOSCALAR);
339 
340  return code;
341 }
342 
343 } // namespace eigenpy
344 
345 #endif // __eigenpy_user_type_hpp__
PyDataType_GetArrFuncs
static PyArray_ArrFuncs * PyDataType_GetArrFuncs(PyArray_Descr *descr)
Definition: numpy.hpp:31
eigenpy::internal::OffsetOf::Data::c
char c
Definition: user-type.hpp:86
register.hpp
fill
void fill(Eigen::Ref< MatType > mat, const typename MatType::Scalar &value)
Definition: eigen_ref.cpp:62
eigenpy::cast
Default cast algo to cast a From to To. Can be specialized for any types.
Definition: user-type.hpp:18
eigenpy::getInstanceClass
boost::python::object getInstanceClass()
Get the class object for a wrapped type that has been exposed through Boost.Python.
Definition: user-type.hpp:288
eigenpy::call_PyArray_DescrFromType
PyArray_Descr * call_PyArray_DescrFromType(int typenum)
Definition: numpy.hpp:251
eigenpy::internal::getitem
Definition: user-type.hpp:42
eigenpy::internal::OffsetOf::value
@ value
Definition: user-type.hpp:90
eigenpy::internal::getitem::run
static PyObject * run(void *data, void *)
Get a python object from an array It returns a standard Python object from a single element of the ar...
Definition: user-type.hpp:53
eigenpy::registerCast
bool registerCast(const bool safe)
Definition: user-type.hpp:244
eigenpy::internal::SpecialMethods< T, NPY_USERDEF >::copyswap
static void copyswap(void *dst, void *src, int swap, void *)
Definition: user-type.hpp:95
fwd.hpp
test_geometry.r
r
Definition: test_geometry.py:39
eigenpy::Register::isRegistered
static bool isRegistered()
Definition: register.hpp:43
setup.data
data
Definition: setup.in.py:48
eigenpy::internal::SpecialMethods< T, NPY_USERDEF >::copyswapn
static void copyswapn(void *dst, long dstride, void *src, long sstride, long n, int swap, void *array)
Definition: user-type.hpp:166
eigenpy::Register::registerNewType
static int registerNewType(PyTypeObject *py_type_ptr, const std::type_info *type_info_ptr, const int type_size, const int alignment, PyArray_GetItemFunc *getitem, PyArray_SetItemFunc *setitem, PyArray_NonzeroFunc *nonzero, PyArray_CopySwapFunc *copyswap, PyArray_CopySwapNFunc *copyswapn, PyArray_DotFunc *dotfunc, PyArray_FillFunc *fill, PyArray_FillWithScalarFunc *fillwithscalar)
Definition: register.cpp:43
ref
Eigen::TensorRef< Tensor > ref(Eigen::TensorRef< Tensor > tensor)
Definition: tensor.cpp:55
eigenpy
Definition: alignment.hpp:14
eigenpy::internal::SpecialMethods::fill
static int fill(void *data_, npy_intp length, void *arr)
eigenpy::internal::SpecialMethods::copyswap
static void copyswap(void *, void *, int, void *)
eigenpy::internal::SpecialMethods::fillwithscalar
static int fillwithscalar(void *buffer_, npy_intp length, void *value, void *arr)
eigenpy::internal::OffsetOf
Definition: user-type.hpp:84
eigenpy::internal::SpecialMethods< T, NPY_USERDEF >::getitem
static PyObject * getitem(void *ip, void *ap)
Definition: user-type.hpp:110
test_matrix.value
float value
Definition: test_matrix.py:161
eigenpy::NumpyEquivalentType
Definition: numpy.hpp:59
eigenpy::Exception
Definition: exception.hpp:19
eigenpy::Register::getTypeCode
static int getTypeCode()
Definition: register.hpp:82
eigenpy::internal::OffsetOf::Data
Definition: user-type.hpp:85
eigenpy::call_PyArray_RegisterCanCast
int call_PyArray_RegisterCanCast(PyArray_Descr *descr, int totype, NPY_SCALARKIND scalar)
Definition: numpy.hpp:267
eigenpy::internal::SpecialMethods
Definition: user-type.hpp:63
eigenpy::internal::SpecialMethods::setitem
static int setitem(PyObject *, void *, void *)
eigenpy::internal::SpecialMethods< T, NPY_USERDEF >::nonzero
static npy_bool nonzero(void *ip, void *array)
Definition: user-type.hpp:184
test_sparse_matrix.m
m
Definition: test_sparse_matrix.py:5
eigenpy::registerNewType
int registerNewType(PyTypeObject *py_type_ptr=NULL)
Definition: user-type.hpp:306
eigenpy::call_PyArray_RegisterCastFunc
int call_PyArray_RegisterCastFunc(PyArray_Descr *descr, int totype, PyArray_VectorUnaryFunc *castfunc)
Definition: numpy.hpp:272
eigenpy::internal::SpecialMethods< T, NPY_USERDEF >::setitem
static int setitem(PyObject *src_obj, void *dest_ptr, void *array)
Set a python object in an array. It sets the Python object "item" into the array, arr,...
Definition: user-type.hpp:129
eigenpy::cast::run
static To run(const From &from)
Definition: user-type.hpp:19
numpy-type.hpp
eigenpy::internal::cast
static void cast(void *from_, void *to_, npy_intp n, void *, void *)
Definition: user-type.hpp:31
test_geometry.v
v
Definition: test_geometry.py:32
eigenpy::internal::SpecialMethods< T, NPY_USERDEF >::fill
static int fill(void *data_, npy_intp length, void *)
Definition: user-type.hpp:226
eigenpy::internal::SpecialMethods< T, NPY_USERDEF >::fillwithscalar
static int fillwithscalar(void *buffer_, npy_intp length, void *value, void *)
Definition: user-type.hpp:214
eigenpy::internal::SpecialMethods::nonzero
static npy_bool nonzero(void *, void *)
eigenpy::internal::SpecialMethods::getitem
static PyObject * getitem(void *, void *)
eigenpy::internal::SpecialMethods::dotfunc
static void dotfunc(void *, npy_intp, void *, npy_intp, void *, npy_intp, void *)
eigenpy::internal::SpecialMethods< T, NPY_USERDEF >::dotfunc
static void dotfunc(void *ip0_, npy_intp is0, void *ip1_, npy_intp is1, void *op, npy_intp n, void *)
Definition: user-type.hpp:199
eigenpy::internal::SpecialMethods::copyswapn
static void copyswapn(void *, long, void *, long, long, int, void *)
eigenpy::internal::OffsetOf::Data::v
T v
Definition: user-type.hpp:87


eigenpy
Author(s): Justin Carpentier, Nicolas Mansard
autogenerated on Fri Apr 26 2024 02:17:35