mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-07 17:32:00 +00:00
Replacing detail::is_smart_holder<H> in cast.h with detail::is_smart_holder_type_caster<T>.
Moving get_local_load_function_ptr, init_instance_for_type to smart_holder_type_caster_class_hooks. Expanding static_assert in py::type::handle_of<> to accommodate smart_holder_type_casters.
This commit is contained in:
parent
87acc89b21
commit
742bc0eaf7
@ -1628,7 +1628,6 @@ using type_caster_holder = conditional_t<is_copy_constructible<holder_type>::val
|
||||
copyable_holder_caster<type, holder_type>,
|
||||
move_only_holder_caster<type, holder_type>>;
|
||||
|
||||
template <typename T, bool Value = false> struct is_smart_holder { static constexpr bool value = Value; };
|
||||
template <typename T, bool Value = false> struct always_construct_holder { static constexpr bool value = Value; };
|
||||
|
||||
/// Create a specialization for custom holder types (silently ignores std::shared_ptr)
|
||||
@ -1643,8 +1642,7 @@ template <typename T, bool Value = false> struct always_construct_holder { stati
|
||||
|
||||
// PYBIND11_DECLARE_HOLDER_TYPE holder types:
|
||||
template <typename base, typename holder> struct is_holder_type :
|
||||
detail::any_of<std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>>,
|
||||
detail::is_smart_holder<holder>> {};
|
||||
std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>> {};
|
||||
// Specialization for always-supported unique_ptr holders:
|
||||
template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> :
|
||||
std::true_type {};
|
||||
@ -2263,15 +2261,22 @@ object object_api<Derived>::call(Args &&...args) const {
|
||||
return operator()<policy>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, typename SFINAE = void>
|
||||
struct is_smart_holder_type_caster : std::false_type {};
|
||||
template <typename T>
|
||||
struct is_smart_holder_type_caster<
|
||||
T,
|
||||
enable_if_t<type_caster<T>::is_smart_holder_type_caster::value, void>> : std::true_type {};
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
||||
|
||||
template<typename T>
|
||||
handle type::handle_of() {
|
||||
static_assert(
|
||||
std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>::value,
|
||||
"py::type::of<T> only supports the case where T is a registered C++ types."
|
||||
);
|
||||
static_assert(
|
||||
detail::any_of<std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>,
|
||||
detail::is_smart_holder_type_caster<T>>::value,
|
||||
"py::type::of<T> only supports the case where T is a registered C++ types.");
|
||||
|
||||
return detail::get_type_handle(typeid(T), true);
|
||||
}
|
||||
|
@ -228,6 +228,41 @@ public:
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
struct smart_holder_type_caster_class_hooks {
|
||||
using is_smart_holder_type_caster = std::true_type;
|
||||
|
||||
static decltype(&modified_type_caster_generic_load_impl::local_load)
|
||||
get_local_load_function_ptr() {
|
||||
return &modified_type_caster_generic_load_impl::local_load;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void init_instance_for_type(detail::instance *inst, const void *holder_const_void_ptr) {
|
||||
// Need for const_cast is a consequence of the type_info::init_instance type:
|
||||
// void (*init_instance)(instance *, const void *);
|
||||
auto holder_void_ptr = const_cast<void *>(holder_const_void_ptr);
|
||||
|
||||
auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(T)));
|
||||
if (!v_h.instance_registered()) {
|
||||
register_instance(inst, v_h.value_ptr(), v_h.type);
|
||||
v_h.set_instance_registered();
|
||||
}
|
||||
using holder_type = pybindit::memory::smart_holder;
|
||||
if (holder_void_ptr) {
|
||||
// Note: inst->owned ignored.
|
||||
auto holder_ptr = static_cast<holder_type *>(holder_void_ptr);
|
||||
new (std::addressof(v_h.holder<holder_type>())) holder_type(std::move(*holder_ptr));
|
||||
} else if (inst->owned) {
|
||||
new (std::addressof(v_h.holder<holder_type>()))
|
||||
holder_type(holder_type::from_raw_ptr_take_ownership(v_h.value_ptr<T>()));
|
||||
} else {
|
||||
new (std::addressof(v_h.holder<holder_type>()))
|
||||
holder_type(holder_type::from_raw_ptr_unowned(v_h.value_ptr<T>()));
|
||||
}
|
||||
v_h.set_holder_constructed();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct smart_holder_type_caster_load {
|
||||
using holder_type = pybindit::memory::smart_holder;
|
||||
@ -305,7 +340,8 @@ struct make_constructor : private type_caster_base<int> { // Any type, nothing s
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct smart_holder_type_caster : smart_holder_type_caster_load<T> {
|
||||
struct smart_holder_type_caster : smart_holder_type_caster_load<T>,
|
||||
smart_holder_type_caster_class_hooks {
|
||||
static constexpr auto name = _<T>();
|
||||
|
||||
// static handle cast(T, ...)
|
||||
@ -462,7 +498,8 @@ struct smart_holder_type_caster : smart_holder_type_caster_load<T> {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct smart_holder_type_caster<std::shared_ptr<T>> : smart_holder_type_caster_load<T> {
|
||||
struct smart_holder_type_caster<std::shared_ptr<T>> : smart_holder_type_caster_load<T>,
|
||||
smart_holder_type_caster_class_hooks {
|
||||
static constexpr auto name = _<std::shared_ptr<T>>();
|
||||
|
||||
static handle cast(const std::shared_ptr<T> &src, return_value_policy policy, handle parent) {
|
||||
@ -506,7 +543,8 @@ struct smart_holder_type_caster<std::shared_ptr<T>> : smart_holder_type_caster_l
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct smart_holder_type_caster<std::shared_ptr<T const>> : smart_holder_type_caster_load<T> {
|
||||
struct smart_holder_type_caster<std::shared_ptr<T const>> : smart_holder_type_caster_load<T>,
|
||||
smart_holder_type_caster_class_hooks {
|
||||
static constexpr auto name = _<std::shared_ptr<T const>>();
|
||||
|
||||
static handle
|
||||
@ -524,7 +562,8 @@ struct smart_holder_type_caster<std::shared_ptr<T const>> : smart_holder_type_ca
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct smart_holder_type_caster<std::unique_ptr<T>> : smart_holder_type_caster_load<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>>();
|
||||
|
||||
static handle cast(std::unique_ptr<T> &&src, return_value_policy policy, handle parent) {
|
||||
@ -566,7 +605,8 @@ struct smart_holder_type_caster<std::unique_ptr<T>> : smart_holder_type_caster_l
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct smart_holder_type_caster<std::unique_ptr<T const>> : smart_holder_type_caster_load<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) {
|
||||
@ -582,42 +622,6 @@ struct smart_holder_type_caster<std::unique_ptr<T const>> : smart_holder_type_ca
|
||||
operator std::unique_ptr<T const>() { return this->loaded_as_unique_ptr(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_smart_holder<pybindit::memory::smart_holder>
|
||||
: is_smart_holder<pybindit::memory::smart_holder, true> {
|
||||
|
||||
static decltype(&modified_type_caster_generic_load_impl::local_load)
|
||||
get_type_caster_local_load_function_ptr() {
|
||||
return &modified_type_caster_generic_load_impl::local_load;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void init_instance_for_type(detail::instance *inst, const void *holder_const_void_ptr) {
|
||||
// Need for const_cast is a consequence of the type_info::init_instance type:
|
||||
// void (*init_instance)(instance *, const void *);
|
||||
auto holder_void_ptr = const_cast<void *>(holder_const_void_ptr);
|
||||
|
||||
auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(T)));
|
||||
if (!v_h.instance_registered()) {
|
||||
register_instance(inst, v_h.value_ptr(), v_h.type);
|
||||
v_h.set_instance_registered();
|
||||
}
|
||||
using holder_type = pybindit::memory::smart_holder;
|
||||
if (holder_void_ptr) {
|
||||
// Note: inst->owned ignored.
|
||||
auto holder_ptr = static_cast<holder_type *>(holder_void_ptr);
|
||||
new (std::addressof(v_h.holder<holder_type>())) holder_type(std::move(*holder_ptr));
|
||||
} else if (inst->owned) {
|
||||
new (std::addressof(v_h.holder<holder_type>()))
|
||||
holder_type(holder_type::from_raw_ptr_take_ownership(v_h.value_ptr<T>()));
|
||||
} else {
|
||||
new (std::addressof(v_h.holder<holder_type>()))
|
||||
holder_type(holder_type::from_raw_ptr_unowned(v_h.value_ptr<T>()));
|
||||
}
|
||||
v_h.set_holder_constructed();
|
||||
}
|
||||
};
|
||||
|
||||
#define PYBIND11_SMART_HOLDER_TYPE_CASTERS(T) \
|
||||
namespace pybind11 { \
|
||||
namespace detail { \
|
||||
|
@ -1242,9 +1242,13 @@ auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(
|
||||
|
||||
template <typename type_, typename... options>
|
||||
class class_ : public detail::generic_type {
|
||||
template <typename T> using is_holder = detail::is_holder_type<type_, T>;
|
||||
template <typename T> using is_subtype = detail::is_strict_base_of<type_, T>;
|
||||
template <typename T> using is_base = detail::is_strict_base_of<T, type_>;
|
||||
template <typename T>
|
||||
using is_holder = detail::any_of<detail::is_holder_type<type_, T>,
|
||||
detail::all_of<detail::negation<is_base<T>>,
|
||||
detail::negation<is_subtype<T>>,
|
||||
detail::is_smart_holder_type_caster<type_>>>;
|
||||
// struct instead of using here to help MSVC:
|
||||
template <typename T> struct is_valid_class_option :
|
||||
detail::any_of<is_holder<T>, is_subtype<T>, is_base<T>> {};
|
||||
@ -1502,14 +1506,19 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename H = holder_type, detail::enable_if_t<!detail::is_smart_holder<H>::value, int> = 0>
|
||||
template <typename T = type,
|
||||
detail::enable_if_t<
|
||||
std::is_base_of<detail::type_caster_generic, detail::type_caster<T>>::value,
|
||||
int> = 0>
|
||||
void generic_type_initialize(const detail::type_record &record) {
|
||||
generic_type::initialize(record, &detail::type_caster_generic::local_load);
|
||||
}
|
||||
|
||||
template <typename H = holder_type, detail::enable_if_t<detail::is_smart_holder<H>::value, int> = 0>
|
||||
template <
|
||||
typename T = type,
|
||||
detail::enable_if_t<detail::type_caster<T>::is_smart_holder_type_caster::value, int> = 0>
|
||||
void generic_type_initialize(const detail::type_record &record) {
|
||||
generic_type::initialize(record, detail::is_smart_holder<H>::get_type_caster_local_load_function_ptr());
|
||||
generic_type::initialize(record, detail::type_caster<T>::get_local_load_function_ptr());
|
||||
}
|
||||
|
||||
/// Initialize holder object, variant 1: object derives from enable_shared_from_this
|
||||
@ -1556,7 +1565,10 @@ private:
|
||||
/// instance. Should be called as soon as the `type` value_ptr is set for an instance. Takes an
|
||||
/// optional pointer to an existing holder to use; if not specified and the instance is
|
||||
/// `.owned`, a new holder will be constructed to manage the value pointer.
|
||||
template <typename H = holder_type, detail::enable_if_t<!detail::is_smart_holder<H>::value, int> = 0>
|
||||
template <typename T = type,
|
||||
detail::enable_if_t<
|
||||
std::is_base_of<detail::type_caster_generic, detail::type_caster<T>>::value,
|
||||
int> = 0>
|
||||
static void init_instance(detail::instance *inst, const void *holder_ptr) {
|
||||
auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(type)));
|
||||
if (!v_h.instance_registered()) {
|
||||
@ -1566,9 +1578,11 @@ private:
|
||||
init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr<type>());
|
||||
}
|
||||
|
||||
template <typename H = holder_type, detail::enable_if_t<detail::is_smart_holder<H>::value, int> = 0>
|
||||
template <
|
||||
typename T = type,
|
||||
detail::enable_if_t<detail::type_caster<T>::is_smart_holder_type_caster::value, int> = 0>
|
||||
static void init_instance(detail::instance *inst, const void *holder_ptr) {
|
||||
detail::is_smart_holder<H>::template init_instance_for_type<type>(inst, holder_ptr);
|
||||
detail::type_caster<T>::template init_instance_for_type<type>(inst, holder_ptr);
|
||||
}
|
||||
|
||||
/// Deallocates an instance; via holder, if constructed; otherwise via operator delete.
|
||||
|
@ -93,6 +93,10 @@ TEST_SUBMODULE(class_sh_basic, m) {
|
||||
// These require selected functions above to work first, as indicated:
|
||||
m.def("get_mtxt", get_mtxt); // pass_cref_atyp
|
||||
m.def("unique_ptr_roundtrip", unique_ptr_roundtrip); // pass_uqmp_atyp, rtrn_uqmp_atyp
|
||||
|
||||
m.def("py_type_handle_of_atyp", []() {
|
||||
return py::type::handle_of<atyp>(); // Exercises static_cast in this function.
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace class_sh_basic
|
||||
|
@ -5,12 +5,12 @@ from pybind11_tests import class_sh_basic as m
|
||||
|
||||
|
||||
def test_atyp_constructors():
|
||||
e = m.atyp()
|
||||
assert e.__class__.__name__ == "atyp"
|
||||
e = m.atyp("")
|
||||
assert e.__class__.__name__ == "atyp"
|
||||
e = m.atyp("txtm")
|
||||
assert e.__class__.__name__ == "atyp"
|
||||
obj = m.atyp()
|
||||
assert obj.__class__.__name__ == "atyp"
|
||||
obj = m.atyp("")
|
||||
assert obj.__class__.__name__ == "atyp"
|
||||
obj = m.atyp("txtm")
|
||||
assert obj.__class__.__name__ == "atyp"
|
||||
|
||||
|
||||
def test_cast():
|
||||
@ -80,3 +80,8 @@ def test_unique_ptr_roundtrip(num_round_trips=1000):
|
||||
# Ensure the returned object is a different Python instance.
|
||||
assert id_rtrn != id_orig
|
||||
id_orig = id_rtrn
|
||||
|
||||
|
||||
def test_py_type_handle_of_atyp():
|
||||
obj = m.py_type_handle_of_atyp()
|
||||
assert obj.__class__.__name__ == "pybind11_type"
|
||||
|
Loading…
Reference in New Issue
Block a user