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 
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);
140 
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()
148  << std::endl;
149  eigenpy::Exception(ss.str());
150  return -1;
151  }
152 
153  dest = T(src_value);
154 
155  } else {
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()
162  << std::endl;
163  eigenpy::Exception(ss.str());
164  return -1;
165  }
166 
167  const T& src = extract_src_obj();
168  T& dest = *static_cast<T*>(dest_ptr);
169  dest = src;
170  }
171 
172  return 0;
173  }
174 
175  inline static void copyswapn(void* dst, long dstride, void* src, long sstride,
176  long n, int swap, void* array) {
177  // std::cout << "copyswapn" << std::endl;
178 
179  char* dstptr = static_cast<char*>(dst);
180  char* srcptr = static_cast<char*>(src);
181 
182  PyArrayObject* py_array = static_cast<PyArrayObject*>(array);
183  PyArray_CopySwapFunc* copyswap =
184  PyDataType_GetArrFuncs(PyArray_DESCR(py_array))->copyswap;
185 
186  for (npy_intp i = 0; i < n; i++) {
187  copyswap(dstptr, srcptr, swap, array);
188  dstptr += dstride;
189  srcptr += sstride;
190  }
191  }
192 
193  inline static npy_bool nonzero(void* ip, void* array) {
194  // std::cout << "nonzero" << std::endl;
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);
200  } else {
201  T tmp_value;
202  PyDataType_GetArrFuncs(PyArray_DESCR(py_array))
203  ->copyswap(&tmp_value, ip, PyArray_ISBYTESWAPPED(py_array), array);
204  return (npy_bool)(tmp_value != ZeroValue);
205  }
206  }
207 
208  inline static void dotfunc(void* ip0_, npy_intp is0, void* ip1_, npy_intp is1,
209  void* op, npy_intp n, void* /*arr*/) {
210  // std::cout << "dotfunc" << std::endl;
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;
214 
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)));
219 
220  *static_cast<T*>(op) = v0.dot(v1);
221  }
222 
223  inline static int fillwithscalar(void* buffer_, npy_intp length, void* value,
224  void* /*arr*/) {
225  // std::cout << "fillwithscalar" << std::endl;
226  T r = *static_cast<T*>(value);
227  T* buffer = static_cast<T*>(buffer_);
228  npy_intp i;
229  for (i = 0; i < length; i++) {
230  buffer[i] = r;
231  }
232  return 0;
233  }
234 
235  static int fill(void* data_, npy_intp length, void* /*arr*/) {
236  // std::cout << "fill" << std::endl;
237  T* data = static_cast<T*>(data_);
238  const T delta = data[1] - data[0];
239  T r = data[1];
240  npy_intp i;
241  for (i = 2; i < length; i++) {
242  r = r + delta;
243  data[i] = r;
244  }
245  return 0;
246  }
247 
248 }; // struct SpecialMethods<T,NPY_USERDEF>
249 
250 } // namespace internal
251 
252 template <typename From, typename To>
253 bool registerCast(const bool safe) {
254  PyArray_Descr* from_array_descr = Register::getPyArrayDescr<From>();
255  // int from_typenum = Register::getTypeCode<From>();
256 
257  // PyTypeObject * to_py_type = Register::getPyType<To>();
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");
261 
262  // std::cout << "From: " << bp::type_info(typeid(From)).name() << " " <<
263  // Register::getTypeCode<From>()
264  // << " to: " << bp::type_info(typeid(To)).name() << " " <<
265  // Register::getTypeCode<To>()
266  // << "\n to_typenum: " << to_typenum
267  // << std::endl;
268 
269  if (call_PyArray_RegisterCastFunc(from_array_descr, to_typenum,
270  static_cast<PyArray_VectorUnaryFunc*>(
271  &eigenpy::internal::cast<From, To>)) <
272  0) {
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());
278  return false;
279  }
280 
281  if (safe && call_PyArray_RegisterCanCast(from_array_descr, to_typenum,
282  NPY_NOSCALAR) < 0) {
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());
288  return false;
289  }
290 
291  return true;
292 }
293 
296 template <typename T>
297 boost::python::object getInstanceClass() {
298  // Query into the registry for type T.
299  bp::type_info type = bp::type_id<T>();
300  const bp::converter::registration* registration =
301  bp::converter::registry::query(type);
302 
303  // If the class is not registered, return None.
304  if (!registration) {
305  // std::cerr<<"Class Not Registered. Returning Empty."<<std::endl;
306  return bp::object();
307  }
308 
309  bp::handle<PyTypeObject> handle(
310  bp::borrowed(registration->get_class_object()));
311  return bp::object(handle);
312 }
313 
314 template <typename Scalar>
315 int registerNewType(PyTypeObject* py_type_ptr = NULL) {
316  // Check whether the type is a Numpy native type.
317  // In this case, the registration is not required.
318  if (isNumpyNativeType<Scalar>())
320 
321  // Retrieve the registered type for the current Scalar
322  if (py_type_ptr == NULL) { // retrive the type from Boost.Python
323  py_type_ptr = Register::getPyType<Scalar>();
324  }
325 
326  if (Register::isRegistered(py_type_ptr))
327  return Register::getTypeCode(
328  py_type_ptr); // the type is already registered
329 
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*>(
336  PyArray_DotFunc* dotfunc = &internal::SpecialMethods<Scalar>::dotfunc;
337  PyArray_FillFunc* fill = &internal::SpecialMethods<Scalar>::fill;
338  PyArray_FillWithScalarFunc* fillwithscalar =
340 
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);
345 
347  NPY_NOSCALAR);
348 
349  return code;
350 }
351 
352 } // namespace eigenpy
353 
354 #endif // __eigenpy_user_type_hpp__
PyDataType_GetArrFuncs
static PyArray_ArrFuncs * PyDataType_GetArrFuncs(PyArray_Descr *descr)
Definition: numpy.hpp:44
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:297
eigenpy::call_PyArray_DescrFromType
PyArray_Descr * call_PyArray_DescrFromType(int typenum)
Definition: numpy.hpp:274
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:253
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:175
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 *)
test_std_map.t2
dictionary t2
Definition: test_std_map.py:4
eigenpy::internal::SpecialMethods::fillwithscalar
static int fillwithscalar(void *buffer_, npy_intp length, void *value, void *arr)
eigenpy::type_info
boost::typeindex::type_index type_info(const T &value)
Definition: type_info.hpp:17
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:74
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:290
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:193
test_sparse_matrix.m
m
Definition: test_sparse_matrix.py:5
eigenpy::registerNewType
int registerNewType(PyTypeObject *py_type_ptr=NULL)
Definition: user-type.hpp:315
eigenpy::call_PyArray_RegisterCastFunc
int call_PyArray_RegisterCastFunc(PyArray_Descr *descr, int totype, PyArray_VectorUnaryFunc *castfunc)
Definition: numpy.hpp:295
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:235
eigenpy::internal::SpecialMethods< T, NPY_USERDEF >::fillwithscalar
static int fillwithscalar(void *buffer_, npy_intp length, void *value, void *)
Definition: user-type.hpp:223
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:208
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 Feb 14 2025 03:16:26