8000 Add PyObject_VisitManagedDict() (#76) · python/pythoncapi-compat@a594354 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a594354

Browse files
authored
Add PyObject_VisitManagedDict() (#76)
Add PyObject_VisitManagedDict() and PyObject_ClearManagedDict() functions.
1 parent 671fb69 commit a594354

File tree

4 files changed

+117
-0
lines changed

4 files changed

+117
-0
lines changed

docs/api.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,14 @@ Python 3.13
9999
100100
See `PyLong_AsInt() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_AsInt>`__.
101101
102+
.. c:function:: int PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
103+
104+
See `PyObject_VisitManagedDict() documentation <https://docs.python.org/dev/c-api/object.html#c.PyObject_VisitManagedDict>`__.
105+
106+
.. c:function:: void PyObject_ClearManagedDict(PyObject *obj)
107+
108+
See `PyObject_ClearManagedDict() documentation <https://docs.python.org/dev/c-api/object.html#c.PyObject_ClearManagedDict>`__.
109+
102110
103111
Python 3.12
104112
-----------

docs/changelog.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
Changelog
22
=========
33

4+
* 2023-10-03: Add ``PyObject_VisitManagedDict()`` and
5+
``PyObject_ClearManagedDict()`` functions.
46
* 2023-09-29: Add functions:
57

68
* ``PyMapping_HasKeyWithError()``

pythoncapi_compat.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,31 @@ static inline int PyLong_AsInt(PyObject *obj)
905905
#endif
906906

907907

908+
// gh-107073 added PyObject_VisitManagedDict() to Python 3.13.0a1
909+
#if PY_VERSION_HEX < 0x030D00A1
910+
static inline int
911+
PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
912+
{
913+
PyObject **dict = _PyObject_GetDictPtr(obj);
914+
if (*dict == NULL) {
915+
return -1;
916+
}
917+
Py_VISIT(*dict);
918+
return 0;
919+
}
920+
921+
static inline void
922+
PyObject_ClearManagedDict(PyObject *obj)
923+
{
924+
PyObject **dict = _PyObject_GetDictPtr(obj);
925+
if (*dict == NULL) {
926+
return;
927+
}
928+
Py_CLEAR(*dict);
929+
}
930+
#endif
931+
932+
908933
#ifdef __cplusplus
909934
}
910935
#endif

tests/test_pythoncapi_compat_cext.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,85 @@ test_long_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
12771277
}
12781278

12791279

1280+
// --- HeapCTypeWithManagedDict --------------------------------------------
1281+
1282+
// Py_TPFLAGS_MANAGED_DICT was added to Python 3.11.0a3
1283+
#if PY_VERSION_HEX >= 0x030B00A3
1284+
# define TEST_MANAGED_DICT
1285+
1286+
typedef struct {
1287+
PyObject_HEAD
1288+
} HeapCTypeObject;
1289+
1290+
static int
1291+
heapmanaged_traverse(PyObject *self, visitproc visit, void *arg)
1292+
{
1293+
Py_VISIT(Py_TYPE(self));
1294+
return PyObject_VisitManagedDict(self, visit, arg);
1295+
}
1296+
1297+
static int
1298+
heapmanaged_clear(PyObject *self)
1299+
{
1300+
PyObject_ClearManagedDict(self);
1301+
return 0;
1302+
}
1303+
1304+
static void
1305+
heapmanaged_dealloc(HeapCTypeObject *self)
1306+
{
1307+
PyTypeObject *tp = Py_TYPE(self);
1308+
PyObject_ClearManagedDict((PyObject *)self);
1309+
PyObject_GC_UnTrack(self);
1310+
PyObject_GC_Del(self);
1311+
Py_DECREF(tp);
1312+
}
1313+
1314+
static PyType_Slot HeapCTypeWithManagedDict_slots[] = {
1315+
{Py_tp_traverse, _Py_CAST(void*, heapmanaged_traverse)},
1316+
{Py_tp_clear, _Py_CAST(void*, heapmanaged_clear)},
1317+
{Py_tp_dealloc, _Py_CAST(void*, heapmanaged_dealloc)},
1318+
{0, 0},
1319+
};
1320+
1321+
static PyType_Spec HeapCTypeWithManagedDict_spec = {
1322+
"test_pythoncapi_compat.HeapCTypeWithManagedDict",
1323+
sizeof(PyObject),
1324+
0,
1325+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_MANAGED_DICT,
1326+
HeapCTypeWithManagedDict_slots
1327+
};
1328+
1329+
static PyObject *
1330+
test_managed_dict(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
1331+
{
1332+
PyObject *type = PyType_FromSpec(&HeapCTypeWithManagedDict_spec);
1333+
if (type == NULL) {
1334+
return NULL;
1335+
}
1336+
1337+
PyObject *obj = PyObject_CallNoArgs(type);
1338+
if (obj == NULL) {
1339+
Py_DECREF(type);
1340+
return NULL;
1341+
}
1342+
1343+
// call heapmanaged_traverse()
1344+
PyGC_Collect();
1345+
1346+
// call heapmanaged_clear()
1347+
Py_DECREF(obj);
1348+
PyGC_Collect();
1349+
1350+
Py_DECREF(type);
1351+
// Just in case!
1352+
PyGC_Collect();
1353+
1354+
Py_RETURN_NONE;
1355+
}
1356+
#endif // PY_VERSION_HEX >= 0x030B00A3
1357+
1358+
12801359
static struct PyMethodDef methods[] = {
12811360
{"test_object", test_object, METH_NOARGS, _Py_NULL},
12821361
{"test_py_is", test_py_is, METH_NOARGS, _Py_NULL},
@@ -1303,6 +1382,9 @@ static struct PyMethodDef methods[] = {
13031382
{"test_getitem", test_getitem, METH_NOARGS, _Py_NULL},
13041383
{"test_dict_api", test_dict_api, METH_NOARGS, _Py_NULL},
13051384
{"test_long_api", test_long_api, METH_NOARGS, _Py_NULL},
1385+
#ifdef TEST_MANAGED_DICT
1386+
{"test_managed_dict", test_managed_dict, METH_NOARGS, _Py_NULL},
1387+
#endif
13061388
{_Py_NULL, _Py_NULL, 0, _Py_NULL}
13071389
};
13081390

0 commit comments

Comments
 (0)
0