mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-18 06:30:54 +00:00
Unification of unique_ptr, unique_ptr_with_deleter code in smart_holder_poc.h. Leads to more fitting error messages. Enables use of unique_ptr<T, D> smart_holder_type_casters also for unique_ptr<T>.
This commit is contained in:
parent
a9bfcbdcc3
commit
72f52be256
@ -104,24 +104,6 @@ struct smart_holder {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
void ensure_compatible_rtti_uqp_del(const char *context) const {
|
||||
if (!rtti_uqp_del) {
|
||||
throw std::runtime_error(std::string("Missing unique_ptr deleter (") + context + ").");
|
||||
}
|
||||
const std::type_info *rtti_requested = &typeid(D);
|
||||
if (!(*rtti_requested == *rtti_uqp_del)) {
|
||||
throw std::runtime_error(std::string("Incompatible unique_ptr deleter (") + context
|
||||
+ ").");
|
||||
}
|
||||
}
|
||||
|
||||
void ensure_has_pointee(const char *context) const {
|
||||
if (!has_pointee()) {
|
||||
throw std::runtime_error(std::string("Disowned holder (") + context + ").");
|
||||
}
|
||||
}
|
||||
|
||||
void ensure_vptr_is_using_builtin_delete(const char *context) const {
|
||||
if (vptr_is_external_shared_ptr) {
|
||||
throw std::runtime_error(std::string("Cannot disown external shared_ptr (") + context
|
||||
@ -137,6 +119,29 @@ struct smart_holder {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename D>
|
||||
void ensure_compatible_rtti_uqp_del(const char *context) const {
|
||||
const std::type_info *rtti_requested = &typeid(D);
|
||||
if (!rtti_uqp_del) {
|
||||
// IMPROVABLE: const-correctness.
|
||||
if (!(*rtti_requested == typeid(std::default_delete<T>)
|
||||
|| *rtti_requested == typeid(std::default_delete<T const>))) {
|
||||
throw std::runtime_error(std::string("Missing unique_ptr deleter (") + context
|
||||
+ ").");
|
||||
}
|
||||
ensure_vptr_is_using_builtin_delete(context);
|
||||
} else if (!(*rtti_requested == *rtti_uqp_del)) {
|
||||
throw std::runtime_error(std::string("Incompatible unique_ptr deleter (") + context
|
||||
+ ").");
|
||||
}
|
||||
}
|
||||
|
||||
void ensure_has_pointee(const char *context) const {
|
||||
if (!has_pointee()) {
|
||||
throw std::runtime_error(std::string("Disowned holder (") + context + ").");
|
||||
}
|
||||
}
|
||||
|
||||
void ensure_use_count_1(const char *context) const {
|
||||
if (vptr.get() == nullptr) {
|
||||
throw std::runtime_error(std::string("Cannot disown nullptr (") + context + ").");
|
||||
@ -209,41 +214,30 @@ struct smart_holder {
|
||||
return raw_ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static smart_holder from_unique_ptr(std::unique_ptr<T> &&unq_ptr) {
|
||||
template <typename T, typename D = std::default_delete<T>>
|
||||
static smart_holder from_unique_ptr(std::unique_ptr<T, D> &&unq_ptr) {
|
||||
smart_holder hld(true);
|
||||
hld.vptr.reset(unq_ptr.get(),
|
||||
guarded_builtin_delete<T>(hld.vptr_deleter_armed_flag_ptr.get()));
|
||||
unq_ptr.release();
|
||||
hld.vptr_is_using_builtin_delete = true;
|
||||
hld.is_populated = true;
|
||||
return hld;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::unique_ptr<T> as_unique_ptr() {
|
||||
return std::unique_ptr<T>(as_raw_ptr_release_ownership<T>("as_unique_ptr"));
|
||||
}
|
||||
|
||||
template <typename T, typename D>
|
||||
static smart_holder from_unique_ptr_with_deleter(std::unique_ptr<T, D> &&unq_ptr) {
|
||||
smart_holder hld(true);
|
||||
hld.rtti_uqp_del = &typeid(D);
|
||||
hld.vptr.reset(unq_ptr.get(),
|
||||
guarded_custom_deleter<T, D>(hld.vptr_deleter_armed_flag_ptr.get()));
|
||||
hld.rtti_uqp_del = &typeid(D);
|
||||
hld.vptr_is_using_builtin_delete = (*hld.rtti_uqp_del == typeid(std::default_delete<T>));
|
||||
if (hld.vptr_is_using_builtin_delete) {
|
||||
hld.vptr.reset(unq_ptr.get(),
|
||||
guarded_builtin_delete<T>(hld.vptr_deleter_armed_flag_ptr.get()));
|
||||
} else {
|
||||
hld.vptr.reset(unq_ptr.get(),
|
||||
guarded_custom_deleter<T, D>(hld.vptr_deleter_armed_flag_ptr.get()));
|
||||
}
|
||||
unq_ptr.release();
|
||||
hld.is_populated = true;
|
||||
return hld;
|
||||
}
|
||||
|
||||
template <typename T, typename D>
|
||||
std::unique_ptr<T, D> as_unique_ptr_with_deleter() {
|
||||
static const char *context = "as_unique_ptr_with_deleter";
|
||||
ensure_compatible_rtti_uqp_del<D>(context);
|
||||
template <typename T, typename D = std::default_delete<T>>
|
||||
std::unique_ptr<T, D> as_unique_ptr() {
|
||||
static const char *context = "as_unique_ptr";
|
||||
ensure_compatible_rtti_uqp_del<T, D>(context);
|
||||
ensure_use_count_1(context);
|
||||
T *raw_ptr = as_raw_ptr_unowned<T>();
|
||||
*vptr_deleter_armed_flag_ptr = false;
|
||||
vptr.reset();
|
||||
T *raw_ptr = as_raw_ptr_unowned<T>();
|
||||
release_ownership();
|
||||
return std::unique_ptr<T, D>(raw_ptr);
|
||||
}
|
||||
|
||||
|
@ -297,31 +297,10 @@ struct smart_holder_type_caster_load {
|
||||
return std::shared_ptr<T>(void_ptr, convert_type(void_ptr.get()));
|
||||
}
|
||||
|
||||
std::unique_ptr<T> loaded_as_unique_ptr() {
|
||||
holder().ensure_can_release_ownership();
|
||||
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>(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;
|
||||
}
|
||||
|
||||
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");
|
||||
template <typename D = std::default_delete<T>>
|
||||
std::unique_ptr<T, D> loaded_as_unique_ptr(const char *context = "loaded_as_unique_ptr") {
|
||||
holder().template ensure_compatible_rtti_uqp_del<T, D>(context);
|
||||
holder().ensure_use_count_1(context);
|
||||
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).
|
||||
@ -584,12 +563,12 @@ struct smart_holder_type_caster<std::shared_ptr<T const>> : smart_holder_type_ca
|
||||
operator std::shared_ptr<T const>() { return this->loaded_as_shared_ptr(); } // Mutbl2Const
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct smart_holder_type_caster<std::unique_ptr<T>> : smart_holder_type_caster_load<T>,
|
||||
smart_holder_type_caster_class_hooks {
|
||||
static constexpr auto name = _<std::unique_ptr<T>>();
|
||||
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> &&src, return_value_policy policy, handle parent) {
|
||||
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.
|
||||
@ -621,73 +600,10 @@ struct smart_holder_type_caster<std::unique_ptr<T>> : smart_holder_type_caster_l
|
||||
return inst.release();
|
||||
}
|
||||
|
||||
template <typename>
|
||||
using cast_op_type = std::unique_ptr<T>;
|
||||
|
||||
operator std::unique_ptr<T>() { return this->loaded_as_unique_ptr(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct smart_holder_type_caster<std::unique_ptr<T const>> : smart_holder_type_caster_load<T>,
|
||||
smart_holder_type_caster_class_hooks {
|
||||
static constexpr auto name = _<std::unique_ptr<T const>>();
|
||||
|
||||
static handle cast(std::unique_ptr<T const> &&src, return_value_policy policy, handle parent) {
|
||||
return smart_holder_type_caster<std::unique_ptr<T>>::cast(
|
||||
std::unique_ptr<T>(const_cast<T *>(src.release())), // Const2Mutbl
|
||||
policy,
|
||||
parent);
|
||||
}
|
||||
|
||||
template <typename>
|
||||
using cast_op_type = std::unique_ptr<T const>;
|
||||
|
||||
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>();
|
||||
}
|
||||
operator std::unique_ptr<T, D>() { return this->template loaded_as_unique_ptr<D>(); }
|
||||
};
|
||||
|
||||
template <typename T, typename D>
|
||||
@ -706,9 +622,7 @@ struct smart_holder_type_caster<std::unique_ptr<T const, D>>
|
||||
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>();
|
||||
}
|
||||
operator std::unique_ptr<T const, D>() { return this->template loaded_as_unique_ptr<D>(); }
|
||||
};
|
||||
|
||||
#define PYBIND11_SMART_HOLDER_TYPE_CASTERS(T) \
|
||||
@ -722,12 +636,6 @@ struct smart_holder_type_caster<std::unique_ptr<T const, D>>
|
||||
template <> \
|
||||
class type_caster<std::shared_ptr<T const>> \
|
||||
: public smart_holder_type_caster<std::shared_ptr<T const>> {}; \
|
||||
template <> \
|
||||
class type_caster<std::unique_ptr<T>> : public smart_holder_type_caster<std::unique_ptr<T>> { \
|
||||
}; \
|
||||
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>> {}; \
|
||||
|
@ -66,10 +66,9 @@ TEST_CASE("from_raw_ptr_unowned+as_unique_ptr_with_deleter", "[E]") {
|
||||
static int value = 19;
|
||||
auto hld = smart_holder::from_raw_ptr_unowned(&value);
|
||||
auto condense_for_macro = [](smart_holder &hld) {
|
||||
hld.as_unique_ptr_with_deleter<int, helpers::functor_builtin_delete<int>>();
|
||||
hld.as_unique_ptr<int, helpers::functor_builtin_delete<int>>();
|
||||
};
|
||||
REQUIRE_THROWS_WITH(condense_for_macro(hld),
|
||||
"Missing unique_ptr deleter (as_unique_ptr_with_deleter).");
|
||||
REQUIRE_THROWS_WITH(condense_for_macro(hld), "Missing unique_ptr deleter (as_unique_ptr).");
|
||||
}
|
||||
|
||||
TEST_CASE("from_raw_ptr_unowned+as_shared_ptr", "[S]") {
|
||||
@ -114,10 +113,9 @@ TEST_CASE("from_raw_ptr_take_ownership+as_unique_ptr2", "[E]") {
|
||||
TEST_CASE("from_raw_ptr_take_ownership+as_unique_ptr_with_deleter", "[E]") {
|
||||
auto hld = smart_holder::from_raw_ptr_take_ownership(new int(19));
|
||||
auto condense_for_macro = [](smart_holder &hld) {
|
||||
hld.as_unique_ptr_with_deleter<int, helpers::functor_builtin_delete<int>>();
|
||||
hld.as_unique_ptr<int, helpers::functor_builtin_delete<int>>();
|
||||
};
|
||||
REQUIRE_THROWS_WITH(condense_for_macro(hld),
|
||||
"Missing unique_ptr deleter (as_unique_ptr_with_deleter).");
|
||||
REQUIRE_THROWS_WITH(condense_for_macro(hld), "Missing unique_ptr deleter (as_unique_ptr).");
|
||||
}
|
||||
|
||||
TEST_CASE("from_raw_ptr_take_ownership+as_shared_ptr", "[S]") {
|
||||
@ -174,10 +172,10 @@ TEST_CASE("from_unique_ptr+as_unique_ptr_with_deleter", "[E]") {
|
||||
auto hld = smart_holder::from_unique_ptr(std::move(orig_owner));
|
||||
REQUIRE(orig_owner.get() == nullptr);
|
||||
auto condense_for_macro = [](smart_holder &hld) {
|
||||
hld.as_unique_ptr_with_deleter<int, helpers::functor_builtin_delete<int>>();
|
||||
hld.as_unique_ptr<int, helpers::functor_builtin_delete<int>>();
|
||||
};
|
||||
REQUIRE_THROWS_WITH(condense_for_macro(hld),
|
||||
"Missing unique_ptr deleter (as_unique_ptr_with_deleter).");
|
||||
"Incompatible unique_ptr deleter (as_unique_ptr).");
|
||||
}
|
||||
|
||||
TEST_CASE("from_unique_ptr+as_shared_ptr", "[S]") {
|
||||
@ -191,14 +189,14 @@ TEST_CASE("from_unique_ptr+as_shared_ptr", "[S]") {
|
||||
|
||||
TEST_CASE("from_unique_ptr_with_deleter+as_lvalue_ref", "[S]") {
|
||||
std::unique_ptr<int, helpers::functor_builtin_delete<int>> orig_owner(new int(19));
|
||||
auto hld = smart_holder::from_unique_ptr_with_deleter(std::move(orig_owner));
|
||||
auto hld = smart_holder::from_unique_ptr(std::move(orig_owner));
|
||||
REQUIRE(orig_owner.get() == nullptr);
|
||||
REQUIRE(hld.as_lvalue_ref<int>() == 19);
|
||||
}
|
||||
|
||||
TEST_CASE("from_unique_ptr_with_deleter+as_raw_ptr_release_ownership", "[E]") {
|
||||
std::unique_ptr<int, helpers::functor_builtin_delete<int>> orig_owner(new int(19));
|
||||
auto hld = smart_holder::from_unique_ptr_with_deleter(std::move(orig_owner));
|
||||
auto hld = smart_holder::from_unique_ptr(std::move(orig_owner));
|
||||
REQUIRE(orig_owner.get() == nullptr);
|
||||
REQUIRE_THROWS_WITH(hld.as_raw_ptr_release_ownership<int>(),
|
||||
"Cannot disown custom deleter (as_raw_ptr_release_ownership).");
|
||||
@ -206,35 +204,35 @@ TEST_CASE("from_unique_ptr_with_deleter+as_raw_ptr_release_ownership", "[E]") {
|
||||
|
||||
TEST_CASE("from_unique_ptr_with_deleter+as_unique_ptr", "[E]") {
|
||||
std::unique_ptr<int, helpers::functor_builtin_delete<int>> orig_owner(new int(19));
|
||||
auto hld = smart_holder::from_unique_ptr_with_deleter(std::move(orig_owner));
|
||||
auto hld = smart_holder::from_unique_ptr(std::move(orig_owner));
|
||||
REQUIRE(orig_owner.get() == nullptr);
|
||||
REQUIRE_THROWS_WITH(hld.as_unique_ptr<int>(), "Cannot disown custom deleter (as_unique_ptr).");
|
||||
REQUIRE_THROWS_WITH(hld.as_unique_ptr<int>(),
|
||||
"Incompatible unique_ptr deleter (as_unique_ptr).");
|
||||
}
|
||||
|
||||
TEST_CASE("from_unique_ptr_with_deleter+as_unique_ptr_with_deleter1", "[S]") {
|
||||
std::unique_ptr<int, helpers::functor_builtin_delete<int>> orig_owner(new int(19));
|
||||
auto hld = smart_holder::from_unique_ptr_with_deleter(std::move(orig_owner));
|
||||
auto hld = smart_holder::from_unique_ptr(std::move(orig_owner));
|
||||
REQUIRE(orig_owner.get() == nullptr);
|
||||
std::unique_ptr<int, helpers::functor_builtin_delete<int>> new_owner
|
||||
= hld.as_unique_ptr_with_deleter<int, helpers::functor_builtin_delete<int>>();
|
||||
= hld.as_unique_ptr<int, helpers::functor_builtin_delete<int>>();
|
||||
REQUIRE(!hld.has_pointee());
|
||||
REQUIRE(*new_owner == 19);
|
||||
}
|
||||
|
||||
TEST_CASE("from_unique_ptr_with_deleter+as_unique_ptr_with_deleter2", "[E]") {
|
||||
std::unique_ptr<int, helpers::functor_builtin_delete<int>> orig_owner(new int(19));
|
||||
auto hld = smart_holder::from_unique_ptr_with_deleter(std::move(orig_owner));
|
||||
auto hld = smart_holder::from_unique_ptr(std::move(orig_owner));
|
||||
REQUIRE(orig_owner.get() == nullptr);
|
||||
auto condense_for_macro = [](smart_holder &hld) {
|
||||
hld.as_unique_ptr_with_deleter<int, helpers::functor_other_delete<int>>();
|
||||
};
|
||||
auto condense_for_macro
|
||||
= [](smart_holder &hld) { hld.as_unique_ptr<int, helpers::functor_other_delete<int>>(); };
|
||||
REQUIRE_THROWS_WITH(condense_for_macro(hld),
|
||||
"Incompatible unique_ptr deleter (as_unique_ptr_with_deleter).");
|
||||
"Incompatible unique_ptr deleter (as_unique_ptr).");
|
||||
}
|
||||
|
||||
TEST_CASE("from_unique_ptr_with_deleter+as_shared_ptr", "[S]") {
|
||||
std::unique_ptr<int, helpers::functor_builtin_delete<int>> orig_owner(new int(19));
|
||||
auto hld = smart_holder::from_unique_ptr_with_deleter(std::move(orig_owner));
|
||||
auto hld = smart_holder::from_unique_ptr(std::move(orig_owner));
|
||||
REQUIRE(orig_owner.get() == nullptr);
|
||||
std::shared_ptr<int> new_owner = hld.as_shared_ptr<int>();
|
||||
REQUIRE(hld.has_pointee());
|
||||
@ -265,10 +263,9 @@ TEST_CASE("from_shared_ptr+as_unique_ptr_with_deleter", "[E]") {
|
||||
std::shared_ptr<int> orig_owner(new int(19));
|
||||
auto hld = smart_holder::from_shared_ptr(orig_owner);
|
||||
auto condense_for_macro = [](smart_holder &hld) {
|
||||
hld.as_unique_ptr_with_deleter<int, helpers::functor_builtin_delete<int>>();
|
||||
hld.as_unique_ptr<int, helpers::functor_builtin_delete<int>>();
|
||||
};
|
||||
REQUIRE_THROWS_WITH(condense_for_macro(hld),
|
||||
"Missing unique_ptr deleter (as_unique_ptr_with_deleter).");
|
||||
REQUIRE_THROWS_WITH(condense_for_macro(hld), "Missing unique_ptr deleter (as_unique_ptr).");
|
||||
}
|
||||
|
||||
TEST_CASE("from_shared_ptr+as_shared_ptr", "[S]") {
|
||||
|
Loading…
Reference in New Issue
Block a user