]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-132108: Add Buffer Protocol support to int.from_bytes to improve performance ...
authorCody Maloney <cmaloney@users.noreply.github.com>
Tue, 13 Jan 2026 09:33:26 +0000 (01:33 -0800)
committerGitHub <noreply@github.com>
Tue, 13 Jan 2026 09:33:26 +0000 (10:33 +0100)
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>
Misc/NEWS.d/next/Core_and_Builtins/2025-04-04-20-38-29.gh-issue-132108.UwZIQy.rst [new file with mode: 0644]
Objects/longobject.c

diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-04-20-38-29.gh-issue-132108.UwZIQy.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-04-20-38-29.gh-issue-132108.UwZIQy.rst
new file mode 100644 (file)
index 0000000..8c2d947
--- /dev/null
@@ -0,0 +1,2 @@
+Speed up :meth:`int.from_bytes` when passed object supports :ref:`buffer
+protocol <bufferobjects>`, like :class:`bytearray` by ~1.2x.
index 8ba1fd65078f488518e8e6942bc7479428f13e1a..74958cb8b9bbb03d3e9032d9891d0b8b1a12e9bb 100644 (file)
@@ -6476,14 +6476,33 @@ int_from_bytes_impl(PyTypeObject *type, PyObject *bytes_obj,
         return NULL;
     }
 
-    bytes = PyObject_Bytes(bytes_obj);
-    if (bytes == NULL)
-        return NULL;
-
-    long_obj = _PyLong_FromByteArray(
-        (unsigned char *)PyBytes_AS_STRING(bytes), Py_SIZE(bytes),
-        little_endian, is_signed);
-    Py_DECREF(bytes);
+    /* Fast-path exact bytes. */
+    if (PyBytes_CheckExact(bytes_obj)) {
+        long_obj = _PyLong_FromByteArray(
+            (unsigned char *)PyBytes_AS_STRING(bytes_obj), Py_SIZE(bytes_obj),
+            little_endian, is_signed);
+    }
+    /* Use buffer protocol to avoid copies. */
+    else if (PyObject_CheckBuffer(bytes_obj)) {
+        Py_buffer view;
+        if (PyObject_GetBuffer(bytes_obj, &view, PyBUF_SIMPLE) != 0) {
+            return NULL;
+        }
+        long_obj = _PyLong_FromByteArray(view.buf, view.len, little_endian,
+            is_signed);
+        PyBuffer_Release(&view);
+    }
+    else {
+        /* fallback: Construct a bytes then convert. */
+        bytes = PyObject_Bytes(bytes_obj);
+        if (bytes == NULL) {
+            return NULL;
+        }
+        long_obj = _PyLong_FromByteArray(
+            (unsigned char *)PyBytes_AS_STRING(bytes), Py_SIZE(bytes),
+            little_endian, is_signed);
+        Py_DECREF(bytes);
+    }
 
     if (long_obj != NULL && type != &PyLong_Type) {
         Py_SETREF(long_obj, PyObject_CallOneArg((PyObject *)type, long_obj));