Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add std::unique_ptr support #433

Merged
merged 18 commits into from
Feb 5, 2024

Conversation

jorisv
Copy link
Contributor

@jorisv jorisv commented Jan 31, 2024

  • Add a CallPolicy to copy the content of a std::unique_ptr for function return
  • Add a CallPolicy to move the content of a std::unique_ptr for function return
  • Add a CallPolicy to get a reference of the content of a std::unique_ptr for member access
  • Specialize to_python_value

Fix #427

@jorisv jorisv self-assigned this Jan 31, 2024
@jorisv jorisv linked an issue Feb 1, 2024 that may be closed by this pull request
@jorisv
Copy link
Contributor Author

jorisv commented Feb 1, 2024

In the current solution, when a function binding that return a std::unique_ptr is defined, the StdUniquePtrCallPolicies must be used.

It's maybe possible to overload boost::python::to_python_value to manage unique_ptr in the boost::python::default_call_policy.
In this case, before defining a function binding that return a std::unique_ptr user should include eigenpy/std_unique_ptr.hpp.

I don't know if the second option is better. User have less code to write, but he should include the right header that will do some magic for him.

@ManifoldFR, @jcarpent Any opinion ? (Not an emergency)

@ManifoldFR
Copy link
Member

In the current solution, when a function binding that return a std::unique_ptr is defined, the StdUniquePtrCallPolicies must be used.

It's maybe possible to overload boost::python::to_python_value to manage unique_ptr in the boost::python::default_call_policy. In this case, before defining a function binding that return a std::unique_ptr user should include eigenpy/std_unique_ptr.hpp.

I don't know if the second option is better. User have less code to write, but he should include the right header that will do some magic for him.

@ManifoldFR, @jcarpent Any opinion ? (Not an emergency)

Both solutions seem sound to me.

If we go for an overload of to_python_value we could just include <eigenpy/std_unique_ptr.hpp> in <eigenpy/eigenpy.hpp> to avoid user error?

@jorisv jorisv marked this pull request as ready for review February 1, 2024 16:26
@jorisv
Copy link
Contributor Author

jorisv commented Feb 1, 2024

If we go for an overload of to_python_value we could just include <eigenpy/std_unique_ptr.hpp> in <eigenpy/eigenpy.hpp> to avoid user error?

It would be the safest option.

I will investigate this solution then.

It's not possible to do the same thing with return_internal_reference because the structure only deal with reference or ptr (assert in reference_existing_object).

@ManifoldFR
Copy link
Member

If we go for an overload of to_python_value we could just include <eigenpy/std_unique_ptr.hpp> in <eigenpy/eigenpy.hpp> to avoid user error?

It would be the safest option.

I will investigate this solution then.

It's not possible to do the same thing with return_internal_reference because the structure only deal with reference or ptr (assert in reference_existing_object).

Would it be possible to do it on with_custodian_and_ward then ? Or does it still refer to reference_existing_object

Copy link
Member

@ManifoldFR ManifoldFR left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fantastic @jorisv, thanks a lot

I have a few questions:

  • whether bp::register_ptr_to_python can be used anywhere here as a shortcut,
  • whether unique_ptr can be used as a holder class (an argument in the bp::class_ template, the docs say one could expose a type T through shared_ptr<T> for instance) ; this is something Pybind11 does by default and I'm not sure whether boost.python already does that
  • whether vector<unique_ptr<T>> can be exposed

@jorisv
Copy link
Contributor Author

jorisv commented Feb 5, 2024

Would it be possible to do it on with_custodian_and_ward then ? Or does it still refer to reference_existing_object

Ok, it's mandatory to define a new Policies. We can't specialize bp::return_internal_reference (it doesn't depend of the type). But we need to redefine his postcall method.

@jorisv
Copy link
Contributor Author

jorisv commented Feb 5, 2024

* whether `bp::register_ptr_to_python` can be used anywhere here as a shortcut,

I don't know, it look like it doesn't manage the move like we are doing for unique_ptr.

* whether `unique_ptr` can be used as a holder class (an argument in the `bp::class_` template, the docs say one could expose a type `T` through `shared_ptr<T>` for instance) ; this is something Pybind11 [does by default](https://pybind11.readthedocs.io/en/stable/advanced/smart_ptrs.html) and I'm not sure whether boost.python already does that

When we transfer the ownership to python (return value) the bp::detail::make_owning_holder store the pointer in an unique_ptr.
I have change the method to directly call bp::objects::make_ptr_instance<T, holder_t> so we don't have to call unique_ptr::release.

* whether `vector<unique_ptr<T>>` can be exposed

We have modify the std::vector binding to manage non copiable data

@ManifoldFR
Copy link
Member

* whether `bp::register_ptr_to_python` can be used anywhere here as a shortcut,

I don't know, it look like it doesn't manage the move like we are doing for unique_ptr.

OK, make sense. register_ptr_to_python probably wasn't revamped with move semantics in mind.

* whether `unique_ptr` can be used as a holder class (an argument in the `bp::class_` template, the docs say one could expose a type `T` through `shared_ptr<T>` for instance) ; this is something Pybind11 [does by default](https://pybind11.readthedocs.io/en/stable/advanced/smart_ptrs.html) and I'm not sure whether boost.python already does that

When we transfer the ownership to python (return value) the bp::detail::make_owning_holder store the pointer in an unique_ptr. I have change the method to directly call bp::objects::make_ptr_instance<T, holder_t> so we don't have to call unique_ptr::release.

After checking we saw that unique_ptr is somewhat the default holder in Boost.Python as well.
I guess calling make_ptr_instance allows to having a leak in case an exception is triggered, so that's a good change!

@jorisv jorisv merged commit 5ea4023 into stack-of-tasks:devel Feb 5, 2024
29 checks passed
@jorisv jorisv deleted the topic/add_std_unique_ptr branch February 5, 2024 17:06
@ManifoldFR
Copy link
Member

Best PR ever

nim65s added a commit to nim65s/robotpkg that referenced this pull request Mar 12, 2024
Upstream changelog:

    ## [3.4.0] - 2024-02-26

    ### Added
    - Support for `Eigen::SparseMatrix` types (stack-of-tasks/eigenpy#426)
    - Support for `boost::variant` types with `VariantConverter` (stack-of-tasks/eigenpy#430)
    - Support for `std::variant` types with `VariantConverter` (stack-of-tasks/eigenpy#431)
    - Support for `std::unique_ptr` as a return types with `StdUniquePtrCallPolicies` and `boost::python::default_call_policies` (stack-of-tasks/eigenpy#433)
    - Support for `std::unique_ptr` as an internal reference with `ReturnInternalStdUniquePtr` (stack-of-tasks/eigenpy#433)
    - Support for `Eigen::Simplicial{LLT,LDLT}` and `Eigen::Cholmod{Simplicial,Supernodal}{LLT,LDLT}` Cholesky de compositions (stack-of-tasks/eigenpy#438)
    - Switch to ruff for lints, format, and import sort (stack-of-tasks/eigenpy#441)

    ### Fixed
    - Fix the issue of missing exposition of Eigen types with __int64 scalar type (stack-of-tasks/eigenpy#426)
    - Fix namespace use in unittest/std_pair.cpp (stack-of-tasks/eigenpy#429)
    - Fix case of zero-size sparse matrices (stack-of-tasks/eigenpy#437)

Packaging changes:
- remove patch-aa, fixed upstream
nim65s added a commit to nim65s/robotpkg that referenced this pull request Mar 29, 2024
Upstream changelog:

    ## [3.4.0] - 2024-02-26

    ### Added
    - Support for `Eigen::SparseMatrix` types (stack-of-tasks/eigenpy#426)
    - Support for `boost::variant` types with `VariantConverter` (stack-of-tasks/eigenpy#430)
    - Support for `std::variant` types with `VariantConverter` (stack-of-tasks/eigenpy#431)
    - Support for `std::unique_ptr` as a return types with `StdUniquePtrCallPolicies` and `boost::python::default_call_policies` (stack-of-tasks/eigenpy#433)
    - Support for `std::unique_ptr` as an internal reference with `ReturnInternalStdUniquePtr` (stack-of-tasks/eigenpy#433)
    - Support for `Eigen::Simplicial{LLT,LDLT}` and `Eigen::Cholmod{Simplicial,Supernodal}{LLT,LDLT}` Cholesky de compositions (stack-of-tasks/eigenpy#438)
    - Switch to ruff for lints, format, and import sort (stack-of-tasks/eigenpy#441)

    ### Fixed
    - Fix the issue of missing exposition of Eigen types with __int64 scalar type (stack-of-tasks/eigenpy#426)
    - Fix namespace use in unittest/std_pair.cpp (stack-of-tasks/eigenpy#429)
    - Fix case of zero-size sparse matrices (stack-of-tasks/eigenpy#437)

Packaging changes:
- remove patch-aa, fixed upstream
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for unique_ptr<T>
3 participants