From 6e1a89a41cceaa5e14191b30a5bd231f080661c8 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 7 Feb 2024 20:44:57 +0000 Subject: [PATCH] Rename to PyLong_AsNativeBytes --- Doc/c-api/long.rst | 8 ++-- Doc/whatsnew/3.13.rst | 7 ++-- Include/cpython/longobject.h | 18 +++++---- Lib/test/test_capi/test_long.py | 39 ++++++++++--------- ...-02-05-17-11-15.gh-issue-111140.WMEjid.rst | 2 + ...-02-05-17-11-15.gh-issue-111140.WMEjid.rst | 2 - Modules/_testcapi/long.c | 14 +++---- Objects/longobject.c | 14 +++---- 8 files changed, 56 insertions(+), 48 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2024-02-05-17-11-15.gh-issue-111140.WMEjid.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-02-05-17-11-15.gh-issue-111140.WMEjid.rst diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index f7488c81d4bd39..f4c70b951df403 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -113,10 +113,10 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. retrieved from the resulting value using :c:func:`PyLong_AsVoidPtr`. -.. c:function:: PyObject* PyLong_FromBits(const void* buffer, size_t n_bytes, int endianness) +.. c:function:: PyObject* PyLong_FromNativeBytes(const void* buffer, size_t n_bytes, int endianness) Create a Python integer from the value contained in the first *n_bytes* of - *buffer*, interpreted as twos-complement. + *buffer*, interpreted as a two's-complement signed number. *endianness* may be passed ``-1`` for the native endian that CPython was compiled with, or ``0`` for big endian and ``1`` for little. @@ -124,7 +124,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionadded:: 3.13 -.. c:function:: PyObject* PyLong_FromUnsignedBits(const void* buffer, size_t n_bytes, int endianness) +.. c:function:: PyObject* PyLong_FromUnsignedNativeBytes(const void* buffer, size_t n_bytes, int endianness) Create a Python integer from the value contained in the first *n_bytes* of *buffer*, interpreted as an unsigned number. @@ -354,7 +354,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Returns ``NULL`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. -.. c:function:: int PyLong_CopyBits(PyObject *pylong, void* buffer, size_t n_bytes, int endianness) +.. c:function:: int PyLong_AsNativeBytes(PyObject *pylong, void* buffer, size_t n_bytes, int endianness) Copy the Python integer value to a native *buffer* of size *n_bytes*:: diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 2782cf78c246b6..bd9b002e13fb60 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -560,6 +560,7 @@ Tier 2 IR by Mark Shannon and Guido van Rossum. Tier 2 optimizer by Ken Jin.) + Deprecated ========== @@ -1490,9 +1491,9 @@ New Features * Add :c:func:`Py_HashPointer` function to hash a pointer. (Contributed by Victor Stinner in :gh:`111545`.) -* Add :c:func:`PyLong_CopyBits`, :c:func:`PyLong_FromBits` and - :c:func:`PyLong_FromUnsignedBits` functions to simplify converting between - native integer types and Python ``int`` objects. +* Add :c:func:`PyLong_AsNativeBytes`, :c:func:`PyLong_FromNativeBytes` and + :c:func:`PyLong_FromUnsignedNativeBytes` functions to simplify converting + between native integer types and Python ``int`` objects. (Contributed by Steve Dower in :gh:`111140`.) diff --git a/Include/cpython/longobject.h b/Include/cpython/longobject.h index 94852325c05a57..1675ee6d0dbaf6 100644 --- a/Include/cpython/longobject.h +++ b/Include/cpython/longobject.h @@ -4,10 +4,14 @@ PyAPI_FUNC(PyObject*) PyLong_FromUnicodeObject(PyObject *u, int base); -/* PyLong_CopyBits: Copy the integer value to a native buffer. +/* PyLong_AsNativeBytes: Copy the integer value to a native variable. + buffer points to the first byte of the variable. n_bytes is the number of bytes available in the buffer. Pass 0 to request the required size for the value. endianness is -1 for native endian, 0 for big endian or 1 for little. + Big endian mode will write the most significant byte into the address + directly referenced by buffer; little endian will write the least significant + byte into that address. If an exception is raised, returns a negative value. Otherwise, returns the number of bytes that are required to store the value. @@ -19,20 +23,20 @@ PyAPI_FUNC(PyObject*) PyLong_FromUnicodeObject(PyObject *u, int base); may be larger than necessary - this function is not an accurate way to calculate the bit length of an integer object. */ -PyAPI_FUNC(int) PyLong_CopyBits(PyObject* v, void* buffer, size_t n_bytes, +PyAPI_FUNC(int) PyLong_AsNativeBytes(PyObject* v, void* buffer, size_t n_bytes, int endianness); -/* PyLong_FromBits: Create an int value from a native integer +/* PyLong_FromNativeBytes: Create an int value from a native integer n_bytes is the number of bytes to read from the buffer. Passing 0 will always produce the zero int. - PyLong_FromUnsignedBits always produces a non-negative int. + PyLong_FromUnsignedNativeBytes always produces a non-negative int. endianness is -1 for native endian, 0 for big endian or 1 for little. Returns the int object, or NULL with an exception set. */ -PyAPI_FUNC(PyObject*) PyLong_FromBits(const void* buffer, size_t n_bytes, - int endianness); -PyAPI_FUNC(PyObject*) PyLong_FromUnsignedBits(const void* buffer, size_t n_bytes, +PyAPI_FUNC(PyObject*) PyLong_FromNativeBytes(const void* buffer, size_t n_bytes, int endianness); +PyAPI_FUNC(PyObject*) PyLong_FromUnsignedNativeBytes(const void* buffer, + size_t n_bytes, int endianness); PyAPI_FUNC(int) PyUnstable_Long_IsCompact(const PyLongObject* op); PyAPI_FUNC(Py_ssize_t) PyUnstable_Long_CompactValue(const PyLongObject* op); diff --git a/Lib/test/test_capi/test_long.py b/Lib/test/test_capi/test_long.py index 20e2b7e3b17a90..140c257d8c9ced 100644 --- a/Lib/test/test_capi/test_long.py +++ b/Lib/test/test_capi/test_long.py @@ -424,9 +424,9 @@ def test_long_asvoidptr(self): self.assertRaises(OverflowError, asvoidptr, -2**1000) # CRASHES asvoidptr(NULL) - def test_long_copybits(self): + def test_long_asnativebytes(self): import math - from _testcapi import pylong_copybits as copybits, SIZE_MAX + from _testcapi import pylong_asnativebytes as asnativebytes, SIZE_MAX # Abbreviate sizeof(Py_ssize_t) to SZ because we use it a lot SZ = int(math.ceil(math.log(SIZE_MAX + 1) / math.log(2)) / 8) @@ -451,8 +451,8 @@ def test_long_copybits(self): ]: with self.subTest(f"sizeof-{v:X}"): buffer = bytearray(1) - self.assertEqual(expect, copybits(v, buffer, 0, -1), - "PyLong_CopyBits(v, NULL, 0, -1)") + self.assertEqual(expect, asnativebytes(v, buffer, 0, -1), + "PyLong_AsNativeBytes(v, NULL, 0, -1)") # We request as many bytes as `expect_be` contains, and always check # the result (both big and little endian). We check the return value @@ -507,16 +507,19 @@ def test_long_copybits(self): buffer = bytearray(n) expect_le = expect_be[::-1] - self.assertEqual(expect_n, copybits(v, buffer, n, 0), - f"PyLong_CopyBits(v, buffer, {n}, )") + self.assertEqual(expect_n, asnativebytes(v, buffer, n, 0), + f"PyLong_AsNativeBytes(v, buffer, {n}, )") self.assertEqual(expect_be, buffer[:n], "") - self.assertEqual(expect_n, copybits(v, buffer, n, 1), - f"PyLong_CopyBits(v, buffer, {n}, )") + self.assertEqual(expect_n, asnativebytes(v, buffer, n, 1), + f"PyLong_AsNativeBytes(v, buffer, {n}, )") self.assertEqual(expect_le, buffer[:n], "") - def test_long_frombits(self): + def test_long_fromnativebytes(self): import math - from _testcapi import pylong_frombits as frombits, SIZE_MAX + from _testcapi import ( + pylong_fromnativebytes as fromnativebytes, + SIZE_MAX, + ) # Abbreviate sizeof(Py_ssize_t) to SZ because we use it a lot SZ = int(math.ceil(math.log(SIZE_MAX + 1) / math.log(2)) / 8) @@ -534,14 +537,14 @@ def test_long_frombits(self): n = len(v_be) v_le = v_be[::-1] - self.assertEqual(expect_s, frombits(v_be, n, 0, 1), - f"PyLong_FromBits(buffer, {n}, )") - self.assertEqual(expect_s, frombits(v_le, n, 1, 1), - f"PyLong_FromBits(buffer, {n}, )") - self.assertEqual(expect_u, frombits(v_be, n, 0, 0), - f"PyLong_FromUnsignedBits(buffer, {n}, )") - self.assertEqual(expect_u, frombits(v_le, n, 1, 0), - f"PyLong_FromUnsignedBits(buffer, {n}, )") + self.assertEqual(expect_s, fromnativebytes(v_be, n, 0, 1), + f"PyLong_FromNativeBytes(buffer, {n}, )") + self.assertEqual(expect_s, fromnativebytes(v_le, n, 1, 1), + f"PyLong_FromNativeBytes(buffer, {n}, )") + self.assertEqual(expect_u, fromnativebytes(v_be, n, 0, 0), + f"PyLong_FromUnsignedNativeBytes(buffer, {n}, )") + self.assertEqual(expect_u, fromnativebytes(v_le, n, 1, 0), + f"PyLong_FromUnsignedNativeBytes(buffer, {n}, )") if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/C API/2024-02-05-17-11-15.gh-issue-111140.WMEjid.rst b/Misc/NEWS.d/next/C API/2024-02-05-17-11-15.gh-issue-111140.WMEjid.rst new file mode 100644 index 00000000000000..a8aa191b5eb3ba --- /dev/null +++ b/Misc/NEWS.d/next/C API/2024-02-05-17-11-15.gh-issue-111140.WMEjid.rst @@ -0,0 +1,2 @@ +Adds :c:func:`PyLong_AsNativeBytes`, :c:func:`PyLong_FromNativeBytes` and +:c:func:`PyLong_FromUnsignedNativeBytes` functions. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-02-05-17-11-15.gh-issue-111140.WMEjid.rst b/Misc/NEWS.d/next/Core and Builtins/2024-02-05-17-11-15.gh-issue-111140.WMEjid.rst deleted file mode 100644 index c6f45861b703b9..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-02-05-17-11-15.gh-issue-111140.WMEjid.rst +++ /dev/null @@ -1,2 +0,0 @@ -Adds :c:func:`PyLong_CopyBits`, :c:func:`PyLong_FromBits` and -:c:func:`PyLong_FromUnsignedBits` functions. diff --git a/Modules/_testcapi/long.c b/Modules/_testcapi/long.c index 9694d3c00eae36..1ea7baac57c76e 100644 --- a/Modules/_testcapi/long.c +++ b/Modules/_testcapi/long.c @@ -777,7 +777,7 @@ pylong_asvoidptr(PyObject *module, PyObject *arg) } static PyObject * -pylong_copybits(PyObject *module, PyObject *args) +pylong_asnativebytes(PyObject *module, PyObject *args) { PyObject *v; Py_buffer buffer; @@ -795,13 +795,13 @@ pylong_copybits(PyObject *module, PyObject *args) PyBuffer_Release(&buffer); return NULL; } - int res = PyLong_CopyBits(v, buffer.buf, n, (int)endianness); + int res = PyLong_AsNativeBytes(v, buffer.buf, n, (int)endianness); PyBuffer_Release(&buffer); return res >= 0 ? PyLong_FromLong(res) : NULL; } static PyObject * -pylong_frombits(PyObject *module, PyObject *args) +pylong_fromnativebytes(PyObject *module, PyObject *args) { Py_buffer buffer; Py_ssize_t n, endianness, signed_; @@ -814,8 +814,8 @@ pylong_frombits(PyObject *module, PyObject *args) return NULL; } PyObject *res = signed_ - ? PyLong_FromBits(buffer.buf, n, (int)endianness) - : PyLong_FromUnsignedBits(buffer.buf, n, (int)endianness); + ? PyLong_FromNativeBytes(buffer.buf, n, (int)endianness) + : PyLong_FromUnsignedNativeBytes(buffer.buf, n, (int)endianness); PyBuffer_Release(&buffer); return res; } @@ -849,8 +849,8 @@ static PyMethodDef test_methods[] = { {"pylong_as_size_t", pylong_as_size_t, METH_O}, {"pylong_asdouble", pylong_asdouble, METH_O}, {"pylong_asvoidptr", pylong_asvoidptr, METH_O}, - {"pylong_copybits", pylong_copybits, METH_VARARGS}, - {"pylong_frombits", pylong_frombits, METH_VARARGS}, + {"pylong_asnativebytes", pylong_asnativebytes, METH_VARARGS}, + {"pylong_fromnativebytes", pylong_fromnativebytes, METH_VARARGS}, {NULL}, }; diff --git a/Objects/longobject.c b/Objects/longobject.c index 66022df3c43f7f..1a01123aa7cab1 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -971,9 +971,9 @@ _PyLong_AsByteArray(PyLongObject* v, It's crucial that every Python digit except for the MSD contribute exactly PyLong_SHIFT bits to the total, so first assert that the int is normalized. - NOTE: PyLong_CopyBits() assumes that this function will fill in 'n' bytes - even if it eventually fails to convert the whole number. Make sure you - account for that if you are changing this algorithm to return without + NOTE: PyLong_AsNativeBytes() assumes that this function will fill in 'n' + bytes even if it eventually fails to convert the whole number. Make sure + you account for that if you are changing this algorithm to return without doing that. */ assert(ndigits == 0 || v->long_value.ob_digit[ndigits - 1] != 0); @@ -1081,7 +1081,7 @@ _fits_in_n_bits(Py_ssize_t v, Py_ssize_t n) } int -PyLong_CopyBits(PyObject* vv, void* buffer, size_t n, int endianness) +PyLong_AsNativeBytes(PyObject* vv, void* buffer, size_t n, int endianness) { PyLongObject *v; union { @@ -1097,7 +1097,7 @@ PyLong_CopyBits(PyObject* vv, void* buffer, size_t n, int endianness) } if ((size_t)(int)n != n || (int)n < 0) { - PyErr_SetString(PyExc_SystemError, "n_bytes too big to copy"); + PyErr_SetString(PyExc_SystemError, "n_bytes too big to convert"); return -1; } @@ -1218,7 +1218,7 @@ PyLong_CopyBits(PyObject* vv, void* buffer, size_t n, int endianness) PyObject * -PyLong_FromBits(const void* buffer, size_t n, int endianness) +PyLong_FromNativeBytes(const void* buffer, size_t n, int endianness) { if (!buffer) { PyErr_BadInternalCall(); @@ -1240,7 +1240,7 @@ PyLong_FromBits(const void* buffer, size_t n, int endianness) PyObject * -PyLong_FromUnsignedBits(const void* buffer, size_t n, int endianness) +PyLong_FromUnsignedNativeBytes(const void* buffer, size_t n, int endianness) { if (!buffer) { PyErr_BadInternalCall();