Skip to content

Commit 85b3542

Browse files
authored
Update pythoncapi_compat.h (#93)
1 parent 4a4d625 commit 85b3542

File tree

1 file changed

+142
-66
lines changed

1 file changed

+142
-66
lines changed

immutables/pythoncapi_compat.h

Lines changed: 142 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,29 @@ extern "C" {
2626
// the inline keyword in C (only in C++): use __inline instead.
2727
#if (defined(_MSC_VER) && _MSC_VER < 1900 \
2828
&& !defined(__cplusplus) && !defined(inline))
29-
# define PYCAPI_COMPAT_INLINE(TYPE static __inline TYPE
29+
# define PYCAPI_COMPAT_STATIC_INLINE(TYPE) static __inline TYPE
3030
#else
3131
# define PYCAPI_COMPAT_STATIC_INLINE(TYPE) static inline TYPE
3232
#endif
3333

3434

35-
// C++ compatibility
36-
#ifdef __cplusplus
37-
# define PYCAPI_COMPAT_CAST(TYPE, EXPR) reinterpret_cast<TYPE>(EXPR)
38-
# define PYCAPI_COMPAT_NULL nullptr
39-
#else
40-
# define PYCAPI_COMPAT_CAST(TYPE, EXPR) ((TYPE)(EXPR))
41-
# define PYCAPI_COMPAT_NULL NULL
35+
#ifndef _Py_CAST
36+
# define _Py_CAST(type, expr) ((type)(expr))
37+
#endif
38+
39+
// On C++11 and newer, _Py_NULL is defined as nullptr on C++11,
40+
// otherwise it is defined as NULL.
41+
#ifndef _Py_NULL
42+
# if defined(__cplusplus) && __cplusplus >= 201103
43+
# define _Py_NULL nullptr
44+
# else
45+
# define _Py_NULL NULL
46+
# endif
4247
#endif
4348

4449
// Cast argument to PyObject* type.
4550
#ifndef _PyObject_CAST
46-
# define _PyObject_CAST(op) PYCAPI_COMPAT_CAST(PyObject*, op)
47-
#endif
48-
#ifndef _PyObject_CAST_CONST
49-
# define _PyObject_CAST_CONST(op) PYCAPI_COMPAT_CAST(const PyObject*, op)
51+
# define _PyObject_CAST(op) _Py_CAST(PyObject*, op)
5052
#endif
5153

5254

@@ -74,30 +76,6 @@ _Py_XNewRef(PyObject *obj)
7476
#endif
7577

7678

77-
// See https://bugs.python.org/issue42522
78-
#if !defined(_Py_StealRef)
79-
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
80-
__Py_StealRef(PyObject *obj)
81-
{
82-
Py_DECREF(obj);
83-
return obj;
84-
}
85-
#define _Py_StealRef(obj) __Py_StealRef(_PyObject_CAST(obj))
86-
#endif
87-
88-
89-
// See https://bugs.python.org/issue42522
90-
#if !defined(_Py_XStealRef)
91-
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
92-
__Py_XStealRef(PyObject *obj)
93-
{
94-
Py_XDECREF(obj);
95-
return obj;
96-
}
97-
#define _Py_XStealRef(obj) __Py_XStealRef(_PyObject_CAST(obj))
98-
#endif
99-
100-
10179
// bpo-39573 added Py_SET_REFCNT() to Python 3.9.0a4
10280
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT)
10381
PYCAPI_COMPAT_STATIC_INLINE(void)
@@ -171,36 +149,95 @@ _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
171149
PYCAPI_COMPAT_STATIC_INLINE(PyCodeObject*)
172150
PyFrame_GetCode(PyFrameObject *frame)
173151
{
174-
assert(frame != PYCAPI_COMPAT_NULL);
175-
assert(frame->f_code != PYCAPI_COMPAT_NULL);
176-
return PYCAPI_COMPAT_CAST(PyCodeObject*, Py_NewRef(frame->f_code));
152+
assert(frame != _Py_NULL);
153+
assert(frame->f_code != _Py_NULL);
154+
return _Py_CAST(PyCodeObject*, Py_NewRef(frame->f_code));
177155
}
178156
#endif
179157

180158
PYCAPI_COMPAT_STATIC_INLINE(PyCodeObject*)
181159
_PyFrame_GetCodeBorrow(PyFrameObject *frame)
182160
{
183-
return PYCAPI_COMPAT_CAST(PyCodeObject *,
184-
_Py_StealRef(PyFrame_GetCode(frame)));
161+
PyCodeObject *code = PyFrame_GetCode(frame);
162+
Py_DECREF(code);
163+
return code;
185164
}
186165

187166

188-
// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1
167+
// bpo-40421 added PyFrame_GetBack() to Python 3.9.0b1
189168
#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION)
190169
PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*)
191170
PyFrame_GetBack(PyFrameObject *frame)
192171
{
193-
assert(frame != PYCAPI_COMPAT_NULL);
194-
return PYCAPI_COMPAT_CAST(PyFrameObject*, Py_XNewRef(frame->f_back));
172+
assert(frame != _Py_NULL);
173+
return _Py_CAST(PyFrameObject*, Py_XNewRef(frame->f_back));
195174
}
196175
#endif
197176

198177
#if !defined(PYPY_VERSION)
199178
PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*)
200179
_PyFrame_GetBackBorrow(PyFrameObject *frame)
201180
{
202-
return PYCAPI_COMPAT_CAST(PyFrameObject *,
203-
_Py_XStealRef(PyFrame_GetBack(frame)));
181+
PyFrameObject *back = PyFrame_GetBack(frame);
182+
Py_XDECREF(back);
183+
return back;
184+
}
185+
#endif
186+
187+
188+
// bpo-40421 added PyFrame_GetLocals() to Python 3.11.0a7
189+
#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION)
190+
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
191+
PyFrame_GetLocals(PyFrameObject *frame)
192+
{
193+
#if PY_VERSION_HEX >= 0x030400B1
194+
if (PyFrame_FastToLocalsWithError(frame) < 0) {
195+
return NULL;
196+
}
197+
#else
198+
PyFrame_FastToLocals(frame);
199+
#endif
200+
return Py_NewRef(frame->f_locals);
201+
}
202+
#endif
203+
204+
205+
// bpo-40421 added PyFrame_GetGlobals() to Python 3.11.0a7
206+
#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION)
207+
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
208+
PyFrame_GetGlobals(PyFrameObject *frame)
209+
{
210+
return Py_NewRef(frame->f_globals);
211+
}
212+
#endif
213+
214+
215+
// bpo-40421 added PyFrame_GetBuiltins() to Python 3.11.0a7
216+
#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION)
217+
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
218+
PyFrame_GetBuiltins(PyFrameObject *frame)
219+
{
220+
return Py_NewRef(frame->f_builtins);
221+
}
222+
#endif
223+
224+
225+
// bpo-40421 added PyFrame_GetLasti() to Python 3.11.0b1
226+
#if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION)
227+
PYCAPI_COMPAT_STATIC_INLINE(int)
228+
PyFrame_GetLasti(PyFrameObject *frame)
229+
{
230+
#if PY_VERSION_HEX >= 0x030A00A7
231+
// bpo-27129: Since Python 3.10.0a7, f_lasti is an instruction offset,
232+
// not a bytes offset anymore. Python uses 16-bit "wordcode" (2 bytes)
233+
// instructions.
234+
if (frame->f_lasti < 0) {
235+
return -1;
236+
}
237+
return frame->f_lasti * 2;
238+
#else
239+
return frame->f_lasti;
240+
#endif
204241
}
205242
#endif
206243

@@ -210,7 +247,7 @@ _PyFrame_GetBackBorrow(PyFrameObject *frame)
210247
PYCAPI_COMPAT_STATIC_INLINE(PyInterpreterState *)
211248
PyThreadState_GetInterpreter(PyThreadState *tstate)
212249
{
213-
assert(tstate != PYCAPI_COMPAT_NULL);
250+
assert(tstate != _Py_NULL);
214251
return tstate->interp;
215252
}
216253
#endif
@@ -221,17 +258,18 @@ PyThreadState_GetInterpreter(PyThreadState *tstate)
221258
PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*)
222259
PyThreadState_GetFrame(PyThreadState *tstate)
223260
{
224-
assert(tstate != PYCAPI_COMPAT_NULL);
225-
return PYCAPI_COMPAT_CAST(PyFrameObject *, Py_XNewRef(tstate->frame));
261+
assert(tstate != _Py_NULL);
262+
return _Py_CAST(PyFrameObject *, Py_XNewRef(tstate->frame));
226263
}
227264
#endif
228265

229266
#if !defined(PYPY_VERSION)
230267
PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*)
231268
_PyThreadState_GetFrameBorrow(PyThreadState *tstate)
232269
{
233-
return PYCAPI_COMPAT_CAST(PyFrameObject*,
234-
_Py_XStealRef(PyThreadState_GetFrame(tstate)));
270+
PyFrameObject *frame = PyThreadState_GetFrame(tstate);
271+
Py_XDECREF(frame);
272+
return frame;
235273
}
236274
#endif
237275

@@ -245,11 +283,11 @@ PyInterpreterState_Get(void)
245283
PyInterpreterState *interp;
246284

247285
tstate = PyThreadState_GET();
248-
if (tstate == PYCAPI_COMPAT_NULL) {
286+
if (tstate == _Py_NULL) {
249287
Py_FatalError("GIL released (tstate is NULL)");
250288
}
251289
interp = tstate->interp;
252-
if (interp == PYCAPI_COMPAT_NULL) {
290+
if (interp == _Py_NULL) {
253291
Py_FatalError("no current interpreter");
254292
}
255293
return interp;
@@ -262,7 +300,7 @@ PyInterpreterState_Get(void)
262300
PYCAPI_COMPAT_STATIC_INLINE(uint64_t)
263301
PyThreadState_GetID(PyThreadState *tstate)
264302
{
265-
assert(tstate != PYCAPI_COMPAT_NULL);
303+
assert(tstate != _Py_NULL);
266304
return tstate->id;
267305
}
268306
#endif
@@ -286,8 +324,8 @@ PyThreadState_EnterTracing(PyThreadState *tstate)
286324
PYCAPI_COMPAT_STATIC_INLINE(void)
287325
PyThreadState_LeaveTracing(PyThreadState *tstate)
288326
{
289-
int use_tracing = (tstate->c_tracefunc != PYCAPI_COMPAT_NULL
290-
|| tstate->c_profilefunc != PYCAPI_COMPAT_NULL);
327+
int use_tracing = (tstate->c_tracefunc != _Py_NULL
328+
|| tstate->c_profilefunc != _Py_NULL);
291329
tstate->tracing--;
292330
#if PY_VERSION_HEX >= 0x030A00A1
293331
tstate->cframe->use_tracing = use_tracing;
@@ -322,11 +360,11 @@ PyObject_CallOneArg(PyObject *func, PyObject *arg)
322360
// bpo-1635741 added PyModule_AddObjectRef() to Python 3.10.0a3
323361
#if PY_VERSION_HEX < 0x030A00A3
324362
PYCAPI_COMPAT_STATIC_INLINE(int)
325-
PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value)
363+
PyModule_AddObjectRef(PyObject *module, const char *name, PyObject *value)
326364
{
327365
int res;
328366
Py_XINCREF(value);
329-
res = PyModule_AddObject(mod, name, value);
367+
res = PyModule_AddObject(module, name, value);
330368
if (res < 0) {
331369
Py_XDECREF(value);
332370
}
@@ -338,7 +376,7 @@ PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value)
338376
// bpo-40024 added PyModule_AddType() to Python 3.9.0a5
339377
#if PY_VERSION_HEX < 0x030900A5
340378
PYCAPI_COMPAT_STATIC_INLINE(int)
341-
PyModule_AddType(PyObject *mod, PyTypeObject *type)
379+
PyModule_AddType(PyObject *module, PyTypeObject *type)
342380
{
343381
const char *name, *dot;
344382

@@ -348,13 +386,13 @@ PyModule_AddType(PyObject *mod, PyTypeObject *type)
348386

349387
// inline _PyType_Name()
350388
name = type->tp_name;
351-
assert(name != PYCAPI_COMPAT_NULL);
389+
assert(name != _Py_NULL);
352390
dot = strrchr(name, '.');
353-
if (dot != PYCAPI_COMPAT_NULL) {
391+
if (dot != _Py_NULL) {
354392
name = dot + 1;
355393
}
356394

357-
return PyModule_AddObjectRef(mod, name, _PyObject_CAST(type));
395+
return PyModule_AddObjectRef(module, name, _PyObject_CAST(type));
358396
}
359397
#endif
360398

@@ -375,7 +413,7 @@ PyObject_GC_IsTracked(PyObject* obj)
375413
PYCAPI_COMPAT_STATIC_INLINE(int)
376414
PyObject_GC_IsFinalized(PyObject *obj)
377415
{
378-
PyGC_Head *gc = PYCAPI_COMPAT_CAST(PyGC_Head *, obj) - 1;
416+
PyGC_Head *gc = _Py_CAST(PyGC_Head*, obj) - 1;
379417
return (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(gc));
380418
}
381419
#endif
@@ -384,10 +422,10 @@ PyObject_GC_IsFinalized(PyObject *obj)
384422
// bpo-39573 added Py_IS_TYPE() to Python 3.9.0a4
385423
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE)
386424
PYCAPI_COMPAT_STATIC_INLINE(int)
387-
_Py_IS_TYPE(const PyObject *ob, const PyTypeObject *type) {
388-
return ob->ob_type == type;
425+
_Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
426+
return Py_TYPE(ob) == type;
389427
}
390-
#define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST_CONST(ob), type)
428+
#define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST(ob), type)
391429
#endif
392430

393431

@@ -430,6 +468,44 @@ PyFloat_Unpack8(const char *p, int le)
430468
#endif
431469

432470

471+
// gh-92154 added PyCode_GetCode() to Python 3.11.0b1
472+
#if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION)
473+
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
474+
PyCode_GetCode(PyCodeObject *code)
475+
{
476+
return Py_NewRef(code->co_code);
477+
}
478+
#endif
479+
480+
481+
// gh-95008 added PyCode_GetVarnames() to Python 3.11.0rc1
482+
#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)
483+
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
484+
PyCode_GetVarnames(PyCodeObject *code)
485+
{
486+
return Py_NewRef(code->co_varnames);
487+
}
488+
#endif
489+
490+
// gh-95008 added PyCode_GetFreevars() to Python 3.11.0rc1
491+
#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)
492+
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
493+
PyCode_GetFreevars(PyCodeObject *code)
494+
{
495+
return Py_NewRef(code->co_freevars);
496+
}
497+
#endif
498+
499+
// gh-95008 added PyCode_GetCellvars() to Python 3.11.0rc1
500+
#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)
501+
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
502+
PyCode_GetCellvars(PyCodeObject *code)
503+
{
504+
return Py_NewRef(code->co_cellvars);
505+
}
506+
#endif
507+
508+
433509
// Py_UNUSED() was added to Python 3.4.0b2.
434510
#if PY_VERSION_HEX < 0x030400B2 && !defined(Py_UNUSED)
435511
# if defined(__GNUC__) || defined(__clang__)

0 commit comments

Comments
 (0)