mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-16 13:47:53 +00:00
Inline smart_holder_type_caster_support, trampoline_self_life_support in type_caster_base.h: the organization of the existing code makes it very difficult to factor the added code properly.
This commit is contained in:
parent
2180dd4b6b
commit
70ba91f721
@ -154,8 +154,6 @@ set(PYBIND11_HEADERS
|
||||
include/pybind11/detail/init.h
|
||||
include/pybind11/detail/internals.h
|
||||
include/pybind11/detail/smart_holder_poc.h
|
||||
include/pybind11/detail/smart_holder_type_caster_support.h
|
||||
include/pybind11/detail/smart_holder_value_and_holder_support.h
|
||||
include/pybind11/detail/type_caster_base.h
|
||||
include/pybind11/detail/typeid.h
|
||||
include/pybind11/attr.h
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
#include "detail/common.h"
|
||||
#include "detail/descr.h"
|
||||
#include "detail/smart_holder_type_caster_support.h"
|
||||
#include "detail/type_caster_base.h"
|
||||
#include "detail/typeid.h"
|
||||
#include "pytypes.h"
|
||||
|
@ -1,394 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// BAKEIN_WIP: IWYU cleanup
|
||||
#include "../gil.h"
|
||||
#include "../pytypes.h"
|
||||
#include "../trampoline_self_life_support.h"
|
||||
#include "common.h"
|
||||
#include "dynamic_raw_ptr_cast_if_possible.h"
|
||||
#include "internals.h"
|
||||
#include "smart_holder_value_and_holder_support.h"
|
||||
#include "typeid.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
PYBIND11_NAMESPACE_BEGIN(smart_holder_type_caster_support)
|
||||
|
||||
template <typename T, typename D>
|
||||
handle smart_holder_from_unique_ptr(std::unique_ptr<T, D> &&src,
|
||||
return_value_policy policy,
|
||||
handle parent,
|
||||
const std::pair<const void *, const type_info *> &st) {
|
||||
if (policy != return_value_policy::automatic
|
||||
&& policy != return_value_policy::automatic_reference
|
||||
&& policy != return_value_policy::reference_internal
|
||||
&& policy != return_value_policy::move) {
|
||||
// SMART_HOLDER_WIP: IMPROVABLE: Error message.
|
||||
throw cast_error("Invalid return_value_policy for unique_ptr.");
|
||||
}
|
||||
if (!src) {
|
||||
return none().release();
|
||||
}
|
||||
void *src_raw_void_ptr = const_cast<void *>(st.first);
|
||||
assert(st.second != nullptr);
|
||||
const detail::type_info *tinfo = st.second;
|
||||
if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) {
|
||||
auto *self_life_support
|
||||
= dynamic_raw_ptr_cast_if_possible<trampoline_self_life_support>(src.get());
|
||||
if (self_life_support != nullptr) {
|
||||
value_and_holder &v_h = self_life_support->v_h;
|
||||
if (v_h.inst != nullptr && v_h.vh != nullptr) {
|
||||
auto &holder = v_h.holder<pybindit::memory::smart_holder>();
|
||||
if (!holder.is_disowned) {
|
||||
pybind11_fail("smart_holder_from_unique_ptr: unexpected "
|
||||
"smart_holder.is_disowned failure.");
|
||||
}
|
||||
// Critical transfer-of-ownership section. This must stay together.
|
||||
self_life_support->deactivate_life_support();
|
||||
holder.reclaim_disowned();
|
||||
(void) src.release();
|
||||
// Critical section end.
|
||||
return existing_inst;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
if (static_cast<void *>(src.get()) == src_raw_void_ptr) {
|
||||
// This is a multiple-inheritance situation that is incompatible with the current
|
||||
// shared_from_this handling (see PR #3023).
|
||||
// SMART_HOLDER_WIP: IMPROVABLE: Is there a better solution?
|
||||
src_raw_void_ptr = nullptr;
|
||||
}
|
||||
auto smhldr
|
||||
= pybindit::memory::smart_holder::from_unique_ptr(std::move(src), src_raw_void_ptr);
|
||||
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 T, typename D>
|
||||
handle smart_holder_from_unique_ptr(std::unique_ptr<T const, D> &&src,
|
||||
return_value_policy policy,
|
||||
handle parent,
|
||||
const std::pair<const void *, const type_info *> &st) {
|
||||
return smart_holder_from_unique_ptr(
|
||||
std::unique_ptr<T, D>(const_cast<T *>(src.release()),
|
||||
std::move(src.get_deleter())), // Const2Mutbl
|
||||
policy,
|
||||
parent,
|
||||
st);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
handle smart_holder_from_shared_ptr(const std::shared_ptr<T> &src,
|
||||
return_value_policy policy,
|
||||
handle parent,
|
||||
const std::pair<const void *, const type_info *> &st) {
|
||||
switch (policy) {
|
||||
case return_value_policy::automatic:
|
||||
case return_value_policy::automatic_reference:
|
||||
break;
|
||||
case return_value_policy::take_ownership:
|
||||
throw cast_error("Invalid return_value_policy for shared_ptr (take_ownership).");
|
||||
case return_value_policy::copy:
|
||||
case return_value_policy::move:
|
||||
break;
|
||||
case return_value_policy::reference:
|
||||
throw cast_error("Invalid return_value_policy for shared_ptr (reference).");
|
||||
case return_value_policy::reference_internal:
|
||||
break;
|
||||
}
|
||||
if (!src) {
|
||||
return none().release();
|
||||
}
|
||||
|
||||
auto src_raw_ptr = src.get();
|
||||
assert(st.second != nullptr);
|
||||
void *src_raw_void_ptr = static_cast<void *>(src_raw_ptr);
|
||||
const detail::type_info *tinfo = st.second;
|
||||
if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) {
|
||||
// SMART_HOLDER_WIP: MISSING: Enforcement of consistency with existing smart_holder.
|
||||
// SMART_HOLDER_WIP: MISSING: keep_alive.
|
||||
return existing_inst;
|
||||
}
|
||||
|
||||
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_shared_ptr(
|
||||
std::shared_ptr<void>(src, const_cast<void *>(st.first)));
|
||||
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 T>
|
||||
handle smart_holder_from_shared_ptr(const std::shared_ptr<T const> &src,
|
||||
return_value_policy policy,
|
||||
handle parent,
|
||||
const std::pair<const void *, const type_info *> &st) {
|
||||
return smart_holder_from_shared_ptr(std::const_pointer_cast<T>(src), // Const2Mutbl
|
||||
policy,
|
||||
parent,
|
||||
st);
|
||||
}
|
||||
|
||||
struct shared_ptr_parent_life_support {
|
||||
PyObject *parent;
|
||||
explicit shared_ptr_parent_life_support(PyObject *parent) : parent{parent} {
|
||||
Py_INCREF(parent);
|
||||
}
|
||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||
void operator()(void *) {
|
||||
gil_scoped_acquire gil;
|
||||
Py_DECREF(parent);
|
||||
}
|
||||
};
|
||||
|
||||
struct shared_ptr_trampoline_self_life_support {
|
||||
PyObject *self;
|
||||
explicit shared_ptr_trampoline_self_life_support(instance *inst)
|
||||
: self{reinterpret_cast<PyObject *>(inst)} {
|
||||
gil_scoped_acquire gil;
|
||||
Py_INCREF(self);
|
||||
}
|
||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||
void operator()(void *) {
|
||||
gil_scoped_acquire gil;
|
||||
Py_DECREF(self);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T,
|
||||
typename D,
|
||||
typename std::enable_if<std::is_default_constructible<D>::value, int>::type = 0>
|
||||
inline std::unique_ptr<T, D> unique_with_deleter(T *raw_ptr, std::unique_ptr<D> &&deleter) {
|
||||
if (deleter == nullptr) {
|
||||
return std::unique_ptr<T, D>(raw_ptr);
|
||||
}
|
||||
return std::unique_ptr<T, D>(raw_ptr, std::move(*deleter));
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename D,
|
||||
typename std::enable_if<!std::is_default_constructible<D>::value, int>::type = 0>
|
||||
inline std::unique_ptr<T, D> unique_with_deleter(T *raw_ptr, std::unique_ptr<D> &&deleter) {
|
||||
if (deleter == nullptr) {
|
||||
pybind11_fail("smart_holder_type_casters: deleter is not default constructible and no"
|
||||
" instance available to return.");
|
||||
}
|
||||
return std::unique_ptr<T, D>(raw_ptr, std::move(*deleter));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct load_helper
|
||||
: smart_holder_value_and_holder_support::value_and_holder_helper<value_and_holder> {
|
||||
using holder_type = pybindit::memory::smart_holder;
|
||||
|
||||
value_and_holder loaded_v_h;
|
||||
|
||||
load_helper()
|
||||
: smart_holder_value_and_holder_support::value_and_holder_helper<value_and_holder>(
|
||||
&loaded_v_h) {}
|
||||
|
||||
T *loaded_as_raw_ptr_unowned() const {
|
||||
void *void_ptr = nullptr;
|
||||
if (have_holder()) {
|
||||
throw_if_uninitialized_or_disowned_holder(typeid(T));
|
||||
void_ptr = holder().template as_raw_ptr_unowned<void>();
|
||||
} else if (loaded_v_h.vh != nullptr) {
|
||||
void_ptr = loaded_v_h.value_ptr();
|
||||
}
|
||||
if (void_ptr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return convert_type(void_ptr);
|
||||
}
|
||||
|
||||
T &loaded_as_lvalue_ref() const {
|
||||
T *raw_ptr = loaded_as_raw_ptr_unowned();
|
||||
if (raw_ptr == nullptr) {
|
||||
throw reference_cast_error();
|
||||
}
|
||||
return *raw_ptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<T> make_shared_ptr_with_responsible_parent(handle parent) const {
|
||||
return std::shared_ptr<T>(loaded_as_raw_ptr_unowned(),
|
||||
shared_ptr_parent_life_support(parent.ptr()));
|
||||
}
|
||||
|
||||
std::shared_ptr<T> loaded_as_shared_ptr(handle responsible_parent = nullptr) const {
|
||||
if (!have_holder()) {
|
||||
return nullptr;
|
||||
}
|
||||
throw_if_uninitialized_or_disowned_holder(typeid(T));
|
||||
holder_type &hld = holder();
|
||||
hld.ensure_is_not_disowned("loaded_as_shared_ptr");
|
||||
if (hld.vptr_is_using_noop_deleter) {
|
||||
if (responsible_parent) {
|
||||
return make_shared_ptr_with_responsible_parent(responsible_parent);
|
||||
}
|
||||
throw std::runtime_error("Non-owning holder (loaded_as_shared_ptr).");
|
||||
}
|
||||
auto *void_raw_ptr = hld.template as_raw_ptr_unowned<void>();
|
||||
auto *type_raw_ptr = convert_type(void_raw_ptr);
|
||||
if (hld.pointee_depends_on_holder_owner) {
|
||||
auto *vptr_gd_ptr = std::get_deleter<pybindit::memory::guarded_delete>(hld.vptr);
|
||||
if (vptr_gd_ptr != nullptr) {
|
||||
std::shared_ptr<void> released_ptr = vptr_gd_ptr->released_ptr.lock();
|
||||
if (released_ptr) {
|
||||
return std::shared_ptr<T>(released_ptr, type_raw_ptr);
|
||||
}
|
||||
std::shared_ptr<T> to_be_released(
|
||||
type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst));
|
||||
vptr_gd_ptr->released_ptr = to_be_released;
|
||||
return to_be_released;
|
||||
}
|
||||
auto *sptsls_ptr = std::get_deleter<shared_ptr_trampoline_self_life_support>(hld.vptr);
|
||||
if (sptsls_ptr != nullptr) {
|
||||
// This code is reachable only if there are multiple registered_instances for the
|
||||
// same pointee.
|
||||
if (reinterpret_cast<PyObject *>(loaded_v_h.inst) == sptsls_ptr->self) {
|
||||
pybind11_fail(
|
||||
"ssmart_holder_type_caster_support loaded_as_shared_ptr failure: "
|
||||
"loaded_v_h.inst == sptsls_ptr->self");
|
||||
}
|
||||
}
|
||||
if (sptsls_ptr != nullptr
|
||||
|| !pybindit::memory::type_has_shared_from_this(type_raw_ptr)) {
|
||||
return std::shared_ptr<T>(
|
||||
type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst));
|
||||
}
|
||||
if (hld.vptr_is_external_shared_ptr) {
|
||||
pybind11_fail("smart_holder_type_casters loaded_as_shared_ptr failure: not "
|
||||
"implemented: trampoline-self-life-support for external shared_ptr "
|
||||
"to type inheriting from std::enable_shared_from_this.");
|
||||
}
|
||||
pybind11_fail("smart_holder_type_casters: loaded_as_shared_ptr failure: internal "
|
||||
"inconsistency.");
|
||||
}
|
||||
std::shared_ptr<void> void_shd_ptr = hld.template as_shared_ptr<void>();
|
||||
return std::shared_ptr<T>(void_shd_ptr, type_raw_ptr);
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
std::unique_ptr<T, D> loaded_as_unique_ptr(const char *context = "loaded_as_unique_ptr") {
|
||||
if (!have_holder()) {
|
||||
return unique_with_deleter<T, D>(nullptr, std::unique_ptr<D>());
|
||||
}
|
||||
throw_if_uninitialized_or_disowned_holder(typeid(T));
|
||||
throw_if_instance_is_currently_owned_by_shared_ptr();
|
||||
holder().ensure_is_not_disowned(context);
|
||||
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>();
|
||||
|
||||
void *value_void_ptr = loaded_v_h.value_ptr();
|
||||
if (value_void_ptr != raw_void_ptr) {
|
||||
pybind11_fail("smart_holder_type_casters: loaded_as_unique_ptr failure:"
|
||||
" value_void_ptr != raw_void_ptr");
|
||||
}
|
||||
|
||||
// SMART_HOLDER_WIP: MISSING: Safety checks for type conversions
|
||||
// (T must be polymorphic or meet certain other conditions).
|
||||
T *raw_type_ptr = convert_type(raw_void_ptr);
|
||||
|
||||
auto *self_life_support
|
||||
= dynamic_raw_ptr_cast_if_possible<trampoline_self_life_support>(raw_type_ptr);
|
||||
if (self_life_support == nullptr && holder().pointee_depends_on_holder_owner) {
|
||||
throw value_error("Alias class (also known as trampoline) does not inherit from "
|
||||
"py::trampoline_self_life_support, therefore the ownership of this "
|
||||
"instance cannot safely be transferred to C++.");
|
||||
}
|
||||
|
||||
// Temporary variable to store the extracted deleter in.
|
||||
std::unique_ptr<D> extracted_deleter;
|
||||
|
||||
auto *gd = std::get_deleter<pybindit::memory::guarded_delete>(holder().vptr);
|
||||
if (gd && gd->use_del_fun) { // Note the ensure_compatible_rtti_uqp_del<T, D>() call above.
|
||||
// In smart_holder_poc, a custom deleter is always stored in a guarded delete.
|
||||
// The guarded delete's std::function<void(void*)> actually points at the
|
||||
// custom_deleter type, so we can verify it is of the custom deleter type and
|
||||
// finally extract its deleter.
|
||||
using custom_deleter_D = pybindit::memory::custom_deleter<T, D>;
|
||||
const auto &custom_deleter_ptr = gd->del_fun.template target<custom_deleter_D>();
|
||||
assert(custom_deleter_ptr != nullptr);
|
||||
// Now that we have confirmed the type of the deleter matches the desired return
|
||||
// value we can extract the function.
|
||||
extracted_deleter = std::unique_ptr<D>(new D(std::move(custom_deleter_ptr->deleter)));
|
||||
}
|
||||
|
||||
// Critical transfer-of-ownership section. This must stay together.
|
||||
if (self_life_support != nullptr) {
|
||||
holder().disown();
|
||||
} else {
|
||||
holder().release_ownership();
|
||||
}
|
||||
auto result = unique_with_deleter<T, D>(raw_type_ptr, std::move(extracted_deleter));
|
||||
if (self_life_support != nullptr) {
|
||||
self_life_support->activate_life_support(loaded_v_h);
|
||||
} else {
|
||||
loaded_v_h.value_ptr() = nullptr;
|
||||
deregister_instance(loaded_v_h.inst, value_void_ptr, loaded_v_h.type);
|
||||
}
|
||||
// Critical section end.
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef BAKEIN_WIP // Is this needed? shared_ptr_from_python(responsible_parent)
|
||||
// This function will succeed even if the `responsible_parent` does not own the
|
||||
// wrapped C++ object directly.
|
||||
// It is the responsibility of the caller to ensure that the `responsible_parent`
|
||||
// has a `keep_alive` relationship with the owner of the wrapped C++ object, or
|
||||
// that the wrapped C++ object lives for the duration of the process.
|
||||
static std::shared_ptr<T> shared_ptr_from_python(handle responsible_parent) {
|
||||
smart_holder_type_caster_load<T> loader;
|
||||
loader.load(responsible_parent, false);
|
||||
return loader.loaded_as_shared_ptr(responsible_parent);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
T *convert_type(void *void_ptr) const {
|
||||
#ifdef BAKEIN_WIP // Is this needed? implicit_casts
|
||||
if (void_ptr != nullptr && load_impl.loaded_v_h_cpptype != nullptr
|
||||
&& !load_impl.reinterpret_cast_deemed_ok && !load_impl.implicit_casts.empty()) {
|
||||
for (auto implicit_cast : load_impl.implicit_casts) {
|
||||
void_ptr = implicit_cast(void_ptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return static_cast<T *>(void_ptr);
|
||||
}
|
||||
};
|
||||
|
||||
PYBIND11_NAMESPACE_END(smart_holder_type_caster_support)
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
@ -1,59 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// BAKEIN_WIP: IWYU cleanup
|
||||
#include "common.h"
|
||||
#include "smart_holder_poc.h"
|
||||
#include "typeid.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
PYBIND11_NAMESPACE_BEGIN(smart_holder_value_and_holder_support)
|
||||
|
||||
// BAKEIN_WIP: Factor out `struct value_and_holder` from type_caster_base.h,
|
||||
// then this helper does not have to be templated.
|
||||
template <typename VHType>
|
||||
struct value_and_holder_helper {
|
||||
const VHType *loaded_v_h;
|
||||
|
||||
explicit value_and_holder_helper(const VHType *loaded_v_h) : loaded_v_h{loaded_v_h} {}
|
||||
|
||||
bool have_holder() const {
|
||||
return loaded_v_h->vh != nullptr && loaded_v_h->holder_constructed();
|
||||
}
|
||||
|
||||
pybindit::memory::smart_holder &holder() const {
|
||||
return loaded_v_h->template holder<pybindit::memory::smart_holder>();
|
||||
}
|
||||
|
||||
void throw_if_uninitialized_or_disowned_holder(const char *typeid_name) const {
|
||||
static const std::string missing_value_msg = "Missing value for wrapped C++ type `";
|
||||
if (!holder().is_populated) {
|
||||
throw value_error(missing_value_msg + clean_type_id(typeid_name)
|
||||
+ "`: Python instance is uninitialized.");
|
||||
}
|
||||
if (!holder().has_pointee()) {
|
||||
throw value_error(missing_value_msg + clean_type_id(typeid_name)
|
||||
+ "`: Python instance was disowned.");
|
||||
}
|
||||
}
|
||||
|
||||
void throw_if_uninitialized_or_disowned_holder(const std::type_info &type_info) const {
|
||||
throw_if_uninitialized_or_disowned_holder(type_info.name());
|
||||
}
|
||||
|
||||
// have_holder() must be true or this function will fail.
|
||||
void throw_if_instance_is_currently_owned_by_shared_ptr() const {
|
||||
auto vptr_gd_ptr = std::get_deleter<pybindit::memory::guarded_delete>(holder().vptr);
|
||||
if (vptr_gd_ptr != nullptr && !vptr_gd_ptr->released_ptr.expired()) {
|
||||
throw value_error("Python instance is currently owned by a std::shared_ptr.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PYBIND11_NAMESPACE_END(smart_holder_value_and_holder_support)
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
@ -9,12 +9,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../gil.h"
|
||||
#include "../pytypes.h"
|
||||
#include "common.h"
|
||||
#include "descr.h"
|
||||
#include "dynamic_raw_ptr_cast_if_possible.h"
|
||||
#include "internals.h"
|
||||
#include "smart_holder_poc.h"
|
||||
#include "smart_holder_value_and_holder_support.h"
|
||||
#include "typeid.h"
|
||||
|
||||
#include <cstdint>
|
||||
@ -530,6 +531,455 @@ inline PyThreadState *get_thread_state_unchecked() {
|
||||
void keep_alive_impl(handle nurse, handle patient);
|
||||
inline PyObject *make_new_instance(PyTypeObject *type);
|
||||
|
||||
// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code.
|
||||
inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo);
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
||||
// The original core idea for this struct goes back to PyCLIF:
|
||||
// https://github.com/google/clif/blob/07f95d7e69dca2fcf7022978a55ef3acff506c19/clif/python/runtime.cc#L37
|
||||
// URL provided here mainly to give proper credit. To fully explain the `HoldPyObj` feature, more
|
||||
// context is needed (SMART_HOLDER_WIP).
|
||||
struct trampoline_self_life_support {
|
||||
detail::value_and_holder v_h;
|
||||
|
||||
trampoline_self_life_support() = default;
|
||||
|
||||
void activate_life_support(const detail::value_and_holder &v_h_) {
|
||||
Py_INCREF((PyObject *) v_h_.inst);
|
||||
v_h = v_h_;
|
||||
}
|
||||
|
||||
void deactivate_life_support() {
|
||||
Py_DECREF((PyObject *) v_h.inst);
|
||||
v_h = detail::value_and_holder();
|
||||
}
|
||||
|
||||
~trampoline_self_life_support() {
|
||||
if (v_h.inst != nullptr && v_h.vh != nullptr) {
|
||||
void *value_void_ptr = v_h.value_ptr();
|
||||
if (value_void_ptr != nullptr) {
|
||||
PyGILState_STATE threadstate = PyGILState_Ensure();
|
||||
v_h.value_ptr() = nullptr;
|
||||
v_h.holder<pybindit::memory::smart_holder>().release_disowned();
|
||||
detail::deregister_instance(v_h.inst, value_void_ptr, v_h.type);
|
||||
Py_DECREF((PyObject *) v_h.inst); // Must be after deregister.
|
||||
PyGILState_Release(threadstate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For the next two, the default implementations generate undefined behavior (ASAN failures
|
||||
// manually verified). The reason is that v_h needs to be kept default-initialized.
|
||||
trampoline_self_life_support(const trampoline_self_life_support &) {}
|
||||
trampoline_self_life_support(trampoline_self_life_support &&) noexcept {}
|
||||
|
||||
// These should never be needed (please provide test cases if you think they are).
|
||||
trampoline_self_life_support &operator=(const trampoline_self_life_support &) = delete;
|
||||
trampoline_self_life_support &operator=(trampoline_self_life_support &&) = delete;
|
||||
};
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
PYBIND11_NAMESPACE_BEGIN(smart_holder_type_caster_support)
|
||||
|
||||
struct value_and_holder_helper {
|
||||
value_and_holder loaded_v_h;
|
||||
|
||||
bool have_holder() const {
|
||||
return loaded_v_h.vh != nullptr && loaded_v_h.holder_constructed();
|
||||
}
|
||||
|
||||
pybindit::memory::smart_holder &holder() const {
|
||||
return loaded_v_h.holder<pybindit::memory::smart_holder>();
|
||||
}
|
||||
|
||||
void throw_if_uninitialized_or_disowned_holder(const char *typeid_name) const {
|
||||
static const std::string missing_value_msg = "Missing value for wrapped C++ type `";
|
||||
if (!holder().is_populated) {
|
||||
throw value_error(missing_value_msg + clean_type_id(typeid_name)
|
||||
+ "`: Python instance is uninitialized.");
|
||||
}
|
||||
if (!holder().has_pointee()) {
|
||||
throw value_error(missing_value_msg + clean_type_id(typeid_name)
|
||||
+ "`: Python instance was disowned.");
|
||||
}
|
||||
}
|
||||
|
||||
void throw_if_uninitialized_or_disowned_holder(const std::type_info &type_info) const {
|
||||
throw_if_uninitialized_or_disowned_holder(type_info.name());
|
||||
}
|
||||
|
||||
// have_holder() must be true or this function will fail.
|
||||
void throw_if_instance_is_currently_owned_by_shared_ptr() const {
|
||||
auto vptr_gd_ptr = std::get_deleter<pybindit::memory::guarded_delete>(holder().vptr);
|
||||
if (vptr_gd_ptr != nullptr && !vptr_gd_ptr->released_ptr.expired()) {
|
||||
throw value_error("Python instance is currently owned by a std::shared_ptr.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename D>
|
||||
handle smart_holder_from_unique_ptr(std::unique_ptr<T, D> &&src,
|
||||
return_value_policy policy,
|
||||
handle parent,
|
||||
const std::pair<const void *, const type_info *> &st) {
|
||||
if (policy != return_value_policy::automatic
|
||||
&& policy != return_value_policy::automatic_reference
|
||||
&& policy != return_value_policy::reference_internal
|
||||
&& policy != return_value_policy::move) {
|
||||
// SMART_HOLDER_WIP: IMPROVABLE: Error message.
|
||||
throw cast_error("Invalid return_value_policy for unique_ptr.");
|
||||
}
|
||||
if (!src) {
|
||||
return none().release();
|
||||
}
|
||||
void *src_raw_void_ptr = const_cast<void *>(st.first);
|
||||
assert(st.second != nullptr);
|
||||
const detail::type_info *tinfo = st.second;
|
||||
if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) {
|
||||
auto *self_life_support
|
||||
= dynamic_raw_ptr_cast_if_possible<trampoline_self_life_support>(src.get());
|
||||
if (self_life_support != nullptr) {
|
||||
value_and_holder &v_h = self_life_support->v_h;
|
||||
if (v_h.inst != nullptr && v_h.vh != nullptr) {
|
||||
auto &holder = v_h.holder<pybindit::memory::smart_holder>();
|
||||
if (!holder.is_disowned) {
|
||||
pybind11_fail("smart_holder_from_unique_ptr: unexpected "
|
||||
"smart_holder.is_disowned failure.");
|
||||
}
|
||||
// Critical transfer-of-ownership section. This must stay together.
|
||||
self_life_support->deactivate_life_support();
|
||||
holder.reclaim_disowned();
|
||||
(void) src.release();
|
||||
// Critical section end.
|
||||
return existing_inst;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
if (static_cast<void *>(src.get()) == src_raw_void_ptr) {
|
||||
// This is a multiple-inheritance situation that is incompatible with the current
|
||||
// shared_from_this handling (see PR #3023).
|
||||
// SMART_HOLDER_WIP: IMPROVABLE: Is there a better solution?
|
||||
src_raw_void_ptr = nullptr;
|
||||
}
|
||||
auto smhldr
|
||||
= pybindit::memory::smart_holder::from_unique_ptr(std::move(src), src_raw_void_ptr);
|
||||
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 T, typename D>
|
||||
handle smart_holder_from_unique_ptr(std::unique_ptr<T const, D> &&src,
|
||||
return_value_policy policy,
|
||||
handle parent,
|
||||
const std::pair<const void *, const type_info *> &st) {
|
||||
return smart_holder_from_unique_ptr(
|
||||
std::unique_ptr<T, D>(const_cast<T *>(src.release()),
|
||||
std::move(src.get_deleter())), // Const2Mutbl
|
||||
policy,
|
||||
parent,
|
||||
st);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
handle smart_holder_from_shared_ptr(const std::shared_ptr<T> &src,
|
||||
return_value_policy policy,
|
||||
handle parent,
|
||||
const std::pair<const void *, const type_info *> &st) {
|
||||
switch (policy) {
|
||||
case return_value_policy::automatic:
|
||||
case return_value_policy::automatic_reference:
|
||||
break;
|
||||
case return_value_policy::take_ownership:
|
||||
throw cast_error("Invalid return_value_policy for shared_ptr (take_ownership).");
|
||||
case return_value_policy::copy:
|
||||
case return_value_policy::move:
|
||||
break;
|
||||
case return_value_policy::reference:
|
||||
throw cast_error("Invalid return_value_policy for shared_ptr (reference).");
|
||||
case return_value_policy::reference_internal:
|
||||
break;
|
||||
}
|
||||
if (!src) {
|
||||
return none().release();
|
||||
}
|
||||
|
||||
auto src_raw_ptr = src.get();
|
||||
assert(st.second != nullptr);
|
||||
void *src_raw_void_ptr = static_cast<void *>(src_raw_ptr);
|
||||
const detail::type_info *tinfo = st.second;
|
||||
if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) {
|
||||
// SMART_HOLDER_WIP: MISSING: Enforcement of consistency with existing smart_holder.
|
||||
// SMART_HOLDER_WIP: MISSING: keep_alive.
|
||||
return existing_inst;
|
||||
}
|
||||
|
||||
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_shared_ptr(
|
||||
std::shared_ptr<void>(src, const_cast<void *>(st.first)));
|
||||
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 T>
|
||||
handle smart_holder_from_shared_ptr(const std::shared_ptr<T const> &src,
|
||||
return_value_policy policy,
|
||||
handle parent,
|
||||
const std::pair<const void *, const type_info *> &st) {
|
||||
return smart_holder_from_shared_ptr(std::const_pointer_cast<T>(src), // Const2Mutbl
|
||||
policy,
|
||||
parent,
|
||||
st);
|
||||
}
|
||||
|
||||
struct shared_ptr_parent_life_support {
|
||||
PyObject *parent;
|
||||
explicit shared_ptr_parent_life_support(PyObject *parent) : parent{parent} {
|
||||
Py_INCREF(parent);
|
||||
}
|
||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||
void operator()(void *) {
|
||||
gil_scoped_acquire gil;
|
||||
Py_DECREF(parent);
|
||||
}
|
||||
};
|
||||
|
||||
struct shared_ptr_trampoline_self_life_support {
|
||||
PyObject *self;
|
||||
explicit shared_ptr_trampoline_self_life_support(instance *inst)
|
||||
: self{reinterpret_cast<PyObject *>(inst)} {
|
||||
gil_scoped_acquire gil;
|
||||
Py_INCREF(self);
|
||||
}
|
||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||
void operator()(void *) {
|
||||
gil_scoped_acquire gil;
|
||||
Py_DECREF(self);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T,
|
||||
typename D,
|
||||
typename std::enable_if<std::is_default_constructible<D>::value, int>::type = 0>
|
||||
inline std::unique_ptr<T, D> unique_with_deleter(T *raw_ptr, std::unique_ptr<D> &&deleter) {
|
||||
if (deleter == nullptr) {
|
||||
return std::unique_ptr<T, D>(raw_ptr);
|
||||
}
|
||||
return std::unique_ptr<T, D>(raw_ptr, std::move(*deleter));
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename D,
|
||||
typename std::enable_if<!std::is_default_constructible<D>::value, int>::type = 0>
|
||||
inline std::unique_ptr<T, D> unique_with_deleter(T *raw_ptr, std::unique_ptr<D> &&deleter) {
|
||||
if (deleter == nullptr) {
|
||||
pybind11_fail("smart_holder_type_casters: deleter is not default constructible and no"
|
||||
" instance available to return.");
|
||||
}
|
||||
return std::unique_ptr<T, D>(raw_ptr, std::move(*deleter));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct load_helper : value_and_holder_helper {
|
||||
using holder_type = pybindit::memory::smart_holder;
|
||||
|
||||
T *loaded_as_raw_ptr_unowned() const {
|
||||
void *void_ptr = nullptr;
|
||||
if (have_holder()) {
|
||||
throw_if_uninitialized_or_disowned_holder(typeid(T));
|
||||
void_ptr = holder().template as_raw_ptr_unowned<void>();
|
||||
} else if (loaded_v_h.vh != nullptr) {
|
||||
void_ptr = loaded_v_h.value_ptr();
|
||||
}
|
||||
if (void_ptr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return convert_type(void_ptr);
|
||||
}
|
||||
|
||||
T &loaded_as_lvalue_ref() const {
|
||||
T *raw_ptr = loaded_as_raw_ptr_unowned();
|
||||
if (raw_ptr == nullptr) {
|
||||
throw reference_cast_error();
|
||||
}
|
||||
return *raw_ptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<T> make_shared_ptr_with_responsible_parent(handle parent) const {
|
||||
return std::shared_ptr<T>(loaded_as_raw_ptr_unowned(),
|
||||
shared_ptr_parent_life_support(parent.ptr()));
|
||||
}
|
||||
|
||||
std::shared_ptr<T> loaded_as_shared_ptr(handle responsible_parent = nullptr) const {
|
||||
if (!have_holder()) {
|
||||
return nullptr;
|
||||
}
|
||||
throw_if_uninitialized_or_disowned_holder(typeid(T));
|
||||
holder_type &hld = holder();
|
||||
hld.ensure_is_not_disowned("loaded_as_shared_ptr");
|
||||
if (hld.vptr_is_using_noop_deleter) {
|
||||
if (responsible_parent) {
|
||||
return make_shared_ptr_with_responsible_parent(responsible_parent);
|
||||
}
|
||||
throw std::runtime_error("Non-owning holder (loaded_as_shared_ptr).");
|
||||
}
|
||||
auto *void_raw_ptr = hld.template as_raw_ptr_unowned<void>();
|
||||
auto *type_raw_ptr = convert_type(void_raw_ptr);
|
||||
if (hld.pointee_depends_on_holder_owner) {
|
||||
auto *vptr_gd_ptr = std::get_deleter<pybindit::memory::guarded_delete>(hld.vptr);
|
||||
if (vptr_gd_ptr != nullptr) {
|
||||
std::shared_ptr<void> released_ptr = vptr_gd_ptr->released_ptr.lock();
|
||||
if (released_ptr) {
|
||||
return std::shared_ptr<T>(released_ptr, type_raw_ptr);
|
||||
}
|
||||
std::shared_ptr<T> to_be_released(
|
||||
type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst));
|
||||
vptr_gd_ptr->released_ptr = to_be_released;
|
||||
return to_be_released;
|
||||
}
|
||||
auto *sptsls_ptr = std::get_deleter<shared_ptr_trampoline_self_life_support>(hld.vptr);
|
||||
if (sptsls_ptr != nullptr) {
|
||||
// This code is reachable only if there are multiple registered_instances for the
|
||||
// same pointee.
|
||||
if (reinterpret_cast<PyObject *>(loaded_v_h.inst) == sptsls_ptr->self) {
|
||||
pybind11_fail("smart_holder_type_caster_support loaded_as_shared_ptr failure: "
|
||||
"loaded_v_h.inst == sptsls_ptr->self");
|
||||
}
|
||||
}
|
||||
if (sptsls_ptr != nullptr
|
||||
|| !pybindit::memory::type_has_shared_from_this(type_raw_ptr)) {
|
||||
return std::shared_ptr<T>(
|
||||
type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst));
|
||||
}
|
||||
if (hld.vptr_is_external_shared_ptr) {
|
||||
pybind11_fail("smart_holder_type_casters loaded_as_shared_ptr failure: not "
|
||||
"implemented: trampoline-self-life-support for external shared_ptr "
|
||||
"to type inheriting from std::enable_shared_from_this.");
|
||||
}
|
||||
pybind11_fail("smart_holder_type_casters: loaded_as_shared_ptr failure: internal "
|
||||
"inconsistency.");
|
||||
}
|
||||
std::shared_ptr<void> void_shd_ptr = hld.template as_shared_ptr<void>();
|
||||
return std::shared_ptr<T>(void_shd_ptr, type_raw_ptr);
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
std::unique_ptr<T, D> loaded_as_unique_ptr(const char *context = "loaded_as_unique_ptr") {
|
||||
if (!have_holder()) {
|
||||
return unique_with_deleter<T, D>(nullptr, std::unique_ptr<D>());
|
||||
}
|
||||
throw_if_uninitialized_or_disowned_holder(typeid(T));
|
||||
throw_if_instance_is_currently_owned_by_shared_ptr();
|
||||
holder().ensure_is_not_disowned(context);
|
||||
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>();
|
||||
|
||||
void *value_void_ptr = loaded_v_h.value_ptr();
|
||||
if (value_void_ptr != raw_void_ptr) {
|
||||
pybind11_fail("smart_holder_type_casters: loaded_as_unique_ptr failure:"
|
||||
" value_void_ptr != raw_void_ptr");
|
||||
}
|
||||
|
||||
// SMART_HOLDER_WIP: MISSING: Safety checks for type conversions
|
||||
// (T must be polymorphic or meet certain other conditions).
|
||||
T *raw_type_ptr = convert_type(raw_void_ptr);
|
||||
|
||||
auto *self_life_support
|
||||
= dynamic_raw_ptr_cast_if_possible<trampoline_self_life_support>(raw_type_ptr);
|
||||
if (self_life_support == nullptr && holder().pointee_depends_on_holder_owner) {
|
||||
throw value_error("Alias class (also known as trampoline) does not inherit from "
|
||||
"py::trampoline_self_life_support, therefore the ownership of this "
|
||||
"instance cannot safely be transferred to C++.");
|
||||
}
|
||||
|
||||
// Temporary variable to store the extracted deleter in.
|
||||
std::unique_ptr<D> extracted_deleter;
|
||||
|
||||
auto *gd = std::get_deleter<pybindit::memory::guarded_delete>(holder().vptr);
|
||||
if (gd && gd->use_del_fun) { // Note the ensure_compatible_rtti_uqp_del<T, D>() call above.
|
||||
// In smart_holder_poc, a custom deleter is always stored in a guarded delete.
|
||||
// The guarded delete's std::function<void(void*)> actually points at the
|
||||
// custom_deleter type, so we can verify it is of the custom deleter type and
|
||||
// finally extract its deleter.
|
||||
using custom_deleter_D = pybindit::memory::custom_deleter<T, D>;
|
||||
const auto &custom_deleter_ptr = gd->del_fun.template target<custom_deleter_D>();
|
||||
assert(custom_deleter_ptr != nullptr);
|
||||
// Now that we have confirmed the type of the deleter matches the desired return
|
||||
// value we can extract the function.
|
||||
extracted_deleter = std::unique_ptr<D>(new D(std::move(custom_deleter_ptr->deleter)));
|
||||
}
|
||||
|
||||
// Critical transfer-of-ownership section. This must stay together.
|
||||
if (self_life_support != nullptr) {
|
||||
holder().disown();
|
||||
} else {
|
||||
holder().release_ownership();
|
||||
}
|
||||
auto result = unique_with_deleter<T, D>(raw_type_ptr, std::move(extracted_deleter));
|
||||
if (self_life_support != nullptr) {
|
||||
self_life_support->activate_life_support(loaded_v_h);
|
||||
} else {
|
||||
loaded_v_h.value_ptr() = nullptr;
|
||||
deregister_instance(loaded_v_h.inst, value_void_ptr, loaded_v_h.type);
|
||||
}
|
||||
// Critical section end.
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef BAKEIN_WIP // Is this needed? shared_ptr_from_python(responsible_parent)
|
||||
// This function will succeed even if the `responsible_parent` does not own the
|
||||
// wrapped C++ object directly.
|
||||
// It is the responsibility of the caller to ensure that the `responsible_parent`
|
||||
// has a `keep_alive` relationship with the owner of the wrapped C++ object, or
|
||||
// that the wrapped C++ object lives for the duration of the process.
|
||||
static std::shared_ptr<T> shared_ptr_from_python(handle responsible_parent) {
|
||||
smart_holder_type_caster_load<T> loader;
|
||||
loader.load(responsible_parent, false);
|
||||
return loader.loaded_as_shared_ptr(responsible_parent);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
T *convert_type(void *void_ptr) const {
|
||||
#ifdef BAKEIN_WIP // Is this needed? implicit_casts
|
||||
if (void_ptr != nullptr && load_impl.loaded_v_h_cpptype != nullptr
|
||||
&& !load_impl.reinterpret_cast_deemed_ok && !load_impl.implicit_casts.empty()) {
|
||||
for (auto implicit_cast : load_impl.implicit_casts) {
|
||||
void_ptr = implicit_cast(void_ptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return static_cast<T *>(void_ptr);
|
||||
}
|
||||
};
|
||||
|
||||
PYBIND11_NAMESPACE_END(smart_holder_type_caster_support)
|
||||
|
||||
class type_caster_generic {
|
||||
public:
|
||||
PYBIND11_NOINLINE explicit type_caster_generic(const std::type_info &type_info)
|
||||
@ -635,10 +1085,10 @@ public:
|
||||
// Base methods for generic caster; there are overridden in copyable_holder_caster
|
||||
void load_value(value_and_holder &&v_h) {
|
||||
if (typeinfo->default_holder) {
|
||||
smart_holder_value_and_holder_support::value_and_holder_helper<value_and_holder>
|
||||
vh_helper(&v_h);
|
||||
if (vh_helper.have_holder()) {
|
||||
vh_helper.throw_if_uninitialized_or_disowned_holder(typeid(cpptype));
|
||||
smart_holder_type_caster_support::value_and_holder_helper v_h_helper;
|
||||
v_h_helper.loaded_v_h = v_h;
|
||||
if (v_h_helper.have_holder()) {
|
||||
v_h_helper.throw_if_uninitialized_or_disowned_holder(typeid(cpptype));
|
||||
}
|
||||
}
|
||||
auto *&vptr = v_h.value_ptr();
|
||||
|
@ -1,61 +1,8 @@
|
||||
// Copyright (c) 2021 The Pybind Development Team.
|
||||
// Copyright (c) 2024 The Pybind Development Team.
|
||||
// All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "detail/common.h"
|
||||
#include "detail/smart_holder_poc.h"
|
||||
// BAKEIN_WIP: Needs refactoring of existing pybind11 code.
|
||||
#include "detail/type_caster_base.h"
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code.
|
||||
inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo);
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
||||
// The original core idea for this struct goes back to PyCLIF:
|
||||
// https://github.com/google/clif/blob/07f95d7e69dca2fcf7022978a55ef3acff506c19/clif/python/runtime.cc#L37
|
||||
// URL provided here mainly to give proper credit. To fully explain the `HoldPyObj` feature, more
|
||||
// context is needed (SMART_HOLDER_WIP).
|
||||
struct trampoline_self_life_support {
|
||||
detail::value_and_holder v_h;
|
||||
|
||||
trampoline_self_life_support() = default;
|
||||
|
||||
void activate_life_support(const detail::value_and_holder &v_h_) {
|
||||
Py_INCREF((PyObject *) v_h_.inst);
|
||||
v_h = v_h_;
|
||||
}
|
||||
|
||||
void deactivate_life_support() {
|
||||
Py_DECREF((PyObject *) v_h.inst);
|
||||
v_h = detail::value_and_holder();
|
||||
}
|
||||
|
||||
~trampoline_self_life_support() {
|
||||
if (v_h.inst != nullptr && v_h.vh != nullptr) {
|
||||
void *value_void_ptr = v_h.value_ptr();
|
||||
if (value_void_ptr != nullptr) {
|
||||
PyGILState_STATE threadstate = PyGILState_Ensure();
|
||||
v_h.value_ptr() = nullptr;
|
||||
v_h.holder<pybindit::memory::smart_holder>().release_disowned();
|
||||
detail::deregister_instance(v_h.inst, value_void_ptr, v_h.type);
|
||||
Py_DECREF((PyObject *) v_h.inst); // Must be after deregister.
|
||||
PyGILState_Release(threadstate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For the next two, the default implementations generate undefined behavior (ASAN failures
|
||||
// manually verified). The reason is that v_h needs to be kept default-initialized.
|
||||
trampoline_self_life_support(const trampoline_self_life_support &) {}
|
||||
trampoline_self_life_support(trampoline_self_life_support &&) noexcept {}
|
||||
|
||||
// These should never be needed (please provide test cases if you think they are).
|
||||
trampoline_self_life_support &operator=(const trampoline_self_life_support &) = delete;
|
||||
trampoline_self_life_support &operator=(trampoline_self_life_support &&) = delete;
|
||||
};
|
||||
|
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
@ -60,8 +60,6 @@ detail_headers = {
|
||||
"include/pybind11/detail/init.h",
|
||||
"include/pybind11/detail/internals.h",
|
||||
"include/pybind11/detail/smart_holder_poc.h",
|
||||
"include/pybind11/detail/smart_holder_type_caster_support.h",
|
||||
"include/pybind11/detail/smart_holder_value_and_holder_support.h",
|
||||
"include/pybind11/detail/type_caster_base.h",
|
||||
"include/pybind11/detail/typeid.h",
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user