Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 67a7f32

Browse filesBrowse files
committed
Replace list_preallocate_exact to list_ensure_capacity
1 parent 556c016 commit 67a7f32
Copy full SHA for 67a7f32

File tree

Expand file treeCollapse file tree

2 files changed

+61
-5
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+61
-5
lines changed

‎Lib/test/test_list.py

Copy file name to clipboardExpand all lines: Lib/test/test_list.py
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,6 @@ def __eq__(self, other):
230230
self.assertFalse(list3 == list4)
231231

232232
@cpython_only
233-
@unittest.skipIf(Py_GIL_DISABLED, 'Only for the default build')
234233
def test_preallocation(self):
235234
iterable = [0] * 10
236235
iter_size = sys.getsizeof(iterable)

‎Objects/listobject.c

Copy file name to clipboardExpand all lines: Objects/listobject.c
+61-4Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,56 @@ list_allocate_items(size_t capacity)
6767
PyObject **items = PyMem_Malloc(capacity * sizeof(PyObject *));
6868
return items;
6969
}
70+
71+
/* Ensure ob_item has room for at least newsize elements, and set
72+
* ob_size to newsize. If newsize > ob_size on entry, the content
73+
* of the new slots at exit is undefined heap trash; it's the caller's
74+
* responsibility to overwrite them with sane values.
75+
* The number of allocated elements may grow, shrink, or stay the same.
76+
* Note that self->ob_item may change, and even if newsize is less
77+
* than ob_size on entry.
78+
*/
79+
static int
80+
list_ensure_capacity_slow(PyListObject *self, Py_ssize_t base, Py_ssize_t extra)
81+
{
82+
if (base > PY_SSIZE_T_MAX/(Py_ssize_t)sizeof(PyObject*) - extra) {
83+
PyErr_NoMemory();
84+
return -1;
85+
}
86+
87+
Py_ssize_t reqsize = base + extra;
88+
Py_ssize_t allocated = self->allocated;
89+
if (allocated >= reqsize) {
90+
assert(self->ob_item != NULL || reqsize == 0);
91+
return 0;
92+
}
93+
94+
if (!_Py_IsOwnedByCurrentThread((PyObject *)self)) {
95+
_PyObject_GC_SET_SHARED(self);
96+
}
97+
98+
size_t capacity = list_good_size(reqsize);
99+
PyObject **items = list_allocate_items(capacity);
100+
if (items == NULL) {
101+
PyErr_NoMemory();
102+
return -1;
103+
}
104+
PyObject **old = self->ob_item;
105+
if (self->ob_item) {
106+
memcpy(items, self->ob_item, allocated * sizeof(PyObject*));
107+
}
108+
_Py_atomic_store_ptr_release(&self->ob_item, items);
109+
self->allocated = capacity;
110+
if (old) {
111+
if (_PyObject_GC_IS_SHARED(self)) {
112+
_PyMem_FreeDelayed(old);
113+
}
114+
else {
115+
PyMem_Free(old);
116+
}
117+
}
118+
return 0;
119+
}
70120
#endif
71121

72122
static PyListObject *
@@ -184,8 +234,14 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
184234
}
185235

186236
static int
187-
list_preallocate_exact(PyListObject *self, Py_ssize_t size)
237+
list_ensure_capacity(PyListObject *self, Py_ssize_t base, Py_ssize_t extra)
188238
{
239+
#ifdef Py_GIL_DISABLED
240+
if (base > self->allocated - extra) {
241+
return list_ensure_capacity_slow(self, base, extra);
242+
}
243+
#else
244+
Py_ssize_t size = extra;
189245
assert(self->ob_item == NULL);
190246
assert(size > 0);
191247

@@ -202,6 +258,7 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size)
202258
}
203259
self->ob_item = items;
204260
self->allocated = size;
261+
#endif
205262
return 0;
206263
}
207264

@@ -389,7 +446,7 @@ PyList_Insert(PyObject *op, Py_ssize_t where, PyObject *newitem)
389446
int
390447
_PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem)
391448
{
392-
Py_ssize_t len = Py_SIZE(self);
449+
Py_ssize_t len = PyList_GET_SIZE(self);
393450
assert(self->allocated == -1 || self->allocated == len);
394451
if (list_resize(self, len + 1) < 0) {
395452
Py_DECREF(newitem);
@@ -1027,7 +1084,7 @@ list_extend_fast(PyListObject *self, PyObject *iterable)
10271084
// an overflow on any relevant platform.
10281085
assert(m < PY_SSIZE_T_MAX - n);
10291086
if (self->ob_item == NULL) {
1030-
if (list_preallocate_exact(self, n) < 0) {
1087+
if (list_ensure_capacity(self, m, n) < 0) {
10311088
return -1;
10321089
}
10331090
Py_SET_SIZE(self, n);
@@ -1075,7 +1132,7 @@ list_extend_iter(PyListObject *self, PyObject *iterable)
10751132
*/
10761133
}
10771134
else if (self->ob_item == NULL) {
1078-
if (n && list_preallocate_exact(self, n) < 0)
1135+
if (n && list_ensure_capacity(self, m, n) < 0)
10791136
goto error;
10801137
}
10811138
else {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.