From a2b653ab53898e1486e83d988be8f3081acf4294 Mon Sep 17 00:00:00 2001
From: Justin Carpentier <justin.carpentier@inria.fr>
Date: Fri, 21 Feb 2020 18:40:08 +0100
Subject: [PATCH] core: move EigenFromPy to a dedicated file

---
 include/eigenpy/details.hpp           | 249 +------------------------
 include/eigenpy/eigen-from-python.hpp | 259 ++++++++++++++++++++++++++
 2 files changed, 260 insertions(+), 248 deletions(-)
 create mode 100644 include/eigenpy/eigen-from-python.hpp

diff --git a/include/eigenpy/details.hpp b/include/eigenpy/details.hpp
index 699afb41..c676733e 100644
--- a/include/eigenpy/details.hpp
+++ b/include/eigenpy/details.hpp
@@ -18,6 +18,7 @@
 
 #include "eigenpy/eigen-allocator.hpp"
 #include "eigenpy/eigen-to-python.hpp"
+#include "eigenpy/eigen-from-python.hpp"
 
 #include "eigenpy/registration.hpp"
 #include "eigenpy/map.hpp"
@@ -58,254 +59,6 @@ namespace boost { namespace python { namespace detail {
 
 namespace eigenpy
 {
-
-  
-  
-  /* --- FROM PYTHON ------------------------------------------------------------ */
-
-  template<typename MatType>
-  struct EigenFromPy
-  {
-    
-    static bool isScalarConvertible(const int np_type)
-    {
-      if(NumpyEquivalentType<typename MatType::Scalar>::type_code == np_type)
-        return true;
-      
-      switch(np_type)
-      {
-        case NPY_INT:
-          return FromTypeToType<int,typename MatType::Scalar>::value;
-        case NPY_LONG:
-          return FromTypeToType<long,typename MatType::Scalar>::value;
-        case NPY_FLOAT:
-          return FromTypeToType<float,typename MatType::Scalar>::value;
-        case NPY_CFLOAT:
-          return FromTypeToType<std::complex<float>,typename MatType::Scalar>::value;
-        case NPY_DOUBLE:
-          return FromTypeToType<double,typename MatType::Scalar>::value;
-        case NPY_CDOUBLE:
-          return FromTypeToType<std::complex<double>,typename MatType::Scalar>::value;
-        case NPY_LONGDOUBLE:
-          return FromTypeToType<long double,typename MatType::Scalar>::value;
-        case NPY_CLONGDOUBLE:
-          return FromTypeToType<std::complex<long double>,typename MatType::Scalar>::value;
-        default:
-          return false;
-      }
-    }
-    
-    /// \brief Determine if pyObj can be converted into a MatType object
-    static void* convertible(PyArrayObject* pyArray)
-    {
-      if(!PyArray_Check(pyArray))
-        return 0;
-      
-      if(!isScalarConvertible(EIGENPY_GET_PY_ARRAY_TYPE(pyArray)))
-        return 0;
-
-      if(MatType::IsVectorAtCompileTime)
-      {
-        const Eigen::DenseIndex size_at_compile_time
-        = MatType::IsRowMajor
-        ? MatType::ColsAtCompileTime
-        : MatType::RowsAtCompileTime;
-        
-        switch(PyArray_NDIM(pyArray))
-        {
-          case 0:
-            return 0;
-          case 1:
-          {
-            if(size_at_compile_time != Eigen::Dynamic)
-            {
-              // check that the sizes at compile time matche
-              if(PyArray_DIMS(pyArray)[0] == size_at_compile_time)
-                return pyArray;
-              else
-                return 0;
-            }
-            else // This is a dynamic MatType
-              return pyArray;
-          }
-          case 2:
-          {
-            // Special care of scalar matrix of dimension 1x1.
-            if(PyArray_DIMS(pyArray)[0] == 1 && PyArray_DIMS(pyArray)[1] == 1)
-            {
-              if(size_at_compile_time != Eigen::Dynamic)
-              {
-                if(size_at_compile_time == 1)
-                  return pyArray;
-                else
-                  return 0;
-              }
-              else // This is a dynamic MatType
-                return pyArray;
-            }
-            
-            if(PyArray_DIMS(pyArray)[0] > 1 && PyArray_DIMS(pyArray)[1] > 1)
-            {
-#ifndef NDEBUG
-              std::cerr << "The number of dimension of the object does not correspond to a vector" << std::endl;
-#endif
-              return 0;
-            }
-            
-            if(((PyArray_DIMS(pyArray)[0] == 1) && (MatType::ColsAtCompileTime == 1))
-               || ((PyArray_DIMS(pyArray)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
-            {
-#ifndef NDEBUG
-              if(MatType::ColsAtCompileTime == 1)
-                std::cerr << "The object is not a column vector" << std::endl;
-              else
-                std::cerr << "The object is not a row vector" << std::endl;
-#endif
-              return 0;
-            }
-            
-            if(size_at_compile_time != Eigen::Dynamic)
-            { // This is a fixe size vector
-              const Eigen::DenseIndex pyArray_size
-              = PyArray_DIMS(pyArray)[0] > PyArray_DIMS(pyArray)[1]
-              ? PyArray_DIMS(pyArray)[0]
-              : PyArray_DIMS(pyArray)[1];
-              if(size_at_compile_time != pyArray_size)
-                return 0;
-            }
-            break;
-          }
-          default:
-            return 0;
-        }
-      }
-      else // this is a matrix
-      {
-        if(PyArray_NDIM(pyArray) == 1) // We can always convert a vector into a matrix
-        {
-          return pyArray;
-        }
-        
-        if(PyArray_NDIM(pyArray) != 2)
-        {
-#ifndef NDEBUG
-            std::cerr << "The number of dimension of the object is not correct." << std::endl;
-#endif
-          return 0;
-        }
-       
-        if(PyArray_NDIM(pyArray) == 2)
-        {
-          const int R = (int)PyArray_DIMS(pyArray)[0];
-          const int C = (int)PyArray_DIMS(pyArray)[1];
-          
-          if( (MatType::RowsAtCompileTime!=R)
-             && (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
-            return 0;
-          if( (MatType::ColsAtCompileTime!=C)
-             && (MatType::ColsAtCompileTime!=Eigen::Dynamic) )
-            return 0;
-        }
-      }
-        
-#ifdef NPY_1_8_API_VERSION
-      if(!(PyArray_FLAGS(pyArray)))
-#else
-      if(!(PyArray_FLAGS(pyArray) & NPY_ALIGNED))
-#endif
-      {
-#ifndef NDEBUG
-        std::cerr << "NPY non-aligned matrices are not implemented." << std::endl;
-#endif
-        return 0;
-      }
-      
-      return pyArray;
-    }
- 
-    /// \brief Allocate memory and copy pyObj in the new storage
-    static void construct(PyObject* pyObj,
-                          bp::converter::rvalue_from_python_stage1_data* memory)
-    {
-      PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
-      assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX));
-      
-      void* storage = reinterpret_cast<bp::converter::rvalue_from_python_storage<MatType>*>
-                     (reinterpret_cast<void*>(memory))->storage.bytes;
-      
-      EigenAllocator<MatType>::allocate(pyArray,storage);
-
-      memory->convertible = storage;
-    }
-    
-    static void registration()
-    {
-      bp::converter::registry::push_back
-      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
-       &EigenFromPy::construct,bp::type_id<MatType>());
-    }
-  };
-  
-  template<typename MatType>
-  struct EigenFromPyConverter
-  {
-    static void registration()
-    {
-      EigenFromPy<MatType>::registration();
-
-      // Add also conversion to Eigen::MatrixBase<MatType>
-      typedef Eigen::MatrixBase<MatType> MatrixBase;
-      EigenFromPy<MatrixBase>::registration();
-
-      // Add also conversion to Eigen::EigenBase<MatType>
-      typedef Eigen::EigenBase<MatType> EigenBase;
-      EigenFromPy<EigenBase>::registration();
-    }
-  };
-
-  template<typename MatType>
-  struct EigenFromPy< Eigen::MatrixBase<MatType> > : EigenFromPy<MatType>
-  {
-    typedef EigenFromPy<MatType> EigenFromPyDerived;
-    typedef Eigen::MatrixBase<MatType> Base;
-
-    static void registration()
-    {
-      bp::converter::registry::push_back
-      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
-       &EigenFromPy::construct,bp::type_id<Base>());
-    }
-  };
-    
-  template<typename MatType>
-  struct EigenFromPy< Eigen::EigenBase<MatType> > : EigenFromPy<MatType>
-  {
-    typedef EigenFromPy<MatType> EigenFromPyDerived;
-    typedef Eigen::EigenBase<MatType> Base;
-
-    static void registration()
-    {
-      bp::converter::registry::push_back
-      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
-       &EigenFromPy::construct,bp::type_id<Base>());
-    }
-  };
-
-#if EIGEN_VERSION_AT_LEAST(3,2,0)
-  // Template specialization for Eigen::Ref
-  template<typename MatType>
-  struct EigenFromPyConverter< eigenpy::Ref<MatType> >
-  {
-    static void registration()
-    {
-      bp::converter::registry::push_back
-      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy<MatType>::convertible),
-       &EigenFromPy<MatType>::construct,bp::type_id<MatType>());
-    }
-  };
-
-#endif
-  
   template<typename MatType,typename EigenEquivalentType>
   EIGENPY_DEPRECATED
   void enableEigenPySpecific()
diff --git a/include/eigenpy/eigen-from-python.hpp b/include/eigenpy/eigen-from-python.hpp
new file mode 100644
index 00000000..07482697
--- /dev/null
+++ b/include/eigenpy/eigen-from-python.hpp
@@ -0,0 +1,259 @@
+//
+// Copyright (c) 2014-2020 CNRS INRIA
+//
+
+#ifndef __eigenpy_eigen_from_python_hpp__
+#define __eigenpy_eigen_from_python_hpp__
+
+#include "eigenpy/fwd.hpp"
+#include "eigenpy/numpy-type.hpp"
+#include "eigenpy/eigen-allocator.hpp"
+#include "eigenpy/scalar-conversion.hpp"
+
+namespace eigenpy
+{
+  template<typename MatType>
+  struct EigenFromPy
+  {
+    
+    static bool isScalarConvertible(const int np_type)
+    {
+      if(NumpyEquivalentType<typename MatType::Scalar>::type_code == np_type)
+        return true;
+      
+      switch(np_type)
+      {
+        case NPY_INT:
+          return FromTypeToType<int,typename MatType::Scalar>::value;
+        case NPY_LONG:
+          return FromTypeToType<long,typename MatType::Scalar>::value;
+        case NPY_FLOAT:
+          return FromTypeToType<float,typename MatType::Scalar>::value;
+        case NPY_CFLOAT:
+          return FromTypeToType<std::complex<float>,typename MatType::Scalar>::value;
+        case NPY_DOUBLE:
+          return FromTypeToType<double,typename MatType::Scalar>::value;
+        case NPY_CDOUBLE:
+          return FromTypeToType<std::complex<double>,typename MatType::Scalar>::value;
+        case NPY_LONGDOUBLE:
+          return FromTypeToType<long double,typename MatType::Scalar>::value;
+        case NPY_CLONGDOUBLE:
+          return FromTypeToType<std::complex<long double>,typename MatType::Scalar>::value;
+        default:
+          return false;
+      }
+    }
+    
+    /// \brief Determine if pyObj can be converted into a MatType object
+    static void* convertible(PyArrayObject* pyArray)
+    {
+      if(!PyArray_Check(pyArray))
+        return 0;
+      
+      if(!isScalarConvertible(EIGENPY_GET_PY_ARRAY_TYPE(pyArray)))
+        return 0;
+
+      if(MatType::IsVectorAtCompileTime)
+      {
+        const Eigen::DenseIndex size_at_compile_time
+        = MatType::IsRowMajor
+        ? MatType::ColsAtCompileTime
+        : MatType::RowsAtCompileTime;
+        
+        switch(PyArray_NDIM(pyArray))
+        {
+          case 0:
+            return 0;
+          case 1:
+          {
+            if(size_at_compile_time != Eigen::Dynamic)
+            {
+              // check that the sizes at compile time matche
+              if(PyArray_DIMS(pyArray)[0] == size_at_compile_time)
+                return pyArray;
+              else
+                return 0;
+            }
+            else // This is a dynamic MatType
+              return pyArray;
+          }
+          case 2:
+          {
+            // Special care of scalar matrix of dimension 1x1.
+            if(PyArray_DIMS(pyArray)[0] == 1 && PyArray_DIMS(pyArray)[1] == 1)
+            {
+              if(size_at_compile_time != Eigen::Dynamic)
+              {
+                if(size_at_compile_time == 1)
+                  return pyArray;
+                else
+                  return 0;
+              }
+              else // This is a dynamic MatType
+                return pyArray;
+            }
+            
+            if(PyArray_DIMS(pyArray)[0] > 1 && PyArray_DIMS(pyArray)[1] > 1)
+            {
+#ifndef NDEBUG
+              std::cerr << "The number of dimension of the object does not correspond to a vector" << std::endl;
+#endif
+              return 0;
+            }
+            
+            if(((PyArray_DIMS(pyArray)[0] == 1) && (MatType::ColsAtCompileTime == 1))
+               || ((PyArray_DIMS(pyArray)[1] == 1) && (MatType::RowsAtCompileTime == 1)))
+            {
+#ifndef NDEBUG
+              if(MatType::ColsAtCompileTime == 1)
+                std::cerr << "The object is not a column vector" << std::endl;
+              else
+                std::cerr << "The object is not a row vector" << std::endl;
+#endif
+              return 0;
+            }
+            
+            if(size_at_compile_time != Eigen::Dynamic)
+            { // This is a fixe size vector
+              const Eigen::DenseIndex pyArray_size
+              = PyArray_DIMS(pyArray)[0] > PyArray_DIMS(pyArray)[1]
+              ? PyArray_DIMS(pyArray)[0]
+              : PyArray_DIMS(pyArray)[1];
+              if(size_at_compile_time != pyArray_size)
+                return 0;
+            }
+            break;
+          }
+          default:
+            return 0;
+        }
+      }
+      else // this is a matrix
+      {
+        if(PyArray_NDIM(pyArray) == 1) // We can always convert a vector into a matrix
+        {
+          return pyArray;
+        }
+        
+        if(PyArray_NDIM(pyArray) != 2)
+        {
+#ifndef NDEBUG
+            std::cerr << "The number of dimension of the object is not correct." << std::endl;
+#endif
+          return 0;
+        }
+       
+        if(PyArray_NDIM(pyArray) == 2)
+        {
+          const int R = (int)PyArray_DIMS(pyArray)[0];
+          const int C = (int)PyArray_DIMS(pyArray)[1];
+          
+          if( (MatType::RowsAtCompileTime!=R)
+             && (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
+            return 0;
+          if( (MatType::ColsAtCompileTime!=C)
+             && (MatType::ColsAtCompileTime!=Eigen::Dynamic) )
+            return 0;
+        }
+      }
+        
+#ifdef NPY_1_8_API_VERSION
+      if(!(PyArray_FLAGS(pyArray)))
+#else
+      if(!(PyArray_FLAGS(pyArray) & NPY_ALIGNED))
+#endif
+      {
+#ifndef NDEBUG
+        std::cerr << "NPY non-aligned matrices are not implemented." << std::endl;
+#endif
+        return 0;
+      }
+      
+      return pyArray;
+    }
+ 
+    /// \brief Allocate memory and copy pyObj in the new storage
+    static void construct(PyObject* pyObj,
+                          bp::converter::rvalue_from_python_stage1_data* memory)
+    {
+      PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
+      assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX));
+      
+      void* storage = reinterpret_cast<bp::converter::rvalue_from_python_storage<MatType>*>
+                     (reinterpret_cast<void*>(memory))->storage.bytes;
+      
+      EigenAllocator<MatType>::allocate(pyArray,storage);
+
+      memory->convertible = storage;
+    }
+    
+    static void registration()
+    {
+      bp::converter::registry::push_back
+      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
+       &EigenFromPy::construct,bp::type_id<MatType>());
+    }
+  };
+  
+  template<typename MatType>
+  struct EigenFromPyConverter
+  {
+    static void registration()
+    {
+      EigenFromPy<MatType>::registration();
+
+      // Add also conversion to Eigen::MatrixBase<MatType>
+      typedef Eigen::MatrixBase<MatType> MatrixBase;
+      EigenFromPy<MatrixBase>::registration();
+
+      // Add also conversion to Eigen::EigenBase<MatType>
+      typedef Eigen::EigenBase<MatType> EigenBase;
+      EigenFromPy<EigenBase>::registration();
+    }
+  };
+
+  template<typename MatType>
+  struct EigenFromPy< Eigen::MatrixBase<MatType> > : EigenFromPy<MatType>
+  {
+    typedef EigenFromPy<MatType> EigenFromPyDerived;
+    typedef Eigen::MatrixBase<MatType> Base;
+
+    static void registration()
+    {
+      bp::converter::registry::push_back
+      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
+       &EigenFromPy::construct,bp::type_id<Base>());
+    }
+  };
+    
+  template<typename MatType>
+  struct EigenFromPy< Eigen::EigenBase<MatType> > : EigenFromPy<MatType>
+  {
+    typedef EigenFromPy<MatType> EigenFromPyDerived;
+    typedef Eigen::EigenBase<MatType> Base;
+
+    static void registration()
+    {
+      bp::converter::registry::push_back
+      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
+       &EigenFromPy::construct,bp::type_id<Base>());
+    }
+  };
+
+#if EIGEN_VERSION_AT_LEAST(3,2,0)
+  // Template specialization for Eigen::Ref
+  template<typename MatType>
+  struct EigenFromPyConverter< eigenpy::Ref<MatType> >
+  {
+    static void registration()
+    {
+      bp::converter::registry::push_back
+      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy<MatType>::convertible),
+       &EigenFromPy<MatType>::construct,bp::type_id<MatType>());
+    }
+  };
+
+#endif
+}
+
+#endif // __eigenpy_eigen_from_python_hpp__
-- 
GitLab