mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 14:45:12 +00:00
Start pybind11/detail/smart_holder_type_caster_support.h, move unique_ptr_to_python() there, add smart_holder_from_unique_ptr()
This commit is contained in:
parent
6ff547e18a
commit
ae08f51e38
@ -12,6 +12,7 @@
|
||||
|
||||
#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"
|
||||
@ -931,8 +932,10 @@ struct move_only_holder_caster<type, std::unique_ptr<type, deleter>> {
|
||||
static_assert(std::is_base_of<type_caster_base<type>, type_caster<type>>::value,
|
||||
"Holder classes are only supported for custom types");
|
||||
|
||||
static handle cast(std::unique_ptr<type, deleter> &&src, return_value_policy, handle) {
|
||||
return type_caster_base<type>::unique_ptr_to_python(std::move(src));
|
||||
static handle
|
||||
cast(std::unique_ptr<type, deleter> &&src, return_value_policy policy, handle parent) {
|
||||
return smart_holder_type_caster_support::unique_ptr_to_python(
|
||||
std::move(src), policy, parent);
|
||||
}
|
||||
static constexpr auto name = type_caster_base<type>::name;
|
||||
};
|
||||
|
107
include/pybind11/detail/smart_holder_type_caster_support.h
Normal file
107
include/pybind11/detail/smart_holder_type_caster_support.h
Normal file
@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include "../pytypes.h"
|
||||
#include "../trampoline_self_life_support.h"
|
||||
#include "common.h"
|
||||
#include "dynamic_raw_ptr_cast_if_possible.h"
|
||||
#include "internals.h"
|
||||
#include "type_caster_base.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
|
||||
unique_ptr_to_python(std::unique_ptr<T, D> &&unq_ptr, return_value_policy policy, handle parent) {
|
||||
auto *src = unq_ptr.get();
|
||||
auto st = type_caster_base<T>::src_and_type(src);
|
||||
if (st.second == nullptr) {
|
||||
return handle(); // no type info: error will be set already
|
||||
}
|
||||
if (st.second->default_holder) {
|
||||
return smart_holder_from_unique_ptr(std::move(unq_ptr), policy, parent, st);
|
||||
}
|
||||
return type_caster_generic::cast(st.first,
|
||||
return_value_policy::take_ownership,
|
||||
{},
|
||||
st.second,
|
||||
nullptr,
|
||||
nullptr,
|
||||
std::addressof(unq_ptr));
|
||||
}
|
||||
|
||||
PYBIND11_NAMESPACE_END(smart_holder_type_caster_support)
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
@ -1160,22 +1160,6 @@ public:
|
||||
holder);
|
||||
}
|
||||
|
||||
template <typename T, typename D>
|
||||
static handle unique_ptr_to_python(std::unique_ptr<T, D> &&unq_ptr) {
|
||||
auto *src = unq_ptr.get();
|
||||
auto st = src_and_type(src);
|
||||
if (st.second->default_holder) {
|
||||
throw std::runtime_error("BAKEIN_WIP");
|
||||
}
|
||||
return type_caster_generic::cast(st.first,
|
||||
return_value_policy::take_ownership,
|
||||
{},
|
||||
st.second,
|
||||
nullptr,
|
||||
nullptr,
|
||||
std::addressof(unq_ptr));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using cast_op_type = detail::cast_op_type<T>;
|
||||
|
||||
|
61
include/pybind11/trampoline_self_life_support.h
Normal file
61
include/pybind11/trampoline_self_life_support.h
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2021 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"
|
||||
#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)
|
Loading…
Reference in New Issue
Block a user