Calling deregister_instance after disowning via unique_ptr.

This commit is contained in:
Ralf W. Grosse-Kunstleve 2021-01-14 22:23:07 -08:00
parent b85cc69714
commit b41a0db1b1
2 changed files with 46 additions and 21 deletions

View File

@ -54,17 +54,35 @@ using namespace pybind11_tests::classh_wip;
template <typename T>
struct smart_holder_type_caster_load {
using holder_type = pybindit::memory::smart_holder;
bool load(handle src, bool /*convert*/) {
if (!isinstance<T>(src))
return false;
auto inst = reinterpret_cast<instance *>(src.ptr());
auto v_h = inst->get_value_and_holder(get_type_info(typeid(T)));
smhldr_ptr = &v_h.holder<pybindit::memory::smart_holder>();
loaded_v_h = inst->get_value_and_holder(get_type_info(typeid(T)));
if (!loaded_v_h.holder_constructed()) {
// IMPROVEABLE: Error message.
throw std::runtime_error("Missing value for wrapped C++ type:"
" Python instance is uninitialized or was disowned.");
}
loaded_smhldr_ptr = &loaded_v_h.holder<holder_type>();
return true;
}
std::unique_ptr<T> loaded_as_unique_ptr() {
void *value_void_ptr = loaded_v_h.value_ptr();
auto unq_ptr = loaded_smhldr_ptr->as_unique_ptr<mpty>();
loaded_v_h.holder<holder_type>().~holder_type();
loaded_v_h.set_holder_constructed(false);
loaded_v_h.value_ptr() = nullptr;
deregister_instance(loaded_v_h.inst, value_void_ptr, loaded_v_h.type);
return unq_ptr;
}
protected:
pybindit::memory::smart_holder *smhldr_ptr = nullptr;
value_and_holder loaded_v_h;
holder_type *loaded_smhldr_ptr = nullptr;
};
template <>
@ -127,12 +145,12 @@ struct type_caster<mpty> : smart_holder_type_caster_load<mpty> {
// clang-format off
operator mpty() { return smhldr_ptr->lvalue_ref<mpty>(); }
operator mpty&&() && { return smhldr_ptr->rvalue_ref<mpty>(); }
operator mpty const&() { return smhldr_ptr->lvalue_ref<mpty>(); }
operator mpty&() { return smhldr_ptr->lvalue_ref<mpty>(); }
operator mpty const*() { return smhldr_ptr->as_raw_ptr_unowned<mpty>(); }
operator mpty*() { return smhldr_ptr->as_raw_ptr_unowned<mpty>(); }
operator mpty() { return loaded_smhldr_ptr->lvalue_ref<mpty>(); }
operator mpty&&() && { return loaded_smhldr_ptr->rvalue_ref<mpty>(); }
operator mpty const&() { return loaded_smhldr_ptr->lvalue_ref<mpty>(); }
operator mpty&() { return loaded_smhldr_ptr->lvalue_ref<mpty>(); }
operator mpty const*() { return loaded_smhldr_ptr->as_raw_ptr_unowned<mpty>(); }
operator mpty*() { return loaded_smhldr_ptr->as_raw_ptr_unowned<mpty>(); }
// clang-format on
@ -331,7 +349,7 @@ struct type_caster<std::shared_ptr<mpty>> : smart_holder_type_caster_load<mpty>
template <typename>
using cast_op_type = std::shared_ptr<mpty>;
operator std::shared_ptr<mpty>() { return smhldr_ptr->as_shared_ptr<mpty>(); }
operator std::shared_ptr<mpty>() { return loaded_smhldr_ptr->as_shared_ptr<mpty>(); }
};
template <>
@ -349,7 +367,7 @@ struct type_caster<std::shared_ptr<mpty const>> : smart_holder_type_caster_load<
template <typename>
using cast_op_type = std::shared_ptr<mpty const>;
operator std::shared_ptr<mpty const>() { return smhldr_ptr->as_shared_ptr<mpty>(); }
operator std::shared_ptr<mpty const>() { return loaded_smhldr_ptr->as_shared_ptr<mpty>(); }
};
template <>
@ -398,10 +416,7 @@ struct type_caster<std::unique_ptr<mpty>> : smart_holder_type_caster_load<mpty>
template <typename>
using cast_op_type = std::unique_ptr<mpty>;
operator std::unique_ptr<mpty>() {
// MISSING: value_and_holder value_ptr reset, deregister_instance.
return smhldr_ptr->as_unique_ptr<mpty>();
}
operator std::unique_ptr<mpty>() { return loaded_as_unique_ptr(); }
};
template <>
@ -419,10 +434,7 @@ struct type_caster<std::unique_ptr<mpty const>> : smart_holder_type_caster_load<
template <typename>
using cast_op_type = std::unique_ptr<mpty const>;
operator std::unique_ptr<mpty const>() {
// MISSING: value_and_holder value_ptr reset, deregister_instance.
return smhldr_ptr->as_unique_ptr<mpty>();
}
operator std::unique_ptr<mpty const>() { return loaded_as_unique_ptr(); }
};
} // namespace detail
@ -466,7 +478,10 @@ TEST_SUBMODULE(classh_wip, m) {
m.def("pass_mpty_uqmp", pass_mpty_uqmp);
m.def("pass_mpty_uqcp", pass_mpty_uqcp);
m.def("get_mtxt", get_mtxt); // Requires pass_mpty_cref to work properly.
// Helpers, these require selected functions above to work, as indicated:
m.def("get_mtxt", get_mtxt); // pass_mpty_cref
m.def("unique_ptr_roundtrip",
[](std::unique_ptr<mpty> obj) { return obj; }); // pass_mpty_uqmp, rtrn_mpty_uqmp
}
} // namespace classh_wip

View File

@ -63,4 +63,14 @@ def test_pass_unique_ptr_disowns(pass_mpty, argm, rtrn):
assert pass_mpty(obj) == rtrn
with pytest.raises(RuntimeError) as exc_info:
m.pass_mpty_uqmp(obj)
assert str(exc_info.value) == "Cannot disown nullptr (as_unique_ptr)."
assert str(exc_info.value) == (
"Missing value for wrapped C++ type:"
" Python instance is uninitialized or was disowned."
)
def test_unique_ptr_roundtrip(num_round_trips=1000):
recycled = m.mpty("passenger")
for _ in range(num_round_trips):
recycled = m.unique_ptr_roundtrip(recycled)
assert m.get_mtxt(recycled) == "passenger"