From 0a5d672e2a539d1a988f5907b3f1541f2271654e Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Tue, 8 Mar 2022 13:38:08 +0800 Subject: [PATCH 01/15] bpo-39829: __len__() called twice in the list() constructor --- Objects/listobject.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 783ae88a17f3be..845e27f1bd001c 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -889,9 +889,16 @@ list_extend(PyListObject *self, PyObject *iterable) /* It should not be possible to allocate a list large enough to cause an overflow on any relevant platform */ assert(m < PY_SSIZE_T_MAX - n); - if (list_resize(self, m + n) < 0) { - Py_DECREF(iterable); - return NULL; + if (self->ob_item == NULL) { + if (list_preallocate_exact(self, n) < 0) { + Py_DECREF(iterable); + return NULL; + } + else { + if (list_resize(self, m + n) < 0) { + Py_DECREF(iterable); + return NULL; + } } /* note that we may still have self == iterable here for the * situation a.extend(a), but the following code works @@ -929,10 +936,16 @@ list_extend(PyListObject *self, PyObject *iterable) */ } else { - mn = m + n; - /* Make room. */ - if (list_resize(self, mn) < 0) - goto error; + if (self->ob_item == NULL) { + if (list_preallocate_exact(self, n) < 0) + goto error; + } + else { + mn = m + n; + /* Make room. */ + if (list_resize(self, mn) < 0) + goto error; + } /* Make the list sane again. */ Py_SET_SIZE(self, m); } @@ -2814,19 +2827,6 @@ list___init___impl(PyListObject *self, PyObject *iterable) (void)_list_clear(self); } if (iterable != NULL) { - if (_PyObject_HasLen(iterable)) { - Py_ssize_t iter_len = PyObject_Size(iterable); - if (iter_len == -1) { - if (!PyErr_ExceptionMatches(PyExc_TypeError)) { - return -1; - } - PyErr_Clear(); - } - if (iter_len > 0 && self->ob_item == NULL - && list_preallocate_exact(self, iter_len)) { - return -1; - } - } PyObject *rv = list_extend(self, iterable); if (rv == NULL) return -1; From ac00535bb1ecfcf6fd4566637b08e92eeb76c767 Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Tue, 8 Mar 2022 13:44:15 +0800 Subject: [PATCH 02/15] bpo-39829: __len__ called twice in the list() constructor --- Objects/listobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/listobject.c b/Objects/listobject.c index 845e27f1bd001c..7fac6ac0d004ac 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -894,6 +894,7 @@ list_extend(PyListObject *self, PyObject *iterable) Py_DECREF(iterable); return NULL; } + } else { if (list_resize(self, m + n) < 0) { Py_DECREF(iterable); From 12eba0364b67fb0d75d372b2c06ab1126cb79574 Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Tue, 8 Mar 2022 13:46:37 +0800 Subject: [PATCH 03/15] bpo-39829: __len__ called twice in the list() constructor --- Objects/listobject.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 7fac6ac0d004ac..004fb2c678a2eb 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -895,11 +895,9 @@ list_extend(PyListObject *self, PyObject *iterable) return NULL; } } - else { - if (list_resize(self, m + n) < 0) { - Py_DECREF(iterable); - return NULL; - } + else if (list_resize(self, m + n) < 0) { + Py_DECREF(iterable); + return NULL; } /* note that we may still have self == iterable here for the * situation a.extend(a), but the following code works From fc50d3676a2a13dd532036c01f2d6f7300de22c7 Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Tue, 8 Mar 2022 14:22:05 +0800 Subject: [PATCH 04/15] bpo-39829: __len__ called twice in the list() constructor --- Objects/listobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 004fb2c678a2eb..653c7fda2e801a 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -889,7 +889,7 @@ list_extend(PyListObject *self, PyObject *iterable) /* It should not be possible to allocate a list large enough to cause an overflow on any relevant platform */ assert(m < PY_SSIZE_T_MAX - n); - if (self->ob_item == NULL) { + if (n && self->ob_item == NULL) { if (list_preallocate_exact(self, n) < 0) { Py_DECREF(iterable); return NULL; @@ -935,7 +935,7 @@ list_extend(PyListObject *self, PyObject *iterable) */ } else { - if (self->ob_item == NULL) { + if (n && self->ob_item == NULL) { if (list_preallocate_exact(self, n) < 0) goto error; } From 37382e84ea003e73d73c4614ef1d93011f4dec42 Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Tue, 8 Mar 2022 20:30:42 +0800 Subject: [PATCH 05/15] bpo-43574 + bpo-39829: Optimize allocations --- Objects/listobject.c | 84 +++++++++++--------------------------------- 1 file changed, 21 insertions(+), 63 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 653c7fda2e801a..61194dce0e55ce 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -74,8 +74,9 @@ list_resize(PyListObject *self, Py_ssize_t newsize) 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; + /* Don't overallocate for lists that start empty or are set to empty. */ + if (newsize == 0 || Py_SIZE(self) == 0) + new_allocated = newsize; num_allocated_bytes = new_allocated * sizeof(PyObject *); items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes); if (items == NULL) { @@ -218,7 +219,6 @@ valid_index(Py_ssize_t i, Py_ssize_t limit) { /* The cast to size_t lets us use just a single comparison to check whether i is in the range: 0 <= i < limit. - See: Section 14.2 "Bounds Checking" in the Agner Fog optimization manual found at: https://www.agner.org/optimize/optimizing_cpp.pdf @@ -787,11 +787,9 @@ list_ass_item(PyListObject *a, Py_ssize_t i, PyObject *v) /*[clinic input] list.insert - index: Py_ssize_t object: object / - Insert object before index. [clinic start generated code]*/ @@ -806,7 +804,6 @@ list_insert_impl(PyListObject *self, Py_ssize_t index, PyObject *object) /*[clinic input] list.clear - Remove all items from list. [clinic start generated code]*/ @@ -820,7 +817,6 @@ list_clear_impl(PyListObject *self) /*[clinic input] list.copy - Return a shallow copy of the list. [clinic start generated code]*/ @@ -833,10 +829,8 @@ list_copy_impl(PyListObject *self) /*[clinic input] list.append - object: object / - Append object to the end of the list. [clinic start generated code]*/ @@ -851,10 +845,8 @@ list_append(PyListObject *self, PyObject *object) /*[clinic input] list.extend - iterable: object / - Extend list by appending elements from the iterable. [clinic start generated code]*/ @@ -865,7 +857,6 @@ list_extend(PyListObject *self, PyObject *iterable) PyObject *it; /* iter(v) */ Py_ssize_t m; /* size of self */ Py_ssize_t n; /* guess for size of iterable */ - Py_ssize_t mn; /* m + n */ Py_ssize_t i; PyObject *(*iternext)(PyObject *); @@ -889,13 +880,7 @@ list_extend(PyListObject *self, PyObject *iterable) /* It should not be possible to allocate a list large enough to cause an overflow on any relevant platform */ assert(m < PY_SSIZE_T_MAX - n); - if (n && self->ob_item == NULL) { - if (list_preallocate_exact(self, n) < 0) { - Py_DECREF(iterable); - return NULL; - } - } - else if (list_resize(self, m + n) < 0) { + if (list_resize(self, m + n) < 0) { Py_DECREF(iterable); return NULL; } @@ -935,16 +920,13 @@ list_extend(PyListObject *self, PyObject *iterable) */ } else { - if (n && self->ob_item == NULL) { + /* Make room. */ + if (self->ob_item == NULL) { if (list_preallocate_exact(self, n) < 0) goto error; } - else { - mn = m + n; - /* Make room. */ - if (list_resize(self, mn) < 0) - goto error; - } + else if (list_resize(self, m + n) < 0) + goto error; /* Make the list sane again. */ Py_SET_SIZE(self, m); } @@ -1009,12 +991,9 @@ list_inplace_concat(PyListObject *self, PyObject *other) /*[clinic input] list.pop - index: Py_ssize_t = -1 / - Remove and return item at index (default last). - Raises IndexError if list is empty or index is out of range. [clinic start generated code]*/ @@ -1301,19 +1280,14 @@ binarysort(MergeState *ms, sortslice lo, PyObject **hi, PyObject **start) /* Return the length of the run beginning at lo, in the slice [lo, hi). lo < hi is required on entry. "A run" is the longest ascending sequence, with - lo[0] <= lo[1] <= lo[2] <= ... - or the longest descending sequence, with - lo[0] > lo[1] > lo[2] > ... - Boolean *descending is set to 0 in the former case, or to 1 in the latter. For its intended use in a stable mergesort, the strictness of the defn of "descending" is needed so that the caller can safely reverse a descending sequence without violating stability (strict > ensures there are no equal elements to get out of order). - Returns -1 in case of error. */ static Py_ssize_t @@ -1355,20 +1329,14 @@ Locate the proper position of key in a sorted vector; if the vector contains an element equal to key, return the position immediately to the left of the leftmost equal element. [gallop_right() does the same except returns the position to the right of the rightmost equal element (if any).] - "a" is a sorted vector with n elements, starting at a[0]. n must be > 0. - "hint" is an index at which to begin the search, 0 <= hint < n. The closer hint is to the final result, the faster this runs. - The return value is the int k in 0..n such that - a[k-1] < key <= a[k] - pretending that *(a-1) is minus infinity and a[n] is plus infinity. IOW, key belongs at index k; or, IOW, the first k elements of a should precede key, and the last n-k should follow key. - Returns -1 on error. See listsort.txt for info on the method. */ static Py_ssize_t @@ -1449,13 +1417,9 @@ gallop_left(MergeState *ms, PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_ /* Exactly like gallop_left(), except that if key already exists in a[0:n], finds the position immediately to the right of the rightmost equal value. - The return value is the int k in 0..n such that - a[k-1] <= key < a[k] - or -1 if error. - The code duplication is massive, but this is enough different given that we're sticking to "<" comparisons that it's much harder to follow if written as one routine with yet another "left or right?" flag. @@ -2286,19 +2250,14 @@ unsafe_tuple_compare(PyObject *v, PyObject *w, MergeState *ms) */ /*[clinic input] list.sort - * key as keyfunc: object = None reverse: bool(accept={int}) = False - Sort the list in ascending order and return None. - The sort is in-place (i.e. the list itself is modified) and stable (i.e. the order of two equal elements is maintained). - If a key function is given, apply it once to each list item and sort them, ascending or descending, according to their function values. - The reverse flag can be set to sort in descending order. [clinic start generated code]*/ @@ -2584,7 +2543,6 @@ PyList_Sort(PyObject *v) /*[clinic input] list.reverse - Reverse *IN PLACE*. [clinic start generated code]*/ @@ -2623,14 +2581,11 @@ PyList_AsTuple(PyObject *v) /*[clinic input] list.index - value: object start: slice_index(accept={int}) = 0 stop: slice_index(accept={int}, c_default="PY_SSIZE_T_MAX") = sys.maxsize / - Return first index of value. - Raises ValueError if the value is not present. [clinic start generated code]*/ @@ -2667,10 +2622,8 @@ list_index_impl(PyListObject *self, PyObject *value, Py_ssize_t start, /*[clinic input] list.count - value: object / - Return number of occurrences of value. [clinic start generated code]*/ @@ -2700,12 +2653,9 @@ list_count(PyListObject *self, PyObject *value) /*[clinic input] list.remove - value: object / - Remove first occurrence of value. - Raises ValueError if the value is not present. [clinic start generated code]*/ @@ -2801,12 +2751,9 @@ list_richcompare(PyObject *v, PyObject *w, int op) /*[clinic input] list.__init__ - iterable: object(c_default="NULL") = () / - Built-in mutable sequence. - If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified. [clinic start generated code]*/ @@ -2826,6 +2773,19 @@ list___init___impl(PyListObject *self, PyObject *iterable) (void)_list_clear(self); } if (iterable != NULL) { + if (_PyObject_HasLen(iterable)) { + Py_ssize_t iter_len = PyObject_Size(iterable); + if (iter_len == -1) { + if (!PyErr_ExceptionMatches(PyExc_TypeError)) { + return -1; + } + PyErr_Clear(); + } + if (iter_len > 0 && self->ob_item == NULL + && list_preallocate_exact(self, iter_len)) { + return -1; + } + } PyObject *rv = list_extend(self, iterable); if (rv == NULL) return -1; @@ -2862,7 +2822,6 @@ list_vectorcall(PyObject *type, PyObject * const*args, /*[clinic input] list.__sizeof__ - Return the size of the list in memory, in bytes. [clinic start generated code]*/ @@ -3390,7 +3349,6 @@ PyTypeObject PyListRevIter_Type = { /*[clinic input] list.__reversed__ - Return a reverse iterator over the list. [clinic start generated code]*/ From 4b9631937b98f18d2fcdcacd45902e5b808b5797 Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Wed, 9 Mar 2022 08:09:25 +0800 Subject: [PATCH 06/15] bpo-43574 + bpo-39829: Optimize list allocations --- Objects/listobject.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 61194dce0e55ce..899fd48b9e48a3 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -68,15 +68,17 @@ list_resize(PyListObject *self, Py_ssize_t newsize) * is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t. */ new_allocated = ((size_t)newsize + (newsize >> 3) + 6) & ~(size_t)3; - /* Do not overallocate if the new size is closer to overallocated 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; /* Don't overallocate for lists that start empty or are set to empty. */ if (newsize == 0 || Py_SIZE(self) == 0) new_allocated = newsize; + else if (newsize - Py_SIZE(self) > (Py_ssize_t)(new_allocated - newsize)) { + /* Do not overallocate if the new size is closer to overallocated size + * than to the old size. + */ + new_allocated = ((size_t)newsize + 3) & ~(size_t)3; + } + num_allocated_bytes = new_allocated * sizeof(PyObject *); items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes); if (items == NULL) { From ecb8c897d518cffd20bcdb25c6bc9317db50856d Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Wed, 9 Mar 2022 09:45:44 +0800 Subject: [PATCH 07/15] bpo-39829: __len__ called twice in the list() constructor --- Objects/listobject.c | 46 +++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 899fd48b9e48a3..b85d06941e5866 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -68,17 +68,14 @@ list_resize(PyListObject *self, Py_ssize_t newsize) * is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t. */ new_allocated = ((size_t)newsize + (newsize >> 3) + 6) & ~(size_t)3; - - /* Don't overallocate for lists that start empty or are set to empty. */ - if (newsize == 0 || Py_SIZE(self) == 0) - new_allocated = newsize; - else if (newsize - Py_SIZE(self) > (Py_ssize_t)(new_allocated - newsize)) { - /* Do not overallocate if the new size is closer to overallocated size - * than to the old size. - */ + /* Do not overallocate if the new size is closer to overallocated 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; num_allocated_bytes = new_allocated * sizeof(PyObject *); items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes); if (items == NULL) { @@ -882,7 +879,13 @@ list_extend(PyListObject *self, PyObject *iterable) /* It should not be possible to allocate a list large enough to cause an overflow on any relevant platform */ assert(m < PY_SSIZE_T_MAX - n); - if (list_resize(self, m + n) < 0) { + if (self->ob_item == NULL) { + if (list_preallocate_exact(self, n) < 0) { + return NULL; + } + Py_SET_SIZE(self, n); + } + else if (list_resize(self, m + n) < 0) { Py_DECREF(iterable); return NULL; } @@ -921,13 +924,13 @@ list_extend(PyListObject *self, PyObject *iterable) * eventually run out of memory during the loop. */ } + else if (self->ob_item == NULL) { + if (list_preallocate_exact(self, n) < 0) + goto error; + } else { /* Make room. */ - if (self->ob_item == NULL) { - if (list_preallocate_exact(self, n) < 0) - goto error; - } - else if (list_resize(self, m + n) < 0) + if (list_resize(self, m + n) < 0) goto error; /* Make the list sane again. */ Py_SET_SIZE(self, m); @@ -2775,19 +2778,6 @@ list___init___impl(PyListObject *self, PyObject *iterable) (void)_list_clear(self); } if (iterable != NULL) { - if (_PyObject_HasLen(iterable)) { - Py_ssize_t iter_len = PyObject_Size(iterable); - if (iter_len == -1) { - if (!PyErr_ExceptionMatches(PyExc_TypeError)) { - return -1; - } - PyErr_Clear(); - } - if (iter_len > 0 && self->ob_item == NULL - && list_preallocate_exact(self, iter_len)) { - return -1; - } - } PyObject *rv = list_extend(self, iterable); if (rv == NULL) return -1; From 66c024686a0ec206eaf3bc21897288dd65b02360 Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Wed, 9 Mar 2022 15:10:16 +0800 Subject: [PATCH 08/15] bpo-39829: __len__ called twice in the list() constructor --- Objects/listobject.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Objects/listobject.c b/Objects/listobject.c index b85d06941e5866..4da51e907cc6a7 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -218,6 +218,7 @@ valid_index(Py_ssize_t i, Py_ssize_t limit) { /* The cast to size_t lets us use just a single comparison to check whether i is in the range: 0 <= i < limit. + See: Section 14.2 "Bounds Checking" in the Agner Fog optimization manual found at: https://www.agner.org/optimize/optimizing_cpp.pdf @@ -786,9 +787,11 @@ list_ass_item(PyListObject *a, Py_ssize_t i, PyObject *v) /*[clinic input] list.insert + index: Py_ssize_t object: object / + Insert object before index. [clinic start generated code]*/ @@ -803,6 +806,7 @@ list_insert_impl(PyListObject *self, Py_ssize_t index, PyObject *object) /*[clinic input] list.clear + Remove all items from list. [clinic start generated code]*/ @@ -816,6 +820,7 @@ list_clear_impl(PyListObject *self) /*[clinic input] list.copy + Return a shallow copy of the list. [clinic start generated code]*/ @@ -828,8 +833,10 @@ list_copy_impl(PyListObject *self) /*[clinic input] list.append + object: object / + Append object to the end of the list. [clinic start generated code]*/ @@ -844,8 +851,10 @@ list_append(PyListObject *self, PyObject *object) /*[clinic input] list.extend + iterable: object / + Extend list by appending elements from the iterable. [clinic start generated code]*/ @@ -996,9 +1005,12 @@ list_inplace_concat(PyListObject *self, PyObject *other) /*[clinic input] list.pop + index: Py_ssize_t = -1 / + Remove and return item at index (default last). + Raises IndexError if list is empty or index is out of range. [clinic start generated code]*/ @@ -1285,14 +1297,19 @@ binarysort(MergeState *ms, sortslice lo, PyObject **hi, PyObject **start) /* Return the length of the run beginning at lo, in the slice [lo, hi). lo < hi is required on entry. "A run" is the longest ascending sequence, with + lo[0] <= lo[1] <= lo[2] <= ... + or the longest descending sequence, with + lo[0] > lo[1] > lo[2] > ... + Boolean *descending is set to 0 in the former case, or to 1 in the latter. For its intended use in a stable mergesort, the strictness of the defn of "descending" is needed so that the caller can safely reverse a descending sequence without violating stability (strict > ensures there are no equal elements to get out of order). + Returns -1 in case of error. */ static Py_ssize_t @@ -1334,14 +1351,20 @@ Locate the proper position of key in a sorted vector; if the vector contains an element equal to key, return the position immediately to the left of the leftmost equal element. [gallop_right() does the same except returns the position to the right of the rightmost equal element (if any).] + "a" is a sorted vector with n elements, starting at a[0]. n must be > 0. + "hint" is an index at which to begin the search, 0 <= hint < n. The closer hint is to the final result, the faster this runs. + The return value is the int k in 0..n such that + a[k-1] < key <= a[k] + pretending that *(a-1) is minus infinity and a[n] is plus infinity. IOW, key belongs at index k; or, IOW, the first k elements of a should precede key, and the last n-k should follow key. + Returns -1 on error. See listsort.txt for info on the method. */ static Py_ssize_t @@ -1422,9 +1445,13 @@ gallop_left(MergeState *ms, PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_ /* Exactly like gallop_left(), except that if key already exists in a[0:n], finds the position immediately to the right of the rightmost equal value. + The return value is the int k in 0..n such that + a[k-1] <= key < a[k] + or -1 if error. + The code duplication is massive, but this is enough different given that we're sticking to "<" comparisons that it's much harder to follow if written as one routine with yet another "left or right?" flag. @@ -2255,14 +2282,19 @@ unsafe_tuple_compare(PyObject *v, PyObject *w, MergeState *ms) */ /*[clinic input] list.sort + * key as keyfunc: object = None reverse: bool(accept={int}) = False + Sort the list in ascending order and return None. + The sort is in-place (i.e. the list itself is modified) and stable (i.e. the order of two equal elements is maintained). + If a key function is given, apply it once to each list item and sort them, ascending or descending, according to their function values. + The reverse flag can be set to sort in descending order. [clinic start generated code]*/ @@ -2548,6 +2580,7 @@ PyList_Sort(PyObject *v) /*[clinic input] list.reverse + Reverse *IN PLACE*. [clinic start generated code]*/ @@ -2586,11 +2619,14 @@ PyList_AsTuple(PyObject *v) /*[clinic input] list.index + value: object start: slice_index(accept={int}) = 0 stop: slice_index(accept={int}, c_default="PY_SSIZE_T_MAX") = sys.maxsize / + Return first index of value. + Raises ValueError if the value is not present. [clinic start generated code]*/ @@ -2627,8 +2663,10 @@ list_index_impl(PyListObject *self, PyObject *value, Py_ssize_t start, /*[clinic input] list.count + value: object / + Return number of occurrences of value. [clinic start generated code]*/ @@ -2658,9 +2696,12 @@ list_count(PyListObject *self, PyObject *value) /*[clinic input] list.remove + value: object / + Remove first occurrence of value. + Raises ValueError if the value is not present. [clinic start generated code]*/ @@ -2756,8 +2797,10 @@ list_richcompare(PyObject *v, PyObject *w, int op) /*[clinic input] list.__init__ + iterable: object(c_default="NULL") = () / + Built-in mutable sequence. If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified. @@ -2814,6 +2857,7 @@ list_vectorcall(PyObject *type, PyObject * const*args, /*[clinic input] list.__sizeof__ + Return the size of the list in memory, in bytes. [clinic start generated code]*/ @@ -3341,6 +3385,7 @@ PyTypeObject PyListRevIter_Type = { /*[clinic input] list.__reversed__ + Return a reverse iterator over the list. [clinic start generated code]*/ From 1f706b4f85ecdab3cd88f04720be3db292bd4c6f Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Wed, 9 Mar 2022 15:10:50 +0800 Subject: [PATCH 09/15] bpo-39829: __len__ called twice in the list() constructor --- Objects/listobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/listobject.c b/Objects/listobject.c index 4da51e907cc6a7..d94f339f292103 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2802,6 +2802,7 @@ list.__init__ / Built-in mutable sequence. + If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified. [clinic start generated code]*/ From 75ec222c2ec82b1b1928e5ccadd651960d8dbe9c Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Thu, 10 Mar 2022 08:34:30 +0800 Subject: [PATCH 10/15] bpo-39829: __len__() called twice when constructing a list --- Objects/listobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index d94f339f292103..f7ccec94a7ec4c 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -933,7 +933,7 @@ list_extend(PyListObject *self, PyObject *iterable) * eventually run out of memory during the loop. */ } - else if (self->ob_item == NULL) { + else if (n && self->ob_item == NULL) { if (list_preallocate_exact(self, n) < 0) goto error; } From b5841b9010429c6f435504a10c80c8c15c88cc89 Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Thu, 10 Mar 2022 19:04:42 +0800 Subject: [PATCH 11/15] bpo-39829: __len__ called twice in the list() constructor --- Objects/listobject.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index f7ccec94a7ec4c..95fe3153984d72 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -933,8 +933,9 @@ list_extend(PyListObject *self, PyObject *iterable) * eventually run out of memory during the loop. */ } - else if (n && self->ob_item == NULL) { - if (list_preallocate_exact(self, n) < 0) + else if (self->ob_item == NULL) { + /* We have to rely on n being correct in this case. */ + if (n && list_preallocate_exact(self, n) < 0) goto error; } else { From e08c4263c2d0f43498a76acf4f892d1595da1bae Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Fri, 11 Mar 2022 09:39:02 +0000 Subject: [PATCH 12/15] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core and Builtins/2022-03-11-09-39-01.bpo-39829.mlW3Su.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-03-11-09-39-01.bpo-39829.mlW3Su.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-11-09-39-01.bpo-39829.mlW3Su.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-11-09-39-01.bpo-39829.mlW3Su.rst new file mode 100644 index 00000000000000..1f3d945188a32a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-11-09-39-01.bpo-39829.mlW3Su.rst @@ -0,0 +1 @@ +Removed the ``__len__()`` call when initializing a list and moved initializing to ``list_extend``. Patch by Jeremiah Pascual. From 0eb28714c459b9212e91f3edf735586c5ce93478 Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Fri, 11 Mar 2022 17:40:33 +0800 Subject: [PATCH 13/15] bpo-39829: __len__ called twice in the list() constructor --- Misc/ACKS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/ACKS b/Misc/ACKS index df851bb834cd4e..e202b4439b994c 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1335,6 +1335,7 @@ William Park Claude Paroz Heikki Partanen Harri Pasanen +Jeremiah Pascual Gaël Pasgrimaud Feanil Patel Ashish Nitin Patil @@ -1863,7 +1864,6 @@ Kurt Vile Norman Vine Pauli Virtanen Frank Visser -Jeremiah Vivian (Pascual) Johannes Vogel Michael Vogt Radu Voicilas From 39b88e3ddf5fbd29791a758b5ffcda7f29cea326 Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Sat, 12 Mar 2022 06:06:18 +0800 Subject: [PATCH 14/15] bpo-39829: __len__() called twice in the list() constructor --- Objects/listobject.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 95fe3153984d72..d50633d2b31321 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -934,7 +934,6 @@ list_extend(PyListObject *self, PyObject *iterable) */ } else if (self->ob_item == NULL) { - /* We have to rely on n being correct in this case. */ if (n && list_preallocate_exact(self, n) < 0) goto error; } From ad547f539539e2695ebc81df7010a72d9b71f1c9 Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Sun, 13 Mar 2022 22:34:09 +0800 Subject: [PATCH 15/15] bpo-39829: __len__ called twice in the list() constructor --- Misc/ACKS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/ACKS b/Misc/ACKS index e202b4439b994c..45573bd96c1435 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1335,7 +1335,7 @@ William Park Claude Paroz Heikki Partanen Harri Pasanen -Jeremiah Pascual +Jeremiah Gabriel Pascual Gaël Pasgrimaud Feanil Patel Ashish Nitin Patil