Author: Armin Rigo <[email protected]>
Branch: fix-2198
Changeset: r81383:83cd07a3e10e
Date: 2015-12-18 19:51 +0100
http://bitbucket.org/pypy/pypy/changeset/83cd07a3e10e/
Log: Write more tests (that are passing) and refactor a little bit
setslice() with the JIT in mind and some more comments about corner
cases
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -1468,47 +1468,47 @@
return
len2 = w_other.length()
- if slicelength == 0 and len2 == 0:
- return # shortcut, really there's nothing to do
items = self.unerase(w_list.lstorage)
if step == 1: # Support list resizing for non-extended slices
- len1 = w_list.length()
+ len1 = len(items)
# Ensure non-negative slicing
- if start <= -len1:
- start = 0
- elif start < 0:
+ if start < 0:
start += len1
+ if start < 0:
+ start = 0
assert start >= 0
- if len2 == 0 and slicelength > 0: # shortcut, we already did all
that was needed
+ if len2 == 0: # shortcut, we already did all that was needed
+ # (this condition is needed to avoid self.unerase() on
+ # w_other in the next line: if len2 == 0 then it might
+ # be any strategy; only if it is not 0 do we check that
+ # it is the same strategy as 'self')
del items[start:start + slicelength]
else:
items[start:start + slicelength] =
self.unerase(w_other.lstorage)
return
- elif len2 != slicelength: # No resize for extended slices
+
+ # The rest is the case 'step != 1'
+
+ if len2 != slicelength: # No resize for extended slices
raise oefmt(self.space.w_ValueError,
"attempt to assign sequence of size %d to extended "
"slice of size %d", len2, slicelength)
- if len2 == 0:
- other_items = []
- else:
- # at this point both w_list and w_other have the same type, so
- # self.unerase is valid for both of them
- other_items = self.unerase(w_other.lstorage)
+ if len2 == 0: # == slicelength: shortcut, really there's nothing to do
+ return
+ # at this point both w_list and w_other have the same type, so
+ # self.unerase is valid for both of them
+ other_items = self.unerase(w_other.lstorage)
if other_items is items:
- if step > 1:
- # Always copy starting from the right to avoid
- # having to make a shallow copy in the case where
- # the source and destination lists are the same list.
- i = len2 - 1
- start += i * step
- while i >= 0:
- items[start] = other_items[i]
- start -= step
- i -= 1
- else: # step can only be -1 here, so it's equivalent to :
- assert step == -1
- w_list.reverse()
+ # 'l[x:y:step] = l', with step != 1 and len(l) != 0.
+
+ # This is very obscure, but w_list.reverse() is correct
+ # here for all remaining cases, I believe. It handles the
+ # case 'l[::-1] = l'. Otherwise, if abs(step) > 1 but still
+ # len(l) == len2 == slicelength, then the only possibility
+ # left is that len(l) == 1, and reverse() has no effect.
+ assert step == -1 or len2 == 1
+ w_list.reverse()
return
for i in range(len2):
items[start] = other_items[i]
diff --git a/pypy/objspace/std/test/test_listobject.py
b/pypy/objspace/std/test/test_listobject.py
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -1079,6 +1079,21 @@
b[i:i+1] = ['y']
assert b == ['y'] * count
+ def test_setslice_corner_case_1(self):
+ lst = [5, 6, 7, 8]
+ lst[2:3] = range(2)
+ assert lst == [5, 6, 0, 1, 8]
+
+ def test_setslice_corner_case_2(self):
+ lst = [5]
+ lst[0:-10:-10] = lst
+ assert lst == [5]
+
+ def test_setslice_corner_case_3(self):
+ lst = [5]
+ lst[0:10:10] = lst
+ assert lst == [5]
+
def test_recursive_repr(self):
l = []
assert repr(l) == '[]'
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit