@@ -1720,6 +1720,185 @@ static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue)
17201720#endif
17211721
17221722
1723+ // gh-102471 added import and export API for integers to 3.14.0a2.
1724+ #if PY_VERSION_HEX < 0x030E00A2 && PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
1725+ // Helpers to access PyLongObject internals.
1726+ static inline void
1727+ _PyLong_SetSignAndDigitCount (PyLongObject *op, int sign, Py_ssize_t size)
1728+ {
1729+ #if PY_VERSION_HEX >= 0x030C0000
1730+ op->long_value .lv_tag = (uintptr_t )(1 - sign) | ((uintptr_t )(size) << 3 );
1731+ #elif PY_VERSION_HEX >= 0x030900A4
1732+ Py_SET_SIZE (op, sign * size);
1733+ #else
1734+ Py_SIZE (op) = sign * size;
1735+ #endif
1736+ }
1737+
1738+ static inline Py_ssize_t
1739+ _PyLong_DigitCount (const PyLongObject *op)
1740+ {
1741+ #if PY_VERSION_HEX >= 0x030C0000
1742+ return (Py_ssize_t)(op->long_value .lv_tag >> 3 );
1743+ #else
1744+ return _PyLong_Sign ((PyObject*)op) < 0 ? -Py_SIZE (op) : Py_SIZE (op);
1745+ #endif
1746+ }
1747+
1748+ static inline digit*
1749+ _PyLong_GetDigits (const PyLongObject *op)
1750+ {
1751+ #if PY_VERSION_HEX >= 0x030C0000
1752+ return (digit*)(op->long_value .ob_digit );
1753+ #else
1754+ return (digit*)(op->ob_digit );
1755+ #endif
1756+ }
1757+
1758+ typedef struct PyLongLayout {
1759+ uint8_t bits_per_digit;
1760+ uint8_t digit_size;
1761+ int8_t digits_order;
1762+ int8_t digit_endianness;
1763+ } PyLongLayout;
1764+
1765+ typedef struct PyLongExport {
1766+ int64_t value;
1767+ uint8_t negative;
1768+ Py_ssize_t ndigits;
1769+ const void *digits;
1770+ Py_uintptr_t _reserved;
1771+ } PyLongExport;
1772+
1773+ typedef struct PyLongWriter PyLongWriter;
1774+
1775+ static inline const PyLongLayout*
1776+ PyLong_GetNativeLayout (void )
1777+ {
1778+ static const PyLongLayout PyLong_LAYOUT = {
1779+ PyLong_SHIFT,
1780+ sizeof (digit),
1781+ -1 , // least significant first
1782+ PY_LITTLE_ENDIAN ? -1 : 1 ,
1783+ };
1784+
1785+ return &PyLong_LAYOUT;
1786+ }
1787+
1788+ static inline int
1789+ PyLong_Export (PyObject *obj, PyLongExport *export_long)
1790+ {
1791+ if (!PyLong_Check (obj)) {
1792+ memset (export_long, 0 , sizeof (*export_long));
1793+ PyErr_Format (PyExc_TypeError, " expected int, got %s" ,
1794+ Py_TYPE (obj)->tp_name );
1795+ return -1 ;
1796+ }
1797+
1798+ // Fast-path: try to convert to a int64_t
1799+ PyLongObject *self = (PyLongObject*)obj;
1800+ int overflow;
1801+ #if SIZEOF_LONG == 8
1802+ long value = PyLong_AsLongAndOverflow (obj, &overflow);
1803+ #else
1804+ // Windows has 32-bit long, so use 64-bit long long instead
1805+ long long value = PyLong_AsLongLongAndOverflow (obj, &overflow);
1806+ #endif
1807+ Py_BUILD_ASSERT (sizeof (value) == sizeof (int64_t ));
1808+ // the function cannot fail since obj is a PyLongObject
1809+ assert (!(value == -1 && PyErr_Occurred ()));
1810+
1811+ if (!overflow) {
1812+ export_long->value = value;
1813+ export_long->negative = 0 ;
1814+ export_long->ndigits = 0 ;
1815+ export_long->digits = 0 ;
1816+ export_long->_reserved = 0 ;
1817+ }
1818+ else {
1819+ export_long->value = 0 ;
1820+ export_long->negative = _PyLong_Sign (obj) < 0 ;
1821+ export_long->ndigits = _PyLong_DigitCount (self);
1822+ if (export_long->ndigits == 0 ) {
1823+ export_long->ndigits = 1 ;
1824+ }
1825+ export_long->digits = _PyLong_GetDigits (self);
1826+ export_long->_reserved = (Py_uintptr_t)Py_NewRef (obj);
1827+ }
1828+ return 0 ;
1829+ }
1830+
1831+ static inline void
1832+ PyLong_FreeExport (PyLongExport *export_long)
1833+ {
1834+ PyObject *obj = (PyObject*)export_long->_reserved ;
1835+
1836+ if (obj) {
1837+ export_long->_reserved = 0 ;
1838+ Py_DECREF (obj);
1839+ }
1840+ }
1841+
1842+ static inline PyLongWriter*
1843+ PyLongWriter_Create (int negative, Py_ssize_t ndigits, void **digits)
1844+ {
1845+ if (ndigits <= 0 ) {
1846+ PyErr_SetString (PyExc_ValueError, " ndigits must be positive" );
1847+ return NULL ;
1848+ }
1849+ assert (digits != NULL );
1850+
1851+ PyLongObject *obj = _PyLong_New (ndigits);
1852+ if (obj == NULL ) {
1853+ return NULL ;
1854+ }
1855+ _PyLong_SetSignAndDigitCount (obj, negative?-1 :1 , ndigits);
1856+
1857+ *digits = _PyLong_GetDigits (obj);
1858+ return (PyLongWriter*)obj;
1859+ }
1860+
1861+ static inline void
1862+ PyLongWriter_Discard (PyLongWriter *writer)
1863+ {
1864+ PyLongObject *obj = (PyLongObject *)writer;
1865+
1866+ assert (Py_REFCNT (obj) == 1 );
1867+ Py_DECREF (obj);
1868+ }
1869+
1870+ static inline PyObject*
1871+ PyLongWriter_Finish (PyLongWriter *writer)
1872+ {
1873+ PyObject *obj = (PyObject *)writer;
1874+ PyLongObject *self = (PyLongObject*)obj;
1875+ Py_ssize_t j = _PyLong_DigitCount (self);
1876+ Py_ssize_t i = j;
1877+ int sign = _PyLong_Sign (obj);
1878+
1879+ assert (Py_REFCNT (obj) == 1 );
1880+
1881+ // Normalize and get singleton if possible
1882+ while (i > 0 && _PyLong_GetDigits (self)[i-1 ] == 0 ) {
1883+ --i;
1884+ }
1885+ if (i != j) {
1886+ if (i == 0 ) {
1887+ sign = 0 ;
1888+ }
1889+ _PyLong_SetSignAndDigitCount (self, sign, i);
1890+ }
1891+ if (i <= 1 ) {
1892+ long val = sign * (long )(_PyLong_GetDigits (self)[0 ]);
1893+ Py_DECREF (obj);
1894+ return PyLong_FromLong (val);
1895+ }
1896+
1897+ return obj;
1898+ }
1899+ #endif
1900+
1901+
17231902#ifdef __cplusplus
17241903}
17251904#endif
0 commit comments