From 60c96874ed9f017960037b2a4b20957a169c6cea Mon Sep 17 00:00:00 2001
From: Justin Carpentier <justin.carpentier@inria.fr>
Date: Mon, 24 Feb 2020 22:19:37 +0100
Subject: [PATCH] core: template specialization of EigenAllocator for
 Eigen::Ref<MatrixType>

---
 include/eigenpy/eigen-allocator.hpp | 86 +++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/include/eigenpy/eigen-allocator.hpp b/include/eigenpy/eigen-allocator.hpp
index 9c02687b..f4f5fdb6 100644
--- a/include/eigenpy/eigen-allocator.hpp
+++ b/include/eigenpy/eigen-allocator.hpp
@@ -204,6 +204,92 @@ namespace eigenpy
   };
   
 #if EIGEN_VERSION_AT_LEAST(3,2,0)
+  template<typename MatType>
+  struct EigenAllocator< Eigen::Ref<MatType> >
+  {
+    typedef Eigen::Ref<MatType> RefType;
+    typedef typename MatType::Scalar Scalar;
+
+    typedef typename ::boost::python::detail::referent_storage<RefType&>::StorageType StorageType;
+    
+    static void allocate(PyArrayObject * pyArray,
+                         bp::converter::rvalue_from_python_storage<RefType> * storage)
+    {
+      typedef typename StrideType<MatType,Eigen::internal::traits<RefType>::StrideType::InnerStrideAtCompileTime, Eigen::internal::traits<RefType>::StrideType::OuterStrideAtCompileTime >::type Stride;
+
+      bool need_to_allocate = false;
+      const int pyArray_Type = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
+      if(pyArray_Type != NumpyEquivalentType<Scalar>::type_code)
+        need_to_allocate |= true;
+      if(    (MatType::IsRowMajor && (PyArray_IS_C_CONTIGUOUS(pyArray) && !PyArray_IS_F_CONTIGUOUS(pyArray)))
+          || (!MatType::IsRowMajor && (PyArray_IS_F_CONTIGUOUS(pyArray) && !PyArray_IS_C_CONTIGUOUS(pyArray)))
+          || MatType::IsVectorAtCompileTime
+          || (PyArray_IS_F_CONTIGUOUS(pyArray) && PyArray_IS_C_CONTIGUOUS(pyArray))) // no need to allocate
+        need_to_allocate |= false;
+      else
+        need_to_allocate |= true;
+      
+      void * raw_ptr = storage->storage.bytes;
+      if(need_to_allocate)
+      {
+        MatType * mat_ptr;
+        mat_ptr = details::init_matrix_or_array<MatType>::run(pyArray);
+        RefType mat_ref(*mat_ptr);
+        
+        new (raw_ptr) StorageType(mat_ref,pyArray,mat_ptr);
+        
+        RefType & mat = *reinterpret_cast<RefType*>(raw_ptr);
+        if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code)
+        {
+          mat = MapNumpy<MatType,Scalar>::map(pyArray); // avoid useless cast
+          return;
+        }
+        
+        switch(pyArray_Type)
+        {
+          case NPY_INT:
+            EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,int,Scalar,pyArray,mat);
+            break;
+          case NPY_LONG:
+            EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long,Scalar,pyArray,mat);
+            break;
+          case NPY_FLOAT:
+            EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,float,Scalar,pyArray,mat);
+            break;
+          case NPY_CFLOAT:
+            EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<float>,Scalar,pyArray,mat);
+            break;
+          case NPY_DOUBLE:
+            EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,double,Scalar,pyArray,mat);
+            break;
+          case NPY_CDOUBLE:
+            EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<double>,Scalar,pyArray,mat);
+            break;
+          case NPY_LONGDOUBLE:
+            EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long double,Scalar,pyArray,mat);
+            break;
+          case NPY_CLONGDOUBLE:
+            EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<long double>,Scalar,pyArray,mat);
+            break;
+          default:
+            throw Exception("You asked for a conversion which is not implemented.");
+        }
+      }
+      else
+      {
+        assert(pyArray_Type == NumpyEquivalentType<Scalar>::type_code);
+        typename MapNumpy<MatType,Scalar,Stride>::EigenMap numpyMap = MapNumpy<MatType,Scalar,Stride>::map(pyArray);
+        RefType mat_ref(numpyMap);
+        new (raw_ptr) StorageType(mat_ref,pyArray);
+      }
+    }
+    
+    static void copy(RefType const & ref, PyArrayObject * pyArray)
+    {
+      EigenAllocator<MatType>::copy(ref,pyArray);
+    }
+  };
+
   template<typename MatType>
   struct EigenAllocator< eigenpy::Ref<MatType> >
   {
-- 
GitLab