mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-18 06:30:54 +00:00
Adding smart_holder_type_casters for unique_ptr with custom deleter. SEVERE CODE DUPLICATION. This commit is to establish a baseline for consolidating the unique_ptr code.
This commit is contained in:
parent
231bd84fa0
commit
a9bfcbdcc3
@ -318,6 +318,29 @@ struct smart_holder_type_caster_load {
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
std::unique_ptr<T, D> loaded_as_unique_ptr_with_deleter() {
|
||||
holder().template ensure_compatible_rtti_uqp_del<D>("loaded_as_unique_ptr_with_deleter");
|
||||
holder().ensure_use_count_1("loaded_as_unique_ptr_with_deleter");
|
||||
auto raw_void_ptr = holder().template as_raw_ptr_unowned<void>();
|
||||
// MISSING: Safety checks for type conversions
|
||||
// (T must be polymorphic or meet certain other conditions).
|
||||
T *raw_type_ptr = convert_type(raw_void_ptr);
|
||||
|
||||
// Critical transfer-of-ownership section. This must stay together.
|
||||
holder().release_ownership();
|
||||
auto result = std::unique_ptr<T, D>(raw_type_ptr);
|
||||
|
||||
void *value_void_ptr
|
||||
= load_impl.loaded_v_h.value_ptr(); // Expected to be identical to raw_void_ptr.
|
||||
load_impl.loaded_v_h.holder<holder_type>().~holder_type();
|
||||
load_impl.loaded_v_h.set_holder_constructed(false);
|
||||
load_impl.loaded_v_h.value_ptr() = nullptr;
|
||||
deregister_instance(load_impl.loaded_v_h.inst, value_void_ptr, load_impl.loaded_v_h.type);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
modified_type_caster_generic_load_impl load_impl;
|
||||
|
||||
@ -622,6 +645,72 @@ struct smart_holder_type_caster<std::unique_ptr<T const>> : smart_holder_type_ca
|
||||
operator std::unique_ptr<T const>() { return this->loaded_as_unique_ptr(); }
|
||||
};
|
||||
|
||||
template <typename T, typename D>
|
||||
struct smart_holder_type_caster<std::unique_ptr<T, D>> : smart_holder_type_caster_load<T>,
|
||||
smart_holder_type_caster_class_hooks {
|
||||
static constexpr auto name = _<std::unique_ptr<T, D>>();
|
||||
|
||||
static handle cast(std::unique_ptr<T, D> &&src, return_value_policy policy, handle parent) {
|
||||
if (policy != return_value_policy::automatic
|
||||
&& policy != return_value_policy::reference_internal) {
|
||||
// IMPROVABLE: Error message.
|
||||
throw cast_error("Invalid return_value_policy for unique_ptr.");
|
||||
}
|
||||
|
||||
auto src_raw_ptr = src.get();
|
||||
auto st = type_caster_base<T>::src_and_type(src_raw_ptr);
|
||||
if (st.first == nullptr)
|
||||
return none().release(); // PyErr was set already.
|
||||
|
||||
void *src_raw_void_ptr = static_cast<void *>(src_raw_ptr);
|
||||
const detail::type_info *tinfo = st.second;
|
||||
if (find_registered_python_instance(src_raw_void_ptr, tinfo))
|
||||
throw cast_error("Invalid unique_ptr: another instance owns this pointer already.");
|
||||
|
||||
auto inst = reinterpret_steal<object>(make_new_instance(tinfo->type));
|
||||
auto *inst_raw_ptr = reinterpret_cast<instance *>(inst.ptr());
|
||||
inst_raw_ptr->owned = true;
|
||||
void *&valueptr = values_and_holders(inst_raw_ptr).begin()->value_ptr();
|
||||
valueptr = src_raw_void_ptr;
|
||||
|
||||
auto smhldr = pybindit::memory::smart_holder::from_unique_ptr_with_deleter(std::move(src));
|
||||
tinfo->init_instance(inst_raw_ptr, static_cast<const void *>(&smhldr));
|
||||
|
||||
if (policy == return_value_policy::reference_internal)
|
||||
keep_alive_impl(inst, parent);
|
||||
|
||||
return inst.release();
|
||||
}
|
||||
|
||||
template <typename>
|
||||
using cast_op_type = std::unique_ptr<T, D>;
|
||||
|
||||
operator std::unique_ptr<T, D>() {
|
||||
return this->template loaded_as_unique_ptr_with_deleter<D>();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename D>
|
||||
struct smart_holder_type_caster<std::unique_ptr<T const, D>>
|
||||
: smart_holder_type_caster_load<T>, smart_holder_type_caster_class_hooks {
|
||||
static constexpr auto name = _<std::unique_ptr<T const, D>>();
|
||||
|
||||
static handle
|
||||
cast(std::unique_ptr<T const, D> &&src, return_value_policy policy, handle parent) {
|
||||
return smart_holder_type_caster<std::unique_ptr<T, D>>::cast(
|
||||
std::unique_ptr<T, D>(const_cast<T *>(src.release())), // Const2Mutbl
|
||||
policy,
|
||||
parent);
|
||||
}
|
||||
|
||||
template <typename>
|
||||
using cast_op_type = std::unique_ptr<T const, D>;
|
||||
|
||||
operator std::unique_ptr<T const, D>() {
|
||||
return this->template loaded_as_unique_ptr_with_deleter<D>();
|
||||
}
|
||||
};
|
||||
|
||||
#define PYBIND11_SMART_HOLDER_TYPE_CASTERS(T) \
|
||||
namespace pybind11 { \
|
||||
namespace detail { \
|
||||
@ -639,6 +728,12 @@ struct smart_holder_type_caster<std::unique_ptr<T const>> : smart_holder_type_ca
|
||||
template <> \
|
||||
class type_caster<std::unique_ptr<T const>> \
|
||||
: public smart_holder_type_caster<std::unique_ptr<T const>> {}; \
|
||||
template <typename D> \
|
||||
class type_caster<std::unique_ptr<T, D>> \
|
||||
: public smart_holder_type_caster<std::unique_ptr<T, D>> {}; \
|
||||
template <typename D> \
|
||||
class type_caster<std::unique_ptr<T const, D>> \
|
||||
: public smart_holder_type_caster<std::unique_ptr<T const, D>> {}; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,15 @@ std::unique_ptr<atyp const> rtrn_uqcp_atyp() { return std::unique_ptr<atyp const
|
||||
std::string pass_uqmp_atyp(std::unique_ptr<atyp > obj) { return "pass_uqmp:" + obj->mtxt; }
|
||||
std::string pass_uqcp_atyp(std::unique_ptr<atyp const> obj) { return "pass_uqcp:" + obj->mtxt; }
|
||||
|
||||
struct uqmd : std::default_delete<atyp > {};
|
||||
struct uqcd : std::default_delete<atyp const> {};
|
||||
|
||||
std::unique_ptr<atyp, uqmd> rtrn_uqmp_del_atyp() { return std::unique_ptr<atyp, uqmd>(new atyp{"rtrn_uqmp_del"}); }
|
||||
std::unique_ptr<atyp const, uqcd> rtrn_uqcp_del_atyp() { return std::unique_ptr<atyp const, uqcd>(new atyp{"rtrn_uqcp_del"}); }
|
||||
|
||||
std::string pass_uqmp_del_atyp(std::unique_ptr<atyp, uqmd> obj) { return "pass_uqmp_del:" + obj->mtxt; }
|
||||
std::string pass_uqcp_del_atyp(std::unique_ptr<atyp const, uqcd> obj) { return "pass_uqcp_del:" + obj->mtxt; }
|
||||
|
||||
// clang-format on
|
||||
|
||||
// Helpers for testing.
|
||||
@ -89,6 +98,12 @@ TEST_SUBMODULE(class_sh_basic, m) {
|
||||
m.def("pass_uqmp_atyp", pass_uqmp_atyp);
|
||||
m.def("pass_uqcp_atyp", pass_uqcp_atyp);
|
||||
|
||||
m.def("rtrn_uqmp_del_atyp", rtrn_uqmp_del_atyp);
|
||||
m.def("rtrn_uqcp_del_atyp", rtrn_uqcp_del_atyp);
|
||||
|
||||
m.def("pass_uqmp_del_atyp", pass_uqmp_del_atyp);
|
||||
m.def("pass_uqcp_del_atyp", pass_uqcp_del_atyp);
|
||||
|
||||
// Helpers for testing.
|
||||
// These require selected functions above to work first, as indicated:
|
||||
m.def("get_mtxt", get_mtxt); // pass_cref_atyp
|
||||
|
@ -51,6 +51,16 @@ def test_load_unique_ptr():
|
||||
assert m.pass_uqcp_atyp(m.atyp("Uqcp")) == "pass_uqcp:Uqcp"
|
||||
|
||||
|
||||
def test_cast_unique_ptr_with_deleter():
|
||||
assert m.get_mtxt(m.rtrn_uqmp_del_atyp()) == "rtrn_uqmp_del"
|
||||
assert m.get_mtxt(m.rtrn_uqcp_del_atyp()) == "rtrn_uqcp_del"
|
||||
|
||||
|
||||
def test_load_unique_ptr_with_deleter():
|
||||
assert m.pass_uqmp_del_atyp(m.rtrn_uqmp_del_atyp()) == "pass_uqmp_del:rtrn_uqmp_del"
|
||||
assert m.pass_uqcp_del_atyp(m.rtrn_uqcp_del_atyp()) == "pass_uqcp_del:rtrn_uqcp_del"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"pass_atyp, argm, rtrn",
|
||||
[
|
||||
|
Loading…
Reference in New Issue
Block a user