Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[smart_holder] Remove added return_value_policy members and try_as_void_ptr_capsule feature. #5160

Merged
merged 10 commits into from
Jun 11, 2024
Merged
11 changes: 3 additions & 8 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -476,15 +476,11 @@ struct string_caster {
return true;
}

static handle cast(const StringType &src, return_value_policy policy, handle /* parent */) {
static handle
cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) {
const char *buffer = reinterpret_cast<const char *>(src.data());
auto nbytes = ssize_t(src.size() * sizeof(CharT));
handle s;
if (policy == return_value_policy::_return_as_bytes) {
s = PyBytes_FromStringAndSize(buffer, nbytes);
} else {
s = decode_utfN(buffer, nbytes);
}
handle s = decode_utfN(buffer, nbytes);
if (!s) {
throw error_already_set();
}
Expand Down Expand Up @@ -1170,7 +1166,6 @@ struct return_value_policy_override<
void>> {
static return_value_policy policy(return_value_policy p) {
return !std::is_lvalue_reference<Return>::value && !std::is_pointer<Return>::value
&& p != return_value_policy::_clif_automatic
? return_value_policy::move
: p;
}
Expand Down
26 changes: 1 addition & 25 deletions include/pybind11/detail/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -542,33 +542,9 @@ enum class return_value_policy : uint8_t {
collected while Python is still using the child. More advanced
variations of this scheme are also possible using combinations of
return_value_policy::reference and the keep_alive call policy */
reference_internal,

/** With this policy, C++ string types are converted to Python bytes,
instead of str. This is most useful when a C++ function returns a
container-like type with nested C++ string types, and `py::bytes` cannot
be applied easily. Dictionary like types might not work, for example,
`Dict[str, bytes]`, because this policy forces all string return values
to be converted to bytes. Note that this return_value_policy is not
concerned with lifetime/ownership semantics, like the other policies,
but the purpose of _return_as_bytes is certain to be orthogonal, because
C++ strings are always copied to Python `bytes` or `str`.
NOTE: This policy is NOT available on master. */
_return_as_bytes,

/** This policy should only be used by PyCLIF to automatically select a
return value policy. Legacy PyCLIF automatically decides object lifetime
management based on their properties:
https://github.com/google/clif/tree/main/clif/python#pointers-references-and-object-ownership
With this policy, the return value policy selection is consistent with
legacy PyCLIF.
NOTE: This policy is NOT available on master. */
_clif_automatic
reference_internal
};

#define PYBIND11_HAS_RETURN_VALUE_POLICY_RETURN_AS_BYTES
#define PYBIND11_HAS_RETURN_VALUE_POLICY_CLIF_AUTOMATIC

PYBIND11_NAMESPACE_BEGIN(detail)

inline static constexpr int log2(size_t n, int k = 0) {
Expand Down
122 changes: 3 additions & 119 deletions include/pybind11/detail/smart_holder_type_casters.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,72 +36,6 @@ struct is_smart_holder_type<smart_holder> : std::true_type {};
// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code.
inline void register_instance(instance *self, void *valptr, const type_info *tinfo);
inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo);
extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *);

// 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();
}
}

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;
}

// The modified_type_caster_generic_load_impl could replace type_caster_generic::load_impl but not
// vice versa. The main difference is that the original code only propagates a reference to the
Expand Down Expand Up @@ -176,15 +110,6 @@ class modified_type_caster_generic_load_impl {
return false;
}

bool try_as_void_ptr_capsule(handle src) {
unowned_void_ptr_from_void_ptr_capsule
= try_as_void_ptr_capsule_get_pointer(src, cpptype->name());
if (unowned_void_ptr_from_void_ptr_capsule != nullptr) {
return true;
}
return false;
}

PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) {
std::unique_ptr<modified_type_caster_generic_load_impl> loader(
new modified_type_caster_generic_load_impl(ti));
Expand Down Expand Up @@ -337,16 +262,12 @@ class modified_type_caster_generic_load_impl {
loaded_v_h = value_and_holder();
return true;
}
if (convert && cpptype && try_as_void_ptr_capsule(src)) {
return true;
}
return false;
}

const type_info *typeinfo = nullptr;
const std::type_info *cpptype = nullptr;
void *unowned_void_ptr_from_direct_conversion = nullptr;
void *unowned_void_ptr_from_void_ptr_capsule = nullptr;
const std::type_info *loaded_v_h_cpptype = nullptr;
std::vector<void *(*) (void *)> implicit_casts;
value_and_holder loaded_v_h;
Expand Down Expand Up @@ -499,10 +420,7 @@ struct smart_holder_type_caster_load {
}

T *loaded_as_raw_ptr_unowned() const {
void *void_ptr = load_impl.unowned_void_ptr_from_void_ptr_capsule;
if (void_ptr == nullptr) {
void_ptr = load_impl.unowned_void_ptr_from_direct_conversion;
}
void *void_ptr = load_impl.unowned_void_ptr_from_direct_conversion;
if (void_ptr == nullptr) {
if (have_holder()) {
throw_if_uninitialized_or_disowned_holder(typeid(T));
Expand Down Expand Up @@ -531,13 +449,6 @@ struct smart_holder_type_caster_load {
}

std::shared_ptr<T> loaded_as_shared_ptr(handle responsible_parent = nullptr) const {
if (load_impl.unowned_void_ptr_from_void_ptr_capsule) {
if (responsible_parent) {
return make_shared_ptr_with_responsible_parent(responsible_parent);
}
throw cast_error("Unowned pointer from a void pointer capsule cannot be converted to a"
" std::shared_ptr.");
}
if (load_impl.unowned_void_ptr_from_direct_conversion != nullptr) {
if (responsible_parent) {
return make_shared_ptr_with_responsible_parent(responsible_parent);
Expand Down Expand Up @@ -601,10 +512,6 @@ struct smart_holder_type_caster_load {

template <typename D>
std::unique_ptr<T, D> loaded_as_unique_ptr(const char *context = "loaded_as_unique_ptr") {
if (load_impl.unowned_void_ptr_from_void_ptr_capsule) {
throw cast_error("Unowned pointer from a void pointer capsule cannot be converted to a"
" std::unique_ptr.");
}
if (load_impl.unowned_void_ptr_from_direct_conversion != nullptr) {
throw cast_error("Unowned pointer from direct conversion cannot be converted to a"
" std::unique_ptr.");
Expand Down Expand Up @@ -753,30 +660,19 @@ struct smart_holder_type_caster : smart_holder_type_caster_load<T>,
static handle cast(T const &src, return_value_policy policy, handle parent) {
// type_caster_base BEGIN
if (policy == return_value_policy::automatic
|| policy == return_value_policy::automatic_reference
|| policy == return_value_policy::_clif_automatic) {
|| policy == return_value_policy::automatic_reference) {
policy = return_value_policy::copy;
}
return cast(&src, policy, parent);
// type_caster_base END
}

static handle cast(T &src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::_clif_automatic) {
if (is_move_constructible<T>::value) {
policy = return_value_policy::move;
} else {
policy = return_value_policy::automatic;
}
}
return cast(const_cast<T const &>(src), policy, parent); // Mutbl2Const
}

static handle cast(T const *src, return_value_policy policy, handle parent) {
auto st = type_caster_base<T>::src_and_type(src);
if (policy == return_value_policy::_clif_automatic) {
policy = return_value_policy::copy;
}
return cast_const_raw_ptr( // Originally type_caster_generic::cast.
st.first,
policy,
Expand All @@ -787,13 +683,6 @@ struct smart_holder_type_caster : smart_holder_type_caster_load<T>,
}

static handle cast(T *src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::_clif_automatic) {
if (parent) {
policy = return_value_policy::reference_internal;
} else {
policy = return_value_policy::reference;
}
}
return cast(const_cast<T const *>(src), policy, parent); // Mutbl2Const
}

Expand Down Expand Up @@ -927,16 +816,12 @@ struct smart_holder_type_caster<std::shared_ptr<T>> : smart_holder_type_caster_l
break;
case return_value_policy::take_ownership:
throw cast_error("Invalid return_value_policy for shared_ptr (take_ownership).");
break;
case return_value_policy::copy:
case return_value_policy::move:
break;
case return_value_policy::reference:
throw cast_error("Invalid return_value_policy for shared_ptr (reference).");
break;
case return_value_policy::reference_internal:
case return_value_policy::_return_as_bytes:
case return_value_policy::_clif_automatic:
break;
}
if (!src) {
Expand Down Expand Up @@ -1010,8 +895,7 @@ struct smart_holder_type_caster<std::unique_ptr<T, D>> : smart_holder_type_caste
if (policy != return_value_policy::automatic
&& policy != return_value_policy::automatic_reference
&& policy != return_value_policy::reference_internal
&& policy != return_value_policy::move
&& policy != return_value_policy::_clif_automatic) {
&& policy != return_value_policy::move) {
// SMART_HOLDER_WIP: IMPROVABLE: Error message.
throw cast_error("Invalid return_value_policy for unique_ptr.");
}
Expand Down
4 changes: 0 additions & 4 deletions include/pybind11/detail/type_caster_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -625,10 +625,6 @@ class type_caster_generic {
keep_alive_impl(inst, parent);
break;

case return_value_policy::_return_as_bytes:
pybind11_fail("return_value_policy::_return_as_bytes does not apply.");
break;

default:
throw cast_error("unhandled return_value_policy: should not happen!");
}
Expand Down
3 changes: 0 additions & 3 deletions include/pybind11/eigen/matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,6 @@ struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
return eigen_ref_array<props>(*src);
case return_value_policy::reference_internal:
return eigen_ref_array<props>(*src, parent);
case return_value_policy::_return_as_bytes:
pybind11_fail("return_value_policy::_return_as_bytes does not apply.");
break;
default:
throw cast_error("unhandled return_value_policy: should not happen!");
};
Expand Down
4 changes: 0 additions & 4 deletions include/pybind11/eigen/tensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,6 @@ struct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {
writeable = !std::is_const<C>::value;
break;

case return_value_policy::_return_as_bytes:
pybind11_fail("return_value_policy::_return_as_bytes does not apply.");
break;

default:
pybind11_fail("pybind11 bug in eigen.h, please file a bug report");
}
Expand Down
3 changes: 1 addition & 2 deletions include/pybind11/type_caster_pyobject_ptr.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ class type_caster<PyObject> {
raise_from(PyExc_SystemError, "src != nullptr but PyErr_Occurred()");
throw error_already_set();
}
if (policy == return_value_policy::take_ownership
|| policy == return_value_policy::_clif_automatic) {
if (policy == return_value_policy::take_ownership) {
return src;
}
if (policy == return_value_policy::reference
Expand Down
2 changes: 0 additions & 2 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ set(PYBIND11_TEST_FILES
test_class_sh_unique_ptr_custom_deleter
test_class_sh_unique_ptr_member
test_class_sh_virtual_py_cpp_mix
test_class_sh_void_ptr_capsule
test_classh_mock
test_const_name
test_constants_and_functions
Expand Down Expand Up @@ -167,7 +166,6 @@ set(PYBIND11_TEST_FILES
test_pickling
test_python_multiple_inheritance
test_pytypes
test_return_value_policy_override
test_sequences_and_iterators
test_smart_ptr
test_stl
Expand Down
31 changes: 0 additions & 31 deletions tests/test_builtin_casters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,10 @@

#include "pybind11_tests.h"

#include <utility>

struct ConstRefCasted {
int tag;
};

struct StringAttr {
explicit StringAttr(std::string v) : value(std::move(v)) {}
std::string value;
};

PYBIND11_NAMESPACE_BEGIN(pybind11)
PYBIND11_NAMESPACE_BEGIN(detail)
template <>
Expand Down Expand Up @@ -390,29 +383,5 @@ TEST_SUBMODULE(builtin_casters, m) {
m.def("takes_const_ref_wrap",
[](std::reference_wrapper<const ConstRefCasted> x) { return x.get().tag; });

// test return_value_policy::_return_as_bytes
m.def(
"invalid_utf8_string_as_bytes",
[]() { return std::string("\xba\xd0\xba\xd0"); },
py::return_value_policy::_return_as_bytes);
m.def("invalid_utf8_string_as_str", []() { return std::string("\xba\xd0\xba\xd0"); });
m.def(
"invalid_utf8_char_array_as_bytes",
[]() { return "\xba\xd0\xba\xd0"; },
py::return_value_policy::_return_as_bytes);
py::class_<StringAttr>(m, "StringAttr")
.def(py::init<std::string>())
.def_property(
"value",
py::cpp_function([](StringAttr &self) { return self.value; },
py::return_value_policy::_return_as_bytes),
py::cpp_function([](StringAttr &self, std::string v) { self.value = std::move(v); }));
#ifdef PYBIND11_HAS_STRING_VIEW
m.def(
"invalid_utf8_string_view_as_bytes",
[]() { return std::string_view("\xba\xd0\xba\xd0"); },
py::return_value_policy::_return_as_bytes);
#endif

PYBIND11_WARNING_POP
}
Loading
Loading