@@ -205,39 +205,40 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
205
205
206
206
// / Cleanup the type-info for a pybind11-registered type.
207
207
extern " C" inline void pybind11_meta_dealloc (PyObject *obj) {
208
- auto *type = (PyTypeObject *) obj;
209
- auto &internals = get_internals ();
210
-
211
- // A pybind11-registered type will:
212
- // 1) be found in internals.registered_types_py
213
- // 2) have exactly one associated `detail::type_info`
214
- auto found_type = internals.registered_types_py .find (type);
215
- if (found_type != internals.registered_types_py .end () && found_type->second .size () == 1
216
- && found_type->second [0 ]->type == type) {
217
-
218
- auto *tinfo = found_type->second [0 ];
219
- auto tindex = std::type_index (*tinfo->cpptype );
220
- internals.direct_conversions .erase (tindex);
221
-
222
- if (tinfo->module_local ) {
223
- get_local_internals ().registered_types_cpp .erase (tindex);
224
- } else {
225
- internals.registered_types_cpp .erase (tindex);
226
- }
227
- internals.registered_types_py .erase (tinfo->type );
228
-
229
- // Actually just `std::erase_if`, but that's only available in C++20
230
- auto &cache = internals.inactive_override_cache ;
231
- for (auto it = cache.begin (), last = cache.end (); it != last;) {
232
- if (it->first == (PyObject *) tinfo->type ) {
233
- it = cache.erase (it);
208
+ with_internals ([obj](internals &internals) {
209
+ auto *type = (PyTypeObject *) obj;
210
+
211
+ // A pybind11-registered type will:
212
+ // 1) be found in internals.registered_types_py
213
+ // 2) have exactly one associated `detail::type_info`
214
+ auto found_type = internals.registered_types_py .find (type);
215
+ if (found_type != internals.registered_types_py .end () && found_type->second .size () == 1
216
+ && found_type->second [0 ]->type == type) {
217
+
218
+ auto *tinfo = found_type->second [0 ];
219
+ auto tindex = std::type_index (*tinfo->cpptype );
220
+ internals.direct_conversions .erase (tindex);
221
+
222
+ if (tinfo->module_local ) {
223
+ get_local_internals ().registered_types_cpp .erase (tindex);
234
224
} else {
235
- ++it;
225
+ internals.registered_types_cpp .erase (tindex);
226
+ }
227
+ internals.registered_types_py .erase (tinfo->type );
228
+
229
+ // Actually just `std::erase_if`, but that's only available in C++20
230
+ auto &cache = internals.inactive_override_cache ;
231
+ for (auto it = cache.begin (), last = cache.end (); it != last;) {
232
+ if (it->first == (PyObject *) tinfo->type ) {
233
+ it = cache.erase (it);
234
+ } else {
235
+ ++it;
236
+ }
236
237
}
237
- }
238
238
239
- delete tinfo;
240
- }
239
+ delete tinfo;
240
+ }
241
+ });
241
242
242
243
PyType_Type.tp_dealloc (obj);
243
244
}
@@ -310,19 +311,20 @@ inline void traverse_offset_bases(void *valueptr,
310
311
}
311
312
312
313
inline bool register_instance_impl (void *ptr, instance *self) {
313
- get_internals (). registered_instances . emplace (ptr, self);
314
+ with_instance_map (ptr, [&](instance_map &instances) { instances. emplace (ptr, self); } );
314
315
return true ; // unused, but gives the same signature as the deregister func
315
316
}
316
317
inline bool deregister_instance_impl (void *ptr, instance *self) {
317
- auto ®istered_instances = get_internals ().registered_instances ;
318
- auto range = registered_instances.equal_range (ptr);
319
- for (auto it = range.first ; it != range.second ; ++it) {
320
- if (self == it->second ) {
321
- registered_instances.erase (it);
322
- return true ;
318
+ return with_instance_map (ptr, [&](instance_map &instances) {
319
+ auto range = instances.equal_range (ptr);
320
+ for (auto it = range.first ; it != range.second ; ++it) {
321
+ if (self == it->second ) {
322
+ instances.erase (it);
323
+ return true ;
324
+ }
323
325
}
324
- }
325
- return false ;
326
+ return false ;
327
+ }) ;
326
328
}
327
329
328
330
inline void register_instance (instance *self, void *valptr, const type_info *tinfo) {
@@ -377,27 +379,32 @@ extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject
377
379
}
378
380
379
381
inline void add_patient (PyObject *nurse, PyObject *patient) {
380
- auto &internals = get_internals ();
381
382
auto *instance = reinterpret_cast <detail::instance *>(nurse);
382
383
instance->has_patients = true ;
383
384
Py_INCREF (patient);
384
- internals.patients [nurse].push_back (patient);
385
+
386
+ with_internals ([&](internals &internals) { internals.patients [nurse].push_back (patient); });
385
387
}
386
388
387
389
inline void clear_patients (PyObject *self) {
388
390
auto *instance = reinterpret_cast <detail::instance *>(self);
389
- auto &internals = get_internals ();
390
- auto pos = internals.patients .find (self);
391
+ std::vector<PyObject *> patients;
391
392
392
- if (pos == internals.patients .end ()) {
393
- pybind11_fail (" FATAL: Internal consistency check failed: Invalid clear_patients() call." );
394
- }
393
+ with_internals ([&](internals &internals) {
394
+ auto pos = internals.patients .find (self);
395
+
396
+ if (pos == internals.patients .end ()) {
397
+ pybind11_fail (
398
+ " FATAL: Internal consistency check failed: Invalid clear_patients() call." );
399
+ }
400
+
401
+ // Clearing the patients can cause more Python code to run, which
402
+ // can invalidate the iterator. Extract the vector of patients
403
+ // from the unordered_map first.
404
+ patients = std::move (pos->second );
405
+ internals.patients .erase (pos);
406
+ });
395
407
396
- // Clearing the patients can cause more Python code to run, which
397
- // can invalidate the iterator. Extract the vector of patients
398
- // from the unordered_map first.
399
- auto patients = std::move (pos->second );
400
- internals.patients .erase (pos);
401
408
instance->has_patients = false ;
402
409
for (PyObject *&patient : patients) {
403
410
Py_CLEAR (patient);
@@ -662,10 +669,13 @@ inline PyObject *make_new_python_type(const type_record &rec) {
662
669
663
670
char *tp_doc = nullptr ;
664
671
if (rec.doc && options::show_user_defined_docstrings ()) {
665
- /* Allocate memory for docstring (using PyObject_MALLOC, since
666
- Python will free this later on) */
672
+ /* Allocate memory for docstring (Python will free this later on) */
667
673
size_t size = std::strlen (rec.doc ) + 1 ;
674
+ #if PY_VERSION_HEX >= 0x030D0000
675
+ tp_doc = (char *) PyMem_MALLOC (size);
676
+ #else
668
677
tp_doc = (char *) PyObject_MALLOC (size);
678
+ #endif
669
679
std::memcpy ((void *) tp_doc, rec.doc , size);
670
680
}
671
681
0 commit comments