diff --git a/CMakeLists.txt b/CMakeLists.txt index d8d8a79e61072d0e53893512824df798a89ffe74..f280d6b5b93a02b10daba1d500a65944ff6b353d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,6 +167,7 @@ set(${PROJECT_NAME}_HEADERS include/eigenpy/scipy-allocator.hpp include/eigenpy/scipy-type.hpp include/eigenpy/variant.hpp + include/eigenpy/std_unique_ptr.hpp include/eigenpy/swig.hpp include/eigenpy/version.hpp) diff --git a/include/eigenpy/std_unique_ptr.hpp b/include/eigenpy/std_unique_ptr.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c45dbd08751c183f75562cefbc9541975582f7df --- /dev/null +++ b/include/eigenpy/std_unique_ptr.hpp @@ -0,0 +1,49 @@ +// +// Copyright (c) 2024 INRIA +// + +#ifndef __eigenpy_utils_std_unique_ptr_hpp__ +#define __eigenpy_utils_std_unique_ptr_hpp__ + +#include "eigenpy/fwd.hpp" + +#include <boost/python.hpp> + +#include <memory> +#include <iostream> + +namespace eigenpy { + +/// result_converter of StdUniquePtrCallPolicies +struct StdUniquePtrResultConverter { + template <class T> + struct apply { + struct type { + typedef typename bp::detail::value_arg<T>::type argument_type; + + /// TODO, this work by copy + /// We maybe can transfer the ownership to Python for class type + /// and when argument_type is an lvalue ref + PyObject* operator()(argument_type x) const { + return bp::to_python_value<const typename T::element_type&>()(*x); + } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + PyTypeObject const* get_pytype() const { + return bp::to_python_value<const typename T::element_type&>() + .get_pytype(); + } +#endif + BOOST_STATIC_CONSTANT(bool, uses_registry = true); + }; + }; +}; + +/// Access CallPolicie to get std::unique_ptr value from a functio +/// that return an std::unique_ptr +struct StdUniquePtrCallPolicies : bp::default_call_policies { + typedef StdUniquePtrResultConverter result_converter; +}; + +} // namespace eigenpy + +#endif // ifndef __eigenpy_utils_std_unique_ptr_hpp__ diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index 097aab1f08ed7f4ad1dd67923b27b9f52f1fb4f3..8dc425fa98c7fed420bea094e195661d3c8b8324 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -45,6 +45,7 @@ add_lib_unit_test(std_vector) add_lib_unit_test(std_array) add_lib_unit_test(std_pair) add_lib_unit_test(user_struct) +add_lib_unit_test(std_unique_ptr) function(config_test test tagname opttype) set(MODNAME ${test}_${tagname}) diff --git a/unittest/python/test_std_unique_ptr.py b/unittest/python/test_std_unique_ptr.py new file mode 100644 index 0000000000000000000000000000000000000000..cb8f7d462c033c3d928b38f42564312a85a13648 --- /dev/null +++ b/unittest/python/test_std_unique_ptr.py @@ -0,0 +1,12 @@ +from std_unique_ptr import make_unique_int, make_unique_v1, make_unique_null, V1 + +v = make_unique_int() +assert isinstance(v, int) +assert v == 10 + +v = make_unique_v1() +assert isinstance(v, V1) +assert v.v == 10 + +v = make_unique_null() +assert v is None diff --git a/unittest/std_unique_ptr.cpp b/unittest/std_unique_ptr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2fdad8c33085c1baaed09ab14a88d3ca1d89e313 --- /dev/null +++ b/unittest/std_unique_ptr.cpp @@ -0,0 +1,45 @@ +/// @file +/// @copyright Copyright 2023 CNRS INRIA + +#include <iostream> +#include <eigenpy/eigenpy.hpp> +#include <eigenpy/std_unique_ptr.hpp> +#include <memory> + +namespace bp = boost::python; + +struct V1 { + V1() = default; + V1(double p_v) : v(p_v) {} + + double v = 100; +}; + +std::unique_ptr<int> make_unique_int() { return std::make_unique<int>(10); } + +std::unique_ptr<V1> make_unique_v1() { return std::make_unique<V1>(10); } + +std::unique_ptr<V1> make_unique_null() { return nullptr; } + +struct UniquePtrHolder { + std::unique_ptr<int> int_ptr; + std::unique_ptr<V1> v1_ptr; + std::unique_ptr<V1> null_ptr; +}; + +BOOST_PYTHON_MODULE(std_unique_ptr) { + eigenpy::enableEigenPy(); + + bp::class_<V1>("V1", bp::init<>()).def_readwrite("v", &V1::v); + + bp::def("make_unique_int", make_unique_int, + eigenpy::StdUniquePtrCallPolicies()); + bp::def("make_unique_v1", make_unique_v1, + eigenpy::StdUniquePtrCallPolicies()); + bp::def("make_unique_null", make_unique_null, + eigenpy::StdUniquePtrCallPolicies()); + // TODO allow access with a CallPolicie like return_internal_reference + // boost::python::class_<UniquePtrHolder>("UniquePtrHolder", bp::init<>()) + // .add_property("int_ptr", bp::make_getter(&UniquePtrHolder::int_ptr), + // bp::make_setter(&UniquePtrHolder::int_ptr)); +}