Skip to content

Commit

Permalink
Transfer the try_as_void_ptr_capsule feature from smart_holder_type…
Browse files Browse the repository at this point in the history
…_casters.h to type_caster_base.h

Restore the original, complete test_class_sh_void_ptr_capsule.py
  • Loading branch information
Ralf W. Grosse-Kunstleve committed Aug 4, 2024
1 parent 27e94ff commit b71bbfb
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 7 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ set(PYBIND11_HEADERS
include/pybind11/detail/internals.h
include/pybind11/detail/native_enum_data.h
include/pybind11/detail/smart_holder_poc.h
include/pybind11/detail/try_as_void_ptr_capsule_get_pointer.h
include/pybind11/detail/type_caster_base.h
include/pybind11/detail/type_caster_odr_guard.h
include/pybind11/detail/typeid.h
Expand Down
53 changes: 51 additions & 2 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,7 @@ struct copyable_holder_caster : public type_caster_base<type> {
}

static bool try_direct_conversions(handle) { return false; }
static bool try_as_void_ptr_capsule(handle) { return false; }

holder_type holder;
};
Expand Down Expand Up @@ -998,6 +999,14 @@ struct copyable_holder_caster<

explicit operator std::shared_ptr<type> &() {
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
if (from_direct_conversion) {
throw cast_error("Unowned pointer from direct conversion cannot be converted to a "
"std::shared_ptr.");
}
if (from_as_void_ptr_capsule) {
throw cast_error("Unowned pointer from a void pointer capsule cannot be converted "
"to a std::shared_ptr.");
}
shared_ptr_holder = sh_load_helper.load_as_shared_ptr(value);
}
return shared_ptr_holder;
Expand Down Expand Up @@ -1083,10 +1092,26 @@ struct copyable_holder_caster<
return false;
}

static bool try_direct_conversions(handle) { return false; }
bool try_direct_conversions(handle src) {
if (type_caster_base<type>::try_direct_conversions(src)) {
from_direct_conversion = true;
return true;
}
return false;
}

bool try_as_void_ptr_capsule(handle src) {
if (type_caster_base<type>::try_as_void_ptr_capsule(src)) {
from_as_void_ptr_capsule = true;
return true;
}
return false;
}

std::shared_ptr<type> shared_ptr_holder;
smart_holder_type_caster_support::load_helper<remove_cv_t<type>> sh_load_helper; // Const2Mutbl
bool from_direct_conversion = false;
bool from_as_void_ptr_capsule = false;
};

#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
Expand Down Expand Up @@ -1188,6 +1213,14 @@ struct move_only_holder_caster<

explicit operator std::unique_ptr<type, deleter>() {
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
if (from_direct_conversion) {
throw cast_error("Unowned pointer from direct conversion cannot be converted to a "
"std::unique_ptr.");
}
if (from_as_void_ptr_capsule) {
throw cast_error("Unowned pointer from a void pointer capsule cannot be converted "
"to a std::unique_ptr.");
}
return sh_load_helper.template load_as_unique_ptr<deleter>(value);
}
pybind11_fail("Expected to be UNREACHABLE: " __FILE__ ":" PYBIND11_TOSTRING(__LINE__));
Expand All @@ -1210,9 +1243,25 @@ struct move_only_holder_caster<
return false;
}

static bool try_direct_conversions(handle) { return false; }
bool try_direct_conversions(handle src) {
if (type_caster_base<type>::try_direct_conversions(src)) {
from_direct_conversion = true;
return true;
}
return false;
}

bool try_as_void_ptr_capsule(handle src) {
if (type_caster_base<type>::try_as_void_ptr_capsule(src)) {
from_as_void_ptr_capsule = true;
return true;
}
return false;
}

smart_holder_type_caster_support::load_helper<remove_cv_t<type>> sh_load_helper; // Const2Mutbl
bool from_direct_conversion = false;
bool from_as_void_ptr_capsule = false;
};

#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
Expand Down
85 changes: 85 additions & 0 deletions include/pybind11/detail/try_as_void_ptr_capsule_get_pointer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) 2024 The pybind Community.

#pragma once

#include "../pytypes.h"
#include "common.h"
#include "typeid.h"

#include <string>

PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)

// Replace all occurrences of substrings in a string.
inline void replace_all(std::string &str, const std::string &from, const std::string &to) {
if (str.empty()) {
return;
}
size_t pos = 0;
while ((pos = str.find(from, pos)) != std::string::npos) {
str.replace(pos, from.length(), to);
pos += to.length();
}
}

// Forward declaration needed here: Refactoring opportunity.
extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *);

inline bool type_is_pybind11_class_(PyTypeObject *type_obj) {
#if defined(PYPY_VERSION)
auto &internals = get_internals();
return bool(internals.registered_types_py.find(type_obj)
!= internals.registered_types_py.end());
#else
return bool(type_obj->tp_new == pybind11_object_new);
#endif
}

inline bool is_instance_method_of_type(PyTypeObject *type_obj, PyObject *attr_name) {
PyObject *descr = _PyType_Lookup(type_obj, attr_name);
return bool((descr != nullptr) && PyInstanceMethod_Check(descr));
}

inline object try_get_as_capsule_method(PyObject *obj, PyObject *attr_name) {
if (PyType_Check(obj)) {
return object();
}
PyTypeObject *type_obj = Py_TYPE(obj);
bool known_callable = false;
if (type_is_pybind11_class_(type_obj)) {
if (!is_instance_method_of_type(type_obj, attr_name)) {
return object();
}
known_callable = true;
}
PyObject *method = PyObject_GetAttr(obj, attr_name);
if (method == nullptr) {
PyErr_Clear();
return object();
}
if (!known_callable && PyCallable_Check(method) == 0) {
Py_DECREF(method);
return object();
}
return reinterpret_steal<object>(method);
}

inline void *try_as_void_ptr_capsule_get_pointer(handle src, const char *typeid_name) {
std::string suffix = clean_type_id(typeid_name);
replace_all(suffix, "::", "_"); // Convert `a::b::c` to `a_b_c`.
replace_all(suffix, "*", "");
object as_capsule_method = try_get_as_capsule_method(src.ptr(), str("as_" + suffix).ptr());
if (as_capsule_method) {
object void_ptr_capsule = as_capsule_method();
if (isinstance<capsule>(void_ptr_capsule)) {
return reinterpret_borrow<capsule>(void_ptr_capsule).get_pointer();
}
}
return nullptr;
}

#define PYBIND11_HAS_TRY_AS_VOID_PTR_CAPSULE_GET_POINTER

PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
12 changes: 12 additions & 0 deletions include/pybind11/detail/type_caster_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "descr.h"
#include "dynamic_raw_ptr_cast_if_possible.h"
#include "internals.h"
#include "try_as_void_ptr_capsule_get_pointer.h"
#include "typeid.h"
#include "using_smart_holder.h"
#include "value_and_holder.h"
Expand Down Expand Up @@ -985,6 +986,13 @@ class type_caster_generic {
}
return false;
}
bool try_as_void_ptr_capsule(handle src) {
value = try_as_void_ptr_capsule_get_pointer(src, cpptype->name());
if (value != nullptr) {
return true;
}
return false;
}
void check_holder_compat() {}

PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) {
Expand Down Expand Up @@ -1116,6 +1124,10 @@ class type_caster_generic {
return true;
}

if (convert && cpptype && this_.try_as_void_ptr_capsule(src)) {
return true;
}

return false;
}

Expand Down
1 change: 1 addition & 0 deletions tests/extra_python_package/test_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"include/pybind11/detail/internals.h",
"include/pybind11/detail/native_enum_data.h",
"include/pybind11/detail/smart_holder_poc.h",
"include/pybind11/detail/try_as_void_ptr_capsule_get_pointer.h",
"include/pybind11/detail/type_caster_base.h",
"include/pybind11/detail/type_caster_odr_guard.h",
"include/pybind11/detail/typeid.h",
Expand Down
5 changes: 0 additions & 5 deletions tests/test_class_sh_void_ptr_capsule.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@

from pybind11_tests import class_sh_void_ptr_capsule as m

pytest.skip(
"PYBIND11K_MERGE_SH_AFTER_PR5257_WIP: void_ptr_capsule feature needs to be re-integrated",
allow_module_level=True,
)


class Valid:
def __init__(self):
Expand Down

0 comments on commit b71bbfb

Please sign in to comment.