]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-38373: Change list overallocating strategy. (GH-18952)
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 17 Mar 2020 21:46:00 +0000 (23:46 +0200)
committerGitHub <noreply@github.com>
Tue, 17 Mar 2020 21:46:00 +0000 (23:46 +0200)
* Add padding to make the allocated size multiple of 4.
* Do not overallocate if the new size is closer to overalocated size
  than to the old size.

Misc/NEWS.d/next/Core and Builtins/2020-03-11-12-28-16.bpo-38373.FE9S21.rst [new file with mode: 0644]
Objects/listobject.c

diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-03-11-12-28-16.bpo-38373.FE9S21.rst b/Misc/NEWS.d/next/Core and Builtins/2020-03-11-12-28-16.bpo-38373.FE9S21.rst
new file mode 100644 (file)
index 0000000..83d60e0
--- /dev/null
@@ -0,0 +1,2 @@
+Chaged list overallocation strategy. It no longer overallocates if the new
+size is closer to overalocated size than to the old size and adds padding.
index 46bc7779218bcb1327d3cd2cdb3a47ed7ce2eb16..4e2b6a9c1609acf0971b3ab36cad47c2be114b58 100644 (file)
@@ -54,15 +54,17 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
      * enough to give linear-time amortized behavior over a long
      * sequence of appends() in the presence of a poorly-performing
      * system realloc().
-     * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
+     * Add padding to make the allocated size multiple of 4.
+     * The growth pattern is:  0, 4, 8, 16, 24, 32, 40, 52, 64, 76, ...
      * Note: new_allocated won't overflow because the largest possible value
      *       is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t.
      */
-    new_allocated = (size_t)newsize + (newsize >> 3) + (newsize < 9 ? 3 : 6);
-    if (new_allocated > (size_t)PY_SSIZE_T_MAX / sizeof(PyObject *)) {
-        PyErr_NoMemory();
-        return -1;
-    }
+    new_allocated = ((size_t)newsize + (newsize >> 3) + 6) & ~(size_t)3;
+    /* Do not overallocate if the new size is closer to overalocated size
+     * than to the old size.
+     */
+    if (newsize - Py_SIZE(self) > (Py_ssize_t)(new_allocated - newsize))
+        new_allocated = ((size_t)newsize + 3) & ~(size_t)3;
 
     if (newsize == 0)
         new_allocated = 0;