diff --git a/include/eigenpy/eigen-from-python.hpp b/include/eigenpy/eigen-from-python.hpp index b5717e330dde421ae9785eaee674aeff7a807413..c923079153e02cedf8eedd479955674927628e58 100644 --- a/include/eigenpy/eigen-from-python.hpp +++ b/include/eigenpy/eigen-from-python.hpp @@ -14,12 +14,11 @@ namespace boost { namespace python { namespace converter { - /// \brief Template specialization of rvalue_from_python_data - template<typename Derived> - struct rvalue_from_python_data<Eigen::MatrixBase<Derived> const & > - : rvalue_from_python_storage<Derived const & > + template<typename MatrixReference> + struct rvalue_from_python_data_eigen + : rvalue_from_python_storage<MatrixReference> { - typedef Eigen::MatrixBase<Derived> const & T; + typedef MatrixReference T; # if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \ && (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \ @@ -30,7 +29,7 @@ namespace boost { namespace python { namespace converter { # endif // The usual constructor - rvalue_from_python_data(rvalue_from_python_stage1_data const & _stage1) + rvalue_from_python_data_eigen(rvalue_from_python_stage1_data const & _stage1) { this->stage1 = _stage1; } @@ -38,56 +37,48 @@ namespace boost { namespace python { namespace converter { // This constructor just sets m_convertible -- used by // implicitly_convertible<> to perform the final step of the // conversion, where the construct() function is already known. - rvalue_from_python_data(void* convertible) + rvalue_from_python_data_eigen(void* convertible) { this->stage1.convertible = convertible; } // Destroys any object constructed in the storage. - ~rvalue_from_python_data() + ~rvalue_from_python_data_eigen() { + typedef typename boost::remove_const<typename boost::remove_reference<MatrixReference>::type>::type MatrixType; if (this->stage1.convertible == this->storage.bytes) - static_cast<Derived *>((void *)this->storage.bytes)->~Derived(); + static_cast<MatrixType *>((void *)this->storage.bytes)->~MatrixType(); } }; + +#define RVALUE_FROM_PYTHON_DATA_INIT(type) \ + typedef rvalue_from_python_data_eigen<type> Base; \ + \ + rvalue_from_python_data(rvalue_from_python_stage1_data const & _stage1) \ + : Base(_stage1) \ + {} \ + \ + rvalue_from_python_data(void* convertible) : Base(convertible) {}; + /// \brief Template specialization of rvalue_from_python_data template<typename Derived> - struct rvalue_from_python_data<Eigen::EigenBase<Derived> const & > - : rvalue_from_python_storage<Derived const & > + struct rvalue_from_python_data<Eigen::MatrixBase<Derived> const &> + : rvalue_from_python_data_eigen<Derived const &> { - typedef Eigen::EigenBase<Derived> const & T; - -# if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \ -&& (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \ -&& (!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) \ -&& !defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing this */ - // This must always be a POD struct with m_data its first member. - BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0); -# endif - - // The usual constructor - rvalue_from_python_data(rvalue_from_python_stage1_data const & _stage1) - { - this->stage1 = _stage1; - } - - // This constructor just sets m_convertible -- used by - // implicitly_convertible<> to perform the final step of the - // conversion, where the construct() function is already known. - rvalue_from_python_data(void* convertible) - { - this->stage1.convertible = convertible; - } - - // Destroys any object constructed in the storage. - ~rvalue_from_python_data() - { - if (this->stage1.convertible == this->storage.bytes) - static_cast<Derived *>((void *)this->storage.bytes)->~Derived(); - } + RVALUE_FROM_PYTHON_DATA_INIT(Derived const &) + }; + + /// \brief Template specialization of rvalue_from_python_data + template<typename Derived> + struct rvalue_from_python_data<Eigen::EigenBase<Derived> const &> + : rvalue_from_python_data_eigen<Derived const &> + { + RVALUE_FROM_PYTHON_DATA_INIT(Derived const &) }; +#undef RVALUE_FROM_PYTHON_DATA_INIT + } } } namespace eigenpy @@ -95,61 +86,59 @@ 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; - } - } + typedef typename MatType::Scalar Scalar; /// \brief Determine if pyObj can be converted into a MatType object - static void* convertible(PyArrayObject* pyArray) + static void* convertible(PyArrayObject* pyArray); + + /// \brief Allocate memory and copy pyObj in the new storage + static void construct(PyObject* pyObj, + bp::converter::rvalue_from_python_stage1_data* memory); + + static void registration(); + }; + + template<typename MatType> + void* EigenFromPy<MatType>::convertible(PyArrayObject* pyArray) + { + if(!PyArray_Check(pyArray)) + return 0; + + if(!np_type_is_convertible_into_scalar<Scalar>(EIGENPY_GET_PY_ARRAY_TYPE(pyArray))) + return 0; + + if(MatType::IsVectorAtCompileTime) { - if(!PyArray_Check(pyArray)) - return 0; + const Eigen::DenseIndex size_at_compile_time + = MatType::IsRowMajor + ? MatType::ColsAtCompileTime + : MatType::RowsAtCompileTime; - if(!isScalarConvertible(EIGENPY_GET_PY_ARRAY_TYPE(pyArray))) - return 0; - - if(MatType::IsVectorAtCompileTime) + switch(PyArray_NDIM(pyArray)) { - const Eigen::DenseIndex size_at_compile_time - = MatType::IsRowMajor - ? MatType::ColsAtCompileTime - : MatType::RowsAtCompileTime; - - switch(PyArray_NDIM(pyArray)) + case 0: + return 0; + case 1: { - 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) { - // check that the sizes at compile time matche - if(PyArray_DIMS(pyArray)[0] == size_at_compile_time) + if(size_at_compile_time == 1) return pyArray; else return 0; @@ -157,108 +146,93 @@ namespace eigenpy else // This is a dynamic MatType return pyArray; } - case 2: + + if(PyArray_DIMS(pyArray)[0] > 1 && PyArray_DIMS(pyArray)[1] > 1) { - // 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) - { - return 0; - } - - if(((PyArray_DIMS(pyArray)[0] == 1) && (MatType::ColsAtCompileTime == 1)) - || ((PyArray_DIMS(pyArray)[1] == 1) && (MatType::RowsAtCompileTime == 1))) - { - 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; + return 0; } - default: + + if(((PyArray_DIMS(pyArray)[0] == 1) && (MatType::ColsAtCompileTime == 1)) + || ((PyArray_DIMS(pyArray)[1] == 1) && (MatType::RowsAtCompileTime == 1))) + { 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 + } + else // this is a matrix + { + if(PyArray_NDIM(pyArray) == 1) // We can always convert a vector into a matrix { - if(PyArray_NDIM(pyArray) == 1) // We can always convert a vector into a matrix - { - return pyArray; - } - - if(PyArray_NDIM(pyArray) != 2) - { - 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; - } + return pyArray; } - -#ifdef NPY_1_8_API_VERSION - if(!(PyArray_FLAGS(pyArray))) -#else - if(!(PyArray_FLAGS(pyArray) & NPY_ALIGNED)) -#endif + + if(PyArray_NDIM(pyArray) != 2) { 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; + 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; + } } - static void registration() +#ifdef NPY_1_8_API_VERSION + if(!(PyArray_FLAGS(pyArray))) +#else + if(!(PyArray_FLAGS(pyArray) & NPY_ALIGNED)) +#endif { - bp::converter::registry::push_back - (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible), - &EigenFromPy::construct,bp::type_id<MatType>()); + return 0; } - }; + + return pyArray; + } + + template<typename MatType> + void EigenFromPy<MatType>::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; + } + + template<typename MatType> + void EigenFromPy<MatType>::registration() + { + bp::converter::registry::push_back + (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible), + &EigenFromPy::construct,bp::type_id<MatType>()); + } template<typename MatType> struct EigenFromPyConverter @@ -317,8 +291,8 @@ namespace eigenpy &EigenFromPy<MatType>::construct,bp::type_id<MatType>()); } }; - #endif + } #endif // __eigenpy_eigen_from_python_hpp__ diff --git a/include/eigenpy/numpy-type.hpp b/include/eigenpy/numpy-type.hpp index 2bf7d03b9737563d873bbaea8600d90fb6eff4c0..3085b55e8ffe1dd33f4752900a97b934fad1a4c9 100644 --- a/include/eigenpy/numpy-type.hpp +++ b/include/eigenpy/numpy-type.hpp @@ -6,6 +6,7 @@ #define __eigenpy_numpy_type_hpp__ #include "eigenpy/fwd.hpp" +#include "eigenpy/scalar-conversion.hpp" #include <patchlevel.h> // For PY_MAJOR_VERSION @@ -23,6 +24,35 @@ namespace eigenpy template <> struct NumpyEquivalentType< std::complex<long double> > { enum { type_code = NPY_CLONGDOUBLE };}; template <> struct NumpyEquivalentType<int> { enum { type_code = NPY_INT };}; template <> struct NumpyEquivalentType<long> { enum { type_code = NPY_LONG };}; + + template<typename Scalar> + bool np_type_is_convertible_into_scalar(const int np_type) + { + if(NumpyEquivalentType<Scalar>::type_code == np_type) + return true; + + switch(np_type) + { + case NPY_INT: + return FromTypeToType<int,Scalar>::value; + case NPY_LONG: + return FromTypeToType<long,Scalar>::value; + case NPY_FLOAT: + return FromTypeToType<float,Scalar>::value; + case NPY_CFLOAT: + return FromTypeToType<std::complex<float>,Scalar>::value; + case NPY_DOUBLE: + return FromTypeToType<double,Scalar>::value; + case NPY_CDOUBLE: + return FromTypeToType<std::complex<double>,Scalar>::value; + case NPY_LONGDOUBLE: + return FromTypeToType<long double,Scalar>::value; + case NPY_CLONGDOUBLE: + return FromTypeToType<std::complex<long double>,Scalar>::value; + default: + return false; + } + } enum NP_TYPE {