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:
Ralf W. Grosse-Kunstleve 2021-02-01 16:56:17 -08:00
parent a9bfcbdcc3
commit 72f52be256
3 changed files with 71 additions and 172 deletions

View File

@ -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);
}

View File

@ -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>> {}; \

View File

@ -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]") {