Skip to content

Commit

Permalink
Rename to PyLong_AsNativeBytes
Browse files Browse the repository at this point in the history
  • Loading branch information
zooba committed Feb 7, 2024
1 parent 22c2a64 commit 6e1a89a
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 48 deletions.
8 changes: 4 additions & 4 deletions Doc/c-api/long.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,18 +113,18 @@ 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.
.. 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.
Expand Down Expand Up @@ -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*::
Expand Down
7 changes: 4 additions & 3 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ Tier 2 IR by Mark Shannon and Guido van Rossum.
Tier 2 optimizer by Ken Jin.)



Deprecated
==========

Expand Down Expand Up @@ -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`.)


Expand Down
18 changes: 11 additions & 7 deletions Include/cpython/longobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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);
Expand Down
39 changes: 21 additions & 18 deletions Lib/test/test_capi/test_long.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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}, <big>)")
self.assertEqual(expect_n, asnativebytes(v, buffer, n, 0),
f"PyLong_AsNativeBytes(v, buffer, {n}, <big>)")
self.assertEqual(expect_be, buffer[:n], "<big>")
self.assertEqual(expect_n, copybits(v, buffer, n, 1),
f"PyLong_CopyBits(v, buffer, {n}, <little>)")
self.assertEqual(expect_n, asnativebytes(v, buffer, n, 1),
f"PyLong_AsNativeBytes(v, buffer, {n}, <little>)")
self.assertEqual(expect_le, buffer[:n], "<little>")

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)
Expand All @@ -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}, <big>)")
self.assertEqual(expect_s, frombits(v_le, n, 1, 1),
f"PyLong_FromBits(buffer, {n}, <little>)")
self.assertEqual(expect_u, frombits(v_be, n, 0, 0),
f"PyLong_FromUnsignedBits(buffer, {n}, <big>)")
self.assertEqual(expect_u, frombits(v_le, n, 1, 0),
f"PyLong_FromUnsignedBits(buffer, {n}, <little>)")
self.assertEqual(expect_s, fromnativebytes(v_be, n, 0, 1),
f"PyLong_FromNativeBytes(buffer, {n}, <big>)")
self.assertEqual(expect_s, fromnativebytes(v_le, n, 1, 1),
f"PyLong_FromNativeBytes(buffer, {n}, <little>)")
self.assertEqual(expect_u, fromnativebytes(v_be, n, 0, 0),
f"PyLong_FromUnsignedNativeBytes(buffer, {n}, <big>)")
self.assertEqual(expect_u, fromnativebytes(v_le, n, 1, 0),
f"PyLong_FromUnsignedNativeBytes(buffer, {n}, <little>)")

if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Adds :c:func:`PyLong_AsNativeBytes`, :c:func:`PyLong_FromNativeBytes` and
:c:func:`PyLong_FromUnsignedNativeBytes` functions.

This file was deleted.

14 changes: 7 additions & 7 deletions Modules/_testcapi/long.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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_;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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},
};

Expand Down
14 changes: 7 additions & 7 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
}

Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand Down

0 comments on commit 6e1a89a

Please sign in to comment.