@@ -479,6 +479,20 @@ inline PyThreadState *get_thread_state_unchecked() {
479479inline void keep_alive_impl (handle nurse, handle patient);
480480inline PyObject *make_new_instance (PyTypeObject *type);
481481
482+ inline bool reclaim_existing_if_needed (
483+ instance *inst, const detail::type_info *tinfo, const void *existing_holder) {
484+ // Only reclaim if (a) we have an existing holder and (b) if it's a move-only holder.
485+ // TODO: Remove `default_holder`, store more descriptive holder information.
486+ if (existing_holder && tinfo->default_holder ) {
487+ // Requesting reclaim from C++.
488+ value_and_holder v_h = inst->get_value_and_holder (tinfo);
489+ // TODO(eric.cousineau): Add `holder_type_erased` to avoid need for `const_cast`.
490+ tinfo->holder_info .reclaim (v_h, const_cast <void *>(existing_holder));
491+ return true ;
492+ }
493+ return false ;
494+ }
495+
482496class type_caster_generic {
483497public:
484498 PYBIND11_NOINLINE type_caster_generic (const std::type_info &type_info)
@@ -506,8 +520,12 @@ class type_caster_generic {
506520 auto it_instances = get_internals ().registered_instances .equal_range (src);
507521 for (auto it_i = it_instances.first ; it_i != it_instances.second ; ++it_i) {
508522 for (auto instance_type : detail::all_type_info (Py_TYPE (it_i->second ))) {
509- if (instance_type && same_type (*instance_type->cpptype , *tinfo->cpptype ))
510- return handle ((PyObject *) it_i->second ).inc_ref ();
523+ if (instance_type && same_type (*instance_type->cpptype , *tinfo->cpptype )) {
524+ // Casting for an already registered type. Return existing reference.
525+ instance *inst = it_i->second ;
526+ reclaim_existing_if_needed (inst, tinfo, existing_holder);
527+ return handle ((PyObject *) inst).inc_ref ();
528+ }
511529 }
512530 }
513531
@@ -1373,6 +1391,16 @@ struct holder_helper {
13731391 static auto get (const T &p) -> decltype(p.get()) { return p.get (); }
13741392};
13751393
1394+ template <typename holder_type>
1395+ cast_error cast_error_holder_unheld () {
1396+ return cast_error (" Unable to cast from non-held to held instance (T& to Holder<T>) "
1397+ #if defined(NDEBUG)
1398+ " (compile in debug mode for type information)" );
1399+ #else
1400+ " of type '" + type_id<holder_type>() + " ''" );
1401+ #endif
1402+ }
1403+
13761404// / Type caster for holder types like std::shared_ptr, etc.
13771405template <typename type, typename holder_type>
13781406struct copyable_holder_caster : public type_caster_base <type> {
@@ -1419,12 +1447,7 @@ struct copyable_holder_caster : public type_caster_base<type> {
14191447 holder = v_h.template holder <holder_type>();
14201448 return true ;
14211449 } else {
1422- throw cast_error (" Unable to cast from non-held to held instance (T& to Holder<T>) "
1423- #if defined(NDEBUG)
1424- " (compile in debug mode for type information)" );
1425- #else
1426- " of type '" + type_id<holder_type>() + " ''" );
1427- #endif
1450+ throw cast_error_holder_unheld<holder_type>();
14281451 }
14291452 }
14301453
@@ -1446,7 +1469,7 @@ struct copyable_holder_caster : public type_caster_base<type> {
14461469
14471470 static bool try_direct_conversions (handle) { return false ; }
14481471
1449-
1472+ private:
14501473 holder_type holder;
14511474};
14521475
@@ -1455,24 +1478,56 @@ template <typename T>
14551478class type_caster <std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> { };
14561479
14571480template <typename type, typename holder_type>
1458- struct move_only_holder_caster {
1459- static_assert (std::is_base_of<type_caster_base<type>, type_caster<type>>::value,
1481+ struct move_only_holder_caster : type_caster_base<type> {
1482+ using base = type_caster_base<type>;
1483+ static_assert (std::is_base_of<base, type_caster<type>>::value,
14601484 " Holder classes are only supported for custom types" );
1485+ using base::base;
1486+ using base::cast;
1487+ using base::typeinfo;
1488+ using base::value;
14611489
1462- static handle cast (holder_type &&src, return_value_policy, handle) {
1463- auto *ptr = holder_helper<holder_type>::get (src);
1464- return type_caster_base<type>::cast_holder (ptr, &src);
1490+ bool load (handle src, bool convert) {
1491+ return base::template load_impl<move_only_holder_caster<type, holder_type>>(src, convert);
14651492 }
14661493
14671494 // Force rvalue.
14681495 template <typename T>
14691496 using cast_op_type = holder_type&&;
14701497
14711498 operator holder_type&&() {
1472- throw std::runtime_error (" Currently unsupported" );
1499+ return std::move (holder);
1500+ }
1501+
1502+ static handle cast (holder_type &&src, return_value_policy, handle) {
1503+ auto *ptr = holder_helper<holder_type>::get (src);
1504+ handle h = type_caster_base<type>::cast_holder (ptr, &src);
1505+ assert (src.get () == nullptr );
1506+ return h;
1507+ }
1508+
1509+ protected:
1510+ friend class type_caster_generic ;
1511+ void check_holder_compat () {}
1512+
1513+ bool load_value (value_and_holder &&v_h) {
1514+ if (v_h.holder_constructed ()) {
1515+ // Do NOT use `v_h.type`.
1516+ typeinfo->holder_info .release (v_h, &holder);
1517+ assert (v_h.holder <holder_type>().get () == nullptr );
1518+ return true ;
1519+ } else {
1520+ throw cast_error_holder_unheld<holder_type>();
1521+ }
14731522 }
14741523
1475- static constexpr auto name = type_caster_base<type>::name;
1524+ // TODO(eric.cousineau): Resolve this.
1525+ bool try_implicit_casts (handle, bool ) { return false ; }
1526+
1527+ static bool try_direct_conversions (handle) { return false ; }
1528+
1529+ private:
1530+ holder_type holder;
14761531};
14771532
14781533template <typename type, typename deleter>
@@ -1630,6 +1685,26 @@ object cast(const T &value, return_value_policy policy = return_value_policy::au
16301685template <typename T> T handle::cast () const { return pybind11::cast<T>(*this ); }
16311686template <> inline void handle::cast () const { return ; }
16321687
1688+ template <typename T>
1689+ detail::enable_if_t <
1690+ // TODO(eric.cousineau): Figure out how to prevent perfect-forwarding more elegantly.
1691+ std::is_rvalue_reference<T&&>::value && !detail::is_pyobject<detail::intrinsic_t <T>>::value, object>
1692+ move (T&& value) {
1693+ // TODO(eric.cousineau): Add policies, parent, etc.
1694+ // It'd be nice to supply a parent, but for now, just leave it as-is.
1695+ handle no_parent;
1696+ return reinterpret_steal<object>(
1697+ detail::make_caster<T>::cast (std::move (value), return_value_policy::take_ownership, no_parent));
1698+ }
1699+
1700+ template <typename T>
1701+ detail::enable_if_t <
1702+ std::is_rvalue_reference<T&&>::value && !detail::is_pyobject<detail::intrinsic_t <T>>::value, object>
1703+ cast (T&& value) {
1704+ // Have to use `pybind11::move` because some compilers might try to bind `move` to `std::move`...
1705+ return pybind11::move<T>(std::move (value));
1706+ }
1707+
16331708template <typename T>
16341709detail::enable_if_t <!detail::move_never<T>::value, T> move (object &&obj) {
16351710 if (obj.ref_count () > 1 )
@@ -1642,7 +1717,7 @@ detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
16421717#endif
16431718
16441719 // Move into a temporary and return that, because the reference may be a local value of `conv`
1645- T ret = std::move (detail::load_type<T>(obj). operator T&( ));
1720+ T ret = std::move (detail::cast_op<T>(detail:: load_type<T>(obj)));
16461721 return ret;
16471722}
16481723
0 commit comments