Author: Lukas Diekmann <[email protected]>
Branch: list-strategies
Changeset: r47491:4729d45b3dc6
Date: 2011-03-30 14:02 +0200
http://bitbucket.org/pypy/pypy/changeset/4729d45b3dc6/

Log:    Optimized W_ListObject.setslice to take w_list as slice instead of
        sequence_w This avoids unnecessary wrapping and unwrapping
        (listview)

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
@@ -89,6 +89,15 @@
     def clone(self):
         return self.strategy.clone(self)
 
+    def _temporarily_as_objects(self):
+        if self.strategy is self.space.fromcache(ObjectListStrategy):
+            return self
+        list_w = self.getitems()
+        strategy = self.space.fromcache(ObjectListStrategy)
+        storage = strategy.cast_to_void_star(list_w)
+        w_objectlist = W_ListObject.from_storage_and_strategy(self.space, 
storage, strategy)
+        return w_objectlist
+
     def copy_into(self, other):
         self.strategy.copy_into(self, other)
     # ___________________________________________________
@@ -251,8 +260,10 @@
     def setitem(self, w_list, index, w_item):
         raise IndexError
 
-    def setslice(self, w_list, start, step, slicelength, sequence_w):
-        w_list.__init__(self.space, sequence_w)
+    def setslice(self, w_list, start, step, slicelength, w_other):
+        #XXX now we have wrapping/unwrapping here!
+        #XXX BUT: shouldn't we use from_strage_and_strategy here anyway?
+        w_list.__init__(self.space, w_other.getitems())
 
     def insert(self, w_list, index, w_item):
         assert index == 0
@@ -510,7 +521,7 @@
             return
         elif w_other.strategy is self.space.fromcache(EmptyListStrategy):
             return
-
+        #XXX use _temporarily_as_objects here
         list_w = w_other.getitems()
         strategy = self.space.fromcache(ObjectListStrategy)
         storage = strategy.cast_to_void_star(list_w)
@@ -531,20 +542,23 @@
         w_list.switch_to_object_strategy()
         w_list.setitem(index, w_item)
 
-    def setslice(self, w_list, start, step, slicelength, sequence_w):
+    def setslice(self, w_list, start, step, slicelength, w_other):
         #XXX inefficient
         assert slicelength >= 0
         items = self.cast_from_void_star(w_list.lstorage)
 
-        if (self is not self.space.fromcache(ObjectListStrategy) and
-                not self.list_is_correct_type(W_ListObject(self.space, 
sequence_w)) and
-                len(sequence_w) != 0):
+        if self is self.space.fromcache(ObjectListStrategy):
+            w_other = w_other._temporarily_as_objects()
+        elif (not self.list_is_correct_type(w_other) and
+               w_other.length() != 0):
             w_list.switch_to_object_strategy()
-            w_list.setslice(start, step, slicelength, sequence_w)
+            w_other_as_object = w_other._temporarily_as_objects()
+            assert w_other_as_object.strategy is 
self.space.fromcache(ObjectListStrategy)
+            w_list.setslice(start, step, slicelength, w_other_as_object)
             return
 
         oldsize = len(items)
-        len2 = len(sequence_w)
+        len2 = w_other.length()
         if step == 1:  # Support list resizing for non-extended slices
             delta = slicelength - len2
             if delta < 0:
@@ -566,7 +580,13 @@
                   "assign sequence of size %d to extended slice of size %d",
                   len2, slicelength)
 
-        if sequence_w is items:
+        if w_other.strategy is self.space.fromcache(EmptyListStrategy):
+            other_items = []
+        else:
+            # at this point both w_list and w_other have the same type, so
+            # self.cast_from_void_star is valid for both of them
+            other_items = self.cast_from_void_star(w_other.lstorage)
+        if other_items is items:
             if step > 0:
                 # Always copy starting from the right to avoid
                 # having to make a shallow copy in the case where
@@ -574,18 +594,22 @@
                 i = len2 - 1
                 start += i*step
                 while i >= 0:
-                    items[start] = self.unwrap(sequence_w[i])
+                    items[start] = other_items[i]
                     start -= step
                     i -= 1
                 return
             else:
                 # Make a shallow copy to more easily handle the reversal case
                 # XXX why is this needed ???
-                sequence_w = list(sequence_w)
+                w_list.reverse()
+                return
+                #other_items = list(other_items)
         for i in range(len2):
-            items[start] = self.unwrap(sequence_w[i])
+            items[start] = other_items[i]
             start += step
 
+        w_list.check_empty_strategy()
+
     def deleteitem(self, w_list, index):
         l = self.cast_from_void_star(w_list.lstorage)
         del l[index]
@@ -755,11 +779,17 @@
     start, stop = normalize_simple_slice(space, length, w_start, w_stop)
     return w_list.getslice(start, stop, 1, stop - start)
 
+def setslice__List_ANY_ANY_List(space, w_list, w_start, w_stop, w_other):
+    length = w_list.length()
+    start, stop = normalize_simple_slice(space, length, w_start, w_stop)
+    w_list.setslice(start, 1, stop-start, w_other)
+
 def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_iterable):
     length = w_list.length()
     start, stop = normalize_simple_slice(space, length, w_start, w_stop)
     sequence_w = space.listview(w_iterable)
-    w_list.setslice(start, 1, stop-start, sequence_w)
+    w_other = W_ListObject(space, sequence_w)
+    w_list.setslice(start, 1, stop-start, w_other)
 
 def delslice__List_ANY_ANY(space, w_list, w_start, w_stop):
     length = w_list.length()
@@ -896,11 +926,17 @@
                              space.wrap("list index out of range"))
     return space.w_None
 
+def setitem__List_Slice_List(space, w_list, w_slice, w_other):
+    oldsize = w_list.length()
+    start, stop, step, slicelength = w_slice.indices4(space, oldsize)
+    w_list.setslice(start, step, slicelength, w_other)
+
 def setitem__List_Slice_ANY(space, w_list, w_slice, w_iterable):
     oldsize = w_list.length()
     start, stop, step, slicelength = w_slice.indices4(space, oldsize)
     sequence_w = space.listview(w_iterable)
-    w_list.setslice(start, step, slicelength, sequence_w)
+    w_other = W_ListObject(space, sequence_w)
+    w_list.setslice(start, step, slicelength, w_other)
 
 app = gateway.applevel("""
     def listrepr(currently_in_repr, l):
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
@@ -657,6 +657,7 @@
 
         l = [1,2,3]
         raises(ValueError, "l[0:2:2] = [1,2,3,4]")
+        raises(ValueError, "l[::2] = []")
 
     def test_recursive_repr(self):
         l = []
diff --git a/pypy/objspace/std/test/test_liststrategies.py 
b/pypy/objspace/std/test/test_liststrategies.py
--- a/pypy/objspace/std/test/test_liststrategies.py
+++ b/pypy/objspace/std/test/test_liststrategies.py
@@ -111,24 +111,62 @@
     def test_setslice(self):
         l = W_ListObject(self.space, [])
         assert isinstance(l.strategy, EmptyListStrategy)
-        l.setslice(0, 1, 2, [self.space.wrap(1), self.space.wrap(2), 
self.space.wrap(3)])
+        l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap(1), 
self.space.wrap(2), self.space.wrap(3)]))
         assert isinstance(l.strategy, IntegerListStrategy)
 
         l = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), 
self.space.wrap(3)])
         assert isinstance(l.strategy, IntegerListStrategy)
-        l.setslice(0, 1, 2, [self.space.wrap(4), self.space.wrap(5), 
self.space.wrap(6)])
+        l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap(4), 
self.space.wrap(5), self.space.wrap(6)]))
         assert isinstance(l.strategy, IntegerListStrategy)
 
         l = W_ListObject(self.space, [self.space.wrap(1), 
self.space.wrap('b'), self.space.wrap(3)])
         assert isinstance(l.strategy, ObjectListStrategy)
-        l.setslice(0, 1, 2, [self.space.wrap(1), self.space.wrap(2), 
self.space.wrap(3)])
+        l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap(1), 
self.space.wrap(2), self.space.wrap(3)]))
         assert isinstance(l.strategy, ObjectListStrategy)
 
         l = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), 
self.space.wrap(3)])
         assert isinstance(l.strategy, IntegerListStrategy)
-        l.setslice(0, 1, 2, [self.space.wrap('a'), self.space.wrap('b'), 
self.space.wrap('c')])
+        l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap('a'), 
self.space.wrap('b'), self.space.wrap('c')]))
         assert isinstance(l.strategy, ObjectListStrategy)
 
+    def test_setslice_List(self):
+
+        def wrapitems(items):
+            items_w = []
+            for i in items:
+                items_w.append(self.space.wrap(i))
+            return items_w
+
+        def keep_other_strategy(w_list, start, step, length, w_other):
+            other_strategy = w_other.strategy
+            w_list.setslice(start, step, length, w_other)
+            assert w_other.strategy is other_strategy
+
+        l = W_ListObject(self.space, wrapitems([1,2,3,4,5]))
+        other = W_ListObject(self.space, wrapitems(["a", "b", "c"]))
+        keep_other_strategy(l, 0, 2, other.length(), other)
+        assert l.strategy is self.space.fromcache(ObjectListStrategy)
+
+        l = W_ListObject(self.space, wrapitems([1,2,3,4,5]))
+        other = W_ListObject(self.space, wrapitems([6, 6, 6]))
+        keep_other_strategy(l, 0, 2, other.length(), other)
+        assert l.strategy is self.space.fromcache(IntegerListStrategy)
+
+        l = W_ListObject(self.space, wrapitems(["a","b","c","d","e"]))
+        other = W_ListObject(self.space, wrapitems(["a", "b", "c"]))
+        keep_other_strategy(l, 0, 2, other.length(), other)
+        assert l.strategy is self.space.fromcache(StringListStrategy)
+
+        l = W_ListObject(self.space, wrapitems(["a",3,"c",4,"e"]))
+        other = W_ListObject(self.space, wrapitems(["a", "b", "c"]))
+        keep_other_strategy(l, 0, 2, other.length(), other)
+        assert l.strategy is self.space.fromcache(ObjectListStrategy)
+
+        l = W_ListObject(self.space, wrapitems(["a",3,"c",4,"e"]))
+        other = W_ListObject(self.space, [])
+        keep_other_strategy(l, 0, 1, l.length(), other)
+        assert l.strategy is self.space.fromcache(EmptyListStrategy)
+
     def test_extend(self):
         l = W_ListObject(self.space, [])
         assert isinstance(l.strategy, EmptyListStrategy)
@@ -230,7 +268,7 @@
     def test_range_setslice(self):
         l = make_range_list(self.space, 1, 3, 5)
         assert isinstance(l.strategy, RangeListStrategy)
-        l.setslice(0, 1, 3, [self.space.wrap(1), self.space.wrap(2), 
self.space.wrap(3)])
+        l.setslice(0, 1, 3, W_ListObject(self.space, [self.space.wrap(1), 
self.space.wrap(2), self.space.wrap(3)]))
         assert isinstance(l.strategy, IntegerListStrategy)
 
     def test_get_items_copy(self):
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to