Skip to content

Commit 510ab7d

Browse files
cmaloneyskirpichevvstinner
authored
gh-132108: Add Buffer Protocol support to int.from_bytes to improve performance (#132109)
Speed up conversion from `bytes-like` objects like `bytearray` while keeping conversion from `bytes` stable. Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com> Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent e5b5a15 commit 510ab7d

File tree

2 files changed

+29
-8
lines changed

2 files changed

+29
-8
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Speed up :meth:`int.from_bytes` when passed object supports :ref:`buffer
2+
protocol <bufferobjects>`, like :class:`bytearray` by ~1.2x.

Objects/longobject.c

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6476,14 +6476,33 @@ int_from_bytes_impl(PyTypeObject *type, PyObject *bytes_obj,
64766476
return NULL;
64776477
}
64786478

6479-
bytes = PyObject_Bytes(bytes_obj);
6480-
if (bytes == NULL)
6481-
return NULL;
6482-
6483-
long_obj = _PyLong_FromByteArray(
6484-
(unsigned char *)PyBytes_AS_STRING(bytes), Py_SIZE(bytes),
6485-
little_endian, is_signed);
6486-
Py_DECREF(bytes);
6479+
/* Fast-path exact bytes. */
6480+
if (PyBytes_CheckExact(bytes_obj)) {
6481+
long_obj = _PyLong_FromByteArray(
6482+
(unsigned char *)PyBytes_AS_STRING(bytes_obj), Py_SIZE(bytes_obj),
6483+
little_endian, is_signed);
6484+
}
6485+
/* Use buffer protocol to avoid copies. */
6486+
else if (PyObject_CheckBuffer(bytes_obj)) {
6487+
Py_buffer view;
6488+
if (PyObject_GetBuffer(bytes_obj, &view, PyBUF_SIMPLE) != 0) {
6489+
return NULL;
6490+
}
6491+
long_obj = _PyLong_FromByteArray(view.buf, view.len, little_endian,
6492+
is_signed);
6493+
PyBuffer_Release(&view);
6494+
}
6495+
else {
6496+
/* fallback: Construct a bytes then convert. */
6497+
bytes = PyObject_Bytes(bytes_obj);
6498+
if (bytes == NULL) {
6499+
return NULL;
6500+
}
6501+
long_obj = _PyLong_FromByteArray(
6502+
(unsigned char *)PyBytes_AS_STRING(bytes), Py_SIZE(bytes),
6503+
little_endian, is_signed);
6504+
Py_DECREF(bytes);
6505+
}
64876506

64886507
if (long_obj != NULL && type != &PyLong_Type) {
64896508
Py_SETREF(long_obj, PyObject_CallOneArg((PyObject *)type, long_obj));

0 commit comments

Comments
 (0)