Skip to content
Snippets Groups Projects
Unverified Commit 558e3919 authored by Joris Vaillant's avatar Joris Vaillant
Browse files

unique_ptr: Manage string and complex type

parent f565ce8e
No related branches found
No related tags found
No related merge requests found
...@@ -104,7 +104,8 @@ search_for_boost_python(REQUIRED) ...@@ -104,7 +104,8 @@ search_for_boost_python(REQUIRED)
# ---------------------------------------------------- # ----------------------------------------------------
set(${PROJECT_NAME}_UTILS_HEADERS set(${PROJECT_NAME}_UTILS_HEADERS
include/eigenpy/utils/scalar-name.hpp include/eigenpy/utils/is-approx.hpp include/eigenpy/utils/scalar-name.hpp include/eigenpy/utils/is-approx.hpp
include/eigenpy/utils/is-aligned.hpp) include/eigenpy/utils/is-aligned.hpp include/eigenpy/utils/traits.hpp
include/eigenpy/utils/python-compat.hpp)
set(${PROJECT_NAME}_SOLVERS_HEADERS set(${PROJECT_NAME}_SOLVERS_HEADERS
include/eigenpy/solvers/solvers.hpp include/eigenpy/solvers/solvers.hpp
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "eigenpy/fwd.hpp" #include "eigenpy/fwd.hpp"
#include "eigenpy/utils/traits.hpp" #include "eigenpy/utils/traits.hpp"
#include "eigenpy/utils/python-compat.hpp"
#include <boost/python.hpp> #include <boost/python.hpp>
...@@ -19,8 +20,7 @@ namespace details { ...@@ -19,8 +20,7 @@ namespace details {
/// Transfer std::unique_ptr ownership to an owning holder /// Transfer std::unique_ptr ownership to an owning holder
template <typename T> template <typename T>
typename std::enable_if<is_class_or_union_remove_cvref<T>::value, typename std::enable_if<!is_python_primitive_type<T>::value, PyObject*>::type
PyObject*>::type
unique_ptr_to_python(std::unique_ptr<T>&& x) { unique_ptr_to_python(std::unique_ptr<T>&& x) {
typedef bp::objects::pointer_holder<std::unique_ptr<T>, T> holder_t; typedef bp::objects::pointer_holder<std::unique_ptr<T>, T> holder_t;
if (!x) { if (!x) {
...@@ -32,8 +32,7 @@ unique_ptr_to_python(std::unique_ptr<T>&& x) { ...@@ -32,8 +32,7 @@ unique_ptr_to_python(std::unique_ptr<T>&& x) {
/// Convert and copy the primitive value to python /// Convert and copy the primitive value to python
template <typename T> template <typename T>
typename std::enable_if<!is_class_or_union_remove_cvref<T>::value, typename std::enable_if<is_python_primitive_type<T>::value, PyObject*>::type
PyObject*>::type
unique_ptr_to_python(std::unique_ptr<T>&& x) { unique_ptr_to_python(std::unique_ptr<T>&& x) {
if (!x) { if (!x) {
return bp::detail::none(); return bp::detail::none();
...@@ -45,8 +44,7 @@ unique_ptr_to_python(std::unique_ptr<T>&& x) { ...@@ -45,8 +44,7 @@ unique_ptr_to_python(std::unique_ptr<T>&& x) {
/// std::unique_ptr keep the ownership but a reference to the std::unique_ptr /// std::unique_ptr keep the ownership but a reference to the std::unique_ptr
/// value is created /// value is created
template <typename T> template <typename T>
typename std::enable_if<is_class_or_union_remove_cvref<T>::value, typename std::enable_if<!is_python_primitive_type<T>::value, PyObject*>::type
PyObject*>::type
internal_unique_ptr_to_python(std::unique_ptr<T>& x) { internal_unique_ptr_to_python(std::unique_ptr<T>& x) {
if (!x) { if (!x) {
return bp::detail::none(); return bp::detail::none();
...@@ -57,8 +55,7 @@ internal_unique_ptr_to_python(std::unique_ptr<T>& x) { ...@@ -57,8 +55,7 @@ internal_unique_ptr_to_python(std::unique_ptr<T>& x) {
/// Convert and copy the primitive value to python /// Convert and copy the primitive value to python
template <typename T> template <typename T>
typename std::enable_if<!is_class_or_union_remove_cvref<T>::value, typename std::enable_if<is_python_primitive_type<T>::value, PyObject*>::type
PyObject*>::type
internal_unique_ptr_to_python(std::unique_ptr<T>& x) { internal_unique_ptr_to_python(std::unique_ptr<T>& x) {
if (!x) { if (!x) {
return bp::detail::none(); return bp::detail::none();
...@@ -123,7 +120,8 @@ struct ReturnInternalStdUniquePtr : bp::return_internal_reference<> { ...@@ -123,7 +120,8 @@ struct ReturnInternalStdUniquePtr : bp::return_internal_reference<> {
template <class ArgumentPackage> template <class ArgumentPackage>
static PyObject* postcall(ArgumentPackage const& args_, PyObject* result) { static PyObject* postcall(ArgumentPackage const& args_, PyObject* result) {
// Don't run return_internal_reference postcall on primitive type // Don't run return_internal_reference postcall on primitive type
if (PyLong_Check(result) || PyBool_Check(result) || PyFloat_Check(result)) { if (PyInt_Check(result) || PyBool_Check(result) || PyFloat_Check(result) ||
PyStr_Check(result) || PyComplex_Check(result)) {
return result; return result;
} }
return bp::return_internal_reference<>::postcall(args_, result); return bp::return_internal_reference<>::postcall(args_, result);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "eigenpy/register.hpp" #include "eigenpy/register.hpp"
#include "eigenpy/user-type.hpp" #include "eigenpy/user-type.hpp"
#include "eigenpy/utils/python-compat.hpp"
namespace eigenpy { namespace eigenpy {
namespace internal { namespace internal {
...@@ -207,11 +208,7 @@ void registerCommonUfunc() { ...@@ -207,11 +208,7 @@ void registerCommonUfunc() {
const int type_code = Register::getTypeCode<Scalar>(); const int type_code = Register::getTypeCode<Scalar>();
PyObject *numpy_str; PyObject *numpy_str;
#if PY_MAJOR_VERSION >= 3 numpy_str = PyStr_FromString("numpy");
numpy_str = PyUnicode_FromString("numpy");
#else
numpy_str = PyString_FromString("numpy");
#endif
PyObject *numpy; PyObject *numpy;
numpy = PyImport_Import(numpy_str); numpy = PyImport_Import(numpy_str);
Py_DECREF(numpy_str); Py_DECREF(numpy_str);
......
//
// Copyright (c) 2024 INRIA
//
//
#ifndef __eigenpy_utils_python_compat_hpp__
#define __eigenpy_utils_python_compat_hpp__
#if PY_MAJOR_VERSION >= 3
#define PyInt_Check PyLong_Check
#define PyStr_Check PyUnicode_Check
#define PyStr_FromString PyUnicode_FromString
#else
#define PyStr_Check PyString_Check
#define PyStr_FromString PyString_FromString
#endif
#endif // ifndef __eigenpy_utils_python_compat_hpp__
...@@ -7,25 +7,47 @@ ...@@ -7,25 +7,47 @@
#define __eigenpy_utils_traits_hpp__ #define __eigenpy_utils_traits_hpp__
#include <type_traits> #include <type_traits>
#include <string>
#include <complex>
namespace eigenpy { namespace eigenpy {
namespace details { namespace details {
/// Trait to remove const&
template <typename T>
struct remove_cvref : std::remove_cv<typename std::remove_reference<T>::type> {
};
/// Trait to detect if T is a class or an union /// Trait to detect if T is a class or an union
template <typename T> template <typename T>
struct is_class_or_union struct is_class_or_union
: std::integral_constant<bool, std::is_class<T>::value || : std::integral_constant<bool, std::is_class<T>::value ||
std::is_union<T>::value> {}; std::is_union<T>::value> {};
/// trait to detect if T is a std::complex managed by Boost Python
template <typename T> template <typename T>
struct remove_cvref : std::remove_cv<typename std::remove_reference<T>::type> { struct is_python_complex : std::false_type {};
};
/// From boost/python/converter/builtin_converters
template <>
struct is_python_complex<std::complex<float> > : std::true_type {};
template <>
struct is_python_complex<std::complex<double> > : std::true_type {};
template <>
struct is_python_complex<std::complex<long double> > : std::true_type {};
template <typename T>
struct is_python_primitive_type_helper
: std::integral_constant<bool, !is_class_or_union<T>::value ||
std::is_same<T, std::string>::value ||
std::is_same<T, std::wstring>::value ||
is_python_complex<T>::value> {};
/// Trait to remove cvref and call is_class_or_union /// Trait to detect if T is a Python primitive type
template <typename T> template <typename T>
struct is_class_or_union_remove_cvref struct is_python_primitive_type
: is_class_or_union<typename remove_cvref<T>::type> {}; : is_python_primitive_type_helper<typename remove_cvref<T>::type> {};
} // namespace details } // namespace details
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "eigenpy/fwd.hpp" #include "eigenpy/fwd.hpp"
#include "eigenpy/utils/traits.hpp" #include "eigenpy/utils/traits.hpp"
#include "eigenpy/utils/python-compat.hpp"
#include <boost/python.hpp> #include <boost/python.hpp>
#include <boost/variant.hpp> #include <boost/variant.hpp>
...@@ -147,7 +148,7 @@ struct NumericConvertibleImpl< ...@@ -147,7 +148,7 @@ struct NumericConvertibleImpl<
std::is_integral<T>::value>::type> { std::is_integral<T>::value>::type> {
static void* convertible(PyObject* obj) { static void* convertible(PyObject* obj) {
// PyLong return true for bool type // PyLong return true for bool type
return (PyLong_Check(obj) && !PyBool_Check(obj)) ? obj : nullptr; return (PyInt_Check(obj) && !PyBool_Check(obj)) ? obj : nullptr;
} }
static PyTypeObject const* expected_pytype() { return &PyLong_Type; } static PyTypeObject const* expected_pytype() { return &PyLong_Type; }
...@@ -220,14 +221,14 @@ struct VariantRefToObject : VariantVisitorType<PyObject*, Variant> { ...@@ -220,14 +221,14 @@ struct VariantRefToObject : VariantVisitorType<PyObject*, Variant> {
} }
template <typename T, template <typename T,
typename std::enable_if<!is_class_or_union_remove_cvref<T>::value, typename std::enable_if<is_python_primitive_type<T>::value,
bool>::type = true> bool>::type = true>
result_type operator()(T t) const { result_type operator()(T t) const {
return bp::incref(bp::object(t).ptr()); return bp::incref(bp::object(t).ptr());
} }
template <typename T, template <typename T,
typename std::enable_if<is_class_or_union_remove_cvref<T>::value, typename std::enable_if<!is_python_primitive_type<T>::value,
bool>::type = true> bool>::type = true>
result_type operator()(T& t) const { result_type operator()(T& t) const {
return bp::detail::make_reference_holder::execute(&t); return bp::detail::make_reference_holder::execute(&t);
...@@ -301,7 +302,8 @@ struct ReturnInternalVariant : bp::return_internal_reference<> { ...@@ -301,7 +302,8 @@ struct ReturnInternalVariant : bp::return_internal_reference<> {
template <class ArgumentPackage> template <class ArgumentPackage>
static PyObject* postcall(ArgumentPackage const& args_, PyObject* result) { static PyObject* postcall(ArgumentPackage const& args_, PyObject* result) {
// Don't run return_internal_reference postcall on primitive type // Don't run return_internal_reference postcall on primitive type
if (PyLong_Check(result) || PyBool_Check(result) || PyFloat_Check(result)) { if (PyInt_Check(result) || PyBool_Check(result) || PyFloat_Check(result) ||
PyStr_Check(result) || PyComplex_Check(result)) {
return result; return result;
} }
return bp::return_internal_reference<>::postcall(args_, result); return bp::return_internal_reference<>::postcall(args_, result);
......
...@@ -2,6 +2,8 @@ from std_unique_ptr import ( ...@@ -2,6 +2,8 @@ from std_unique_ptr import (
make_unique_int, make_unique_int,
make_unique_v1, make_unique_v1,
make_unique_null, make_unique_null,
make_unique_str,
make_unique_complex,
V1, V1,
UniquePtrHolder, UniquePtrHolder,
) )
...@@ -17,6 +19,14 @@ assert v.v == 10 ...@@ -17,6 +19,14 @@ assert v.v == 10
v = make_unique_null() v = make_unique_null()
assert v is None assert v is None
v = make_unique_str()
assert isinstance(v, str)
assert v == "str"
v = make_unique_complex()
assert isinstance(v, complex)
assert v == 1 + 0j
unique_ptr_holder = UniquePtrHolder() unique_ptr_holder = UniquePtrHolder()
v = unique_ptr_holder.int_ptr v = unique_ptr_holder.int_ptr
...@@ -33,6 +43,19 @@ assert v.v == 200 ...@@ -33,6 +43,19 @@ assert v.v == 200
v.v = 10 v.v = 10
assert unique_ptr_holder.v1_ptr.v == 10 assert unique_ptr_holder.v1_ptr.v == 10
v = unique_ptr_holder.null_ptr v = unique_ptr_holder.null_ptr
assert v is None assert v is None
v = unique_ptr_holder.str_ptr
assert isinstance(v, str)
assert v == "str"
# v is a copy, str_ptr will not be updated
v = "str_updated"
assert unique_ptr_holder.str_ptr == "str"
v = unique_ptr_holder.complex_ptr
assert isinstance(v, complex)
assert v == 1 + 0j
# v is a copy, complex_ptr will not be updated
v = 1 + 2j
assert unique_ptr_holder.complex_ptr == 1 + 0j
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include <eigenpy/std-unique-ptr.hpp> #include <eigenpy/std-unique-ptr.hpp>
#include <memory> #include <memory>
#include <string>
#include <complex>
namespace bp = boost::python; namespace bp = boost::python;
...@@ -21,13 +23,26 @@ std::unique_ptr<V1> make_unique_v1() { return std::make_unique<V1>(10); } ...@@ -21,13 +23,26 @@ std::unique_ptr<V1> make_unique_v1() { return std::make_unique<V1>(10); }
std::unique_ptr<V1> make_unique_null() { return nullptr; } std::unique_ptr<V1> make_unique_null() { return nullptr; }
std::unique_ptr<std::string> make_unique_str() {
return std::make_unique<std::string>("str");
}
std::unique_ptr<std::complex<double> > make_unique_complex() {
return std::make_unique<std::complex<double> >(1., 0.);
}
struct UniquePtrHolder { struct UniquePtrHolder {
UniquePtrHolder() UniquePtrHolder()
: int_ptr(std::make_unique<int>(20)), v1_ptr(std::make_unique<V1>(200)) {} : int_ptr(std::make_unique<int>(20)),
v1_ptr(std::make_unique<V1>(200)),
str_ptr(std::make_unique<std::string>("str")),
complex_ptr(std::make_unique<std::complex<double> >(1., 0.)) {}
std::unique_ptr<int> int_ptr; std::unique_ptr<int> int_ptr;
std::unique_ptr<V1> v1_ptr; std::unique_ptr<V1> v1_ptr;
std::unique_ptr<V1> null_ptr; std::unique_ptr<V1> null_ptr;
std::unique_ptr<std::string> str_ptr;
std::unique_ptr<std::complex<double> > complex_ptr;
}; };
BOOST_PYTHON_MODULE(std_unique_ptr) { BOOST_PYTHON_MODULE(std_unique_ptr) {
...@@ -39,6 +54,8 @@ BOOST_PYTHON_MODULE(std_unique_ptr) { ...@@ -39,6 +54,8 @@ BOOST_PYTHON_MODULE(std_unique_ptr) {
bp::def("make_unique_v1", make_unique_v1); bp::def("make_unique_v1", make_unique_v1);
bp::def("make_unique_null", make_unique_null, bp::def("make_unique_null", make_unique_null,
eigenpy::StdUniquePtrCallPolicies()); eigenpy::StdUniquePtrCallPolicies());
bp::def("make_unique_str", make_unique_str);
bp::def("make_unique_complex", make_unique_complex);
boost::python::class_<UniquePtrHolder, boost::noncopyable>("UniquePtrHolder", boost::python::class_<UniquePtrHolder, boost::noncopyable>("UniquePtrHolder",
bp::init<>()) bp::init<>())
...@@ -50,5 +67,11 @@ BOOST_PYTHON_MODULE(std_unique_ptr) { ...@@ -50,5 +67,11 @@ BOOST_PYTHON_MODULE(std_unique_ptr) {
eigenpy::ReturnInternalStdUniquePtr())) eigenpy::ReturnInternalStdUniquePtr()))
.add_property("null_ptr", .add_property("null_ptr",
bp::make_getter(&UniquePtrHolder::null_ptr, bp::make_getter(&UniquePtrHolder::null_ptr,
eigenpy::ReturnInternalStdUniquePtr()))
.add_property("str_ptr",
bp::make_getter(&UniquePtrHolder::str_ptr,
eigenpy::ReturnInternalStdUniquePtr()))
.add_property("complex_ptr",
bp::make_getter(&UniquePtrHolder::complex_ptr,
eigenpy::ReturnInternalStdUniquePtr())); eigenpy::ReturnInternalStdUniquePtr()));
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment