diff --git a/docs/api.rst b/docs/api.rst index c0adfc4..c2564f5 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -99,6 +99,14 @@ Python 3.13 See `PyLong_AsInt() documentation `__. +.. c:function:: int PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg) + + See `PyObject_VisitManagedDict() documentation `__. + +.. c:function:: void PyObject_ClearManagedDict(PyObject *obj) + + See `PyObject_ClearManagedDict() documentation `__. + Python 3.12 ----------- diff --git a/docs/changelog.rst b/docs/changelog.rst index 7a21348..b5203b8 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,8 @@ Changelog ========= +* 2023-10-03: Add ``PyObject_VisitManagedDict()`` and + ``PyObject_ClearManagedDict()`` functions. * 2023-09-29: Add functions: * ``PyMapping_HasKeyWithError()`` diff --git a/pythoncapi_compat.h b/pythoncapi_compat.h index e6a388e..fa32887 100644 --- a/pythoncapi_compat.h +++ b/pythoncapi_compat.h @@ -905,6 +905,31 @@ static inline int PyLong_AsInt(PyObject *obj) #endif +// gh-107073 added PyObject_VisitManagedDict() to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D00A1 +static inline int +PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg) +{ + PyObject **dict = _PyObject_GetDictPtr(obj); + if (*dict == NULL) { + return -1; + } + Py_VISIT(*dict); + return 0; +} + +static inline void +PyObject_ClearManagedDict(PyObject *obj) +{ + PyObject **dict = _PyObject_GetDictPtr(obj); + if (*dict == NULL) { + return; + } + Py_CLEAR(*dict); +} +#endif + + #ifdef __cplusplus } #endif diff --git a/tests/test_pythoncapi_compat_cext.c b/tests/test_pythoncapi_compat_cext.c index 7e08402..b50333d 100644 --- a/tests/test_pythoncapi_compat_cext.c +++ b/tests/test_pythoncapi_compat_cext.c @@ -1277,6 +1277,85 @@ test_long_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) } +// --- HeapCTypeWithManagedDict -------------------------------------------- + +// Py_TPFLAGS_MANAGED_DICT was added to Python 3.11.0a3 +#if PY_VERSION_HEX >= 0x030B00A3 +# define TEST_MANAGED_DICT + +typedef struct { + PyObject_HEAD +} HeapCTypeObject; + +static int +heapmanaged_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return PyObject_VisitManagedDict(self, visit, arg); +} + +static int +heapmanaged_clear(PyObject *self) +{ + PyObject_ClearManagedDict(self); + return 0; +} + +static void +heapmanaged_dealloc(HeapCTypeObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_ClearManagedDict((PyObject *)self); + PyObject_GC_UnTrack(self); + PyObject_GC_Del(self); + Py_DECREF(tp); +} + +static PyType_Slot HeapCTypeWithManagedDict_slots[] = { + {Py_tp_traverse, _Py_CAST(void*, heapmanaged_traverse)}, + {Py_tp_clear, _Py_CAST(void*, heapmanaged_clear)}, + {Py_tp_dealloc, _Py_CAST(void*, heapmanaged_dealloc)}, + {0, 0}, +}; + +static PyType_Spec HeapCTypeWithManagedDict_spec = { + "test_pythoncapi_compat.HeapCTypeWithManagedDict", + sizeof(PyObject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_MANAGED_DICT, + HeapCTypeWithManagedDict_slots +}; + +static PyObject * +test_managed_dict(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) +{ + PyObject *type = PyType_FromSpec(&HeapCTypeWithManagedDict_spec); + if (type == NULL) { + return NULL; + } + + PyObject *obj = PyObject_CallNoArgs(type); + if (obj == NULL) { + Py_DECREF(type); + return NULL; + } + + // call heapmanaged_traverse() + PyGC_Collect(); + + // call heapmanaged_clear() + Py_DECREF(obj); + PyGC_Collect(); + + Py_DECREF(type); + // Just in case! + PyGC_Collect(); + + Py_RETURN_NONE; +} +#endif // PY_VERSION_HEX >= 0x030B00A3 + + static struct PyMethodDef methods[] = { {"test_object", test_object, METH_NOARGS, _Py_NULL}, {"test_py_is", test_py_is, METH_NOARGS, _Py_NULL}, @@ -1303,6 +1382,9 @@ static struct PyMethodDef methods[] = { {"test_getitem", test_getitem, METH_NOARGS, _Py_NULL}, {"test_dict_api", test_dict_api, METH_NOARGS, _Py_NULL}, {"test_long_api", test_long_api, METH_NOARGS, _Py_NULL}, +#ifdef TEST_MANAGED_DICT + {"test_managed_dict", test_managed_dict, METH_NOARGS, _Py_NULL}, +#endif {_Py_NULL, _Py_NULL, 0, _Py_NULL} }; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy