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 = PyArray_DESCR(py_array)->f->copyswap;
175 
176  for (npy_intp i = 0; i < n; i++) {
177  copyswap(dstptr, srcptr, swap, array);
178  dstptr += dstride;
179  srcptr += sstride;
180  }
181  }
182 
183  inline static npy_bool nonzero(void* ip, void* array) {
184  // std::cout << "nonzero" << std::endl;
185  static const T ZeroValue = T(0);
186  PyArrayObject* py_array = static_cast<PyArrayObject*>(array);
187  if (py_array == NULL || PyArray_ISBEHAVED_RO(py_array)) {
188  const T& value = *static_cast<T*>(ip);
189  return (npy_bool)(value != ZeroValue);
190  } else {
191  T tmp_value;
192  PyArray_DESCR(py_array)->f->copyswap(
193  &tmp_value, ip, PyArray_ISBYTESWAPPED(py_array), array);
194  return (npy_bool)(tmp_value != ZeroValue);
195  }
196  }
197 
198  inline static void dotfunc(void* ip0_, npy_intp is0, void* ip1_, npy_intp is1,
199  void* op, npy_intp n, void* /*arr*/) {
200  // std::cout << "dotfunc" << std::endl;
201  typedef Eigen::Matrix<T, Eigen::Dynamic, 1> VectorT;
202  typedef Eigen::InnerStride<Eigen::Dynamic> InputStride;
203  typedef const Eigen::Map<const VectorT, 0, InputStride> ConstMapType;
204 
205  ConstMapType v0(static_cast<T*>(ip0_), n,
206  InputStride(is0 / (Eigen::DenseIndex)sizeof(T))),
207  v1(static_cast<T*>(ip1_), n,
208  InputStride(is1 / (Eigen::DenseIndex)sizeof(T)));
209 
210  *static_cast<T*>(op) = v0.dot(v1);
211  }
212 
213  inline static int fillwithscalar(void* buffer_, npy_intp length, void* value,
214  void* /*arr*/) {
215  // std::cout << "fillwithscalar" << std::endl;
216  T r = *static_cast<T*>(value);
217  T* buffer = static_cast<T*>(buffer_);
218  npy_intp i;
219  for (i = 0; i < length; i++) {
220  buffer[i] = r;
221  }
222  return 0;
223  }
224 
225  static int fill(void* data_, npy_intp length, void* /*arr*/) {
226  // std::cout << "fill" << std::endl;
227  T* data = static_cast<T*>(data_);
228  const T delta = data[1] - data[0];
229  T r = data[1];
230  npy_intp i;
231  for (i = 2; i < length; i++) {
232  r = r + delta;
233  data[i] = r;
234  }
235  return 0;
236  }
237 
238 }; // struct SpecialMethods<T,NPY_USERDEF>
239 
240 } // namespace internal
241 
242 template <typename From, typename To>
243 bool registerCast(const bool safe) {
244  PyArray_Descr* from_array_descr = Register::getPyArrayDescr<From>();
245  // int from_typenum = Register::getTypeCode<From>();
246 
247  // PyTypeObject * to_py_type = Register::getPyType<To>();
248  int to_typenum = Register::getTypeCode<To>();
249  assert(to_typenum >= 0 && "to_typenum is not valid");
250  assert(from_array_descr != NULL && "from_array_descr is not valid");
251 
252  // std::cout << "From: " << bp::type_info(typeid(From)).name() << " " <<
253  // Register::getTypeCode<From>()
254  // << " to: " << bp::type_info(typeid(To)).name() << " " <<
255  // Register::getTypeCode<To>()
256  // << "\n to_typenum: " << to_typenum
257  // << std::endl;
258 
259  if (call_PyArray_RegisterCastFunc(from_array_descr, to_typenum,
260  static_cast<PyArray_VectorUnaryFunc*>(
261  &eigenpy::internal::cast<From, To>)) <
262  0) {
263  std::stringstream ss;
264  ss << "PyArray_RegisterCastFunc of the cast from "
265  << bp::type_info(typeid(From)).name() << " to "
266  << bp::type_info(typeid(To)).name() << " has failed.";
267  eigenpy::Exception(ss.str());
268  return false;
269  }
270 
271  if (safe && call_PyArray_RegisterCanCast(from_array_descr, to_typenum,
272  NPY_NOSCALAR) < 0) {
273  std::stringstream ss;
274  ss << "PyArray_RegisterCanCast 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());
278  return false;
279  }
280 
281  return true;
282 }
283 
286 template <typename T>
287 boost::python::object getInstanceClass() {
288  // Query into the registry for type T.
289  bp::type_info type = bp::type_id<T>();
290  const bp::converter::registration* registration =
291  bp::converter::registry::query(type);
292 
293  // If the class is not registered, return None.
294  if (!registration) {
295  // std::cerr<<"Class Not Registered. Returning Empty."<<std::endl;
296  return bp::object();
297  }
298 
299  bp::handle<PyTypeObject> handle(
300  bp::borrowed(registration->get_class_object()));
301  return bp::object(handle);
302 }
303 
304 template <typename Scalar>
305 int registerNewType(PyTypeObject* py_type_ptr = NULL) {
306  // Check whether the type is a Numpy native type.
307  // In this case, the registration is not required.
308  if (isNumpyNativeType<Scalar>())
310 
311  // Retrieve the registered type for the current Scalar
312  if (py_type_ptr == NULL) { // retrive the type from Boost.Python
313  py_type_ptr = Register::getPyType<Scalar>();
314  }
315 
316  if (Register::isRegistered(py_type_ptr))
317  return Register::getTypeCode(
318  py_type_ptr); // the type is already registered
319 
320  PyArray_GetItemFunc* getitem = &internal::SpecialMethods<Scalar>::getitem;
321  PyArray_SetItemFunc* setitem = &internal::SpecialMethods<Scalar>::setitem;
322  PyArray_NonzeroFunc* nonzero = &internal::SpecialMethods<Scalar>::nonzero;
323  PyArray_CopySwapFunc* copyswap = &internal::SpecialMethods<Scalar>::copyswap;
324  PyArray_CopySwapNFunc* copyswapn = reinterpret_cast<PyArray_CopySwapNFunc*>(
326  PyArray_DotFunc* dotfunc = &internal::SpecialMethods<Scalar>::dotfunc;
327  PyArray_FillFunc* fill = &internal::SpecialMethods<Scalar>::fill;
328  PyArray_FillWithScalarFunc* fillwithscalar =
330 
331  int code = Register::registerNewType(
332  py_type_ptr, &typeid(Scalar), sizeof(Scalar),
333  internal::OffsetOf<Scalar>::value, getitem, setitem, nonzero, copyswap,
334  copyswapn, dotfunc, fill, fillwithscalar);
335 
337  NPY_NOSCALAR);
338 
339  return code;
340 }
341 
342 } // namespace eigenpy
343 
344 #endif // __eigenpy_user_type_hpp__
static npy_bool nonzero(void *ip, void *array)
Definition: user-type.hpp:183
static PyObject * getitem(void *ip, void *ap)
Definition: user-type.hpp:110
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
boost::python::object getInstanceClass()
Get the class object for a wrapped type that has been exposed through Boost.Python.
Definition: user-type.hpp:287
static int getTypeCode()
Definition: register.hpp:63
data
Definition: setup.in.py:48
bool registerCast(const bool safe)
Definition: user-type.hpp:243
static void dotfunc(void *ip0_, npy_intp is0, void *ip1_, npy_intp is1, void *op, npy_intp n, void *)
Definition: user-type.hpp:198
static int fillwithscalar(void *buffer_, npy_intp length, void *value, void *)
Definition: user-type.hpp:213
static To run(const From &from)
Definition: user-type.hpp:19
static int fill(void *data_, npy_intp length, void *)
Definition: user-type.hpp:225
int call_PyArray_RegisterCastFunc(PyArray_Descr *descr, int totype, PyArray_VectorUnaryFunc *castfunc)
Definition: numpy.hpp:186
int call_PyArray_RegisterCanCast(PyArray_Descr *descr, int totype, NPY_SCALARKIND scalar)
Definition: numpy.hpp:181
Default cast algo to cast a From to To. Can be specialized for any types.
Definition: user-type.hpp:18
static bool isRegistered()
Definition: register.hpp:24
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
Eigen::TensorRef< Tensor > ref(Eigen::TensorRef< Tensor > tensor)
Definition: tensor.cpp:55
static void copyswap(void *dst, void *src, int swap, void *)
Definition: user-type.hpp:95
int registerNewType(PyTypeObject *py_type_ptr=NULL)
Definition: user-type.hpp:305
PyArray_Descr * call_PyArray_DescrFromType(int typenum)
Definition: numpy.hpp:165
static void cast(void *from_, void *to_, npy_intp n, void *, void *)
Definition: user-type.hpp:31
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:32
static void copyswapn(void *dst, long dstride, void *src, long sstride, long n, int swap, void *array)
Definition: user-type.hpp:166
void fill(Eigen::Ref< MatType > mat, const typename MatType::Scalar &value)
Definition: eigen_ref.cpp:62


eigenpy
Author(s): Justin Carpentier, Nicolas Mansard
autogenerated on Fri Jun 2 2023 02:10:26