Skip to content

Commit 645081f

Browse files
authored
1 parent aa0b6f0 commit 645081f

File tree

1 file changed

+249
-6
lines changed

1 file changed

+249
-6
lines changed

mypyc/lib-rt/pythoncapi_compat.h

Lines changed: 249 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// https://github.com/python/pythoncapi_compat
88
//
99
// Latest version:
10-
// https://raw.githubusercontent.com/python/pythoncapi_compat/master/pythoncapi_compat.h
10+
// https://raw.githubusercontent.com/python/pythoncapi-compat/main/pythoncapi_compat.h
1111
//
1212
// SPDX-License-Identifier: 0BSD
1313

@@ -24,6 +24,9 @@ extern "C" {
2424
#if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION)
2525
# include "frameobject.h" // PyFrameObject, PyFrame_GetBack()
2626
#endif
27+
#if PY_VERSION_HEX < 0x030C00A3
28+
# include <structmember.h> // T_SHORT, READONLY
29+
#endif
2730

2831

2932
#ifndef _Py_CAST
@@ -287,7 +290,7 @@ PyFrame_GetVarString(PyFrameObject *frame, const char *name)
287290

288291

289292
// bpo-39947 added PyThreadState_GetInterpreter() to Python 3.9.0a5
290-
#if PY_VERSION_HEX < 0x030900A5 || defined(PYPY_VERSION)
293+
#if PY_VERSION_HEX < 0x030900A5 || (defined(PYPY_VERSION) && PY_VERSION_HEX < 0x030B0000)
291294
static inline PyInterpreterState *
292295
PyThreadState_GetInterpreter(PyThreadState *tstate)
293296
{
@@ -918,7 +921,7 @@ static inline int
918921
PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
919922
{
920923
PyObject **dict = _PyObject_GetDictPtr(obj);
921-
if (*dict == NULL) {
924+
if (dict == NULL || *dict == NULL) {
922925
return -1;
923926
}
924927
Py_VISIT(*dict);
@@ -929,7 +932,7 @@ static inline void
929932
PyObject_ClearManagedDict(PyObject *obj)
930933
{
931934
PyObject **dict = _PyObject_GetDictPtr(obj);
932-
if (*dict == NULL) {
935+
if (dict == NULL || *dict == NULL) {
933936
return;
934937
}
935938
Py_CLEAR(*dict);
@@ -1204,11 +1207,11 @@ static inline int PyTime_PerfCounter(PyTime_t *result)
12041207
#endif
12051208

12061209
// gh-111389 added hash constants to Python 3.13.0a5. These constants were
1207-
// added first as private macros to Python 3.4.0b1 and PyPy 7.3.9.
1210+
// added first as private macros to Python 3.4.0b1 and PyPy 7.3.8.
12081211
#if (!defined(PyHASH_BITS) \
12091212
&& ((!defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x030400B1) \
12101213
|| (defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03070000 \
1211-
&& PYPY_VERSION_NUM >= 0x07090000)))
1214+
&& PYPY_VERSION_NUM >= 0x07030800)))
12121215
# define PyHASH_BITS _PyHASH_BITS
12131216
# define PyHASH_MODULUS _PyHASH_MODULUS
12141217
# define PyHASH_INF _PyHASH_INF
@@ -1520,6 +1523,36 @@ static inline int PyLong_GetSign(PyObject *obj, int *sign)
15201523
}
15211524
#endif
15221525

1526+
// gh-126061 added PyLong_IsPositive/Negative/Zero() to Python in 3.14.0a2
1527+
#if PY_VERSION_HEX < 0x030E00A2
1528+
static inline int PyLong_IsPositive(PyObject *obj)
1529+
{
1530+
if (!PyLong_Check(obj)) {
1531+
PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
1532+
return -1;
1533+
}
1534+
return _PyLong_Sign(obj) == 1;
1535+
}
1536+
1537+
static inline int PyLong_IsNegative(PyObject *obj)
1538+
{
1539+
if (!PyLong_Check(obj)) {
1540+
PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
1541+
return -1;
1542+
}
1543+
return _PyLong_Sign(obj) == -1;
1544+
}
1545+
1546+
static inline int PyLong_IsZero(PyObject *obj)
1547+
{
1548+
if (!PyLong_Check(obj)) {
1549+
PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
1550+
return -1;
1551+
}
1552+
return _PyLong_Sign(obj) == 0;
1553+
}
1554+
#endif
1555+
15231556

15241557
// gh-124502 added PyUnicode_Equal() to Python 3.14.0a0
15251558
#if PY_VERSION_HEX < 0x030E00A0
@@ -1690,6 +1723,216 @@ static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue)
16901723
#endif
16911724

16921725

1726+
// gh-102471 added import and export API for integers to 3.14.0a2.
1727+
#if PY_VERSION_HEX < 0x030E00A2 && PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
1728+
// Helpers to access PyLongObject internals.
1729+
static inline void
1730+
_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
1731+
{
1732+
#if PY_VERSION_HEX >= 0x030C0000
1733+
op->long_value.lv_tag = (uintptr_t)(1 - sign) | ((uintptr_t)(size) << 3);
1734+
#elif PY_VERSION_HEX >= 0x030900A4
1735+
Py_SET_SIZE(op, sign * size);
1736+
#else
1737+
Py_SIZE(op) = sign * size;
1738+
#endif
1739+
}
1740+
1741+
static inline Py_ssize_t
1742+
_PyLong_DigitCount(const PyLongObject *op)
1743+
{
1744+
#if PY_VERSION_HEX >= 0x030C0000
1745+
return (Py_ssize_t)(op->long_value.lv_tag >> 3);
1746+
#else
1747+
return _PyLong_Sign((PyObject*)op) < 0 ? -Py_SIZE(op) : Py_SIZE(op);
1748+
#endif
1749+
}
1750+
1751+
static inline digit*
1752+
_PyLong_GetDigits(const PyLongObject *op)
1753+
{
1754+
#if PY_VERSION_HEX >= 0x030C0000
1755+
return (digit*)(op->long_value.ob_digit);
1756+
#else
1757+
return (digit*)(op->ob_digit);
1758+
#endif
1759+
}
1760+
1761+
typedef struct PyLongLayout {
1762+
uint8_t bits_per_digit;
1763+
uint8_t digit_size;
1764+
int8_t digits_order;
1765+
int8_t digit_endianness;
1766+
} PyLongLayout;
1767+
1768+
typedef struct PyLongExport {
1769+
int64_t value;
1770+
uint8_t negative;
1771+
Py_ssize_t ndigits;
1772+
const void *digits;
1773+
Py_uintptr_t _reserved;
1774+
} PyLongExport;
1775+
1776+
typedef struct PyLongWriter PyLongWriter;
1777+
1778+
static inline const PyLongLayout*
1779+
PyLong_GetNativeLayout(void)
1780+
{
1781+
static const PyLongLayout PyLong_LAYOUT = {
1782+
PyLong_SHIFT,
1783+
sizeof(digit),
1784+
-1, // least significant first
1785+
PY_LITTLE_ENDIAN ? -1 : 1,
1786+
};
1787+
1788+
return &PyLong_LAYOUT;
1789+
}
1790+
1791+
static inline int
1792+
PyLong_Export(PyObject *obj, PyLongExport *export_long)
1793+
{
1794+
if (!PyLong_Check(obj)) {
1795+
memset(export_long, 0, sizeof(*export_long));
1796+
PyErr_Format(PyExc_TypeError, "expected int, got %s",
1797+
Py_TYPE(obj)->tp_name);
1798+
return -1;
1799+
}
1800+
1801+
// Fast-path: try to convert to a int64_t
1802+
PyLongObject *self = (PyLongObject*)obj;
1803+
int overflow;
1804+
#if SIZEOF_LONG == 8
1805+
long value = PyLong_AsLongAndOverflow(obj, &overflow);
1806+
#else
1807+
// Windows has 32-bit long, so use 64-bit long long instead
1808+
long long value = PyLong_AsLongLongAndOverflow(obj, &overflow);
1809+
#endif
1810+
Py_BUILD_ASSERT(sizeof(value) == sizeof(int64_t));
1811+
// the function cannot fail since obj is a PyLongObject
1812+
assert(!(value == -1 && PyErr_Occurred()));
1813+
1814+
if (!overflow) {
1815+
export_long->value = value;
1816+
export_long->negative = 0;
1817+
export_long->ndigits = 0;
1818+
export_long->digits = 0;
1819+
export_long->_reserved = 0;
1820+
}
1821+
else {
1822+
export_long->value = 0;
1823+
export_long->negative = _PyLong_Sign(obj) < 0;
1824+
export_long->ndigits = _PyLong_DigitCount(self);
1825+
if (export_long->ndigits == 0) {
1826+
export_long->ndigits = 1;
1827+
}
1828+
export_long->digits = _PyLong_GetDigits(self);
1829+
export_long->_reserved = (Py_uintptr_t)Py_NewRef(obj);
1830+
}
1831+
return 0;
1832+
}
1833+
1834+
static inline void
1835+
PyLong_FreeExport(PyLongExport *export_long)
1836+
{
1837+
PyObject *obj = (PyObject*)export_long->_reserved;
1838+
1839+
if (obj) {
1840+
export_long->_reserved = 0;
1841+
Py_DECREF(obj);
1842+
}
1843+
}
1844+
1845+
static inline PyLongWriter*
1846+
PyLongWriter_Create(int negative, Py_ssize_t ndigits, void **digits)
1847+
{
1848+
if (ndigits <= 0) {
1849+
PyErr_SetString(PyExc_ValueError, "ndigits must be positive");
1850+
return NULL;
1851+
}
1852+
assert(digits != NULL);
1853+
1854+
PyLongObject *obj = _PyLong_New(ndigits);
1855+
if (obj == NULL) {
1856+
return NULL;
1857+
}
1858+
_PyLong_SetSignAndDigitCount(obj, negative?-1:1, ndigits);
1859+
1860+
*digits = _PyLong_GetDigits(obj);
1861+
return (PyLongWriter*)obj;
1862+
}
1863+
1864+
static inline void
1865+
PyLongWriter_Discard(PyLongWriter *writer)
1866+
{
1867+
PyLongObject *obj = (PyLongObject *)writer;
1868+
1869+
assert(Py_REFCNT(obj) == 1);
1870+
Py_DECREF(obj);
1871+
}
1872+
1873+
static inline PyObject*
1874+
PyLongWriter_Finish(PyLongWriter *writer)
1875+
{
1876+
PyObject *obj = (PyObject *)writer;
1877+
PyLongObject *self = (PyLongObject*)obj;
1878+
Py_ssize_t j = _PyLong_DigitCount(self);
1879+
Py_ssize_t i = j;
1880+
int sign = _PyLong_Sign(obj);
1881+
1882+
assert(Py_REFCNT(obj) == 1);
1883+
1884+
// Normalize and get singleton if possible
1885+
while (i > 0 && _PyLong_GetDigits(self)[i-1] == 0) {
1886+
--i;
1887+
}
1888+
if (i != j) {
1889+
if (i == 0) {
1890+
sign = 0;
1891+
}
1892+
_PyLong_SetSignAndDigitCount(self, sign, i);
1893+
}
1894+
if (i <= 1) {
1895+
long val = sign * (long)(_PyLong_GetDigits(self)[0]);
1896+
Py_DECREF(obj);
1897+
return PyLong_FromLong(val);
1898+
}
1899+
1900+
return obj;
1901+
}
1902+
#endif
1903+
1904+
1905+
#if PY_VERSION_HEX < 0x030C00A3
1906+
# define Py_T_SHORT T_SHORT
1907+
# define Py_T_INT T_INT
1908+
# define Py_T_LONG T_LONG
1909+
# define Py_T_FLOAT T_FLOAT
1910+
# define Py_T_DOUBLE T_DOUBLE
1911+
# define Py_T_STRING T_STRING
1912+
# define _Py_T_OBJECT T_OBJECT
1913+
# define Py_T_CHAR T_CHAR
1914+
# define Py_T_BYTE T_BYTE
1915+
# define Py_T_UBYTE T_UBYTE
1916+
# define Py_T_USHORT T_USHORT
1917+
# define Py_T_UINT T_UINT
1918+
# define Py_T_ULONG T_ULONG
1919+
# define Py_T_STRING_INPLACE T_STRING_INPLACE
1920+
# define Py_T_BOOL T_BOOL
1921+
# define Py_T_OBJECT_EX T_OBJECT_EX
1922+
# define Py_T_LONGLONG T_LONGLONG
1923+
# define Py_T_ULONGLONG T_ULONGLONG
1924+
# define Py_T_PYSSIZET T_PYSSIZET
1925+
1926+
# if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
1927+
# define _Py_T_NONE T_NONE
1928+
# endif
1929+
1930+
# define Py_READONLY READONLY
1931+
# define Py_AUDIT_READ READ_RESTRICTED
1932+
# define _Py_WRITE_RESTRICTED PY_WRITE_RESTRICTED
1933+
#endif
1934+
1935+
16931936
#ifdef __cplusplus
16941937
}
16951938
#endif

0 commit comments

Comments
 (0)