Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 02ea717

Browse files
committed
Add _Py_StealRef() and _Py_XStealRef()
1 parent 91c6d28 commit 02ea717

3 files changed

Lines changed: 65 additions & 12 deletions

File tree

README.rst

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ Borrow variant
152152
To ease migration of C extensions to the new C API, a variant is provided
153153
to return borrowed references rather than strong references::
154154

155+
// Similar to "Py_INCREF(ob); return ob;"
156+
PyObject* _Py_StealRef(PyObject *ob);
157+
158+
// Similar to "Py_XINCREF(ob); return ob;"
159+
PyObject* _Py_XStealRef(PyObject *ob);
160+
155161
// PyThreadState_GetFrame()
156162
PyFrameObject* _PyThreadState_GetFrameBorrow(PyThreadState *tstate)
157163

@@ -290,8 +296,9 @@ Links
290296
Changelog
291297
=========
292298

293-
* 2020-11-30: Creation of the upgrade_pythoncapi.py script.
294-
* 2020-06-04: Creation of the pythoncapi_compat.h header file.
299+
* 2021-02-16: Add ``_Py_StealRef()`` and ``_Py_XStealRef()`` functions.
300+
* 2020-11-30: Creation of the ``upgrade_pythoncapi.py`` script.
301+
* 2020-06-04: Creation of the ``pythoncapi_compat.h`` header file.
295302

296303

297304
Examples of projects using pythoncapi_compat.h

pythoncapi_compat.h

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,28 @@ static inline PyObject* _Py_XNewRef(PyObject *obj)
6363
#endif
6464

6565

66+
// See https://bugs.python.org/issue42522
67+
#if !defined(_Py_StealRef)
68+
static inline PyObject* __Py_StealRef(PyObject *obj)
69+
{
70+
Py_DECREF(obj);
71+
return obj;
72+
}
73+
#define _Py_StealRef(obj) __Py_StealRef(_PyObject_CAST(obj))
74+
#endif
75+
76+
77+
// See https://bugs.python.org/issue42522
78+
#if !defined(_Py_XStealRef)
79+
static inline PyObject* __Py_XStealRef(PyObject *obj)
80+
{
81+
Py_XDECREF(obj);
82+
return obj;
83+
}
84+
#define _Py_XStealRef(obj) __Py_XStealRef(_PyObject_CAST(obj))
85+
#endif
86+
87+
6688
// bpo-39573 added Py_SET_REFCNT() to Python 3.9.0a4
6789
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT)
6890
static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt)
@@ -109,9 +131,7 @@ PyFrame_GetCode(PyFrameObject *frame)
109131
static inline PyCodeObject*
110132
_PyFrame_GetCodeBorrow(PyFrameObject *frame)
111133
{
112-
PyCodeObject *code = PyFrame_GetCode(frame);
113-
Py_DECREF(code);
114-
return code; // borrowed reference
134+
return (PyCodeObject *)_Py_StealRef(PyFrame_GetCode(frame));
115135
}
116136

117137

@@ -128,9 +148,7 @@ PyFrame_GetBack(PyFrameObject *frame)
128148
static inline PyFrameObject*
129149
_PyFrame_GetBackBorrow(PyFrameObject *frame)
130150
{
131-
PyFrameObject *back = PyFrame_GetBack(frame);
132-
Py_XDECREF(back);
133-
return back; // borrowed reference
151+
return (PyFrameObject *)_Py_XStealRef(PyFrame_GetBack(frame));
134152
}
135153

136154

@@ -158,9 +176,7 @@ PyThreadState_GetFrame(PyThreadState *tstate)
158176
static inline PyFrameObject*
159177
_PyThreadState_GetFrameBorrow(PyThreadState *tstate)
160178
{
161-
PyFrameObject *frame = PyThreadState_GetFrame(tstate);
162-
Py_XDECREF(frame);
163-
return frame; // borrowed reference
179+
return (PyFrameObject *)_Py_XStealRef(PyThreadState_GetFrame(tstate));
164180
}
165181

166182

tests/test_pythoncapi_compat_cext.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ test_object(PyObject *self, PyObject *ignored)
2323
}
2424
Py_ssize_t refcnt = Py_REFCNT(obj);
2525

26-
// Py_NewRef() and Py_XNewRef()
26+
// Py_NewRef()
2727
PyObject *ref = Py_NewRef(obj);
2828
assert(ref == obj);
2929
assert(Py_REFCNT(obj) == (refcnt + 1));
@@ -53,6 +53,35 @@ test_object(PyObject *self, PyObject *ignored)
5353
}
5454

5555

56+
static PyObject *
57+
test_steal_ref(PyObject *self, PyObject *ignored)
58+
{
59+
PyObject *obj = PyList_New(0);
60+
if (obj == NULL) {
61+
return NULL;
62+
}
63+
Py_ssize_t refcnt = Py_REFCNT(obj);
64+
65+
// _Py_StealRef()
66+
Py_INCREF(obj);
67+
PyObject *ref = _Py_StealRef(obj);
68+
assert(ref == obj);
69+
assert(Py_REFCNT(obj) == refcnt);
70+
71+
// _Py_XStealRef()
72+
Py_INCREF(obj);
73+
PyObject *xref = _Py_XStealRef(obj);
74+
assert(xref == obj);
75+
assert(Py_REFCNT(obj) == refcnt);
76+
77+
assert(_Py_XStealRef(NULL) == NULL);
78+
79+
assert(Py_REFCNT(obj) == refcnt);
80+
Py_DECREF(obj);
81+
Py_RETURN_NONE;
82+
}
83+
84+
5685
static PyObject *
5786
test_frame(PyObject *self, PyObject *ignored)
5887
{
@@ -285,6 +314,7 @@ test_module(PyObject *self, PyObject *ignored)
285314

286315
static struct PyMethodDef methods[] = {
287316
{"test_object", test_object, METH_NOARGS},
317+
{"test_steal_ref", test_steal_ref, METH_NOARGS},
288318
{"test_frame", test_frame, METH_NOARGS},
289319
{"test_thread_state", test_thread_state, METH_NOARGS},
290320
{"test_interpreter", test_interpreter, METH_NOARGS},

0 commit comments

Comments
 (0)