@@ -1720,6 +1720,187 @@ 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
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 endianness;
1763+ } PyLongLayout;
1764+
1765+ static const PyLongLayout PyLong_LAYOUT = {
1766+ .bits_per_digit = PyLong_SHIFT,
1767+ .digit_size = sizeof (digit),
1768+ .digits_order = -1 , // least significant first
1769+ .endianness = PY_LITTLE_ENDIAN ? -1 : 1 ,
1770+ };
1771+
1772+ typedef struct PyLongExport {
1773+ int64_t value;
1774+ uint8_t negative;
1775+ Py_ssize_t ndigits;
1776+ const void *digits;
1777+ Py_uintptr_t _reserved;
1778+ } PyLongExport;
1779+
1780+ typedef struct PyLongWriter PyLongWriter;
1781+
1782+ static inline const PyLongLayout*
1783+ PyLong_GetNativeLayout (void )
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+ PyErr_Format (PyExc_TypeError, " expected int, got %s" ,
1793+ Py_TYPE (obj)->tp_name );
1794+ return -1 ;
1795+ }
1796+
1797+ // Fast-path: try to convert to a int64_t
1798+ PyLongObject *self = (PyLongObject*)obj;
1799+ int overflow;
1800+ #if SIZEOF_LONG == 8
1801+ long value = PyLong_AsLongAndOverflow (obj, &overflow);
1802+ #else
1803+ // Windows has 32-bit long, so use 64-bit long long instead
1804+ long long value = PyLong_AsLongLongAndOverflow (obj, &overflow);
1805+ #endif
1806+ Py_BUILD_ASSERT (sizeof (value) == sizeof (int64_t ));
1807+ // the function cannot fail since obj is a PyLongObject
1808+ assert (!(value == -1 && PyErr_Occurred ()));
1809+
1810+ if (!overflow) {
1811+ export_long->value = value;
1812+ export_long->negative = 0 ;
1813+ export_long->ndigits = 0 ;
1814+ export_long->digits = 0 ;
1815+ export_long->_reserved = 0 ;
1816+ }
1817+ else {
1818+ export_long->value = 0 ;
1819+ export_long->negative = _PyLong_Sign (obj) < 0 ;
1820+ export_long->ndigits = _PyLong_DigitCount (self);
1821+ if (export_long->ndigits == 0 ) {
1822+ export_long->ndigits = 1 ;
1823+ }
1824+ export_long->digits = _PyLong_GetDigits (self);
1825+ export_long->_reserved = (Py_uintptr_t)Py_NewRef (obj);
1826+ }
1827+ return 0 ;
1828+ }
1829+
1830+ static inline void
1831+ PyLong_FreeExport (PyLongExport *export_long)
1832+ {
1833+ PyObject *obj = (PyObject*)export_long->_reserved ;
1834+
1835+ if (obj) {
1836+ export_long->_reserved = 0 ;
1837+ Py_DECREF (obj);
1838+ }
1839+ }
1840+
1841+ static inline PyLongWriter*
1842+ PyLongWriter_Create (int negative, Py_ssize_t ndigits, void **digits)
1843+ {
1844+ if (ndigits < 0 ) {
1845+ PyErr_SetString (PyExc_ValueError, " ndigits must be positive" );
1846+ return NULL ;
1847+ }
1848+ assert (digits != NULL );
1849+
1850+ PyLongObject *obj = _PyLong_New (ndigits);
1851+ if (obj == NULL ) {
1852+ return NULL ;
1853+ }
1854+ if (ndigits == 0 ) {
1855+ assert (_PyLong_GetDigits (obj)[0 ] == 0 );
1856+ }
1857+ _PyLong_SetSignAndDigitCount (obj, negative?-1 :1 , ndigits);
1858+
1859+ *digits = _PyLong_GetDigits (obj);
1860+ return (PyLongWriter*)obj;
1861+ }
1862+
1863+ static inline void
1864+ PyLongWriter_Discard (PyLongWriter *writer)
1865+ {
1866+ PyLongObject *obj = (PyLongObject *)writer;
1867+
1868+ assert (Py_REFCNT (obj) == 1 );
1869+ Py_DECREF (obj);
1870+ }
1871+
1872+ static inline PyObject*
1873+ PyLongWriter_Finish (PyLongWriter *writer)
1874+ {
1875+ PyObject *obj = (PyObject *)writer;
1876+ PyLongObject *self = (PyLongObject*)obj;
1877+ Py_ssize_t j = _PyLong_DigitCount (self);
1878+ Py_ssize_t i = j;
1879+ int sign = _PyLong_Sign (obj);
1880+
1881+ assert (Py_REFCNT (obj) == 1 );
1882+
1883+ // Normalize and get singleton if possible
1884+ while (i > 0 && _PyLong_GetDigits (self)[i-1 ] == 0 ) {
1885+ --i;
1886+ }
1887+ if (i != j) {
1888+ if (i == 0 ) {
1889+ sign = 0 ;
1890+ }
1891+ _PyLong_SetSignAndDigitCount (self, sign, i);
1892+ }
1893+ if (i <= 1 ) {
1894+ long val = sign*(long )(_PyLong_GetDigits (self)[0 ]);
1895+ Py_DECREF (obj);
1896+ return PyLong_FromLong (val);
1897+ }
1898+
1899+ return obj;
1900+ }
1901+ #endif
1902+
1903+
17231904#ifdef __cplusplus
17241905}
17251906#endif
0 commit comments