diff --git a/CMakeLists.txt b/CMakeLists.txt index a5f0799e7bc9a4c724896bb1d8465dcd9ba00861..6925e0a8c9aacee8139da345c43023a9f09847b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,7 @@ SET(${PROJECT_NAME}_HEADERS include/eigenpy/quaternion.hpp include/eigenpy/user-type.hpp include/eigenpy/ufunc.hpp + include/eigenpy/register.hpp include/eigenpy/stride.hpp include/eigenpy/version.hpp ) @@ -152,7 +153,7 @@ SET(${PROJECT_NAME}_SOURCES src/matrix-float.cpp src/matrix-complex-float.cpp src/matrix-complex-double.cpp - src/user-type.cpp + src/register.cpp src/matrix-double.cpp src/matrix-long-double.cpp src/matrix-complex-long-double.cpp diff --git a/include/eigenpy/eigen-allocator.hpp b/include/eigenpy/eigen-allocator.hpp index 334ad536a7ae0426d48225d4dddb508dca678b42..dc6a84ce43a61a5afeaf3b55a08717e475ff448f 100644 --- a/include/eigenpy/eigen-allocator.hpp +++ b/include/eigenpy/eigen-allocator.hpp @@ -7,7 +7,7 @@ #include "eigenpy/fwd.hpp" #include "eigenpy/numpy-map.hpp" -#include "eigenpy/user-type.hpp" +#include "eigenpy/register.hpp" #include "eigenpy/scalar-conversion.hpp" #include "eigenpy/utils/is-aligned.hpp" diff --git a/include/eigenpy/numpy-allocator.hpp b/include/eigenpy/numpy-allocator.hpp index 760993f19741cec48503792e4f5f821d3de633cd..a627c8abbd66dc810d92109a30817552c6675008 100644 --- a/include/eigenpy/numpy-allocator.hpp +++ b/include/eigenpy/numpy-allocator.hpp @@ -9,7 +9,7 @@ #include "eigenpy/numpy-type.hpp" #include "eigenpy/eigen-allocator.hpp" -#include "eigenpy/user-type.hpp" +#include "eigenpy/register.hpp" namespace eigenpy { diff --git a/include/eigenpy/register.hpp b/include/eigenpy/register.hpp new file mode 100644 index 0000000000000000000000000000000000000000..42df36fc7eecf03e60d84f9e7558d6fa395fe181 --- /dev/null +++ b/include/eigenpy/register.hpp @@ -0,0 +1,184 @@ +// +// Copyright (c) 2020 INRIA +// + +#ifndef __eigenpy_register_hpp__ +#define __eigenpy_register_hpp__ + +#include "eigenpy/fwd.hpp" +#include "eigenpy/numpy-type.hpp" +#include "eigenpy/exception.hpp" + +#include <algorithm> +#include <map> +#include <typeinfo> +#include <string> + +namespace eigenpy +{ + + /// \brief Structure collecting all the types registers in Numpy via EigenPy + struct EIGENPY_DLLEXPORT Register + { + + static PyArray_Descr * getPyArrayDescr(PyTypeObject * py_type_ptr) + { + MapDescr::iterator it = py_array_descr_bindings.find(py_type_ptr); + if(it != py_array_descr_bindings.end()) + return it->second; + else + return NULL; + } + + template<typename Scalar> + static bool isRegistered() + { + return isRegistered(Register::getPyType<Scalar>()); + } + + static bool isRegistered(PyTypeObject * py_type_ptr) + { + if(getPyArrayDescr(py_type_ptr) != NULL) + return true; + else + return false; + } + + static int getTypeCode(PyTypeObject * py_type_ptr) + { + MapCode::iterator it = py_array_code_bindings.find(py_type_ptr); + if(it != py_array_code_bindings.end()) + return it->second; + else + return PyArray_TypeNum(py_type_ptr); + } + + template<typename Scalar> + static PyTypeObject * getPyType() + { + if(!isNumpyNativeType<Scalar>()) + { + const PyTypeObject * const_py_type_ptr = bp::converter::registered_pytype<Scalar>::get_pytype(); + if(const_py_type_ptr == NULL) + { + std::stringstream ss; + ss << "The type " << typeid(Scalar).name() << " does not have a registered converter inside Boot.Python." << std::endl; + throw std::invalid_argument(ss.str()); + } + PyTypeObject * py_type_ptr = const_cast<PyTypeObject *>(const_py_type_ptr); + return py_type_ptr; + } + else + { + PyArray_Descr * new_descr = PyArray_DescrFromType(NumpyEquivalentType<Scalar>::type_code); + return new_descr->typeobj; + } + } + + template<typename Scalar> + static int getTypeCode() + { + if(isNumpyNativeType<Scalar>()) + return NumpyEquivalentType<Scalar>::type_code; + else + { + const std::type_info & info = typeid(Scalar); + if(type_to_py_type_bindings.find(&info) != type_to_py_type_bindings.end()) + { + PyTypeObject * py_type = type_to_py_type_bindings[&info]; + int code = py_array_code_bindings[py_type]; + + return code; + } + else + return -1; // type not registered + } + } + + static int registerNewType(PyTypeObject * py_type_ptr, + const std::type_info * type_info_ptr, + const int type_size, + PyArray_GetItemFunc * getitem, + PyArray_SetItemFunc * setitem, + PyArray_NonzeroFunc * nonzero, + PyArray_CopySwapFunc * copyswap, + PyArray_CopySwapNFunc * copyswapn, + PyArray_DotFunc * dotfunc) + { + namespace bp = boost::python; + + PyArray_Descr * descr_ptr = new PyArray_Descr(*PyArray_DescrFromType(NPY_OBJECT)); + PyArray_Descr & descr = *descr_ptr; + descr.typeobj = py_type_ptr; + descr.kind = 'V'; + descr.byteorder = '='; + descr.elsize = type_size; + descr.flags = NPY_LIST_PICKLE | NPY_USE_GETITEM | NPY_USE_SETITEM | NPY_NEEDS_INIT | NPY_NEEDS_PYAPI; +// descr->names = PyTuple_New(0); +// descr->fields = PyDict_New(); + + PyArray_ArrFuncs * funcs_ptr = new PyArray_ArrFuncs; + PyArray_ArrFuncs & funcs = *funcs_ptr; + descr.f = funcs_ptr; + PyArray_InitArrFuncs(funcs_ptr); + funcs.getitem = getitem; + funcs.setitem = setitem; + funcs.nonzero = nonzero; + funcs.copyswap = copyswap; + funcs.copyswapn = copyswapn; + funcs.dotfunc = dotfunc; +// f->cast = cast; + + const int code = PyArray_RegisterDataType(descr_ptr); + assert(code >= 0 && "The return code should be positive"); + PyArray_Descr * new_descr = PyArray_DescrFromType(code); + + type_to_py_type_bindings.insert(std::make_pair(type_info_ptr,py_type_ptr)); + py_array_descr_bindings[py_type_ptr] = new_descr; + py_array_code_bindings[py_type_ptr] = code; + +// PyArray_RegisterCanCast(descr,NPY_OBJECT,NPY_NOSCALAR); + return code; + } + + static Register & instance() + { + return self; + } + + private: + + Register() {}; + + struct Compare_PyTypeObject + { + bool operator()(const PyTypeObject * a, const PyTypeObject * b) const + { + return std::string(a->tp_name) < std::string(b->tp_name); + } + }; + + struct Compare_TypeInfo + { + bool operator()(const std::type_info * a, const std::type_info * b) const + { + return std::string(a->name()) < std::string(b->name()); + } + }; + + typedef std::map<const std::type_info *,PyTypeObject *,Compare_TypeInfo> MapInfo; + static MapInfo type_to_py_type_bindings; + + typedef std::map<PyTypeObject *,PyArray_Descr *,Compare_PyTypeObject> MapDescr; + static MapDescr py_array_descr_bindings; + + typedef std::map<PyTypeObject *,int,Compare_PyTypeObject> MapCode; + static MapCode py_array_code_bindings; + + static Register self; + + }; + +} // namespace eigenpy + +#endif // __eigenpy_register_hpp__ diff --git a/include/eigenpy/ufunc.hpp b/include/eigenpy/ufunc.hpp index 39504e72009418534fb4f2611844fe21b48ebd16..e9b074bf4dde3671ab395b8313ab3b6694c60ebf 100644 --- a/include/eigenpy/ufunc.hpp +++ b/include/eigenpy/ufunc.hpp @@ -5,7 +5,7 @@ #ifndef __eigenpy_ufunc_hpp__ #define __eigenpy_ufunc_hpp__ -#include "eigenpy/user-type.hpp" +#include "eigenpy/register.hpp" namespace eigenpy { diff --git a/include/eigenpy/user-type.hpp b/include/eigenpy/user-type.hpp index 6d54301e9696bef261852c23e7a8a66028ac5a1d..212ef1dfd856c53cde99632550c847f7ca55f4d4 100644 --- a/include/eigenpy/user-type.hpp +++ b/include/eigenpy/user-type.hpp @@ -7,12 +7,7 @@ #include "eigenpy/fwd.hpp" #include "eigenpy/numpy-type.hpp" -#include "eigenpy/exception.hpp" - -#include <algorithm> -#include <map> -#include <typeinfo> -#include <string> +#include "eigenpy/register.hpp" namespace eigenpy { @@ -171,168 +166,6 @@ namespace eigenpy } // namespace internal - /// \brief Structure collecting all the types registers in Numpy via EigenPy - struct EIGENPY_DLLEXPORT Register - { - - static PyArray_Descr * getPyArrayDescr(PyTypeObject * py_type_ptr) - { - MapDescr::iterator it = py_array_descr_bindings.find(py_type_ptr); - if(it != py_array_descr_bindings.end()) - return it->second; - else - return NULL; - } - - template<typename Scalar> - static bool isRegistered() - { - return isRegistered(Register::getPyType<Scalar>()); - } - - static bool isRegistered(PyTypeObject * py_type_ptr) - { - if(getPyArrayDescr(py_type_ptr) != NULL) - return true; - else - return false; - } - - static int getTypeCode(PyTypeObject * py_type_ptr) - { - MapCode::iterator it = py_array_code_bindings.find(py_type_ptr); - if(it != py_array_code_bindings.end()) - return it->second; - else - return PyArray_TypeNum(py_type_ptr); - } - - template<typename Scalar> - static PyTypeObject * getPyType() - { - if(!isNumpyNativeType<Scalar>()) - { - const PyTypeObject * const_py_type_ptr = bp::converter::registered_pytype<Scalar>::get_pytype(); - if(const_py_type_ptr == NULL) - { - std::stringstream ss; - ss << "The type " << typeid(Scalar).name() << " does not have a registered converter inside Boot.Python." << std::endl; - throw std::invalid_argument(ss.str()); - } - PyTypeObject * py_type_ptr = const_cast<PyTypeObject *>(const_py_type_ptr); - return py_type_ptr; - } - else - { - PyArray_Descr * new_descr = PyArray_DescrFromType(NumpyEquivalentType<Scalar>::type_code); - return new_descr->typeobj; - } - } - - template<typename Scalar> - static int getTypeCode() - { - if(isNumpyNativeType<Scalar>()) - return NumpyEquivalentType<Scalar>::type_code; - else - { - const std::type_info & info = typeid(Scalar); - if(type_to_py_type_bindings.find(&info) != type_to_py_type_bindings.end()) - { - PyTypeObject * py_type = type_to_py_type_bindings[&info]; - int code = py_array_code_bindings[py_type]; - - return code; - } - else - return -1; // type not registered - } - } - - static int registerNewType(PyTypeObject * py_type_ptr, - const std::type_info * type_info_ptr, - const int type_size, - PyArray_GetItemFunc * getitem, - PyArray_SetItemFunc * setitem, - PyArray_NonzeroFunc * nonzero, - PyArray_CopySwapFunc * copyswap, - PyArray_CopySwapNFunc * copyswapn, - PyArray_DotFunc * dotfunc) - { - namespace bp = boost::python; - - PyArray_Descr * descr_ptr = new PyArray_Descr(*PyArray_DescrFromType(NPY_OBJECT)); - PyArray_Descr & descr = *descr_ptr; - descr.typeobj = py_type_ptr; - descr.kind = 'V'; - descr.byteorder = '='; - descr.elsize = type_size; - descr.flags = NPY_LIST_PICKLE | NPY_USE_GETITEM | NPY_USE_SETITEM | NPY_NEEDS_INIT | NPY_NEEDS_PYAPI; -// descr->names = PyTuple_New(0); -// descr->fields = PyDict_New(); - - PyArray_ArrFuncs * funcs_ptr = new PyArray_ArrFuncs; - PyArray_ArrFuncs & funcs = *funcs_ptr; - descr.f = funcs_ptr; - PyArray_InitArrFuncs(funcs_ptr); - funcs.getitem = getitem; - funcs.setitem = setitem; - funcs.nonzero = nonzero; - funcs.copyswap = copyswap; - funcs.copyswapn = copyswapn; - funcs.dotfunc = dotfunc; -// f->cast = cast; - - const int code = PyArray_RegisterDataType(descr_ptr); - assert(code >= 0 && "The return code should be positive"); - PyArray_Descr * new_descr = PyArray_DescrFromType(code); - - type_to_py_type_bindings.insert(std::make_pair(type_info_ptr,py_type_ptr)); - py_array_descr_bindings[py_type_ptr] = new_descr; - py_array_code_bindings[py_type_ptr] = code; - -// PyArray_RegisterCanCast(descr,NPY_OBJECT,NPY_NOSCALAR); - return code; - } - - static Register & instance() - { - return self; - } - - private: - - Register() {}; - - struct Compare_PyTypeObject - { - bool operator()(const PyTypeObject * a, const PyTypeObject * b) const - { - return std::string(a->tp_name) < std::string(b->tp_name); - } - }; - - struct Compare_TypeInfo - { - bool operator()(const std::type_info * a, const std::type_info * b) const - { - return std::string(a->name()) < std::string(b->name()); - } - }; - - typedef std::map<const std::type_info *,PyTypeObject *,Compare_TypeInfo> MapInfo; - static MapInfo type_to_py_type_bindings; - - typedef std::map<PyTypeObject *,PyArray_Descr *,Compare_PyTypeObject> MapDescr; - static MapDescr py_array_descr_bindings; - - typedef std::map<PyTypeObject *,int,Compare_PyTypeObject> MapCode; - static MapCode py_array_code_bindings; - - static Register self; - - }; - template<typename Scalar> int registerNewType(PyTypeObject * py_type_ptr = NULL) { diff --git a/src/user-type.cpp b/src/register.cpp similarity index 88% rename from src/user-type.cpp rename to src/register.cpp index bfdbbee7ba49206a46b0eaf5742589e642745ded..8e12ad752c0885ce4ab0a3e5e9ac5f25f8fb828c 100644 --- a/src/user-type.cpp +++ b/src/register.cpp @@ -2,7 +2,7 @@ * Copyright 2020 INRIA */ -#include "eigenpy/user-type.hpp" +#include "eigenpy/register.hpp" namespace eigenpy {