Skip to content

Commit

Permalink
Put bakein branch @ 18b72c0 on top of smart_holder branch:
Browse files Browse the repository at this point in the history
Commands used:

```
git checkout bakein
git diff smart_holder > ~/zd
git checkout smart_holder
git checkout -b bakein_sh
patch -p 1 < ~/zd
git checkout smart_holder \
MANIFEST.in \
README.rst \
README_smart_holder.rst \
docs/advanced/smart_ptrs.rst \
ubench/holder_comparison.cpp \
ubench/holder_comparison.py \
ubench/holder_comparison_extract_sheet_data.py \
ubench/number_bucket.h \
ubench/python/number_bucket.clif
git add -A
```
  • Loading branch information
Ralf W. Grosse-Kunstleve committed Jul 21, 2024
1 parent 51a968c commit 82c9ce7
Show file tree
Hide file tree
Showing 66 changed files with 1,287 additions and 1,499 deletions.
3 changes: 1 addition & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,9 @@ 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_sfinae_hooks_only.h
include/pybind11/detail/smart_holder_type_casters.h
include/pybind11/detail/type_caster_base.h
include/pybind11/detail/typeid.h
include/pybind11/detail/using_smart_holder.h
include/pybind11/detail/value_and_holder.h
include/pybind11/attr.h
include/pybind11/buffer_info.h
Expand Down
4 changes: 4 additions & 0 deletions include/pybind11/attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,10 @@ struct type_record {
/// Is the class inheritable from python classes?
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 *) ) {
auto *base_info = detail::get_type_info(base, false);
if (!base_info) {
Expand Down
294 changes: 262 additions & 32 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

#include "detail/common.h"
#include "detail/descr.h"
#include "detail/smart_holder_sfinae_hooks_only.h"
#include "detail/type_caster_base.h"
#include "detail/typeid.h"
#include "pytypes.h"
Expand All @@ -29,33 +28,17 @@
#include <utility>
#include <vector>

#ifdef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
# include "detail/smart_holder_type_casters.h"
#endif

PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)

PYBIND11_WARNING_DISABLE_MSVC(4127)

PYBIND11_NAMESPACE_BEGIN(detail)

#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
template <typename T>
class type_caster_for_class_ : public type_caster_base<T> {};
#endif

template <typename type, typename SFINAE = void>
class type_caster : public type_caster_for_class_<type> {};

class type_caster : public type_caster_base<type> {};
template <typename type>
using make_caster = type_caster<intrinsic_t<type>>;

template <typename T>
struct type_uses_smart_holder_type_caster {
static constexpr bool value
= std::is_base_of<smart_holder_type_caster_base_tag, make_caster<T>>::value;
};

// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T
template <typename T>
typename make_caster<T>::template cast_op_type<T> cast_op(make_caster<T> &caster) {
Expand Down Expand Up @@ -852,11 +835,154 @@ struct copyable_holder_caster : public type_caster_base<type> {
holder_type holder;
};

#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT

template <typename, typename SFINAE = void>
struct copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled : std::true_type {};

// BAKEIN_WIP
template <typename type>
struct copyable_holder_caster<
type,
std::shared_ptr<type>,
enable_if_t<copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled<type>::value>>
: public type_caster_base<type> {
public:
using base = type_caster_base<type>;
static_assert(std::is_base_of<base, type_caster<type>>::value,
"Holder classes are only supported for custom types");
using base::base;
using base::cast;
using base::typeinfo;
using base::value;

bool load(handle src, bool convert) {
return base::template load_impl<copyable_holder_caster<type, std::shared_ptr<type>>>(
src, convert);
}

explicit operator type *() {
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
throw std::runtime_error("BAKEIN_WIP: operator type *() shared_ptr");
}
return this->value;
}

explicit operator type &() {
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
throw std::runtime_error("BAKEIN_WIP: operator type &() shared_ptr");
}
// static_cast works around compiler error with MSVC 17 and CUDA 10.2
// see issue #2180
return *(static_cast<type *>(this->value));
}

explicit operator std::shared_ptr<type> *() {
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
throw std::runtime_error("BAKEIN_WIP: operator std::shared_ptr<type> *()");
}
return std::addressof(shared_ptr_holder);
}

explicit operator std::shared_ptr<type> &() {
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
shared_ptr_holder = sh_load_helper.loaded_as_shared_ptr(value);
}
return shared_ptr_holder;
}

static handle
cast(const std::shared_ptr<type> &src, return_value_policy policy, handle parent) {
const auto *ptr = src.get();
auto st = type_caster_base<type>::src_and_type(ptr);
if (st.second == nullptr) {
return handle(); // no type info: error will be set already
}
if (st.second->holder_enum_v == detail::holder_enum_t::smart_holder) {
return smart_holder_type_caster_support::smart_holder_from_shared_ptr(
src, policy, parent, st);
}
return type_caster_base<type>::cast_holder(ptr, &src);
}

// 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<type> shared_ptr_with_responsible_parent(handle responsible_parent) {
copyable_holder_caster loader;
loader.load(responsible_parent, /*convert=*/false);
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);
}

protected:
friend class type_caster_generic;
void check_holder_compat() {
if (typeinfo->default_holder) {
throw cast_error("Unable to load a custom holder type from a default-holder instance");
}
}

void load_value(value_and_holder &&v_h) {
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
sh_load_helper.loaded_v_h = v_h;
value = sh_load_helper.get_void_ptr_or_nullptr();
return;
}
if (v_h.holder_constructed()) {
value = v_h.value_ptr();
shared_ptr_holder = v_h.template holder<std::shared_ptr<type>>();
return;
}
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
# if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for "
"type information)");
# else
"of type '"
+ type_id<std::shared_ptr<type>>() + "''");
# endif
}

template <typename T = std::shared_ptr<type>,
detail::enable_if_t<!std::is_constructible<T, const T &, type *>::value, int> = 0>
bool try_implicit_casts(handle, bool) {
return false;
}

template <typename T = std::shared_ptr<type>,
detail::enable_if_t<std::is_constructible<T, const T &, type *>::value, int> = 0>
bool try_implicit_casts(handle src, bool convert) {
for (auto &cast : typeinfo->implicit_casts) {
copyable_holder_caster sub_caster(*cast.first);
if (sub_caster.load(src, convert)) {
value = cast.second(sub_caster.value);
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
// BAKEIN_WIP: Copy pointer only?
sh_load_helper.loaded_v_h = sub_caster.sh_load_helper.loaded_v_h;
} else {
shared_ptr_holder
= std::shared_ptr<type>(sub_caster.shared_ptr_holder, (type *) value);
}
return true;
}
}
return false;
}

static bool try_direct_conversions(handle) { return false; }

std::shared_ptr<type> shared_ptr_holder;
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
template <typename T>
class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> {};
#endif

/// Type caster for holder types like std::unique_ptr.
/// Please consider the SFINAE hook an implementation detail, as explained
Expand All @@ -873,11 +999,114 @@ struct move_only_holder_caster {
static constexpr auto name = type_caster_base<type>::name;
};

#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT

template <typename, typename SFINAE = void>
struct move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled : std::true_type {};

// BAKEIN_WIP
template <typename type, typename deleter>
struct move_only_holder_caster<
type,
std::unique_ptr<type, deleter>,
enable_if_t<move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled<type>::value>>
: public type_caster_base<type> {
public:
using base = type_caster_base<type>;
static_assert(std::is_base_of<base, type_caster<type>>::value,
"Holder classes are only supported for custom types");
using base::base;
using base::cast;
using base::typeinfo;
using base::value;

static handle
cast(std::unique_ptr<type, deleter> &&src, return_value_policy policy, handle parent) {
auto *ptr = src.get();
auto st = type_caster_base<type>::src_and_type(ptr);
if (st.second == nullptr) {
return handle(); // no type info: error will be set already
}
if (st.second->holder_enum_v == detail::holder_enum_t::smart_holder) {
return smart_holder_type_caster_support::smart_holder_from_unique_ptr(
std::move(src), policy, parent, st);
}
return type_caster_generic::cast(st.first,
return_value_policy::take_ownership,
{},
st.second,
nullptr,
nullptr,
std::addressof(src));
}

static handle
cast(const std::unique_ptr<type, deleter> &src, return_value_policy policy, handle parent) {
if (!src) {
return none().release();
}
if (policy == return_value_policy::automatic) {
policy = return_value_policy::reference_internal;
}
if (policy != return_value_policy::reference_internal) {
throw cast_error("Invalid return_value_policy for unique_ptr&");
}
return type_caster_base<type>::cast(src.get(), policy, parent);
}

bool load(handle src, bool convert) {
return base::template load_impl<
move_only_holder_caster<type, std::unique_ptr<type, deleter>>>(src, convert);
}

void load_value(value_and_holder &&v_h) {
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.type = typeinfo;
value = sh_load_helper.get_void_ptr_or_nullptr();
return;
}
throw std::runtime_error("BAKEIN_WIP: What is the best behavior here (load_value)?");
}

template <typename>
using cast_op_type = std::unique_ptr<type, deleter>;

explicit operator std::unique_ptr<type, deleter>() {
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
return sh_load_helper.template loaded_as_unique_ptr<deleter>(value);
}
pybind11_fail("Passing std::unique_ptr from Python to C++ requires smart_holder.");
}

bool try_implicit_casts(handle src, bool convert) {
for (auto &cast : typeinfo->implicit_casts) {
move_only_holder_caster sub_caster(*cast.first);
if (sub_caster.load(src, convert)) {
value = cast.second(sub_caster.value);
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
// BAKEIN_WIP: Copy pointer only?
sh_load_helper.loaded_v_h = sub_caster.sh_load_helper.loaded_v_h;
} else {
throw std::runtime_error(
"BAKEIN_WIP: What is the best behavior here (try_implicit_casts)?");
}
return true;
}
}
return false;
}

static bool try_direct_conversions(handle) { return false; }

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>
class type_caster<std::unique_ptr<type, deleter>>
: public move_only_holder_caster<type, std::unique_ptr<type, deleter>> {};
#endif

template <typename type, typename holder_type>
using type_caster_holder = conditional_t<is_copy_constructible<holder_type>::value,
Expand Down Expand Up @@ -906,10 +1135,16 @@ struct always_construct_holder {
template <typename base, typename holder>
struct is_holder_type
: std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>> {};
// Specialization for always-supported unique_ptr holders:

// Specializations for always-supported holders:
template <typename base, typename deleter>
struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {};

#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
template <typename base>
struct is_holder_type<base, smart_holder> : std::true_type {};
#endif

#ifdef PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION // See PR #4888

// This leads to compilation errors if a specialization is missing.
Expand Down Expand Up @@ -1141,7 +1376,6 @@ template <typename type>
using cast_is_temporary_value_reference
= bool_constant<(std::is_reference<type>::value || std::is_pointer<type>::value)
&& !std::is_base_of<type_caster_generic, make_caster<type>>::value
&& !type_uses_smart_holder_type_caster<intrinsic_t<type>>::value
&& !std::is_same<intrinsic_t<type>, void>::value>;

// When a value returned from a C++ function is being cast back to Python, we almost always want to
Expand All @@ -1155,9 +1389,7 @@ struct return_value_policy_override {
template <typename Return>
struct return_value_policy_override<
Return,
detail::enable_if_t<std::is_base_of<type_caster_generic, make_caster<Return>>::value
|| type_uses_smart_holder_type_caster<intrinsic_t<Return>>::value,
void>> {
detail::enable_if_t<std::is_base_of<type_caster_generic, make_caster<Return>>::value, void>> {
static return_value_policy policy(return_value_policy p) {
return !std::is_lvalue_reference<Return>::value && !std::is_pointer<Return>::value
? return_value_policy::move
Expand Down Expand Up @@ -1857,10 +2089,8 @@ PYBIND11_NAMESPACE_END(detail)

template <typename T>
handle type::handle_of() {
static_assert(
detail::any_of<std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>,
detail::type_uses_smart_holder_type_caster<T>>::value,
"py::type::of<T> only supports the case where T is a registered C++ types.");
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.");

return detail::get_type_handle(typeid(T), true);
}
Expand All @@ -1869,7 +2099,7 @@ handle type::handle_of() {
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) \
namespace detail { \
template <> \
class type_caster<__VA_ARGS__> : public type_caster_for_class_<__VA_ARGS__> {}; \
class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> {}; \
} \
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

Expand Down
Loading

0 comments on commit 82c9ce7

Please sign in to comment.