Unverified Commit 9d7a07ac authored by Justin Carpentier's avatar Justin Carpentier Committed by GitHub
Browse files

Merge pull request #162 from jcarpent/devel

Factorization of the code
parents 34d530d2 4f8980b6
......@@ -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__
......@@ -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
{
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment