Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ set(PYBIND11_HEADERS
include/pybind11/detail/class.h
include/pybind11/detail/common-inl.h
include/pybind11/detail/common.h
include/pybind11/detail/cpp_conduit-inl.h
include/pybind11/detail/cpp_conduit.h
include/pybind11/detail/descr.h
include/pybind11/detail/dynamic_raw_ptr_cast_if_possible.h
Expand All @@ -210,9 +211,11 @@ set(PYBIND11_HEADERS
include/pybind11/detail/struct_smart_holder.h
include/pybind11/detail/type_caster_base-inl.h
include/pybind11/detail/type_caster_base.h
include/pybind11/detail/typeid-inl.h
include/pybind11/detail/typeid.h
include/pybind11/detail/using_smart_holder.h
include/pybind11/detail/value_and_holder.h
include/pybind11/attr-inl.h
include/pybind11/attr.h
include/pybind11/buffer_info.h
include/pybind11/cast.h
Expand All @@ -230,6 +233,7 @@ set(PYBIND11_HEADERS
include/pybind11/eigen/tensor.h
include/pybind11/embed.h
include/pybind11/eval.h
include/pybind11/gil-inl.h
include/pybind11/gil.h
include/pybind11/gil_safe_call_once.h
include/pybind11/gil_simple.h
Expand Down
64 changes: 64 additions & 0 deletions include/pybind11/attr-inl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
pybind11/attr-inl.h: Out-of-line definitions for attr.h

Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>

All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/

// Every function defined here must start with PYBIND11_INLINE (or
// PYBIND11_NOINLINE_ATTR PYBIND11_INLINE). In the default header-only mode this file is
// included at the bottom of attr.h; when PYBIND11_PRECOMPILED is defined it is only
// compiled into the pybind11 static library (see src/).

#pragma once

#include "attr.h"

#include <string>

PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)

PYBIND11_NOINLINE_ATTR PYBIND11_INLINE type_record::type_record()
: multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false),
module_local(false), is_final(false), release_gil_before_calling_cpp_dtor(false) {}

PYBIND11_NOINLINE_ATTR PYBIND11_INLINE void type_record::add_base(const std::type_info &base,
void *(*caster)(void *) ) {
auto *base_info = detail::get_type_info(base, false);
if (!base_info) {
std::string tname(base.name());
detail::clean_type_id(tname);
pybind11_fail("generic_type: type \"" + std::string(name)
+ "\" referenced unknown base type \"" + tname + "\"");
}

// SMART_HOLDER_BAKEIN_FOLLOW_ON: Refine holder compatibility checks.
bool this_has_unique_ptr_holder = (holder_enum_v == holder_enum_t::std_unique_ptr);
bool base_has_unique_ptr_holder = (base_info->holder_enum_v == holder_enum_t::std_unique_ptr);
if (this_has_unique_ptr_holder != base_has_unique_ptr_holder) {
std::string tname(base.name());
detail::clean_type_id(tname);
pybind11_fail("generic_type: type \"" + std::string(name) + "\" "
+ (this_has_unique_ptr_holder ? "does not have" : "has")
+ " a non-default holder type while its base \"" + tname + "\" "
+ (base_has_unique_ptr_holder ? "does not" : "does"));
}

bases.append(reinterpret_cast<PyObject *>(base_info->type));

#ifdef PYBIND11_BACKWARD_COMPATIBILITY_TP_DICTOFFSET
dynamic_attr |= base_info->type->tp_dictoffset != 0;
#else
dynamic_attr |= (PyType_GetFlags(base_info->type) & Py_TPFLAGS_MANAGED_DICT) != 0;
#endif

if (caster) {
base_info->implicit_casts.emplace_back(type, caster);
}
}

PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
43 changes: 6 additions & 37 deletions include/pybind11/attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,7 @@ struct function_record {

/// Special data structure which (temporarily) holds metadata about a bound class
struct type_record {
PYBIND11_NOINLINE type_record()
: multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false),
module_local(false), is_final(false), release_gil_before_calling_cpp_dtor(false) {}
type_record();

/// Handle to the parent scope
handle scope;
Expand Down Expand Up @@ -351,40 +349,7 @@ struct type_record {

holder_enum_t holder_enum_v = holder_enum_t::undefined;

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) {
std::string tname(base.name());
detail::clean_type_id(tname);
pybind11_fail("generic_type: type \"" + std::string(name)
+ "\" referenced unknown base type \"" + tname + "\"");
}

// SMART_HOLDER_BAKEIN_FOLLOW_ON: Refine holder compatibility checks.
bool this_has_unique_ptr_holder = (holder_enum_v == holder_enum_t::std_unique_ptr);
bool base_has_unique_ptr_holder
= (base_info->holder_enum_v == holder_enum_t::std_unique_ptr);
if (this_has_unique_ptr_holder != base_has_unique_ptr_holder) {
std::string tname(base.name());
detail::clean_type_id(tname);
pybind11_fail("generic_type: type \"" + std::string(name) + "\" "
+ (this_has_unique_ptr_holder ? "does not have" : "has")
+ " a non-default holder type while its base \"" + tname + "\" "
+ (base_has_unique_ptr_holder ? "does not" : "does"));
}

bases.append(reinterpret_cast<PyObject *>(base_info->type));

#ifdef PYBIND11_BACKWARD_COMPATIBILITY_TP_DICTOFFSET
dynamic_attr |= base_info->type->tp_dictoffset != 0;
#else
dynamic_attr |= (PyType_GetFlags(base_info->type) & Py_TPFLAGS_MANAGED_DICT) != 0;
#endif

if (caster) {
base_info->implicit_casts.emplace_back(type, caster);
}
}
void add_base(const std::type_info &base, void *(*caster)(void *) );
};

inline function_call::function_call(const function_record &f, handle p) : func(f), parent(p) {
Expand Down Expand Up @@ -728,3 +693,7 @@ constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) {

PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

#ifndef PYBIND11_PRECOMPILED
# include "attr-inl.h" // IWYU pragma: export
#endif
79 changes: 79 additions & 0 deletions include/pybind11/detail/cpp_conduit-inl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
pybind11/detail/cpp_conduit-inl.h: Out-of-line definitions for cpp_conduit.h

Copyright (c) 2024 The pybind Community.
*/

// Every function defined here must start with PYBIND11_INLINE (or
// PYBIND11_NOINLINE_ATTR PYBIND11_INLINE). In the default header-only mode this file is
// included at the bottom of cpp_conduit.h; when PYBIND11_PRECOMPILED is defined it is only
// compiled into the pybind11 static library (see src/).

#pragma once

#include "../conduit/pybind11_platform_abi_id.h"
#include "cpp_conduit.h"

#include <typeinfo>

PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)

PYBIND11_INLINE bool type_is_managed_by_our_internals(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 (type_obj->tp_new == pybind11_object_new);
#endif
}

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

PYBIND11_INLINE object try_get_cpp_conduit_method(PyObject *obj) {
if (PyType_Check(obj)) {
return object();
}
PyTypeObject *type_obj = Py_TYPE(obj);
str attr_name("_pybind11_conduit_v1_");
bool assumed_to_be_callable = false;
if (type_is_managed_by_our_internals(type_obj)) {
if (!is_instance_method_of_type(type_obj, attr_name.ptr())) {
return object();
}
assumed_to_be_callable = true;
}
PyObject *method = PyObject_GetAttr(obj, attr_name.ptr());
if (method == nullptr) {
PyErr_Clear();
return object();
}
if (!assumed_to_be_callable && PyCallable_Check(method) == 0) {
Py_DECREF(method);
return object();
}
return reinterpret_steal<object>(method);
}

PYBIND11_INLINE void *
try_raw_pointer_ephemeral_from_cpp_conduit(handle src, const std::type_info *cpp_type_info) {
object method = try_get_cpp_conduit_method(src.ptr());
if (method) {
capsule cpp_type_info_capsule(const_cast<void *>(static_cast<const void *>(cpp_type_info)),
typeid(std::type_info).name());
object cpp_conduit = method(bytes(PYBIND11_PLATFORM_ABI_ID),
cpp_type_info_capsule,
bytes("raw_pointer_ephemeral"));
if (isinstance<capsule>(cpp_conduit)) {
return reinterpret_borrow<capsule>(cpp_conduit).get_pointer();
}
}
return nullptr;
}

PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
60 changes: 8 additions & 52 deletions include/pybind11/detail/cpp_conduit.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,61 +15,17 @@ PYBIND11_NAMESPACE_BEGIN(detail)
// Forward declaration needed here: Refactoring opportunity.
extern "C" PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *);

inline bool type_is_managed_by_our_internals(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 (type_obj->tp_new == pybind11_object_new);
#endif
}
bool type_is_managed_by_our_internals(PyTypeObject *type_obj);

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

inline object try_get_cpp_conduit_method(PyObject *obj) {
if (PyType_Check(obj)) {
return object();
}
PyTypeObject *type_obj = Py_TYPE(obj);
str attr_name("_pybind11_conduit_v1_");
bool assumed_to_be_callable = false;
if (type_is_managed_by_our_internals(type_obj)) {
if (!is_instance_method_of_type(type_obj, attr_name.ptr())) {
return object();
}
assumed_to_be_callable = true;
}
PyObject *method = PyObject_GetAttr(obj, attr_name.ptr());
if (method == nullptr) {
PyErr_Clear();
return object();
}
if (!assumed_to_be_callable && PyCallable_Check(method) == 0) {
Py_DECREF(method);
return object();
}
return reinterpret_steal<object>(method);
}
object try_get_cpp_conduit_method(PyObject *obj);

inline void *try_raw_pointer_ephemeral_from_cpp_conduit(handle src,
const std::type_info *cpp_type_info) {
object method = try_get_cpp_conduit_method(src.ptr());
if (method) {
capsule cpp_type_info_capsule(const_cast<void *>(static_cast<const void *>(cpp_type_info)),
typeid(std::type_info).name());
object cpp_conduit = method(bytes(PYBIND11_PLATFORM_ABI_ID),
cpp_type_info_capsule,
bytes("raw_pointer_ephemeral"));
if (isinstance<capsule>(cpp_conduit)) {
return reinterpret_borrow<capsule>(cpp_conduit).get_pointer();
}
}
return nullptr;
}
void *try_raw_pointer_ephemeral_from_cpp_conduit(handle src, const std::type_info *cpp_type_info);

PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

#ifndef PYBIND11_PRECOMPILED
# include "cpp_conduit-inl.h" // IWYU pragma: export
#endif
15 changes: 15 additions & 0 deletions include/pybind11/detail/internals-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,4 +256,19 @@ PYBIND11_INLINE void PYBIND11_PRECOMPILED_CONFIG_CHECK() {}
#endif

PYBIND11_NAMESPACE_END(detail)

PYBIND11_NOINLINE_ATTR PYBIND11_INLINE void *get_shared_data(const std::string &name) {
return detail::with_internals([&](detail::internals &internals) {
auto it = internals.shared_data.find(name);
return it != internals.shared_data.end() ? it->second : nullptr;
});
}

PYBIND11_NOINLINE_ATTR PYBIND11_INLINE void *set_shared_data(const std::string &name, void *data) {
return detail::with_internals([&](detail::internals &internals) {
internals.shared_data[name] = data;
return data;
});
}

PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
14 changes: 2 additions & 12 deletions include/pybind11/detail/internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -917,20 +917,10 @@ PYBIND11_NAMESPACE_END(detail)
/// Returns a named pointer that is shared among all extension modules (using the same
/// pybind11 version) running in the current interpreter. Names starting with underscores
/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
return detail::with_internals([&](detail::internals &internals) {
auto it = internals.shared_data.find(name);
return it != internals.shared_data.end() ? it->second : nullptr;
});
}
void *get_shared_data(const std::string &name);

/// Set the shared data that can be later recovered by `get_shared_data()`.
PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
return detail::with_internals([&](detail::internals &internals) {
internals.shared_data[name] = data;
return data;
});
}
void *set_shared_data(const std::string &name, void *data);

/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
/// such entry exists. Otherwise, a new object of default-constructible type `T` is
Expand Down
45 changes: 45 additions & 0 deletions include/pybind11/detail/type_caster_base-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -550,5 +550,50 @@ type_caster_generic::cast(const cast_sources &srcs,
return inst.release();
}

PYBIND11_INLINE void smart_holder_type_caster_support::value_and_holder_helper::
throw_if_uninitialized_or_disowned_holder(const char *typeid_name) const {
static const std::string missing_value_msg = "Missing value for wrapped C++ type `";
if (!holder().is_populated) {
throw value_error(missing_value_msg + clean_type_id(typeid_name)
+ "`: Python instance is uninitialized.");
}
if (!holder().has_pointee()) {
throw value_error(missing_value_msg + clean_type_id(typeid_name)
+ "`: Python instance was disowned.");
}
}

PYBIND11_NOINLINE_ATTR PYBIND11_INLINE void *type_caster_generic::local_load(PyObject *src,
const type_info *ti) {
auto caster = type_caster_generic(ti);
if (caster.load(src, false)) {
return caster.value;
}
return nullptr;
}

PYBIND11_NOINLINE_ATTR PYBIND11_INLINE bool
type_caster_generic::try_load_foreign_module_local(handle src) {
constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID;
const auto pytype = type::handle_of(src);
if (!hasattr(pytype, local_key)) {
return false;
}

type_info *foreign_typeinfo = reinterpret_borrow<capsule>(getattr(pytype, local_key));
// Only consider this foreign loader if actually foreign and is a loader of the correct cpp
// type
if (foreign_typeinfo->module_local_load == &local_load
|| (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype))) {
return false;
}

if (auto *result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) {
value = result;
return true;
}
return false;
}

PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
Loading
Loading