@@ -479,6 +479,20 @@ inline PyThreadState *get_thread_state_unchecked() {
479
479
inline void keep_alive_impl (handle nurse, handle patient);
480
480
inline PyObject *make_new_instance (PyTypeObject *type);
481
481
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
+
482
496
class type_caster_generic {
483
497
public:
484
498
PYBIND11_NOINLINE type_caster_generic (const std::type_info &type_info)
@@ -506,8 +520,12 @@ class type_caster_generic {
506
520
auto it_instances = get_internals ().registered_instances .equal_range (src);
507
521
for (auto it_i = it_instances.first ; it_i != it_instances.second ; ++it_i) {
508
522
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
+ }
511
529
}
512
530
}
513
531
@@ -1373,6 +1391,16 @@ struct holder_helper {
1373
1391
static auto get (const T &p) -> decltype(p.get()) { return p.get (); }
1374
1392
};
1375
1393
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
+
1376
1404
// / Type caster for holder types like std::shared_ptr, etc.
1377
1405
template <typename type, typename holder_type>
1378
1406
struct copyable_holder_caster : public type_caster_base <type> {
@@ -1419,12 +1447,7 @@ struct copyable_holder_caster : public type_caster_base<type> {
1419
1447
holder = v_h.template holder <holder_type>();
1420
1448
return true ;
1421
1449
} 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>();
1428
1451
}
1429
1452
}
1430
1453
@@ -1446,7 +1469,7 @@ struct copyable_holder_caster : public type_caster_base<type> {
1446
1469
1447
1470
static bool try_direct_conversions (handle) { return false ; }
1448
1471
1449
-
1472
+ private:
1450
1473
holder_type holder;
1451
1474
};
1452
1475
@@ -1455,24 +1478,56 @@ template <typename T>
1455
1478
class type_caster <std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> { };
1456
1479
1457
1480
template <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,
1460
1484
" Holder classes are only supported for custom types" );
1485
+ using base::base;
1486
+ using base::cast;
1487
+ using base::typeinfo;
1488
+ using base::value;
1461
1489
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);
1465
1492
}
1466
1493
1467
1494
// Force rvalue.
1468
1495
template <typename T>
1469
1496
using cast_op_type = holder_type&&;
1470
1497
1471
1498
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
+ }
1473
1522
}
1474
1523
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;
1476
1531
};
1477
1532
1478
1533
template <typename type, typename deleter>
@@ -1630,6 +1685,26 @@ object cast(const T &value, return_value_policy policy = return_value_policy::au
1630
1685
template <typename T> T handle::cast () const { return pybind11::cast<T>(*this ); }
1631
1686
template <> inline void handle::cast () const { return ; }
1632
1687
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
+
1633
1708
template <typename T>
1634
1709
detail::enable_if_t <!detail::move_never<T>::value, T> move (object &&obj) {
1635
1710
if (obj.ref_count () > 1 )
@@ -1642,7 +1717,7 @@ detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
1642
1717
#endif
1643
1718
1644
1719
// 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)));
1646
1721
return ret;
1647
1722
}
1648
1723
0 commit comments