From a56ca1a26926f940002e02488d9564fe38d49d74 Mon Sep 17 00:00:00 2001
From: Joris Vaillant <joris.vaillant@inria.fr>
Date: Thu, 1 Feb 2024 15:37:48 +0100
Subject: [PATCH] unique_ptr: Move object

---
 include/eigenpy/std_unique_ptr.hpp | 48 ++++++++++++++++++++++--------
 1 file changed, 36 insertions(+), 12 deletions(-)

diff --git a/include/eigenpy/std_unique_ptr.hpp b/include/eigenpy/std_unique_ptr.hpp
index c45dbd08..45ac265d 100644
--- a/include/eigenpy/std_unique_ptr.hpp
+++ b/include/eigenpy/std_unique_ptr.hpp
@@ -6,31 +6,53 @@
 #define __eigenpy_utils_std_unique_ptr_hpp__
 
 #include "eigenpy/fwd.hpp"
+#include "eigenpy/utils/traits.hpp"
 
 #include <boost/python.hpp>
 
 #include <memory>
-#include <iostream>
 
 namespace eigenpy {
 
+namespace details {
+
+template <typename T>
+typename std::enable_if<is_class_or_union_remove_cvref<T>::value,
+                        PyObject*>::type
+unique_ptr_to_python(std::unique_ptr<T>&& x) {
+  if (!x) {
+    return bp::detail::none();
+  } else {
+    return bp::detail::make_owning_holder::execute(x.release());
+  }
+}
+
+template <typename T>
+typename std::enable_if<!is_class_or_union_remove_cvref<T>::value,
+                        PyObject*>::type
+unique_ptr_to_python(std::unique_ptr<T>&& x) {
+  if (!x) {
+    return bp::detail::none();
+  } else {
+    return bp::to_python_value<const T&>()(*x);
+  }
+}
+
+}  // namespace details
+
 /// result_converter of StdUniquePtrCallPolicies
 struct StdUniquePtrResultConverter {
-  template <class T>
+  template <typename T>
   struct apply {
     struct type {
-      typedef typename bp::detail::value_arg<T>::type argument_type;
+      typedef typename T::element_type element_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);
+      PyObject* operator()(T&& x) const {
+        return details::unique_ptr_to_python(std::forward<T>(x));
       }
 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
       PyTypeObject const* get_pytype() const {
-        return bp::to_python_value<const typename T::element_type&>()
-            .get_pytype();
+        return bp::to_python_value<const element_type&>().get_pytype();
       }
 #endif
       BOOST_STATIC_CONSTANT(bool, uses_registry = true);
@@ -38,8 +60,10 @@ struct StdUniquePtrResultConverter {
   };
 };
 
-/// Access CallPolicie to get std::unique_ptr value from a functio
-/// that return an std::unique_ptr
+/// CallPolicies to get std::unique_ptr value from a function
+/// that return an std::unique_ptr.
+/// If the object inside the std::unique_ptr is a class or an union
+/// it will be moved. In other case, it will be copied.
 struct StdUniquePtrCallPolicies : bp::default_call_policies {
   typedef StdUniquePtrResultConverter result_converter;
 };
-- 
GitLab