10000 bpo-43574 + bpo-39829: Optimize allocations · python/cpython@37382e8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 37382e8

Browse files
bpo-43574 + bpo-39829: Optimize allocations
1 parent fc50d36 commit 37382e8

File tree

1 file changed

+21
-63
lines changed

1 file changed

+21
-63
lines changed

Objects/listobject.c

Lines changed: 21 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
7474
if (newsize - Py_SIZE(self) > (Py_ssize_t)(new_allocated - newsize))
7575
new_allocated = ((size_t)newsize + 3) & ~(size_t)3;
7676

77-
if (newsize == 0)
78-
new_allocated = 0;
77+
/* Don't overallocate for lists that start empty or are set to empty. */
78+
if (newsize == 0 || Py_SIZE(self) == 0)
79+
new_allocated = newsize;
7980
num_allocated_bytes = new_allocated * sizeof(PyObject *);
8081
items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes);
8182
if (items == NULL) {
@@ -218,7 +219,6 @@ valid_index(Py_ssize_t i, Py_ssize_t limit)
218219
{
219220
/* The cast to size_t lets us use just a single comparison
220221
to check whether i is in the range: 0 <= i < limit.
221-
222222
See: Section 14.2 "Bounds Checking" in the Agner Fog
223223
optimization manual found at:
224224
https://www.agner.org/optimize/optimizing_cpp.pdf
@@ -787,11 +787,9 @@ list_ass_item(PyListObject *a, Py_ssize_t i, PyObject *v)
787787

788788
/*[clinic input]
789789
list.insert
790-
791790
index: Py_ssize_t
792791
object: object
793792
/
794-
795793
Insert object before index.
796794
[clinic start generated code]*/
797795

@@ -806,7 +804,6 @@ list_insert_impl(PyListObject *self, Py_ssize_t index, PyObject *object)
806804

807805
/*[clinic input]
808806
list.clear
809-
810807
Remove all items from list.
811808
[clinic start generated code]*/
812809

@@ -820,7 +817,6 @@ list_clear_impl(PyListObject *self)
820817

821818
/*[clinic input]
822819
list.copy
823-
824820
Return a shallow copy of the list.
825821
[clinic start generated code]*/
826822

@@ -833,10 +829,8 @@ list_copy_impl(PyListObject *self)
833829

834830
/*[clinic input]
835831
list.append
836-
837832
object: object
838833
/
839-
840834
Append object to the end of the list.
841835
[clinic start generated code]*/
842836

@@ -851,10 +845,8 @@ list_append(PyListObject *self, PyObject *object)
851845

852846
/*[clinic input]
853847
list.extend
854-
855848
iterable: object
856849
/
857-
858850
Extend list by appending elements from the iterable.
859851
[clinic start generated code]*/
860852

@@ -865,7 +857,6 @@ list_extend(PyListObject *self, PyObject *iterable)
865857
PyObject *it; /* iter(v) */
866858
Py_ssize_t m; /* size of self */
867859
Py_ssize_t n; /* guess for size of iterable */
868-
Py_ssize_t mn; /* m + n */
869860
Py_ssize_t i;
870861
PyObject *(*iternext)(PyObject *);
871862

@@ -889,13 +880,7 @@ list_extend(PyListObject *self, PyObject *iterable)
889880
/* It should not be possible to allocate a list large enough to cause
890881
an overflow on any relevant platform */
891882
assert(m < PY_SSIZE_T_MAX - n);
892-
if (n && self->ob_item == NULL) {
893-
if (list_preallocate_exact(self, n) < 0) {
894-
Py_DECREF(iterable);
895-
return NULL;
896-
}
897-
}
898-
else if (list_resize(self, m + n) < 0) {
883+
if (list_resize(self, m + n) < 0) {
899884
Py_DECREF(iterable);
900885
return NULL;
901886
}
@@ -935,16 +920,13 @@ list_extend(PyListObject *self, PyObject *iterable)
935920
*/
936921
}
937922
else {
938-
if (n && self->ob_item == NULL) {
923+
/* Make room. */
924+
if (self->ob_item == NULL) {
939925
if (list_preallocate_exact(self, n) < 0)
940926
goto error;
941927
}
942-
else {
943-
mn = m + n;
944-
/* Make room. */
945-
if (list_resize(self, mn) < 0)
946-
goto error;
947-
}
928+
else if (list_resize(self, m + n) < 0)
929+
goto error;
948930
/* Make the list sane again. */
949931
Py_SET_SIZE(self, m);
950932
}
@@ -1009,12 +991,9 @@ list_inplace_concat(PyListObject *self, PyObject *other)
1009991

1010992
/*[clinic input]
1011993
list.pop
1012-
1013994
index: Py_ssize_t = -1
1014995
/
1015-
1016996
Remove and return item at index (default last).
1017-
1018997
Raises IndexError if list is empty or index is out of range.
1019998
[clinic start generated code]*/
1020999

@@ -1301,19 +1280,14 @@ binarysort(MergeState *ms, sortslice lo, PyObject **hi, PyObject **start)
13011280
/*
13021281
Return the length of the run beginning at lo, in the slice [lo, hi). lo < hi
13031282
is required on entry. "A run" is the longest ascending sequence, with
1304-
13051283
lo[0] <= lo[1] <= lo[2] <= ...
1306-
13071284
or the longest descending sequence, with
1308-
13091285
lo[0] > lo[1] > lo[2] > ...
1310-
13111286
Boolean *descending is set to 0 in the former case, or to 1 in the latter.
13121287
For its intended use in a stable mergesort, the strictness of the defn of
13131288
"descending" is needed so that the caller can safely reverse a descending
13141289
sequence without violating stability (strict > ensures there are no equal
13151290
elements to get out of order).
1316-
13171291
Returns -1 in case of error.
13181292
*/
13191293
static Py_ssize_t
@@ -1355,20 +1329,14 @@ Locate the proper position of key in a sorted vector; if the vector contains
13551329
an element equal to key, return the position immediately to the left of
13561330
the leftmost equal element. [gallop_right() does the same except returns
13571331
the position to the right of the rightmost equal element (if any).]
1358-
13591332
"a" is a sorted vector with n elements, starting at a[0]. n must be > 0.
1360-
13611333
"hint" is an index at which to begin the search, 0 <= hint < n. The closer
13621334
hint is to the final result, the faster this runs.
1363-
13641335
The return value is the int k in 0..n such that
1365-
13661336
a[k-1] < key <= a[k]
1367-
13681337
pretending that *(a-1) is minus infinity and a[n] is plus infinity. IOW,
13691338
key belongs at index k; or, IOW, the first k elements of a should precede
13701339
key, and the last n-k should follow key.
1371-
13721340
Returns -1 on error. See listsort.txt for info on the method.
13731341
*/
13741342
static Py_ssize_t
@@ -1449,13 +1417,9 @@ gallop_left(MergeState *ms, PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_
14491417
/*
14501418
Exactly like gallop_left(), except that if key already exists in a[0:n],
14511419
finds the position immediately to the right of the rightmost equal value.
1452-
14531420
The return value is the int k in 0..n such that
1454-
14551421
a[k-1] <= key < a[k]
1456-
14571422
or -1 if error.
1458-
14591423
The code duplication is massive, but this is enough different given that
14601424
we're sticking to "<" comparisons that it's much harder to follow if
14611425
written as one routine with yet another "left or right?" flag.
@@ -2286,19 +2250,14 @@ unsafe_tuple_compare(PyObject *v, PyObject *w, MergeState *ms)
22862250
*/
22872251
/*[clinic input]
22882252
list.sort
2289-
22902253
*
22912254
key as keyfunc: object = None
22922255
reverse: bool(accept={int}) = False
2293-
22942256
Sort the list in ascending order and return None.
2295-
22962257
The sort is in-place (i.e. the list itself is modified) and stable (i.e. the
22972258
order of two equal elements is maintained).
2298-
22992259
If a key function is given, apply it once to each list item and sort them,
23002260
ascending or descending, according to their function values.
2301-
23022261
The reverse flag can be set to sort in descending order.
23032262
[clinic start generated code]*/
23042263

@@ -2584,7 +2543,6 @@ PyList_Sort(PyObject *v)
25842543

25852544
/*[clinic input]
25862545
list.reverse
2587-
25882546
Reverse *IN PLACE*.
25892547
[clinic start generated code]*/
25902548

@@ -2623,14 +2581,11 @@ PyList_AsTuple(PyObject *v)
26232581

26242582
/*[clinic input]
26252583
list.index
2626-
26272584
value: object
26282585
start: slice_index(accept={int}) = 0
26292586
stop: slice_index(accept={int}, c_default="PY_SSIZE_T_MAX") = sys.maxsize
26302587
/
2631-
26322588
Return first index of value.
2633-
26342589
Raises ValueError if the value is not present.
26352590
[clinic start generated code]*/
26362591

@@ -2667,10 +2622,8 @@ list_index_impl(PyListObject *self, PyObject *value, Py_ssize_t start,
26672622

26682623
/*[clinic input]
26692624
list.count
2670-
26712625
value: object
26722626
/
2673-
26742627
Return number of occurrences of value.
26752628
[clinic start generated code]*/
26762629

@@ -2700,12 +2653,9 @@ list_count(PyListObject *self, PyObject *value)
27002653

27012654
/*[clinic input]
27022655
list.remove
2703-
27042656
value: object
27052657
/
2706-
27072658
Remove first occurrence of value.
2708-
27092659
Raises ValueError if the value is not present.
27102660
[clinic start generated code]*/
27112661

@@ -2801,12 +2751,9 @@ list_richcompare(PyObject *v, PyObject *w, int op)
28012751

28022752
/*[clinic input]
28032753
list.__init__
2804-
28052754
iterable: object(c_default="NULL") = ()
28062755
/
2807-
28082756
Built-in mutable sequence.
2809-
28102757
If no argument is given, the constructor creates a new empty list.
28112758
The argument must be an iterable if specified.
28122759
[clinic start generated code]*/
@@ -2826,6 +2773,19 @@ list___init___impl(PyListObject *self, PyObject *iterable)
28262773
(void)_list_clear(self);
28272774
}
28282775
if (iterable != NULL) {
2776+
if (_PyObject_HasLen(iterable)) {
2777+
Py_ssize_t iter_len = PyObject_Size(iterable);
2778+
if (iter_len == -1) {
2779+
if (!PyErr_ExceptionMatches(PyExc_TypeError)) {
2780+
return -1;
2781+
}
2782+
PyErr_Clear();
2783+
}
2784+
if (iter_len > 0 && self->ob_item == NULL
2785+
&& list_preallocate_exact(self, iter_len)) {
2786+
return -1;
2787+
}
2788+
}
28292789
PyObject *rv = list_extend(self, iterable);
28302790
if (rv == NULL)
28312791
return -1;
@@ -2862,7 +2822,6 @@ list_vectorcall(PyObject *type, PyObject * const*args,
28622822

28632823
/*[clinic input]
28642824
list.__sizeof__
2865-
28662825
Return the size of the list in memory, in bytes.
28672826
[clinic start generated code]*/
28682827

@@ -3390,7 +3349,6 @@ PyTypeObject PyListRevIter_Type = {
33903349

33913350
/*[clinic input]
33923351
list.__reversed__
3393-
33943352
Return a reverse iterator over the list.
33953353
[clinic start generated code]*/
33963354

0 commit comments

Comments
 (0)
0