From 52106de3644c78cdf3e55fea0b3acb9c41be1d23 Mon Sep 17 00:00:00 2001
From: Justin Carpentier <justin.carpentier@inria.fr>
Date: Sat, 22 Feb 2020 19:58:20 +0100
Subject: [PATCH] core: add converter to python for Eigen::Matrix

---
 include/eigenpy/details.hpp         |   1 -
 include/eigenpy/eigen-to-python.hpp | 109 ++++++++++++++++++----------
 2 files changed, 72 insertions(+), 38 deletions(-)

diff --git a/include/eigenpy/details.hpp b/include/eigenpy/details.hpp
index 6b15de6c..484e1b98 100644
--- a/include/eigenpy/details.hpp
+++ b/include/eigenpy/details.hpp
@@ -22,7 +22,6 @@
 #include "eigenpy/map.hpp"
 #include "eigenpy/exception.hpp"
 
-
 namespace boost { namespace python { namespace detail {
 
   template<class MatType>
diff --git a/include/eigenpy/eigen-to-python.hpp b/include/eigenpy/eigen-to-python.hpp
index 0696eea1..cc990519 100644
--- a/include/eigenpy/eigen-to-python.hpp
+++ b/include/eigenpy/eigen-to-python.hpp
@@ -8,53 +8,88 @@
 #include "eigenpy/fwd.hpp"
 #include "eigenpy/numpy-type.hpp"
 #include "eigenpy/eigen-allocator.hpp"
+#include "eigenpy/numpy-allocator.hpp"
+
+#include <boost/type_traits.hpp>
+
+namespace boost { namespace python {
+
+  template<typename MatrixRef, class MakeHolder>
+  struct to_python_indirect_eigen
+  {
+    template <class U>
+    inline PyObject* operator()(U const& mat) const
+    {
+      return eigenpy::EigenToPy<MatrixRef>::convert(const_cast<U&>(mat));
+    }
+    
+#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
+    inline PyTypeObject const*
+    get_pytype()const
+    {
+      return converter::registered_pytype<MatrixRef>::get_pytype();
+    }
+#endif
+  };
+
+  template <typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime, int Options, int MaxRowsAtCompileTime, int MaxColsAtCompileTime, class MakeHolder>
+  struct to_python_indirect<Eigen::Matrix<Scalar,RowsAtCompileTime,ColsAtCompileTime,Options,MaxRowsAtCompileTime,MaxColsAtCompileTime>&,MakeHolder>
+  : to_python_indirect_eigen<Eigen::Matrix<Scalar,RowsAtCompileTime,ColsAtCompileTime,Options,MaxRowsAtCompileTime,MaxColsAtCompileTime>&,MakeHolder>
+  {
+  };
+
+  template <typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime, int Options, int MaxRowsAtCompileTime, int MaxColsAtCompileTime, class MakeHolder>
+  struct to_python_indirect<const Eigen::Matrix<Scalar,RowsAtCompileTime,ColsAtCompileTime,Options,MaxRowsAtCompileTime,MaxColsAtCompileTime>&,MakeHolder>
+  : to_python_indirect_eigen<const Eigen::Matrix<Scalar,RowsAtCompileTime,ColsAtCompileTime,Options,MaxRowsAtCompileTime,MaxColsAtCompileTime>&,MakeHolder>
+  {
+  };
+
+}}
 
 namespace eigenpy
 {
   namespace bp = boost::python;
 
-    template<typename MatType>
-    struct EigenToPy
+  template<typename MatType>
+  struct EigenToPy
+  {
+    static PyObject* convert(typename boost::add_reference<typename boost::add_const<MatType>::type>::type mat)
     {
-      static PyObject* convert(MatType const & mat)
+      typedef typename boost::remove_const<typename boost::remove_reference<MatType>::type>::type MatrixDerived;
+      
+      assert( (mat.rows()<INT_MAX) && (mat.cols()<INT_MAX)
+             && "Matrix range larger than int ... should never happen." );
+      const npy_intp R = (npy_intp)mat.rows(), C = (npy_intp)mat.cols();
+      
+      PyArrayObject* pyArray;
+      // Allocate Python memory
+      if( ( ((!(C == 1) != !(R == 1)) && !MatrixDerived::IsVectorAtCompileTime) || MatrixDerived::IsVectorAtCompileTime)
+         && NumpyType::getType() == ARRAY_TYPE) // Handle array with a single dimension
       {
-        typedef typename MatType::Scalar Scalar;
-        assert( (mat.rows()<INT_MAX) && (mat.cols()<INT_MAX)
-          && "Matrix range larger than int ... should never happen." );
-        const npy_intp R = (npy_intp)mat.rows(), C = (npy_intp)mat.cols();
-
-        PyArrayObject* pyArray;
-        // Allocate Python memory
-        if( ( ((!(C == 1) != !(R == 1)) && !MatType::IsVectorAtCompileTime) || MatType::IsVectorAtCompileTime)
-           && NumpyType::getType() == ARRAY_TYPE) // Handle array with a single dimension
-        {
-          npy_intp shape[1] = { C == 1 ? R : C };
-          pyArray = (PyArrayObject*) PyArray_SimpleNew(1, shape,
-                                                       NumpyEquivalentType<Scalar>::type_code);
-        }
-        else
-        {
-          npy_intp shape[2] = { R,C };
-          pyArray = (PyArrayObject*) PyArray_SimpleNew(2, shape,
-                                                       NumpyEquivalentType<Scalar>::type_code);
-        }
-
-        // Copy data
-        EigenAllocator<MatType>::copy(mat,pyArray);
-        
-        // Create an instance (either np.array or np.matrix)
-        return NumpyType::getInstance().make(pyArray).ptr();
+        npy_intp shape[1] = { C == 1 ? R : C };
+        pyArray = NumpyAllocator<MatType>::allocate(const_cast<MatrixDerived &>(mat.derived()),
+                                                    1,shape);
       }
-    };
-
-    template<typename MatType>
-    struct EigenToPyConverter
-    {
-      static void registration()
+      else
       {
-        bp::to_python_converter<MatType,EigenToPy<MatType> >();
+        npy_intp shape[2] = { R,C };
+        pyArray = NumpyAllocator<MatType>::allocate(const_cast<MatrixDerived &>(mat.derived()),
+                                                    2,shape);
       }
-    };
+      
+      // Create an instance (either np.array or np.matrix)
+      return NumpyType::make(pyArray).ptr();
+    }
+  };
+
+  template<typename MatType>
+  struct EigenToPyConverter
+  {
+    static void registration()
+    {
+      bp::to_python_converter<MatType,EigenToPy<MatType> >();
+    }
+  };
 
 #if EIGEN_VERSION_AT_LEAST(3,2,0)
   template<typename MatType>
-- 
GitLab