| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 900c130 commit 61709bf
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,6 +29,42 @@ Latest version of the header file: | |||
| 29 | 29 | Python 3.14 | |
| 30 | 30 | ----------- | |
| 31 | 31 | ||
| 32 | + .. c:struct:: PyLongLayout | ||
| 33 | + | ||
| 34 | + See `PyLongLayout documentation <https://docs.python.org/dev/c-api/long.html#c.PyLongLayout>`__. | ||
| 35 | + | ||
| 36 | + .. c:function:: const PyLongLayout* PyLong_GetNativeLayout(void) | ||
| 37 | + | ||
| 38 | + See `PyLong_GetNativeLayout() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_GetNativeLayout>`__. | ||
| 39 | + | ||
| 40 | + .. c:struct:: PyLongExport | ||
| 41 | + | ||
| 42 | + See `PyLongExport documentation <https://docs.python.org/dev/c-api/long.html#c.PyLongExport>`__. | ||
| 43 | + | ||
| 44 | + .. c:function:: int PyLong_Export(PyObject *obj, PyLongExport *export_long) | ||
| 45 | + | ||
| 46 | + See `PyLong_Export() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_Export>`__. | ||
| 47 | + | ||
| 48 | + .. c:function:: void PyLong_FreeExport(PyLongExport *export_long) | ||
| 49 | + | ||
| 50 | + See `PyLong_FreeExport() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_FreeExport>`__. | ||
| 51 | + | ||
| 52 | + .. c:struct:: PyLongWriter | ||
| 53 | + | ||
| 54 | + See `PyLongWriter documentation <https://docs.python.org/dev/c-api/long.html#c.PyLongWriter>`__. | ||
| 55 | + | ||
| 56 | + .. c:function:: PyLongWriter* PyLongWriter_Create(int negative, Py_ssize_t ndigits, void **digits) | ||
| 57 | + | ||
| 58 | + See `PyLongWriter_Create() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLongWriter_Create>`__. | ||
| 59 | + | ||
| 60 | + .. c:function:: PyObject* PyLongWriter_Finish(PyLongWriter *writer) | ||
| 61 | + | ||
| 62 | + See `PyLongWriter_Finish() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLongWriter_Finish>`__. | ||
| 63 | + | ||
| 64 | + .. c:function:: void PyLongWriter_Discard(PyLongWriter *writer) | ||
| 65 | + | ||
| 66 | + See `PyLongWriter_Discard() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLongWriter_Discard>`__. | ||
| 67 | + | ||
| 32 | 68 | .. c:function:: int PyLong_IsPositive(PyObject *obj) | |
| 33 | 69 | ||
| 34 | 70 | See `PyLong_IsPositive() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_IsPositive>`__. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,18 @@ | |||
| 1 | 1 | Changelog | |
| 2 | 2 | ========= | |
| 3 | 3 | ||
| 4 | + * 2024-12-13: Add functions and structs: | ||
| 5 | + | ||
| 6 | + * ``PyLongLayout`` | ||
| 7 | + * ``PyLong_GetNativeLayout()`` | ||
| 8 | + * ``PyLongExport`` | ||
| 9 | + * ``PyLong_Export()`` | ||
| 10 | + * ``PyLong_FreeExport()`` | ||
| 11 | + * ``PyLongWriter`` | ||
| 12 | + * ``PyLongWriter_Create()`` | ||
| 13 | + * ``PyLongWriter_Finish()`` | ||
| 14 | + * ``PyLongWriter_Discard()`` | ||
| 15 | + | ||
| 4 | 16 | * 2024-11-12: Add functions: | |
| 5 | 17 | ||
| 6 | 18 | * ``PyLong_IsPositive()`` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1720,6 +1720,185 @@ static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue) | |||
| 1720 | 1720 | #endif | |
| 1721 | 1721 | ||
| 1722 | 1722 | ||
| 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 | + | ||
| 1723 | 1902 | #ifdef __cplusplus | |
| 1724 | 1903 | } | |
| 1725 | 1904 | #endif | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1426,6 +1426,50 @@ test_long_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) | |||
| 1426 | 1426 | assert(PyLong_IsNegative(obj) == 0); | |
| 1427 | 1427 | assert(PyLong_IsZero(obj) == 0); | |
| 1428 | 1428 | ||
| 1429 | + #if defined(PYTHON3) && !defined(PYPY_VERSION) | ||
| 1430 | + // test import/export API | ||
| 1431 | + digit *digits; | ||
| 1432 | + PyLongWriter *writer; | ||
| 1433 | + static PyLongExport long_export; | ||
| 1434 | + | ||
| 1435 | + writer = PyLongWriter_Create(1, 1, (void**)&digits); | ||
| 1436 | + PyLongWriter_Discard(writer); | ||
| 1437 | + | ||
| 1438 | + writer = PyLongWriter_Create(1, 1, (void**)&digits); | ||
| 1439 | + digits[0] = 123; | ||
| 1440 | + obj = PyLongWriter_Finish(writer); | ||
| 1441 | + | ||
| 1442 | + check_int(obj, -123); | ||
| 1443 | + PyLong_Export(obj, &long_export); | ||
| 1444 | + assert(long_export.value == -123); | ||
| 1445 | + assert(long_export.digits == NULL); | ||
| 1446 | + PyLong_FreeExport(&long_export); | ||
| 1447 | + Py_DECREF(obj); | ||
| 1448 | + | ||
| 1449 | + writer = PyLongWriter_Create(0, 5, (void**)&digits); | ||
| 1450 | + digits[0] = 1; | ||
| 1451 | + digits[1] = 0; | ||
| 1452 | + digits[2] = 0; | ||
| 1453 | + digits[3] = 0; | ||
| 1454 | + digits[4] = 1; | ||
| 1455 | + obj = PyLongWriter_Finish(writer); | ||
| 1456 | + | ||
| 1457 | + PyLong_Export(obj, &long_export); | ||
| 1458 | + assert(long_export.value == 0); | ||
| 1459 | + digits = (digit*)long_export.digits; | ||
| 1460 | + assert(digits[0] == 1); | ||
| 1461 | + assert(digits[1] == 0); | ||
| 1462 | + assert(digits[2] == 0); | ||
| 1463 | + assert(digits[3] == 0); | ||
| 1464 | + assert(digits[4] == 1); | ||
| 1465 | + PyLong_FreeExport(&long_export); | ||
| 1466 | + Py_DECREF(obj); | ||
| 1467 | + | ||
| 1468 | + const PyLongLayout *layout = PyLong_GetNativeLayout(); | ||
| 1469 | + assert(layout->digits_order == -1); | ||
| 1470 | + assert(layout->digit_size == sizeof(digit)); | ||
| 1471 | + #endif // defined(PYTHON3) && !defined(PYPY_VERSION) | ||
| 1472 | + | ||
| 1429 | 1473 | Py_RETURN_NONE; | |
| 1430 | 1474 | } | |
| 1431 | 1475 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments