PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT

This commit is contained in:
Ralf W. Grosse-Kunstleve 2024-07-18 18:59:52 -07:00
parent 1ea1787745
commit cd4f5f6c5b
5 changed files with 75 additions and 25 deletions

View File

@ -331,6 +331,10 @@ struct type_record {
/// Is the class inheritable from python classes? /// Is the class inheritable from python classes?
bool is_final : 1; bool is_final : 1;
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
holder_enum_t holder_enum_v = holder_enum_t::undefined;
#endif
PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *) ) { PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *) ) {
auto *base_info = detail::get_type_info(base, false); auto *base_info = detail::get_type_info(base, false);
if (!base_info) { if (!base_info) {

View File

@ -835,7 +835,7 @@ protected:
holder_type holder; holder_type holder;
}; };
#define PYBIND11_HAVE_HOLDER_CASTER_WITH_SMART_HOLDER_SUPPORT #ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
template <typename, typename SFINAE = void> template <typename, typename SFINAE = void>
struct copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled : std::true_type {}; struct copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled : std::true_type {};
@ -862,14 +862,14 @@ public:
} }
explicit operator type *() { explicit operator type *() {
if (typeinfo->default_holder) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
throw std::runtime_error("BAKEIN_WIP: operator type *() shared_ptr"); throw std::runtime_error("BAKEIN_WIP: operator type *() shared_ptr");
} }
return this->value; return this->value;
} }
explicit operator type &() { explicit operator type &() {
if (typeinfo->default_holder) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
throw std::runtime_error("BAKEIN_WIP: operator type &() shared_ptr"); throw std::runtime_error("BAKEIN_WIP: operator type &() shared_ptr");
} }
// static_cast works around compiler error with MSVC 17 and CUDA 10.2 // static_cast works around compiler error with MSVC 17 and CUDA 10.2
@ -878,14 +878,14 @@ public:
} }
explicit operator std::shared_ptr<type> *() { explicit operator std::shared_ptr<type> *() {
if (typeinfo->default_holder) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
throw std::runtime_error("BAKEIN_WIP: operator std::shared_ptr<type> *()"); throw std::runtime_error("BAKEIN_WIP: operator std::shared_ptr<type> *()");
} }
return std::addressof(shared_ptr_holder); return std::addressof(shared_ptr_holder);
} }
explicit operator std::shared_ptr<type> &() { explicit operator std::shared_ptr<type> &() {
if (typeinfo->default_holder) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
shared_ptr_holder = sh_load_helper.loaded_as_shared_ptr(value); shared_ptr_holder = sh_load_helper.loaded_as_shared_ptr(value);
} }
return shared_ptr_holder; return shared_ptr_holder;
@ -898,7 +898,7 @@ public:
if (st.second == nullptr) { if (st.second == nullptr) {
return handle(); // no type info: error will be set already return handle(); // no type info: error will be set already
} }
if (st.second->default_holder) { if (st.second->holder_enum_v == detail::holder_enum_t::smart_holder) {
return smart_holder_type_caster_support::smart_holder_from_shared_ptr( return smart_holder_type_caster_support::smart_holder_from_shared_ptr(
src, policy, parent, st); src, policy, parent, st);
} }
@ -913,7 +913,7 @@ public:
static std::shared_ptr<type> shared_ptr_with_responsible_parent(handle responsible_parent) { static std::shared_ptr<type> shared_ptr_with_responsible_parent(handle responsible_parent) {
copyable_holder_caster loader; copyable_holder_caster loader;
loader.load(responsible_parent, /*convert=*/false); loader.load(responsible_parent, /*convert=*/false);
assert(loader.typeinfo->default_holder); assert(loader.typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder);
return loader.sh_load_helper.loaded_as_shared_ptr(loader.value, responsible_parent); return loader.sh_load_helper.loaded_as_shared_ptr(loader.value, responsible_parent);
} }
@ -921,7 +921,7 @@ protected:
friend class type_caster_generic; friend class type_caster_generic;
void load_value(value_and_holder &&v_h) { void load_value(value_and_holder &&v_h) {
if (typeinfo->default_holder) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
sh_load_helper.loaded_v_h = v_h; sh_load_helper.loaded_v_h = v_h;
value = sh_load_helper.get_void_ptr_or_nullptr(); value = sh_load_helper.get_void_ptr_or_nullptr();
return; return;
@ -932,13 +932,13 @@ protected:
return; return;
} }
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) " throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) # if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for " "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for "
"type information)"); "type information)");
#else # else
"of type '" "of type '"
+ type_id<std::shared_ptr<type>>() + "''"); + type_id<std::shared_ptr<type>>() + "''");
#endif # endif
} }
template <typename T = std::shared_ptr<type>, template <typename T = std::shared_ptr<type>,
@ -954,7 +954,7 @@ protected:
copyable_holder_caster sub_caster(*cast.first); copyable_holder_caster sub_caster(*cast.first);
if (sub_caster.load(src, convert)) { if (sub_caster.load(src, convert)) {
value = cast.second(sub_caster.value); value = cast.second(sub_caster.value);
if (typeinfo->default_holder) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
// BAKEIN_WIP: Copy pointer only? // BAKEIN_WIP: Copy pointer only?
sh_load_helper.loaded_v_h = sub_caster.sh_load_helper.loaded_v_h; sh_load_helper.loaded_v_h = sub_caster.sh_load_helper.loaded_v_h;
} else { } else {
@ -973,6 +973,8 @@ protected:
smart_holder_type_caster_support::load_helper<remove_cv_t<type>> sh_load_helper; // Const2Mutbl smart_holder_type_caster_support::load_helper<remove_cv_t<type>> sh_load_helper; // Const2Mutbl
}; };
#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
/// Specialize for the common std::shared_ptr, so users don't need to /// Specialize for the common std::shared_ptr, so users don't need to
template <typename T> template <typename T>
class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> {}; class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> {};
@ -992,6 +994,8 @@ struct move_only_holder_caster {
static constexpr auto name = type_caster_base<type>::name; static constexpr auto name = type_caster_base<type>::name;
}; };
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
template <typename, typename SFINAE = void> template <typename, typename SFINAE = void>
struct move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled : std::true_type {}; struct move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled : std::true_type {};
@ -1018,7 +1022,7 @@ public:
if (st.second == nullptr) { if (st.second == nullptr) {
return handle(); // no type info: error will be set already return handle(); // no type info: error will be set already
} }
if (st.second->default_holder) { if (st.second->holder_enum_v == detail::holder_enum_t::smart_holder) {
return smart_holder_type_caster_support::smart_holder_from_unique_ptr( return smart_holder_type_caster_support::smart_holder_from_unique_ptr(
std::move(src), policy, parent, st); std::move(src), policy, parent, st);
} }
@ -1051,7 +1055,7 @@ public:
} }
void load_value(value_and_holder &&v_h) { void load_value(value_and_holder &&v_h) {
if (typeinfo->default_holder) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
sh_load_helper.loaded_v_h = v_h; sh_load_helper.loaded_v_h = v_h;
sh_load_helper.loaded_v_h.type = typeinfo; sh_load_helper.loaded_v_h.type = typeinfo;
value = sh_load_helper.get_void_ptr_or_nullptr(); value = sh_load_helper.get_void_ptr_or_nullptr();
@ -1064,7 +1068,7 @@ public:
using cast_op_type = std::unique_ptr<type, deleter>; using cast_op_type = std::unique_ptr<type, deleter>;
explicit operator std::unique_ptr<type, deleter>() { explicit operator std::unique_ptr<type, deleter>() {
if (typeinfo->default_holder) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
return sh_load_helper.template loaded_as_unique_ptr<deleter>(value); return sh_load_helper.template loaded_as_unique_ptr<deleter>(value);
} }
pybind11_fail("Passing std::unique_ptr from Python to C++ requires smart_holder."); pybind11_fail("Passing std::unique_ptr from Python to C++ requires smart_holder.");
@ -1075,7 +1079,7 @@ public:
move_only_holder_caster sub_caster(*cast.first); move_only_holder_caster sub_caster(*cast.first);
if (sub_caster.load(src, convert)) { if (sub_caster.load(src, convert)) {
value = cast.second(sub_caster.value); value = cast.second(sub_caster.value);
if (typeinfo->default_holder) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
// BAKEIN_WIP: Copy pointer only? // BAKEIN_WIP: Copy pointer only?
sh_load_helper.loaded_v_h = sub_caster.sh_load_helper.loaded_v_h; sh_load_helper.loaded_v_h = sub_caster.sh_load_helper.loaded_v_h;
} else { } else {
@ -1093,6 +1097,8 @@ public:
smart_holder_type_caster_support::load_helper<remove_cv_t<type>> sh_load_helper; // Const2Mutbl smart_holder_type_caster_support::load_helper<remove_cv_t<type>> sh_load_helper; // Const2Mutbl
}; };
#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
template <typename type, typename deleter> template <typename type, typename deleter>
class type_caster<std::unique_ptr<type, deleter>> class type_caster<std::unique_ptr<type, deleter>>
: public move_only_holder_caster<type, std::unique_ptr<type, deleter>> {}; : public move_only_holder_caster<type, std::unique_ptr<type, deleter>> {};
@ -1128,8 +1134,11 @@ struct is_holder_type
// Specializations for always-supported holders: // Specializations for always-supported holders:
template <typename base, typename deleter> template <typename base, typename deleter>
struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {}; struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {};
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
template <typename base> template <typename base>
struct is_holder_type<base, pybindit::memory::smart_holder> : std::true_type {}; struct is_holder_type<base, pybindit::memory::smart_holder> : std::true_type {};
#endif
#ifdef PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION // See PR #4888 #ifdef PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION // See PR #4888

View File

@ -39,9 +39,9 @@
# if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER) # if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER)
// Version bump for Python 3.12+, before first 3.12 beta release. // Version bump for Python 3.12+, before first 3.12 beta release.
// Version bump for MSVC piggy-backed on PR #4779. See comments there. // Version bump for MSVC piggy-backed on PR #4779. See comments there.
# define PYBIND11_INTERNALS_VERSION 5 # define PYBIND11_INTERNALS_VERSION 6 // BAKEIN_WIP: Only do this for pybind11 v3.0.0
# else # else
# define PYBIND11_INTERNALS_VERSION 4 # define PYBIND11_INTERNALS_VERSION 6 // BAKEIN_WIP: Only do this for pybind11 v3.0.0
# endif # endif
#endif #endif
@ -236,6 +236,20 @@ struct internals {
} }
}; };
#if PYBIND11_INTERNALS_VERSION >= 6
# define PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
enum class holder_enum_t : uint8_t {
undefined,
std_unique_ptr, // Default, lacking interop with std::shared_ptr.
std_shared_ptr, // Lacking interop with std::unique_ptr.
smart_holder, // Full std::unique_ptr / std::shared_ptr interop.
custom_holder,
};
#endif
/// Additional type information which does not fit into the PyTypeObject. /// Additional type information which does not fit into the PyTypeObject.
/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`. /// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`.
struct type_info { struct type_info {
@ -262,6 +276,9 @@ struct type_info {
bool default_holder : 1; bool default_holder : 1;
/* true if this is a type registered with py::module_local */ /* true if this is a type registered with py::module_local */
bool module_local : 1; bool module_local : 1;
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
holder_enum_t holder_enum_v = holder_enum_t::undefined;
#endif
}; };
/// On MSVC, debug and release builds are not ABI-compatible! /// On MSVC, debug and release builds are not ABI-compatible!

View File

@ -935,7 +935,8 @@ public:
// Base methods for generic caster; there are overridden in copyable_holder_caster // Base methods for generic caster; there are overridden in copyable_holder_caster
void load_value(value_and_holder &&v_h) { void load_value(value_and_holder &&v_h) {
if (typeinfo->default_holder) { #ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
smart_holder_type_caster_support::value_and_holder_helper v_h_helper; smart_holder_type_caster_support::value_and_holder_helper v_h_helper;
v_h_helper.loaded_v_h = v_h; v_h_helper.loaded_v_h = v_h;
if (v_h_helper.have_holder()) { if (v_h_helper.have_holder()) {
@ -944,6 +945,7 @@ public:
return; return;
} }
} }
#endif
auto *&vptr = v_h.value_ptr(); auto *&vptr = v_h.value_ptr();
// Lazy allocation for unallocated values: // Lazy allocation for unallocated values:
if (vptr == nullptr) { if (vptr == nullptr) {

View File

@ -1424,6 +1424,9 @@ protected:
tinfo->simple_ancestors = true; tinfo->simple_ancestors = true;
tinfo->default_holder = rec.default_holder; tinfo->default_holder = rec.default_holder;
tinfo->module_local = rec.module_local; tinfo->module_local = rec.module_local;
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
tinfo->holder_enum_v = rec.holder_enum_v;
#endif
with_internals([&](internals &internals) { with_internals([&](internals &internals) {
auto tindex = std::type_index(*rec.type); auto tindex = std::type_index(*rec.type);
@ -1643,6 +1646,8 @@ struct both_t_and_d_use_type_caster_base<
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
// BAKEIN_WIP: Rewrite comment. // BAKEIN_WIP: Rewrite comment.
// smart_holder specializations for raw pointer members. // smart_holder specializations for raw pointer members.
// WARNING: Like the classic implementation, this implementation can lead to dangling pointers. // WARNING: Like the classic implementation, this implementation can lead to dangling pointers.
@ -1662,7 +1667,7 @@ struct property_cpp_function<
template <typename PM, detail::must_be_member_function_pointer<PM> = 0> template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
static cpp_function readonly(PM pm, const handle &hdl) { static cpp_function readonly(PM pm, const handle &hdl) {
detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true); detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true);
if (tinfo->default_holder) { if (tinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
return cpp_function( return cpp_function(
[pm](handle c_hdl) -> std::shared_ptr<drp> { [pm](handle c_hdl) -> std::shared_ptr<drp> {
std::shared_ptr<T> c_sp = detail::type_caster< std::shared_ptr<T> c_sp = detail::type_caster<
@ -1683,7 +1688,7 @@ struct property_cpp_function<
template <typename PM, detail::must_be_member_function_pointer<PM> = 0> template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
static cpp_function write(PM pm, const handle &hdl) { static cpp_function write(PM pm, const handle &hdl) {
detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true); detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true);
if (tinfo->default_holder) { if (tinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
return cpp_function([pm](T &c, D value) { c.*pm = std::forward<D>(value); }, return cpp_function([pm](T &c, D value) { c.*pm = std::forward<D>(value); },
is_method(hdl)); is_method(hdl));
} }
@ -1709,7 +1714,7 @@ struct property_cpp_function<T,
template <typename PM, detail::must_be_member_function_pointer<PM> = 0> template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
static cpp_function readonly(PM pm, const handle &hdl) { static cpp_function readonly(PM pm, const handle &hdl) {
detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true); detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true);
if (tinfo->default_holder) { if (tinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
return cpp_function( return cpp_function(
[pm](handle c_hdl) -> std::shared_ptr<typename std::add_const<D>::type> { [pm](handle c_hdl) -> std::shared_ptr<typename std::add_const<D>::type> {
std::shared_ptr<T> c_sp = detail::type_caster< std::shared_ptr<T> c_sp = detail::type_caster<
@ -1725,7 +1730,7 @@ struct property_cpp_function<T,
template <typename PM, detail::must_be_member_function_pointer<PM> = 0> template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
static cpp_function read(PM pm, const handle &hdl) { static cpp_function read(PM pm, const handle &hdl) {
detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true); detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true);
if (tinfo->default_holder) { if (tinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
return cpp_function( return cpp_function(
[pm](handle c_hdl) -> std::shared_ptr<D> { [pm](handle c_hdl) -> std::shared_ptr<D> {
std::shared_ptr<T> c_sp = detail::type_caster< std::shared_ptr<T> c_sp = detail::type_caster<
@ -1740,7 +1745,7 @@ struct property_cpp_function<T,
template <typename PM, detail::must_be_member_function_pointer<PM> = 0> template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
static cpp_function write(PM pm, const handle &hdl) { static cpp_function write(PM pm, const handle &hdl) {
detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true); detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true);
if (tinfo->default_holder) { if (tinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
return cpp_function([pm](T &c, const D &value) { c.*pm = value; }, is_method(hdl)); return cpp_function([pm](T &c, const D &value) { c.*pm = value; }, is_method(hdl));
} }
return cpp_function([pm](T &c, const D &value) { c.*pm = value; }, is_method(hdl)); return cpp_function([pm](T &c, const D &value) { c.*pm = value; }, is_method(hdl));
@ -1772,7 +1777,7 @@ struct property_cpp_function<
template <typename PM, detail::must_be_member_function_pointer<PM> = 0> template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
static cpp_function read(PM pm, const handle &hdl) { static cpp_function read(PM pm, const handle &hdl) {
detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true); detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true);
if (tinfo->default_holder) { if (tinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
return cpp_function( return cpp_function(
[pm](handle c_hdl) -> D { [pm](handle c_hdl) -> D {
std::shared_ptr<T> c_sp = detail::type_caster< std::shared_ptr<T> c_sp = detail::type_caster<
@ -1790,6 +1795,8 @@ struct property_cpp_function<
} }
}; };
#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
template <typename> template <typename>
using default_holder_type = pybindit::memory::smart_holder; using default_holder_type = pybindit::memory::smart_holder;
@ -1843,6 +1850,17 @@ public:
record.init_instance = init_instance; record.init_instance = init_instance;
record.dealloc = dealloc; record.dealloc = dealloc;
record.default_holder = std::is_same<holder_type, pybindit::memory::smart_holder>::value; record.default_holder = std::is_same<holder_type, pybindit::memory::smart_holder>::value;
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
if (detail::is_instantiation<std::unique_ptr, holder_type>::value) {
record.holder_enum_v = detail::holder_enum_t::std_unique_ptr;
} else if (detail::is_instantiation<std::shared_ptr, holder_type>::value) {
record.holder_enum_v = detail::holder_enum_t::std_shared_ptr;
} else if (std::is_same<holder_type, pybindit::memory::smart_holder>::value) {
record.holder_enum_v = detail::holder_enum_t::smart_holder;
} else {
record.holder_enum_v = detail::holder_enum_t::custom_holder;
}
#endif
set_operator_new<type>(&record); set_operator_new<type>(&record);