mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-08 01:41:59 +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>,
|
copyable_holder_caster<type, holder_type>,
|
||||||
move_only_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; };
|
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)
|
/// 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:
|
// PYBIND11_DECLARE_HOLDER_TYPE holder types:
|
||||||
template <typename base, typename holder> struct is_holder_type :
|
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>>,
|
std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>> {};
|
||||||
detail::is_smart_holder<holder>> {};
|
|
||||||
// Specialization for always-supported unique_ptr holders:
|
// Specialization for always-supported unique_ptr holders:
|
||||||
template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> :
|
template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> :
|
||||||
std::true_type {};
|
std::true_type {};
|
||||||
@ -2263,15 +2261,22 @@ object object_api<Derived>::call(Args &&...args) const {
|
|||||||
return operator()<policy>(std::forward<Args>(args)...);
|
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)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
handle type::handle_of() {
|
handle type::handle_of() {
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>::value,
|
detail::any_of<std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>,
|
||||||
"py::type::of<T> only supports the case where T is a registered C++ types."
|
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);
|
return detail::get_type_handle(typeid(T), true);
|
||||||
}
|
}
|
||||||
|
@ -228,6 +228,41 @@ public:
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// 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>
|
template <typename T>
|
||||||
struct smart_holder_type_caster_load {
|
struct smart_holder_type_caster_load {
|
||||||
using holder_type = pybindit::memory::smart_holder;
|
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>
|
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 constexpr auto name = _<T>();
|
||||||
|
|
||||||
// static handle cast(T, ...)
|
// static handle cast(T, ...)
|
||||||
@ -462,7 +498,8 @@ struct smart_holder_type_caster : smart_holder_type_caster_load<T> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename 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 constexpr auto name = _<std::shared_ptr<T>>();
|
||||||
|
|
||||||
static handle cast(const std::shared_ptr<T> &src, return_value_policy policy, handle parent) {
|
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>
|
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 constexpr auto name = _<std::shared_ptr<T const>>();
|
||||||
|
|
||||||
static handle
|
static handle
|
||||||
@ -524,7 +562,8 @@ struct smart_holder_type_caster<std::shared_ptr<T const>> : smart_holder_type_ca
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
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 constexpr auto name = _<std::unique_ptr<T>>();
|
||||||
|
|
||||||
static handle cast(std::unique_ptr<T> &&src, return_value_policy policy, handle parent) {
|
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>
|
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 constexpr auto name = _<std::unique_ptr<T const>>();
|
||||||
|
|
||||||
static handle cast(std::unique_ptr<T const> &&src, return_value_policy policy, handle parent) {
|
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(); }
|
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) \
|
#define PYBIND11_SMART_HOLDER_TYPE_CASTERS(T) \
|
||||||
namespace pybind11 { \
|
namespace pybind11 { \
|
||||||
namespace detail { \
|
namespace detail { \
|
||||||
|
@ -1242,9 +1242,13 @@ auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(
|
|||||||
|
|
||||||
template <typename type_, typename... options>
|
template <typename type_, typename... options>
|
||||||
class class_ : public detail::generic_type {
|
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_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_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:
|
// struct instead of using here to help MSVC:
|
||||||
template <typename T> struct is_valid_class_option :
|
template <typename T> struct is_valid_class_option :
|
||||||
detail::any_of<is_holder<T>, is_subtype<T>, is_base<T>> {};
|
detail::any_of<is_holder<T>, is_subtype<T>, is_base<T>> {};
|
||||||
@ -1502,14 +1506,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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) {
|
void generic_type_initialize(const detail::type_record &record) {
|
||||||
generic_type::initialize(record, &detail::type_caster_generic::local_load);
|
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) {
|
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
|
/// 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
|
/// 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
|
/// 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.
|
/// `.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) {
|
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)));
|
auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(type)));
|
||||||
if (!v_h.instance_registered()) {
|
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>());
|
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) {
|
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.
|
/// 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:
|
// These require selected functions above to work first, as indicated:
|
||||||
m.def("get_mtxt", get_mtxt); // pass_cref_atyp
|
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("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
|
} // namespace class_sh_basic
|
||||||
|
@ -5,12 +5,12 @@ from pybind11_tests import class_sh_basic as m
|
|||||||
|
|
||||||
|
|
||||||
def test_atyp_constructors():
|
def test_atyp_constructors():
|
||||||
e = m.atyp()
|
obj = m.atyp()
|
||||||
assert e.__class__.__name__ == "atyp"
|
assert obj.__class__.__name__ == "atyp"
|
||||||
e = m.atyp("")
|
obj = m.atyp("")
|
||||||
assert e.__class__.__name__ == "atyp"
|
assert obj.__class__.__name__ == "atyp"
|
||||||
e = m.atyp("txtm")
|
obj = m.atyp("txtm")
|
||||||
assert e.__class__.__name__ == "atyp"
|
assert obj.__class__.__name__ == "atyp"
|
||||||
|
|
||||||
|
|
||||||
def test_cast():
|
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.
|
# Ensure the returned object is a different Python instance.
|
||||||
assert id_rtrn != id_orig
|
assert id_rtrn != id_orig
|
||||||
id_orig = id_rtrn
|
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