Improve extended slicing support in builtin types and classes. Specifically:
- Specialcase extended slices that amount to a shallow copy the same way as
is done for simple slices, in the tuple, string and unicode case.
- Specialcase step-1 extended slices to optimize the common case for all
involved types.
- For lists, allow extended slice assignment of differing lengths as long
as the step is 1. (Previously, 'l[:2:1] = []' failed even though
'l[:2] = []' and 'l[:2:None] = []' do not.)
- Implement extended slicing for buffer, array, structseq, mmap and
UserString.UserString.
- Implement slice-object support (but not non-step-1 slice assignment) for
UserString.MutableString.
- Add tests for all new functionality.
diff --git a/Objects/listobject.c b/Objects/listobject.c
index ac0d018..c0621dc 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -2473,6 +2473,9 @@
if (slicelength <= 0) {
return PyList_New(0);
}
+ else if (step == 1) {
+ return list_slice(self, start, stop);
+ }
else {
result = PyList_New(slicelength);
if (!result) return NULL;
@@ -2516,10 +2519,15 @@
return -1;
}
- /* treat L[slice(a,b)] = v _exactly_ like L[a:b] = v */
- if (step == 1 && ((PySliceObject*)item)->step == Py_None)
+ if (step == 1)
return list_ass_slice(self, start, stop, value);
+ /* Make sure s[5:2] = [..] inserts at the right place:
+ before 5, not before 2. */
+ if ((step < 0 && start < stop) ||
+ (step > 0 && start > stop))
+ stop = start;
+
if (value == NULL) {
/* delete slice */
PyObject **garbage;
@@ -2541,12 +2549,16 @@
return -1;
}
- /* drawing pictures might help
- understand these for loops */
+ /* drawing pictures might help understand these for
+ loops. Basically, we memmove the parts of the
+ list that are *not* part of the slice: step-1
+ items for each item that is part of the slice,
+ and then tail end of the list that was not
+ covered by the slice */
for (cur = start, i = 0;
cur < stop;
cur += step, i++) {
- Py_ssize_t lim = step;
+ Py_ssize_t lim = step - 1;
garbage[i] = PyList_GET_ITEM(self, cur);
@@ -2558,11 +2570,12 @@
self->ob_item + cur + 1,
lim * sizeof(PyObject *));
}
-
- for (cur = start + slicelength*step + 1;
- cur < Py_Size(self); cur++) {
- PyList_SET_ITEM(self, cur - slicelength,
- PyList_GET_ITEM(self, cur));
+ cur = start + slicelength*step;
+ if (cur < Py_Size(self)) {
+ memmove(self->ob_item + cur - slicelength,
+ self->ob_item + cur,
+ (Py_Size(self) - cur) *
+ sizeof(PyObject *));
}
Py_Size(self) -= slicelength;
@@ -2577,7 +2590,8 @@
}
else {
/* assign slice */
- PyObject **garbage, *ins, *seq, **seqitems, **selfitems;
+ PyObject *ins, *seq;
+ PyObject **garbage, **seqitems, **selfitems;
Py_ssize_t cur, i;
/* protect against a[::-1] = a */
@@ -2587,14 +2601,17 @@
}
else {
seq = PySequence_Fast(value,
- "must assign iterable to extended slice");
+ "must assign iterable "
+ "to extended slice");
}
if (!seq)
return -1;
if (PySequence_Fast_GET_SIZE(seq) != slicelength) {
PyErr_Format(PyExc_ValueError,
- "attempt to assign sequence of size %zd to extended slice of size %zd",
+ "attempt to assign sequence of "
+ "size %zd to extended slice of "
+ "size %zd",
PySequence_Fast_GET_SIZE(seq),
slicelength);
Py_DECREF(seq);