Skip to content

Commit c3bf66f

Browse files
committed
Store load member function pointer in typeinfo for module-local types
Simplifies the storage in the python type slightly by just storing the type_info pointer in a capsule (rather than a tuple/pair of capsules). This also avoids the need for an intermediate function to call the member function: the member function pointer can't be stored in a `void *` (and thus not a capsule), but it *can* be stored in the `type_info`.
1 parent 75fa8f9 commit c3bf66f

File tree

2 files changed

+9
-23
lines changed

2 files changed

+9
-23
lines changed

include/pybind11/cast.h

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct type_info {
5151
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
5252
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
5353
void *get_buffer_data = nullptr;
54+
bool (type_caster_generic::*module_local_load)(handle, bool) = nullptr;
5455
/* A simple type never occurs as a (direct or indirect) parent
5556
* of a class that makes use of multiple inheritance */
5657
bool simple_type : 1;
@@ -693,16 +694,6 @@ class type_caster_generic {
693694
}
694695
void check_holder_compat() {}
695696

696-
public:
697-
// Helper to invoke a local `load` on a foreign-module type_caster_generic object. A reference
698-
// to this gets stashed in the type object of module-local types so that external types can call
699-
// into the local module's type_caster_generic::load if their own types fail to load.
700-
static bool local_load(void *caster_in, handle src) {
701-
auto &caster = *reinterpret_cast<type_caster_generic *>(caster_in);
702-
return caster.load(src, false);
703-
}
704-
705-
protected:
706697
// If loading failed with the type visible to this module see if we can load by looking to
707698
// other modules. There are two possibilities here:
708699
// - the input type is actually for another module's `py::module_local` type; we can try getting
@@ -712,16 +703,14 @@ class type_caster_generic {
712703
PYBIND11_NOINLINE bool try_external_load(handle src) {
713704
allow_externals = true; // Don't recurse
714705

715-
str local_key("_pybind11_module_local_data");
706+
str local_key("_pybind11_module_local_typeinfo");
716707
if (hasattr((PyObject *) Py_TYPE(src.ptr()), local_key)) {
717-
tuple t = reinterpret_borrow<tuple>(getattr(src, local_key));
718-
type_info *foreign_typeinfo = reinterpret_borrow<capsule>(t[0]);
719-
auto foreign_load = reinterpret_cast<bool (*)(void *, handle)>((void *) reinterpret_borrow<capsule>(t[1]));
708+
type_info *foreign_typeinfo = reinterpret_borrow<capsule>(getattr(src, local_key));
720709

721710
// Only consider this foreign loader if actually foreign
722-
if (foreign_load != &type_caster_generic::local_load) {
711+
if (foreign_typeinfo->module_local_load != &type_caster_generic::load) {
723712
typeinfo = foreign_typeinfo;
724-
return foreign_load(this, src);
713+
return (this->*(foreign_typeinfo->module_local_load))(src, false);
725714
}
726715
return false;
727716
}

include/pybind11/pybind11.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -868,13 +868,10 @@ class generic_type : public object {
868868
}
869869

870870
if (rec.module_local) {
871-
// Stash a pointer to the local module's type_caster_generic::local_load so that
872-
// external modules can get at our `load` to try loading a C++ type from our local
873-
// Python type.
874-
tuple t(2);
875-
t[0] = capsule(tinfo);
876-
t[1] = capsule((void *) &type_caster_generic::local_load);
877-
setattr(m_ptr, "_pybind11_module_local_data", t);
871+
// Stash a capsule containing the local module's typeinfo so that external modules can
872+
// get at our type loader to try loading a C++ type from our module-local Python type.
873+
tinfo->module_local_load = &type_caster_generic::load;
874+
setattr(m_ptr, "_pybind11_module_local_typeinfo", capsule(tinfo));
878875
}
879876
}
880877

0 commit comments

Comments
 (0)