[pypy-svn] r37981 - in pypy/dist/pypy: config module/__builtin__ objspace/std objspace/std/test

cfbolz at codespeak.net cfbolz at codespeak.net
Mon Feb 5 21:50:02 CET 2007


Author: cfbolz
Date: Mon Feb  5 21:49:56 2007
New Revision: 37981

Added:
   pypy/dist/pypy/objspace/std/listmultiobject.py
   pypy/dist/pypy/objspace/std/test/test_listmultiobject.py
Modified:
   pypy/dist/pypy/config/pypyoption.py
   pypy/dist/pypy/module/__builtin__/functional.py
   pypy/dist/pypy/objspace/std/listtype.py
   pypy/dist/pypy/objspace/std/model.py
   pypy/dist/pypy/objspace/std/objspace.py
   pypy/dist/pypy/objspace/std/test/test_listobject.py
Log:
weekend project: implement multilists similar to multidicts. re-implement
rangelist using them and add a string-list implementation that saves the
unwrapped strings. Also have a special slice implementation, that makes list
slicing a cheap operation as long as the list and the slice are not mutated.


Modified: pypy/dist/pypy/config/pypyoption.py
==============================================================================
--- pypy/dist/pypy/config/pypyoption.py	(original)
+++ pypy/dist/pypy/config/pypyoption.py	Mon Feb  5 21:49:56 2007
@@ -170,6 +170,16 @@
         IntOption("methodcachesize",
                   "size of the method cache (should be a power of 2)",
                   default=2048),
+        BoolOption("withmultilist",
+                   "use lists optimized for flexibility",
+                   default=False,
+                   requires=[("objspace.std.withrangelist", False),
+                             ("objspace.name", "std"),
+                             ("objspace.std.withtproxy", False)]),
+        BoolOption("withfastslice",
+                   "make list slicing lazy",
+                   default=False,
+                   requires=[("objspace.std.withmultilist", True)]),
         BoolOption("optimized_int_add",
                    "special case the addition of two integers in BINARY_ADD",
                    default=False),

Modified: pypy/dist/pypy/module/__builtin__/functional.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/functional.py	(original)
+++ pypy/dist/pypy/module/__builtin__/functional.py	Mon Feb  5 21:49:56 2007
@@ -69,8 +69,9 @@
 get a list in decending order."""
 
     if (space.config.objspace.name == "std" and
-        space.config.objspace.std.withrangelist):
-        return range_withrangelist(space, w_x, w_y, w_step)
+        (space.config.objspace.std.withmultilist or
+         space.config.objspace.std.withrangelist)):
+        return range_withspecialized_implementation(space, w_x, w_y, w_step)
     try:
         # save duplication by redirecting every error to applevel
         x = space.int_w(w_x)
@@ -96,11 +97,9 @@
 range_fallback = applevel(getsource(app_range), getfile(app_range)
                           ).interphook('range')
 
-def range_withrangelist(space, w_x, w_y, w_step):
+def range_withspecialized_implementation(space, w_x, w_y, w_step):
     # XXX object space dependant
-    from pypy.objspace.std.rangeobject import W_RangeListObject
     try:
-        # save duplication by redirecting every error to applevel
         x = space.int_w(w_x)
         if space.is_w(w_y, space.w_None):
             start, stop = 0, x
@@ -110,5 +109,12 @@
         howmany = get_len_of_range(start, stop, step)
     except (OperationError, ValueError, OverflowError):
         return range_fallback(space, w_x, w_y, w_step)
-    return W_RangeListObject(start, step, howmany)
+    if space.config.objspace.std.withrangelist:
+        from pypy.objspace.std.rangeobject import W_RangeListObject
+        return W_RangeListObject(start, step, howmany)
+    if space.config.objspace.std.withmultilist:
+        from pypy.objspace.std.listmultiobject import W_ListMultiObject
+        from pypy.objspace.std.listmultiobject import RangeImplementation
+        impl = RangeImplementation(space, start, step, howmany)
+        return W_ListMultiObject(space, impl)
 

Added: pypy/dist/pypy/objspace/std/listmultiobject.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/objspace/std/listmultiobject.py	Mon Feb  5 21:49:56 2007
@@ -0,0 +1,1192 @@
+from pypy.objspace.std.objspace import *
+from pypy.objspace.std.inttype import wrapint
+from pypy.objspace.std.sliceobject import W_SliceObject
+from pypy.objspace.std.tupleobject import W_TupleObject
+from pypy.objspace.std.stringobject import W_StringObject
+
+from pypy.objspace.std import slicetype
+from pypy.interpreter import gateway, baseobjspace
+from pypy.rlib.listsort import TimSort
+
+
+class ListImplementation(object):
+
+    def __init__(self, space):
+        self.space = space
+
+# A list implementation should implement the following methods:
+
+##     def length(self):
+##         pass
+
+##     def getitem(self, i):
+##         pass
+
+##     def getitem_slice(self, start, stop):
+##         pass
+
+
+# the following operations return the list implementation that should
+# be used after the call
+# If it turns out that the list implementation cannot really perform
+# the operation it can return None for the following ones:
+
+    def setitem(self, i, w_item):
+        pass
+
+    def insert(self, i, w_item):
+        pass
+
+    def delitem(self, index):
+        pass
+
+    def delitem_slice(self, start, stop):
+        pass
+
+    def append(self, w_item):
+        pass
+
+    def extend(self, other):
+        pass
+
+
+# special cases:
+
+    def add(self, other):
+        pass
+
+##     def get_list_w(self):
+##         pass
+
+# default implementations, can (but don't have to be) overridden:
+
+    def reverse(self):
+        l = self.length()
+        for i in range(l // 2):
+            x = self.getitem(i)
+            y = self.getitem(l - i - 1)
+            self = self.i_setitem(i, y)
+            self = self.i_setitem(l - i - 1, x)
+        return self
+
+
+    def getitem_slice_step(self, start, stop, step, slicelength):
+        res_w = [None] * slicelength
+        for i in range(slicelength):
+            res_w[i] = self.getitem(start)
+            start += step
+        return RListImplementation(self.space, res_w)
+
+    def delitem_slice_step(self, start, stop, step, slicelength):
+        n = self.length()
+
+        recycle = [None] * slicelength
+        i = start
+
+        # keep a reference to the objects to be removed,
+        # preventing side effects during destruction
+        recycle[0] = self.getitem(i)
+
+        for discard in range(1, slicelength):
+            j = i+1
+            i += step
+            while j < i:
+                self = self.i_setitem(j - discard, self.getitem(j))
+                j += 1
+            recycle[discard] = self.getitem(i)
+
+        j = i+1
+        while j < n:
+            self = self.i_setitem(j-slicelength, self.getitem(j))
+            j += 1
+        start = n - slicelength
+        assert start >= 0 # annotator hint
+        self = self.i_delitem_slice(start, n)
+        return self
+   
+    def mul(self, times):
+        return make_implementation(self.space, self.get_list_w() * times)
+
+    def copy(self):
+        return self.getitem_slice(0, self.length())
+
+    def to_rlist(self):
+        list_w = self.get_list_w()
+        return RListImplementation(self.space, list_w)
+
+    # interface used by W_ListMultiObject:
+
+    def i_setitem(self, i, w_item):
+        impl = self.setitem(i, w_item)
+        if impl is None: # failed to implement
+            list_w = self.get_list_w()
+            assert i >= 0 and i < len(list_w)
+            list_w[i] = w_item
+            return self.make_implementation(list_w)
+        return impl
+
+    def i_insert(self, i, w_item):
+        impl = self.insert(i, w_item)
+        if impl is None: # failed to implement
+            list_w = self.get_list_w()
+            assert i >= 0 and i <= len(list_w)
+            list_w.insert(i, w_item)
+            return self.make_implementation(list_w)
+        return impl
+
+    def i_append(self, w_item):
+        impl = self.append(w_item)
+        if impl is None: # failed to implement
+            list_w = self.get_list_w()
+            list_w.append(w_item)
+            return self.make_implementation(list_w)
+        return impl
+
+    def i_add(self, other):
+        impl = self.add(other)
+        if impl is None:
+            list_w1 = self.get_list_w()
+            list_w2 = other.get_list_w()
+            return self.make_implementation(list_w1 + list_w2)
+        return impl
+
+    def i_extend(self, other):
+        impl = self.extend(other)
+        if impl is None:
+            list_w1 = self.get_list_w()
+            list_w2 = other.get_list_w()
+            return self.make_implementation(list_w1 + list_w2)
+        return impl
+
+    def i_delitem(self, i):
+        impl = self.delitem(i)
+        if impl is None:
+            list_w = self.get_list_w()
+            del list_w[i]
+            return self.make_implementation(list_w)
+        return impl
+
+    def i_delitem_slice(self, start, stop):
+        impl = self.delitem_slice(start, stop)
+        if impl is None:
+            list_w = self.get_list_w()
+            assert 0 <= start < len(list_w)
+            assert 0 <= stop <= len(list_w)
+            del list_w[start:stop]
+            return self.make_implementation(list_w)
+        return impl
+
+    def make_implementation(self, list_w):
+        space = self.space
+        if space.config.objspace.std.withfastslice:
+            return SliceTrackingListImplementation(space, list_w)
+        else:
+            return RListImplementation(space, list_w)
+
+
+class RListImplementation(ListImplementation):
+    def __init__(self, space, list_w):
+        ListImplementation.__init__(self, space)
+        self.list_w = list_w
+
+    def length(self):
+        return len(self.list_w)
+
+    def getitem(self, i):
+        return self.list_w[i]
+
+    def getitem_slice(self, start, stop):
+        assert start >= 0
+        assert stop >= 0 and stop <= len(self.list_w)
+        return RListImplementation(self.space, self.list_w[start:stop])
+
+    def delitem(self, i):
+        assert i >= 0 and i < len(self.list_w)
+        if len(self.list_w) == 1:
+            return self.space.fromcache(State).empty_impl
+        del self.list_w[i]
+        return self
+
+    def delitem_slice(self, start, stop):
+        assert start >= 0
+        assert stop >= 0 and stop <= len(self.list_w)
+        if len(self.list_w) == stop and start == 0:
+            return self.space.fromcache(State).empty_impl
+        del self.list_w[start:stop]
+        return self
+    
+    def setitem(self, i, w_item):
+        assert i >= 0 and i < len(self.list_w)
+        self.list_w[i] = w_item
+        return self
+
+    def insert(self, i, w_item):
+        assert i >= 0 and i <= len(self.list_w)
+        self.list_w.insert(i, w_item)
+        return self
+
+    def add(self, other):
+        return RListImplementation(
+            self.space, self.list_w + other.get_list_w())
+
+    def append(self, w_item):
+        self.list_w.append(w_item)
+        return self
+
+    def extend(self, other):
+        self.list_w.extend(other.get_list_w())
+        return self
+
+    def reverse(self):
+        self.list_w.reverse()
+        return self
+
+    def get_list_w(self):
+        return self.list_w
+
+    def to_rlist(self):
+        return self
+    
+    def __repr__(self):
+        return "RListImplementation(%s)" % (self.list_w, )
+
+class EmptyListImplementation(ListImplementation):
+    def make_impl(self, w_item):
+        space = self.space
+        if space.config.objspace.std.withfastslice:
+            return SliceTrackingListImplementation(space, [w_item])
+        w_type = space.type(w_item)
+        if space.is_w(w_type, space.w_str):
+            strlist = [space.str_w(w_item)]
+            return StrListImplementation(space, strlist)
+        return RListImplementation(space, [w_item])
+
+    def length(self):
+        return 0
+
+    def getitem(self, i):
+        raise IndexError
+
+    def getitem_slice(self, start, stop):
+        if start == 0 and stop == 0:
+            return self
+        raise IndexError
+
+    def delitem(self, index):
+        raise IndexError
+
+    def delitem_slice(self, start, stop):
+        if start == 0 and stop == 0:
+            return self
+        raise IndexError
+
+    def setitem(self, i, w_item):
+        raise IndexError
+
+    def insert(self, i, w_item):
+        return self.make_impl(w_item)
+
+    def add(self, other):
+        return other.copy()
+
+    def append(self, w_item):
+        return self.make_impl(w_item)
+
+    def extend(self, other):
+        return other.copy()
+
+    def reverse(self):
+        return self
+
+    def get_list_w(self):
+        return []
+
+    def copy(self):
+        return self
+
+    def mul(self, times):
+        return self
+
+    def __repr__(self):
+        return "EmptyListImplementation()"
+
+class StrListImplementation(ListImplementation):
+    def __init__(self, space, strlist):
+        self.strlist = strlist
+        ListImplementation.__init__(self, space)
+
+    def length(self):
+        return len(self.strlist)
+
+    def getitem(self, i):
+        assert 0 <= i < len(self.strlist)
+        return self.space.wrap(self.strlist[i])
+
+    def getitem_slice(self, start, stop):
+        assert 0 <= start < len(self.strlist)
+        assert 0 <= stop <= len(self.strlist)
+        return StrListImplementation(self.space, self.strlist[start:stop])
+
+    def getitem_slice_step(self, start, stop, step, slicelength):
+        assert 0 <= start < len(self.strlist)
+        assert 0 <= stop < len(self.strlist)
+        assert slicelength > 0
+        res = [0] * slicelength
+        for i in range(slicelength):
+            res[i] = self.strlist[start]
+            start += step
+        return StrListImplementation(self.space, res)
+
+    def delitem(self, index):
+        assert 0 <= i < len(self.strlist)
+        if len(self.strlist) == 1:
+            return self.space.fromcache(State).empty_impl
+        del self.strlist[index]
+        return self
+
+    def delitem_slice(self, start, stop):
+        assert 0 <= start < len(self.strlist)
+        assert 0 <= stop < len(self.strlist)
+        if len(self.strlist) == stop and start == 0:
+            return self.space.fromcache(State).empty_impl
+        del self.strlist[start:stop]
+        return self
+    
+    def setitem(self, i, w_item):
+        assert 0 <= i < len(self.strlist)
+        if self.space.is_w(self.space.type(w_item), self.space.w_str):
+            self.strlist[i] = self.space.str_w(w_item)
+            return self
+        return None
+        
+    def insert(self, i, w_item):
+        assert 0 <= i <= len(self.strlist)
+        if self.space.is_w(self.space.type(w_item), self.space.w_str):
+            self.strlist.insert(i, self.space.str_w(w_item))
+            return self
+        return None
+
+    def add(self, other):
+        if isinstance(other, StrListImplementation):
+            return StrListImplementation(
+                self.space, self.strlist + other.strlist)
+
+    def append(self, w_item):
+        if self.space.is_w(self.space.type(w_item), self.space.w_str):
+            self.strlist.append(self.space.str_w(w_item))
+            return self
+        return None
+
+    def extend(self, other):
+        if isinstance(other, StrListImplementation):
+            self.strlist.extend(other.strlist)
+            return self
+
+    def reverse(self):
+        self.strlist.reverse()
+        return self
+
+    def get_list_w(self):
+        return [self.space.wrap(i) for i in self.strlist]
+
+    def __repr__(self):
+        return "StrListImplementation(%s)" % (self.strlist, )
+
+
+class RangeImplementation(ListImplementation):
+    def __init__(self, space, start, step, length):
+        ListImplementation.__init__(self, space)
+        self.start = start
+        self.step = step
+        self.len = length
+
+    def length(self):
+        return self.len
+
+    def getitem_w(self, i):
+        assert 0 <= i < self.len
+        return self.start + i * self.step
+
+    def getitem(self, i):
+        return wrapint(self.space, self.getitem_w(i))
+
+    def getitem_slice(self, start, stop):
+        rangestart = self.getitem_w(start)
+        return RangeImplementation(
+            self.space, rangestart, self.step, stop - start)
+
+    def getitem_slice_step(self, start, stop, step, slicelength):
+        rangestart = self.getitem_w(start)
+        rangestep = self.step * step
+        return RangeImplementation(
+            self.space, rangestart, rangestep, slicelength)
+
+    def delitem(self, index):
+        if index == 0:
+            self.start = self.getitem_w(1)
+            self.len -= 1
+            return self
+        if index == self.len - 1:
+            self.len -= 1
+            return self
+        return None
+
+    def delitem_slice(self, start, stop):
+        if start == 0:
+            if stop == self.len:
+                return self.space.fromcache(State).empty_impl
+            self.start = self.getitem_w(stop)
+            self.len -= stop
+            return self
+        if stop == self.len:
+            self.len = start
+            return self
+        return None
+    
+    def reverse(self):
+        self.start = self.getitem_w(self.len - 1)
+        self.step = -self.step
+        return self
+
+    def get_list_w(self):
+        start = self.start
+        step = self.step
+        length = self.len
+        if not length:
+            return []
+        
+        list_w = [None] * length
+
+        i = start
+        n = 0
+        while n < length:
+            list_w[n] = wrapint(self.space, i)
+            i += step
+            n += 1
+
+        return list_w
+ 
+    def __repr__(self):
+        return "RangeImplementation(%s, %s, %s)" % (
+            self.start, self.len, self.step)
+
+
+class SliceTrackingListImplementation(RListImplementation):
+    def __init__(self, space, list_w):
+        RListImplementation.__init__(self, space, list_w)
+        self.slices = []
+
+    def getitem_slice(self, start, stop):
+        assert start >= 0
+        assert stop >= 0 and stop <= len(self.list_w)
+        # just do this for slices of a certain length
+        if stop - start > 5:
+            index = len(self.slices)
+            sliceimpl = SliceListImplementation(
+                    self.space, self, index, start, stop)
+            self.slices.append(sliceimpl)
+            return sliceimpl
+        else:
+            return self.getitem_true_slice(start, stop)
+
+    def getitem_true_slice(self, start, stop):
+        assert start >= 0
+        assert stop >= 0 and stop <= len(self.list_w)
+        return SliceTrackingListImplementation(
+                self.space, self.list_w[start:stop])
+
+    def getitem_slice_step(self, start, stop, step, slicelength):
+        res_w = [None] * slicelength
+        for i in range(slicelength):
+            res_w[i] = self.getitem(start)
+            start += step
+        return SliceTrackingListImplementation(self.space, res_w)
+
+    def delitem(self, index):
+        assert 0 <= index < len(self.list_w)
+        if len(self.list_w) == 1:
+            return self.space.fromcache(State).empty_impl
+        self.changed()
+        del self.list_w[index]
+        return self
+
+    def delitem_slice(self, start, stop):
+        assert start >= 0
+        assert stop >= 0 and stop <= len(self.list_w)
+        if start == 0 and len(self.list_w) == stop:
+            return self.space.fromcache(State).empty_impl
+        self.changed()
+        del self.list_w[start:stop]
+        return self
+    
+    def setitem(self, i, w_item):
+        self.changed()
+        assert 0 <= i < len(self.list_w)
+        self.list_w[i] = w_item
+        return self
+
+    def insert(self, i, w_item):
+        assert 0 <= i <= len(self.list_w)
+        if i == len(self.list_w):
+            return self.append(w_item)
+        self.changed()
+        self.list_w.insert(i, w_item)
+        return self
+
+    def add(self, other):
+        if isinstance(other, SliceTrackingListImplementation):
+            return SliceTrackingListImplementation(
+                self.space, self.list_w + other.list_w)
+        return SliceTrackingListImplementation(
+            self.space, self.list_w + other.get_list_w())
+
+    # append and extend need not be overridden from RListImplementation.__init__
+    # they change the list but cannot affect slices taken so far
+
+    def reverse(self):
+        # could be optimised: the slices grow steps and their
+        # step is reversed :-)
+        self.changed()
+        self.list_w.reverse()
+        return self
+
+    def to_rlist(self):
+        return RListImplementation(self.space, self.list_w)
+
+    def changed(self):
+        if not self.slices:
+            return
+        self.notify_slices()
+    
+    def notify_slices(self):
+        for slice in self.slices:
+            if slice is not None:
+                slice.detach()
+        self.slices = []
+
+    def unregister_slice(self, index):
+        self.slices[index] = None
+
+    def __repr__(self):
+        return "SliceTrackingListImplementation(%s, <%s slice(s)>)" % (
+            self.list_w, len(self.slices))
+
+class SliceListImplementation(ListImplementation):
+    def __init__(self, space, listimpl, index, start, stop):
+        assert 0 <= start < listimpl.length()
+        assert 0 <= stop <= listimpl.length()
+        ListImplementation.__init__(self, space)
+        self.listimpl = listimpl
+        self.index = index
+        self.start = start
+        self.stop = stop
+        self.len = stop - start
+        self.detached_impl = None
+
+    def detach(self):
+        if self.detached_impl is None:
+            self.detached_impl = self.listimpl.getitem_true_slice(
+                self.start, self.stop)
+            self.listimpl = None # loose the reference
+
+    def detach_and_unregister(self):
+        if self.detached_impl is None:
+            self.listimpl.unregister_slice(self.index)
+            self.detach()
+
+    def length(self):
+        if self.detached_impl is not None:
+            return self.detached_impl.length()
+        return self.len
+
+    def getitem(self, i):
+        if self.detached_impl is not None:
+            return self.detached_impl.getitem(i)
+        return self.listimpl.getitem(self.start + i)
+
+    def getitem_slice(self, start, stop):
+        assert start >= 0
+        assert stop >= 0
+        if self.detached_impl is not None:
+            return self.detached_impl.getitem_slice(start, stop)
+        return self.listimpl.getitem_slice(
+            self.start + start, self.start + stop)
+
+    def delitem(self, index):
+        self.detach_and_unregister()
+        return self.detached_impl.delitem(index)
+
+    def delitem_slice(self, start, stop):
+        self.detach_and_unregister()
+        if start == 0 and self.len == stop:
+            return self.space.fromcache(State).empty_impl
+        return self.detached_impl.delitem_slice(start, stop)
+    
+    def setitem(self, i, w_item):
+        self.detach_and_unregister()
+        return self.detached_impl.setitem(i, w_item)
+
+    def insert(self, i, w_item):
+        self.detach_and_unregister()
+        return self.detached_impl.insert(i, w_item)
+
+    def add(self, other):
+        self.detach_and_unregister()
+        return self.detached_impl.add(other)
+
+    def append(self, w_item):
+        self.detach_and_unregister()
+        return self.detached_impl.append(w_item)
+
+    def extend(self, other):
+        self.detach_and_unregister()
+        return self.detached_impl.extend(other)
+
+    def reverse(self):
+        self.detach_and_unregister()
+        return self.detached_impl.reverse()
+
+    def get_list_w(self):
+        self.detach_and_unregister()
+        return self.detached_impl.get_list_w()
+
+    def __repr__(self):
+        if self.detached_impl is not None:
+            return "SliceListImplementation(%s)" % (self.detached_impl, )
+        return "SliceListImplementation(%s, %s, %s)" % (
+            self.listimpl, self.start, self.stop)
+
+
+def is_homogeneous(space, list_w, w_type):
+    for i in range(len(list_w)):
+        if not space.is_w(w_type, space.type(list_w[i])):
+            return False
+    return True
+
+def make_implementation(space, list_w):
+    if list_w:
+        if space.config.objspace.std.withfastslice:
+            impl = SliceTrackingListImplementation(space, list_w)
+        else:
+            w_type = space.type(list_w[0])
+            if (space.is_w(w_type, space.w_str) and
+                is_homogeneous(space, list_w, w_type)):
+                strlist = [space.str_w(w_i) for w_i in list_w]
+                impl = StrListImplementation(space, strlist)
+            else:
+                impl = RListImplementation(space, list_w)
+    else:
+        impl = space.fromcache(State).empty_impl
+    return impl
+
+def convert_list_w(space, list_w):
+    impl = make_implementation(space, list_w)
+    return W_ListMultiObject(space, impl)
+
+
+class W_ListMultiObject(W_Object):
+    from pypy.objspace.std.listtype import list_typedef as typedef
+    
+    def __init__(w_self, space, implementation=None):
+        if implementation is None:
+            implementation = space.fromcache(State).empty_impl
+        w_self.implementation = implementation
+
+    def __repr__(w_self):
+        """ representation for debugging purposes """
+        return "%s(%s)" % (w_self.__class__.__name__, w_self.implementation)
+
+    def unwrap(w_list, space):
+        items = [space.unwrap(w_item)
+                    for w_item in w_list.implementation.get_list_w()]
+        return items
+
+registerimplementation(W_ListMultiObject)
+
+class State(object):
+    def __init__(self, space):
+        self.empty_impl = EmptyListImplementation(space)
+        self.empty_list = W_ListMultiObject(space, self.empty_impl)
+
+
+def _adjust_index(space, index, length, indexerrormsg):
+    if index < 0:
+        index += length
+    if index < 0 or index >= length:
+        raise OperationError(space.w_IndexError,
+                             space.wrap(indexerrormsg))
+    return index
+
+
+def init__ListMulti(space, w_list, __args__):
+    EMPTY_LIST = space.fromcache(State).empty_list
+    w_iterable, = __args__.parse('list',
+                               (['sequence'], None, None),   # signature
+                               [EMPTY_LIST])                 # default argument
+    if w_iterable is not EMPTY_LIST:
+        list_w = space.unpackiterable(w_iterable)
+        if list_w:
+            w_list.implementation = RListImplementation(space, list_w)
+            return
+    w_list.implementation = space.fromcache(State).empty_impl
+
+def len__ListMulti(space, w_list):
+    result = w_list.implementation.length()
+    return wrapint(space, result)
+
+def getitem__ListMulti_ANY(space, w_list, w_index):
+    idx = space.int_w(w_index)
+    idx = _adjust_index(space, idx, w_list.implementation.length(),
+                        "list index out of range")
+    return w_list.implementation.getitem(idx)
+
+def getitem__ListMulti_Slice(space, w_list, w_slice):
+    length = w_list.implementation.length()
+    start, stop, step, slicelength = w_slice.indices4(space, length)
+    assert slicelength >= 0
+    if step == 1 and 0 <= start <= stop:
+        return W_ListMultiObject(
+            space,
+            w_list.implementation.getitem_slice(start, stop))
+    return W_ListMultiObject(
+        space,
+        w_list.implementation.getitem_slice_step(
+            start, stop, step, slicelength))
+
+def contains__ListMulti_ANY(space, w_list, w_obj):
+    # needs to be safe against eq_w() mutating the w_list behind our back
+    i = 0
+    impl = w_list.implementation
+    while i < impl.length(): # intentionally always calling len!
+        if space.eq_w(impl.getitem(i), w_obj):
+            return space.w_True
+        i += 1
+    return space.w_False
+
+def iter__ListMulti(space, w_list):
+    from pypy.objspace.std import iterobject
+    return iterobject.W_SeqIterObject(w_list)
+
+def add__ListMulti_ListMulti(space, w_list1, w_list2):
+    impl = w_list1.implementation.i_add(w_list2.implementation)
+    return W_ListMultiObject(space, impl)
+
+def inplace_add__ListMulti_ANY(space, w_list1, w_iterable2):
+    list_extend__ListMulti_ANY(space, w_list1, w_iterable2)
+    return w_list1
+
+def inplace_add__ListMulti_ListMulti(space, w_list1, w_list2):
+    list_extend__ListMulti_ListMulti(space, w_list1, w_list2)
+    return w_list1
+
+def mul_list_times(space, w_list, w_times):
+    try:
+        times = space.int_w(w_times)
+    except OperationError, e:
+        if e.match(space, space.w_TypeError):
+            raise FailedToImplement
+        raise
+    return W_ListMultiObject(space, w_list.implementation.mul(times))
+
+def mul__ListMulti_ANY(space, w_list, w_times):
+    return mul_list_times(space, w_list, w_times)
+
+def mul__ANY_ListMulti(space, w_times, w_list):
+    return mul_list_times(space, w_list, w_times)
+
+def inplace_mul__ListMulti_ANY(space, w_list, w_times):
+    try:
+        times = space.int_w(w_times)
+    except OperationError, e:
+        if e.match(space, space.w_TypeError):
+            raise FailedToImplement
+        raise
+    # XXX could be more efficient?
+    w_list.implementation = w_list.implementation.mul(times)
+    return w_list
+
+def eq__ListMulti_ListMulti(space, w_list1, w_list2):
+    # needs to be safe against eq_w() mutating the w_lists behind our back
+    impl1 = w_list1.implementation
+    impl2 = w_list2.implementation
+    return equal_impls(space, impl1, impl2)
+
+def equal_impls(space, impl1, impl2):
+    if impl1.length() != impl2.length():
+        return space.w_False
+    i = 0
+    while i < impl1.length() and i < impl2.length():
+        if not space.eq_w(impl1.getitem(i), impl2.getitem(i)):
+            return space.w_False
+        i += 1
+    return space.w_True
+
+def _min(a, b):
+    if a < b:
+        return a
+    return b
+
+def lessthan_impls(space, impl1, impl2):
+    # needs to be safe against eq_w() mutating the w_lists behind our back
+    # Search for the first index where items are different
+    i = 0
+    while i < impl1.length() and i < impl2.length():
+        w_item1 = impl1.getitem(i)
+        w_item2 = impl2.getitem(i)
+        if not space.eq_w(w_item1, w_item2):
+            return space.lt(w_item1, w_item2)
+        i += 1
+    # No more items to compare -- compare sizes
+    return space.newbool(impl1.length() < impl2.length())
+
+def greaterthan_impls(space, impl1, impl2):
+    # needs to be safe against eq_w() mutating the w_lists behind our back
+    # Search for the first index where items are different
+    i = 0
+    while i < impl1.length() and i < impl2.length():
+        w_item1 = impl1.getitem(i)
+        w_item2 = impl2.getitem(i)
+        if not space.eq_w(w_item1, w_item2):
+            return space.gt(w_item1, w_item2)
+        i += 1
+    # No more items to compare -- compare sizes
+    return space.newbool(impl1.length() > impl2.length())
+
+def lt__ListMulti_ListMulti(space, w_list1, w_list2):
+    return lessthan_impls(space, w_list1.implementation,
+        w_list2.implementation)
+
+def gt__ListMulti_ListMulti(space, w_list1, w_list2):
+    return greaterthan_impls(space, w_list1.implementation,
+        w_list2.implementation)
+
+def delitem__ListMulti_ANY(space, w_list, w_idx):
+    idx = space.int_w(w_idx)
+    length = w_list.implementation.length()
+    idx = _adjust_index(space, idx, length, "list deletion index out of range")
+    w_list.implementation = w_list.implementation.i_delitem(idx)
+    return space.w_None
+
+def delitem__ListMulti_Slice(space, w_list, w_slice):
+    start, stop, step, slicelength = w_slice.indices4(
+        space, w_list.implementation.length())
+
+    if slicelength==0:
+        return
+
+    if step < 0:
+        start = start + step * (slicelength-1)
+        step = -step
+        # stop is invalid
+        
+    if step == 1:
+        _del_slice(w_list, start, start+slicelength)
+    else:
+        w_list.implementation = w_list.implementation.delitem_slice_step(
+            start, start + slicelength, step, slicelength)
+
+    return space.w_None
+
+def setitem__ListMulti_ANY_ANY(space, w_list, w_index, w_any):
+    idx = space.int_w(w_index)
+    idx = _adjust_index(space, idx, w_list.implementation.length(),
+                        "list index out of range")
+    w_list.implementation = w_list.implementation.i_setitem(idx, w_any)
+    return space.w_None
+
+def setitem__ListMulti_Slice_ListMulti(space, w_list, w_slice, w_list2):
+    impl = w_list2.implementation
+    return _setitem_slice_helper(space, w_list, w_slice, impl)
+
+def setitem__ListMulti_Slice_ANY(space, w_list, w_slice, w_iterable):
+    l = RListImplementation(space, space.unpackiterable(w_iterable))
+    return _setitem_slice_helper(space, w_list, w_slice, l)
+
+def _setitem_slice_helper(space, w_list, w_slice, impl2):
+    impl = w_list.implementation
+    oldsize = impl.length()
+    len2 = impl2.length()
+    start, stop, step, slicelength = w_slice.indices4(space, oldsize)
+    assert slicelength >= 0
+
+    if step == 1:  # Support list resizing for non-extended slices
+        delta = len2 - slicelength
+        if delta >= 0:
+            newsize = oldsize + delta
+            impl = impl.i_extend(
+                RListImplementation(space, [space.w_None] * delta))
+            lim = start + len2
+            i = newsize - 1
+            while i >= lim:
+                impl = impl.i_setitem(i, impl.getitem(i-delta))
+                i -= 1
+        else:
+            # shrinking requires the careful memory management of _del_slice()
+            _del_slice(w_list, start, start-delta)
+    elif len2 != slicelength:  # No resize for extended slices
+        raise OperationError(space.w_ValueError, space.wrap("attempt to "
+              "assign sequence of size %d to extended slice of size %d" %
+              (len2,slicelength)))
+
+    if impl2 is impl:
+        if step > 0:
+            # 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:
+                impl = impl.i_setitem(start, impl2.getitem(i))
+                start -= step
+                i -= 1
+            return space.w_None
+        else:
+            # Make a shallow copy to more easily handle the reversal case
+            impl2 = impl2.getitem_slice(0, impl2.length())
+    for i in range(len2):
+        impl = impl.i_setitem(start, impl2.getitem(i))
+        start += step
+    w_list.implementation = impl
+    return space.w_None
+
+app = gateway.applevel("""
+    def listrepr(currently_in_repr, l):
+        'The app-level part of repr().'
+        list_id = id(l)
+        if list_id in currently_in_repr:
+            return '[...]'
+        currently_in_repr[list_id] = 1
+        try:
+            return "[" + ", ".join([repr(x) for x in l]) + ']'
+        finally:
+            try:
+                del currently_in_repr[list_id]
+            except:
+                pass
+""", filename=__file__) 
+
+listrepr = app.interphook("listrepr")
+
+def repr__ListMulti(space, w_list):
+    if w_list.implementation.length() == 0:
+        return space.wrap('[]')
+    w_currently_in_repr = space.getexecutioncontext()._py_repr
+    return listrepr(space, w_currently_in_repr, w_list)
+
+def list_insert__ListMulti_ANY_ANY(space, w_list, w_where, w_any):
+    where = space.int_w(w_where)
+    length = w_list.implementation.length()
+    if where < 0:
+        where += length
+        if where < 0:
+            where = 0
+    elif where > length:
+        where = length
+    w_list.implementation = w_list.implementation.i_insert(where, w_any)
+    return space.w_None
+
+def list_append__ListMulti_ANY(space, w_list, w_any):
+    w_list.implementation = w_list.implementation.i_append(w_any)
+    return space.w_None
+
+def list_extend__ListMulti_ListMulti(space, w_list, w_list2):
+    impl2 = w_list2.implementation
+    w_list.implementation = w_list.implementation.i_extend(impl2)
+    return space.w_None
+
+def list_extend__ListMulti_ANY(space, w_list, w_any):
+    list_w2 = space.unpackiterable(w_any)
+    impl2 = RListImplementation(space, list_w2)
+    w_list.implementation = w_list.implementation.i_extend(impl2)
+    return space.w_None
+
+def _del_slice(w_list, ilow, ihigh):
+    """ similar to the deletion part of list_ass_slice in CPython """
+    impl = w_list.implementation
+    n = impl.length()
+    if ilow < 0:
+        ilow = 0
+    elif ilow > n:
+        ilow = n
+    if ihigh < ilow:
+        ihigh = ilow
+    elif ihigh > n:
+        ihigh = n
+    # keep a reference to the objects to be removed,
+    # preventing side effects during destruction
+    recycle = impl.getitem_slice(ilow, ihigh)
+    w_list.implementation = impl.i_delitem_slice(ilow, ihigh)
+
+
+def list_pop__ListMulti_ANY(space, w_list, w_idx=-1):
+    impl = w_list.implementation
+    length = impl.length()
+    if length == 0:
+        raise OperationError(space.w_IndexError,
+                             space.wrap("pop from empty list"))
+    idx = space.int_w(w_idx)
+    idx = _adjust_index(space, idx, length, "pop index out of range")
+    w_result = impl.getitem(idx)
+    w_list.implementation = impl.i_delitem(idx)
+    return w_result
+
+def list_remove__ListMulti_ANY(space, w_list, w_any):
+    # needs to be safe against eq_w() mutating the w_list behind our back
+    i = 0
+    while i < w_list.implementation.length():
+        if space.eq_w(w_list.implementation.getitem(i), w_any):
+            if i < w_list.implementation.length():
+                w_list.implementation = w_list.implementation.i_delitem(i)
+            return space.w_None
+        i += 1
+    raise OperationError(space.w_ValueError,
+                         space.wrap("list.remove(x): x not in list"))
+
+def list_index__ListMulti_ANY_ANY_ANY(space, w_list, w_any, w_start, w_stop):
+    # needs to be safe against eq_w() mutating the w_list behind our back
+    length = w_list.implementation.length()
+    w_start = slicetype.adapt_bound(space, w_start, space.wrap(length))
+    w_stop = slicetype.adapt_bound(space, w_stop, space.wrap(length))
+    i = space.int_w(w_start)
+    stop = space.int_w(w_stop)
+    while i < stop and i < w_list.implementation.length():
+        if space.eq_w(w_list.implementation.getitem(i), w_any):
+            return space.wrap(i)
+        i += 1
+    raise OperationError(space.w_ValueError,
+                         space.wrap("list.index(x): x not in list"))
+
+def list_count__ListMulti_ANY(space, w_list, w_any):
+    # needs to be safe against eq_w() mutating the w_list behind our back
+    count = 0
+    i = 0
+    while i < w_list.implementation.length():
+        if space.eq_w(w_list.implementation.getitem(i), w_any):
+            count += 1
+        i += 1
+    return space.wrap(count)
+
+def list_reverse__ListMulti(space, w_list):
+    w_list.implementation = w_list.implementation.reverse()
+    return space.w_None
+
+# ____________________________________________________________
+# Sorting
+
+# Reverse a slice of a list in place, from lo up to (exclusive) hi.
+# (used in sort)
+
+class KeyContainer(baseobjspace.W_Root):
+    def __init__(self, w_key, w_item):
+        self.w_key = w_key
+        self.w_item = w_item
+
+# NOTE: all the subclasses of TimSort should inherit from a common subclass,
+#       so make sure that only SimpleSort inherits directly from TimSort.
+#       This is necessary to hide the parent method TimSort.lt() from the
+#       annotator.
+class SimpleSort(TimSort):
+    def lt(self, a, b):
+        space = self.space
+        return space.is_true(space.lt(a, b))
+
+class CustomCompareSort(SimpleSort):
+    def lt(self, a, b):
+        space = self.space
+        w_cmp = self.w_cmp
+        w_result = space.call_function(w_cmp, a, b)
+        try:
+            result = space.int_w(w_result)
+        except OperationError, e:
+            if e.match(space, space.w_TypeError):
+                raise OperationError(space.w_TypeError,
+                    space.wrap("comparison function must return int"))
+            raise
+        return result < 0
+
+class CustomKeySort(SimpleSort):
+    def lt(self, a, b):
+        assert isinstance(a, KeyContainer)
+        assert isinstance(b, KeyContainer)
+        space = self.space
+        return space.is_true(space.lt(a.w_key, b.w_key))
+
+class CustomKeyCompareSort(CustomCompareSort):
+    def lt(self, a, b):
+        assert isinstance(a, KeyContainer)
+        assert isinstance(b, KeyContainer)
+        return CustomCompareSort.lt(self, a.w_key, b.w_key)
+
+def list_sort__ListMulti_ANY_ANY_ANY(space, w_list, w_cmp, w_keyfunc, w_reverse):
+    has_cmp = not space.is_w(w_cmp, space.w_None)
+    has_key = not space.is_w(w_keyfunc, space.w_None)
+    has_reverse = space.is_true(w_reverse)
+
+    # create and setup a TimSort instance
+    if has_cmp: 
+        if has_key: 
+            sorterclass = CustomKeyCompareSort
+        else: 
+            sorterclass = CustomCompareSort
+    else: 
+        if has_key: 
+            sorterclass = CustomKeySort
+        else: 
+            sorterclass = SimpleSort
+    impl = w_list.implementation.to_rlist()
+    w_list.implementation = impl
+    items = impl.list_w
+    sorter = sorterclass(items, impl.length())
+    sorter.space = space
+    sorter.w_cmp = w_cmp
+
+    try:
+        # The list is temporarily made empty, so that mutations performed
+        # by comparison functions can't affect the slice of memory we're
+        # sorting (allowing mutations during sorting is an IndexError or
+        # core-dump factory).
+        w_list.implementation = EmptyListImplementation(space)
+
+        # wrap each item in a KeyContainer if needed
+        if has_key:
+            for i in range(sorter.listlength):
+                w_item = sorter.list[i]
+                w_key = space.call_function(w_keyfunc, w_item)
+                sorter.list[i] = KeyContainer(w_key, w_item)
+
+        # Reverse sort stability achieved by initially reversing the list,
+        # applying a stable forward sort, then reversing the final result.
+        if has_reverse:
+            sorter.list.reverse()
+
+        # perform the sort
+        sorter.sort()
+
+        # reverse again
+        if has_reverse:
+            sorter.list.reverse()
+
+    finally:
+        # unwrap each item if needed
+        if has_key:
+            for i in range(sorter.listlength):
+                w_obj = sorter.list[i]
+                if isinstance(w_obj, KeyContainer):
+                    sorter.list[i] = w_obj.w_item
+
+        # check if the user mucked with the list during the sort
+        mucked = w_list.implementation.length() > 0
+
+        # put the items back into the list
+        impl.list_w = sorter.list
+        w_list.implementation = impl
+
+    if mucked:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("list modified during sort"))
+
+    return space.w_None
+
+
+from pypy.objspace.std import listtype
+register_all(vars(), listtype)

Modified: pypy/dist/pypy/objspace/std/listtype.py
==============================================================================
--- pypy/dist/pypy/objspace/std/listtype.py	(original)
+++ pypy/dist/pypy/objspace/std/listtype.py	Mon Feb  5 21:49:56 2007
@@ -40,9 +40,14 @@
 # ____________________________________________________________
 
 def descr__new__(space, w_listtype, __args__):
-    from pypy.objspace.std.listobject import W_ListObject
-    w_obj = space.allocate_instance(W_ListObject, w_listtype)
-    W_ListObject.__init__(w_obj, [])
+    if space.config.objspace.std.withmultilist:
+        from pypy.objspace.std.listmultiobject import W_ListMultiObject
+        w_obj = space.allocate_instance(W_ListMultiObject, w_listtype)
+        W_ListMultiObject.__init__(w_obj, space)
+    else:
+        from pypy.objspace.std.listobject import W_ListObject
+        w_obj = space.allocate_instance(W_ListObject, w_listtype)
+        W_ListObject.__init__(w_obj, [])
     return w_obj
 
 # ____________________________________________________________

Modified: pypy/dist/pypy/objspace/std/model.py
==============================================================================
--- pypy/dist/pypy/objspace/std/model.py	(original)
+++ pypy/dist/pypy/objspace/std/model.py	Mon Feb  5 21:49:56 2007
@@ -16,6 +16,7 @@
                         "dictstrobject.W_DictStrIterObject"],
     "withmultidict"  : ["dictmultiobject.W_DictMultiObject",
                         "dictmultiobject.W_DictMultiIterObject"],
+    "withmultilist"  : ["listmultiobject.W_ListMultiObject"],
     "withrangelist"  : ["rangeobject.W_RangeListObject",
                         "rangeobject.W_RangeIterObject"],
     "withtproxy" : ["proxyobject.W_TransparentList",
@@ -65,6 +66,7 @@
         from pypy.objspace.std import dictobject
         from pypy.objspace.std import dictstrobject
         from pypy.objspace.std import dictmultiobject
+        from pypy.objspace.std import listmultiobject
         from pypy.objspace.std import stringobject
         from pypy.objspace.std import strsliceobject
         from pypy.objspace.std import strjoinobject
@@ -112,6 +114,7 @@
         imported_but_not_registered = {
             dictobject.W_DictObject: True,
             dictobject.W_DictIterObject: True,
+            listobject.W_ListObject: True,
         }
         for option, value in config.objspace.std:
             if option.startswith("with") and option in option_to_typename:
@@ -127,6 +130,9 @@
             del self.typeorder[dictobject.W_DictObject]
             del self.typeorder[dictobject.W_DictIterObject]
 
+        if config.objspace.std.withmultilist:
+            del self.typeorder[listobject.W_ListObject]
+
         #check if we missed implementations
         from pypy.objspace.std.objspace import _registered_implementations
         for implcls in _registered_implementations:

Modified: pypy/dist/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/std/objspace.py	(original)
+++ pypy/dist/pypy/objspace/std/objspace.py	Mon Feb  5 21:49:56 2007
@@ -348,7 +348,7 @@
             return W_TupleObject(wrappeditems)
         if isinstance(x, list):
             wrappeditems = [self.wrap(item) for item in x]
-            return W_ListObject(wrappeditems)
+            return self.newlist(wrappeditems)
 
         # The following cases are even stranger.
         # Really really only for tests.
@@ -432,7 +432,12 @@
         return W_TupleObject(list_w)
 
     def newlist(self, list_w):
-        return W_ListObject(list_w)
+        if self.config.objspace.std.withmultilist:
+            from pypy.objspace.std.listmultiobject import convert_list_w
+            return convert_list_w(self, list_w)
+        else:
+            from pypy.objspace.std.listobject import W_ListObject
+            return W_ListObject(list_w)
 
     def newdict(self, track_builtin_shadowing=False):
         if self.config.objspace.opcodes.CALL_LIKELY_BUILTIN and track_builtin_shadowing:

Added: pypy/dist/pypy/objspace/std/test/test_listmultiobject.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/objspace/std/test/test_listmultiobject.py	Mon Feb  5 21:49:56 2007
@@ -0,0 +1,119 @@
+import autopath
+from pypy.interpreter.error import OperationError
+from pypy.objspace.std.listmultiobject import W_ListMultiObject, \
+    SliceTrackingListImplementation
+from pypy.conftest import gettestobjspace
+from pypy.objspace.std.test import test_listobject
+from pypy.objspace.std.test.test_dictmultiobject import FakeSpace
+from pypy.objspace.std.test.test_rangeobject import AppTestRangeListObject
+
+class AppTest_ListMultiObject(test_listobject.AppTestW_ListObject):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withmultilist": True})
+
+    def test_slice_with_step(self):
+        l = range(20)
+        l[0] = 14
+        l2 = l[1:-1:2]
+        assert l2 == range(1, 19, 2)
+
+    def test_strlist_literal(self):
+        import pypymagic
+        l = ["1", "2", "3", "4", "5"]
+        assert "StrListImplementation" in pypymagic.pypy_repr(l)
+
+    def test_strlist_append(self):
+        import pypymagic
+        l = []
+        l.append("a")
+        assert "StrListImplementation" in pypymagic.pypy_repr(l)
+        l.extend(["b", "c", "d"])
+        l += ["e", "f"]
+        assert l == ["a", "b", "c", "d", "e", "f"]
+        assert "StrListImplementation" in pypymagic.pypy_repr(l)
+
+
+class AppTestRangeImplementation(AppTestRangeListObject):
+
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withmultilist": True})
+        cls.w_not_forced = cls.space.appexec([], """():
+            import pypymagic
+            def f(r):
+                return (isinstance(r, list) and
+                        "RangeImplementation" in pypymagic.pypy_repr(r))
+            return f
+        """)
+
+    def test_sort(self):
+        pass # won't work with multilists
+
+
+class AppTest_FastSlice(test_listobject.AppTestW_ListObject):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withfastslice": True})
+
+    def test_lazy_slice(self):
+        import pypymagic
+        l = [i for i in range(100)] # force it to not be a range impl
+        l2 = l[1:-1]
+        assert "SliceTrackingListImplementation" in pypymagic.pypy_repr(l)
+        assert "SliceListImplementation" in pypymagic.pypy_repr(l2)
+        result = 0
+        for i in l2:
+            result += i
+        # didn't force l2
+        assert "SliceListImplementation" in pypymagic.pypy_repr(l2)
+        # force l2:
+        l2.append(10)
+        assert l2 == range(1, 99) + [10]
+
+    def test_append_extend_dont_force(self):
+        import pypymagic
+        l = [i for i in range(100)] # force it to not be a range impl
+        l2 = l[1:-1]
+        assert "SliceTrackingListImplementation" in pypymagic.pypy_repr(l)
+        assert "SliceListImplementation" in pypymagic.pypy_repr(l2)
+        l.append(100)
+        l.extend(range(101, 110))
+        assert l == range(110)
+        assert "SliceTrackingListImplementation" in pypymagic.pypy_repr(l)
+        assert "SliceListImplementation" in pypymagic.pypy_repr(l2)
+
+    def test_slice_of_slice(self):
+        import pypymagic
+        l = [i for i in range(100)] # force it to not be a range impl
+        l2 = l[1:-1]
+        l3 = l2[1:-1]
+        l4 = l3[1:-1]
+        assert l2 == range(1, 99)
+        assert l3 == range(2, 98)
+        assert l4 == range(3, 97)
+        assert "SliceListImplementation" in pypymagic.pypy_repr(l4)
+        l2[3] = 4
+        assert "SliceListImplementation" not in pypymagic.pypy_repr(l2)
+        assert "SliceListImplementation" in pypymagic.pypy_repr(l4)
+
+    def test_delitem_to_empty(self):
+        import pypymagic
+        l = [i for i in range(100)] # force it to not be a range impl
+        l1 = l[1:-1]
+        del l1[:]
+        assert "EmptyListImplementation" in pypymagic.pypy_repr(l1)
+        
+
+class TestSliceListImplementation(object):
+    def setup_method(self,method):
+        self.space = FakeSpace()
+
+    def test_simple(self):
+        impl = SliceTrackingListImplementation(self.space, range(20))
+        impl2 = impl.getitem_slice(2, 14)
+        assert impl2.getitem(2) == 4
+        impl = impl.setitem(4, 10)
+        assert impl.getitem(4) == 10
+        # check that impl2 works after detaching
+        assert impl2.getitem(2) == 4
+        impl2 = impl2.setitem(2, 5)
+        assert impl2.getitem(2) == 5
+

Modified: pypy/dist/pypy/objspace/std/test/test_listobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_listobject.py	(original)
+++ pypy/dist/pypy/objspace/std/test/test_listobject.py	Mon Feb  5 21:49:56 2007
@@ -429,7 +429,26 @@
         l = ['a', 'C', 'b']
         l.sort(reverse = True, key = lower)
         assert l == ['C', 'b', 'a']
-        
+    
+    def test_getitem(self):
+        l = [1, 2, 3, 4, 5, 6, 9]
+        assert l[0] == 1
+        assert l[-1] == 9
+        assert l[-2] == 6
+        raises(IndexError, "l[len(l)]")
+        raises(IndexError, "l[-len(l)-1]")
+
+    def test_delitem(self):
+        l = [1, 2, 3, 4, 5, 6, 9]
+        del l[0]
+        assert l == [2, 3, 4, 5, 6, 9]
+        del l[-1]
+        assert l == [2, 3, 4, 5, 6]
+        del l[-2]
+        assert l == [2, 3, 4, 6]
+        raises(IndexError, "del l[len(l)]")
+        raises(IndexError, "del l[-len(l)-1]")
+
     def test_extended_slice(self):
         l = range(10)
         del l[::2]



More information about the Pypy-commit mailing list