[pypy-svn] r17298 - in pypy/dist/pypy: objspace/std objspace/std/test rpython rpython/test translator/c

tismer at codespeak.net tismer at codespeak.net
Tue Sep 6 19:32:52 CEST 2005


Author: tismer
Date: Tue Sep  6 19:32:48 2005
New Revision: 17298

Modified:
   pypy/dist/pypy/objspace/std/listobject.py
   pypy/dist/pypy/objspace/std/marshal_impl.py
   pypy/dist/pypy/objspace/std/test/test_listobject.py
   pypy/dist/pypy/rpython/rlist.py
   pypy/dist/pypy/rpython/rtuple.py
   pypy/dist/pypy/rpython/test/test_rlist.py
   pypy/dist/pypy/translator/c/extfunc.py
Log:
quite a big check-in, this was not my intent.

I removed overallocation from listobject.py
and tried to map as much as possible directly to rlist.py

Also did some simplifications and additions to rlist,
which unfortunately affected quite some code.
new: rlist supports inplace multiplication.
rlist.pop specializes on error checking, now.
The latter causes the rtyper to break. I'm checking in, since
this looks like a bug in rtyper.

Modified: pypy/dist/pypy/objspace/std/listobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/listobject.py	(original)
+++ pypy/dist/pypy/objspace/std/listobject.py	Tue Sep  6 19:32:48 2005
@@ -14,31 +14,18 @@
     
     def __init__(w_self, space, wrappeditems):
         W_Object.__init__(w_self, space)
-        w_self.ob_item = []
-        w_self.ob_size = 0
-        newlen = len(wrappeditems)
-        _list_resize(w_self, newlen)
-        w_self.ob_size = newlen
-        items = w_self.ob_item
-        p = newlen
-        while p:
-            p -= 1
-            items[p] = wrappeditems[p]
+        w_self.wrappeditems = wrappeditems
 
     def __repr__(w_self):
         """ representation for debugging purposes """
-        reprlist = [repr(w_item) for w_item in w_self.ob_item[:w_self.ob_size]]
+        reprlist = [repr(w_item) for w_item in w_self.wrappeditems]
         return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist))
 
     def unwrap(w_list):
         space = w_list.space
-        items = [space.unwrap(w_item) for w_item in w_list.ob_item[:w_list.ob_size]]# XXX generic mixed types unwrap
+        items = [space.unwrap(w_item) for w_item in w_list.wrappeditems]# XXX generic mixed types unwrap
         return list(items)
 
-    def clear(w_list):
-        w_list.ob_item = []
-        w_list.ob_size = 0
-
 
 registerimplementation(W_ListObject)
 
@@ -47,60 +34,45 @@
     w_iterable, = __args__.parse('list',
                                (['sequence'], None, None),   # signature
                                [W_ListObject(space, [])])    # default argument
-    w_list.clear()
-
-    length = 0
-    try:
-        length = space.int_w(space.len(w_iterable))
-        if length < 0:
-            length = 8 
-    except OperationError, e:
-        pass # for now
-    _list_resize(w_list, length)
-    w_iterator = space.iter(w_iterable)
-    while True:
-        try:
-            w_item = space.next(w_iterator)
-        except OperationError, e:
-            if not e.match(space, space.w_StopIteration):
-                raise
-            break  # done
-        _ins1(w_list, w_list.ob_size, w_item)
-
+    w_list.wrappeditems = space.unpackiterable(w_iterable)
 
 def len__List(space, w_list):
-    result = w_list.ob_size
+    result = len(w_list.wrappeditems)
     return W_IntObject(space, result)
 
 def getitem__List_ANY(space, w_list, w_index):
     idx = space.int_w(w_index)
-    if idx < 0:
-        idx += w_list.ob_size
-    if idx < 0 or idx >= w_list.ob_size:
+    try:
+        w_ret = w_list.wrappeditems[idx]
+    except IndexError:
         raise OperationError(space.w_IndexError,
                              space.wrap("list index out of range"))
-    w_item = w_list.ob_item[idx]
-    return w_item
+    return w_ret
 
 def getitem__List_Slice(space, w_list, w_slice):
-    length = w_list.ob_size
+    # XXX consider to extend rlist's functionality?
+    length = len(w_list.wrappeditems)
     start, stop, step, slicelength = slicetype.indices4(space, w_slice, length)
     assert slicelength >= 0
-    w_res = W_ListObject(space, [])
-    _list_resize(w_res, slicelength)
-    items = w_list.ob_item
-    subitems = w_res.ob_item
+    if step == 1 and stop >= start >= 0:
+        assert stop >= 0
+        assert start >= 0
+        return W_ListObject(space, w_list.wrappeditems[start:stop])
+    w_res = W_ListObject(space, [None] * slicelength)
+    items = w_list.wrappeditems
+    subitems = w_res.wrappeditems
     for i in range(slicelength):
         subitems[i] = items[start]
         start += step
-    w_res.ob_size = slicelength
     return w_res
 
 def contains__List_ANY(space, w_list, w_obj):
     # needs to be safe against eq_w() mutating the w_list behind our back
     i = 0
-    while i < w_list.ob_size:
-        if space.eq_w(w_list.ob_item[i], w_obj):
+    items_w = w_list.wrappeditems
+    length = len(items_w)
+    while i < length:
+        if space.eq_w(items_w[i], w_obj):
             return space.w_True
         i += 1
     return space.w_False
@@ -110,21 +82,7 @@
     return iterobject.W_SeqIterObject(space, w_list)
 
 def add__List_List(space, w_list1, w_list2):
-    w_res = W_ListObject(space, [])
-    newlen = w_list1.ob_size + w_list2.ob_size
-    _list_resize(w_res, newlen)
-    p = 0
-    items = w_res.ob_item
-    src = w_list1.ob_item
-    for i in range(w_list1.ob_size):
-        items[p] = src[i]
-        p += 1
-    src = w_list2.ob_item
-    for i in range(w_list2.ob_size):
-        items[p] = src[i]
-        p += 1
-    w_res.ob_size = p
-    return w_res
+    return W_ListObject(space, w_list1.wrappeditems + w_list2.wrappeditems)
 
 def inplace_add__List_ANY(space, w_list1, w_iterable2):
     list_extend__List_ANY(space, w_list1, w_iterable2)
@@ -137,19 +95,7 @@
         if e.match(space, space.w_TypeError):
             raise FailedToImplement
         raise
-    w_res = W_ListObject(space, [])
-    size = w_list.ob_size
-    newlen = size * times  # XXX check overflow
-    _list_resize(w_res, newlen)
-    src = w_list.ob_item
-    items = w_res.ob_item
-    p = 0
-    for _ in range(times):
-        for i in range(size):
-            items[p] = src[i]
-            p += 1
-    w_res.ob_size = p
-    return w_res
+    return W_ListObject(space, w_list.wrappeditems * times)
 
 def mul__List_ANY(space, w_list, w_times):
     return mul_list_times(space, w_list, w_times)
@@ -164,31 +110,19 @@
         if e.match(space, space.w_TypeError):
             raise FailedToImplement
         raise
-    if times <= 0:
-        w_list.clear()
-        return w_list
-    size = w_list.ob_size
-    newlen = size * times  # XXX check overflow
-    _list_resize(w_list, newlen)
-    items = w_list.ob_item
-    p = size
-    for _ in range(1, times):
-        for i in range(size):
-            items[p] = items[i]
-            p += 1
-    w_list.ob_size = newlen
+    w_list.wrappeditems *= times
     return w_list
 
 def eq__List_List(space, w_list1, w_list2):
     # needs to be safe against eq_w() mutating the w_lists behind our back
-    if w_list1.ob_size != w_list2.ob_size:
+    if len(w_list1.wrappeditems) != len(w_list2.wrappeditems):
         return space.w_False
     i = 0
-    while i < w_list1.ob_size and i < w_list2.ob_size:
-        if not space.eq_w(w_list1.ob_item[i], w_list2.ob_item[i]):
+    while i < len(w_list1.wrappeditems) and i < len(w_list2.wrappeditems):
+        if not space.eq_w(w_list1.wrappeditems[i], w_list2.wrappeditems[i]):
             return space.w_False
         i += 1
-    return space.newbool(w_list1.ob_size == w_list2.ob_size)
+    return space.newbool(len(w_list1.wrappeditems) == len(w_list2.wrappeditems))
 
 def _min(a, b):
     if a < b:
@@ -199,57 +133,55 @@
     # 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 < w_list1.ob_size and i < w_list2.ob_size:
-        w_item1 = w_list1.ob_item[i]
-        w_item2 = w_list2.ob_item[i]
+    while i < len(w_list1.wrappeditems) and i < len(w_list2.wrappeditems):
+        w_item1 = w_list1.wrappeditems[i]
+        w_item2 = w_list2.wrappeditems[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(w_list1.ob_size < w_list2.ob_size)
+    return space.newbool(len(w_list1.wrappeditems) < len(w_list2.wrappeditems))
 
 def gt__List_List(space, w_list1, w_list2):
     # 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 < w_list1.ob_size and i < w_list2.ob_size:
-        w_item1 = w_list1.ob_item[i]
-        w_item2 = w_list2.ob_item[i]
+    while i < len(w_list1.wrappeditems) and i < len(w_list2.wrappeditems):
+        w_item1 = w_list1.wrappeditems[i]
+        w_item2 = w_list2.wrappeditems[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(w_list1.ob_size > w_list2.ob_size)
+    return space.newbool(len(w_list1.wrappeditems) > len(w_list2.wrappeditems))
 
-# upto here, lists are nearly identical to tuples, despite the
-# fact that we now support over-allocation!
 
 def delitem__List_ANY(space, w_list, w_idx):
-    i = space.int_w(w_idx)
-    if i < 0:
-        i += w_list.ob_size
-    if i < 0 or i >= w_list.ob_size:
+    idx = space.int_w(w_idx)
+    try:
+        del w_list.wrappeditems[idx]
+    except IndexError:
         raise OperationError(space.w_IndexError,
                              space.wrap("list deletion index out of range"))
-    _del_slice(w_list, i, i+1)
     return space.w_None
 
 def delitem__List_Slice(space, w_list, w_slice):
-    start, stop, step, slicelength = slicetype.indices4(space, w_slice, w_list.ob_size)
+    start, stop, step, slicelength = slicetype.indices4(space, w_slice,
+                                                        len(w_list.wrappeditems))
 
     if slicelength==0:
         return
 
-    if step<0:
-        start = start+step*(slicelength-1)
+    if step < 0:
+        start = start + step * (slicelength-1)
         step = -step
         # stop is invalid
         
     if step == 1:
         _del_slice(w_list, start, start+slicelength)
     else:
-        items = w_list.ob_item
-        n = w_list.ob_size
+        items = w_list.wrappeditems
+        n = len(items)
 
         recycle = [None] * slicelength
         i = start
@@ -267,15 +199,13 @@
             recycle[discard] = items[i]
 
         j = i+1
-        while j<n:
-            items[j-slicelength] = items[j]            
+        while j < n:
+            items[j-slicelength] = items[j]
             j += 1
-        # make sure entries after ob_size are None, to avoid keeping references
-        n -= slicelength
-        assert n >= 0            # annotator hint
-        w_list.ob_size = n
-        for i in range(w_list.ob_size, n):
-            items[i] = None
+        start = n - slicelength
+        assert start >= 0 # annotator hint
+        # XXX allow negative indices in rlist
+        del items[start:]
         # now we can destruct recycle safely, regardless of
         # side-effects to the list
         del recycle[:]
@@ -284,43 +214,38 @@
 
 def setitem__List_ANY_ANY(space, w_list, w_index, w_any):
     idx = space.int_w(w_index)
-    if idx < 0:
-        idx += w_list.ob_size
-    if idx < 0 or idx >= w_list.ob_size:
+    try:
+        w_list.wrappeditems[idx] = w_any
+    except IndexError:
         raise OperationError(space.w_IndexError,
                              space.wrap("list index out of range"))
-    w_list.ob_item[idx] = w_any
     return space.w_None
 
 def setitem__List_Slice_List(space, w_list, w_slice, w_list2):
-    return _setitem_slice_helper(space, w_list, w_slice, w_list2.ob_item, w_list2.ob_size)
+    l = w_list2.wrappeditems
+    return _setitem_slice_helper(space, w_list, w_slice, l, len(l))
 
 def setitem__List_Slice_Tuple(space, w_list, w_slice, w_tuple):
     t = w_tuple.wrappeditems
     return _setitem_slice_helper(space, w_list, w_slice, t, len(t))
 
 def setitem__List_Slice_ANY(space, w_list, w_slice, w_iterable):
-##    if isinstance(w_iterable, W_ListObject):
-##        return _setitem_slice_helper(space, w_list, w_slice,
-##                                     w_iterable.ob_item, w_iterable.ob_size)
-##    if isinstance(w_iterable, W_TupleObject):
-##        t = w_iterable.wrappeditems
-##    else:
-    t = space.unpackiterable(w_iterable)
-    return _setitem_slice_helper(space, w_list, w_slice, t, len(t))
+    l = space.unpackiterable(w_iterable)
+    return _setitem_slice_helper(space, w_list, w_slice, l, len(l))
 
 def _setitem_slice_helper(space, w_list, w_slice, sequence2, len2):
-    start, stop, step, slicelength = slicetype.indices4(space, w_slice, w_list.ob_size)
+    oldsize = len(w_list.wrappeditems)
+    start, stop, step, slicelength = slicetype.indices4(space, w_slice,
+                                                        oldsize)
     assert slicelength >= 0
+    items = w_list.wrappeditems
 
     if step == 1:  # Support list resizing for non-extended slices
-        oldsize = w_list.ob_size
         delta = len2 - slicelength
         if delta >= 0:
             newsize = oldsize + delta
-            _list_resize(w_list, newsize)
-            w_list.ob_size = newsize
-            items = w_list.ob_item
+            # XXX support this in rlist!
+            items += [None] * delta
             for i in range(newsize-1, start+len2-1, -1):
                 items[i] = items[i-delta]
         else:
@@ -331,7 +256,6 @@
               "assign sequence of size %d to extended slice of size %d" %
               (len2,slicelength)))
 
-    items = w_list.ob_item
     if sequence2 is items:
         if step > 0:
             # Always copy starting from the right to avoid
@@ -366,7 +290,7 @@
 listrepr = app.interphook("listrepr")
 
 def repr__List(space, w_list):
-    if w_list.ob_size == 0:
+    if len(w_list.wrappeditems) == 0:
         return space.wrap('[]')
     w_currently_in_repr = space.getexecutioncontext()._py_repr
     return listrepr(space, w_currently_in_repr, w_list)
@@ -374,101 +298,22 @@
 def hash__List(space,w_list):
     raise OperationError(space.w_TypeError,space.wrap("list objects are unhashable"))
 
-# adapted C code
-def _roundupsize(n):
-    nbits = r_uint(0)
-    n2 = n >> 5
-
-##    /* Round up:
-##     * If n <       256, to a multiple of        8.
-##     * If n <      2048, to a multiple of       64.
-##     * If n <     16384, to a multiple of      512.
-##     * If n <    131072, to a multiple of     4096.
-##     * If n <   1048576, to a multiple of    32768.
-##     * If n <   8388608, to a multiple of   262144.
-##     * If n <  67108864, to a multiple of  2097152.
-##     * If n < 536870912, to a multiple of 16777216.
-##     * ...
-##     * If n < 2**(5+3*i), to a multiple of 2**(3*i).
-##     *
-##     * This over-allocates proportional to the list size, making room
-##     * for additional growth.  The over-allocation is mild, but is
-##     * enough to give linear-time amortized behavior over a long
-##     * sequence of appends() in the presence of a poorly-performing
-##     * system realloc() (which is a reality, e.g., across all flavors
-##     * of Windows, with Win9x behavior being particularly bad -- and
-##     * we've still got address space fragmentation problems on Win9x
-##     * even with this scheme, although it requires much longer lists to
-##     * provoke them than it used to).
-##     */
-    while 1:
-        n2 >>= 3
-        nbits += 3
-        if not n2 :
-            break
-    return ((n >> nbits) + 1) << nbits
-
-# before we have real arrays,
-# we use lists, allocated to fixed size.
-# XXX memory overflow is ignored here.
-# See listobject.c for reference.
-
-for_later = """
-#define NRESIZE(var, type, nitems)              \
-do {                                \
-    size_t _new_size = _roundupsize(nitems);         \
-    if (_new_size <= ((~(size_t)0) / sizeof(type)))     \
-        PyMem_RESIZE(var, type, _new_size);     \
-    else                            \
-        var = NULL;                 \
-} while (0)
-"""
-
-def _list_resize(w_list, newlen):
-    if newlen > len(w_list.ob_item):
-        true_size = _roundupsize(newlen)
-        old_items = w_list.ob_item
-        w_list.ob_item = items = [None] * true_size
-        for p in range(len(old_items)):
-            items[p] = old_items[p]
-
-def _ins1(w_list, where, w_any):
-    _list_resize(w_list, w_list.ob_size+1)
-    size = w_list.ob_size
-    items = w_list.ob_item
-    if where < 0:
-        where += size
-    if where < 0:
-        where = 0
-    if (where > size):
-        where = size
-    for i in range(size, where, -1):
-        items[i] = items[i-1]
-    items[where] = w_any
-    w_list.ob_size += 1
-
 def list_insert__List_ANY_ANY(space, w_list, w_where, w_any):
-    _ins1(w_list, space.int_w(w_where), w_any)
+    w_list.wrappeditems.insert(space.int_w(w_where), w_any)
     return space.w_None
 
 def list_append__List_ANY(space, w_list, w_any):
-    _ins1(w_list, w_list.ob_size, w_any)
+    w_list.wrappeditems.append(w_any)
     return space.w_None
 
 def list_extend__List_ANY(space, w_list, w_any):
-    lis = space.unpackiterable(w_any)
-    newlen = w_list.ob_size + len(lis)
-    _list_resize(w_list, newlen)
-    d = w_list.ob_size
-    items = w_list.ob_item
-    for i in range(len(lis)):
-        items[d+i] = lis[i]
-    w_list.ob_size = newlen
+    w_list.wrappeditems += space.unpackiterable(w_any)
     return space.w_None
 
 def _del_slice(w_list, ilow, ihigh):
     """ similar to the deletion part of list_ass_slice in CPython """
-    n = w_list.ob_size
+    items = w_list.wrappeditems
+    n = len(items)
     if ilow < 0:
         ilow = 0
     elif ilow > n:
@@ -477,46 +322,36 @@
         ihigh = ilow
     elif ihigh > n:
         ihigh = n
-    items = w_list.ob_item
-    d = ihigh-ilow
     # keep a reference to the objects to be removed,
     # preventing side effects during destruction
-    recycle = [items[i] for i in range(ilow, ihigh)]
-    for i in range(ilow, n - d):
-        items[i] = items[i+d]
-        items[i+d] = None
-    # make sure entries after ob_size-d are None, to avoid keeping references
-    # (the above loop already set to None all items[ilow+d:old_style])
-    n -= d
-    assert n >= 0            # annotator hint
-    w_list.ob_size = n
-    for i in range(n, ilow + d):
-        items[i] = None
+    recycle = items[ilow:ihigh]
+    del items[ilow:ihigh]
     # now we can destruct recycle safely, regardless of
     # side-effects to the list
     del recycle[:]
 
 # note that the default value will come back wrapped!!!
 def list_pop__List_ANY(space, w_list, w_idx=-1):
-    if w_list.ob_size == 0:
+    items = w_list.wrappeditems
+    if len(items)== 0:
         raise OperationError(space.w_IndexError,
                              space.wrap("pop from empty list"))
-    i = space.int_w(w_idx)
-    if i < 0:
-        i += w_list.ob_size
-    if i < 0 or i >= w_list.ob_size:
+    idx = space.int_w(w_idx)
+    try:
+        w_ret = items.pop(idx)
+    except IndexError:
         raise OperationError(space.w_IndexError,
                              space.wrap("pop index out of range"))
-    w_res = w_list.ob_item[i]
-    _del_slice(w_list, i, i+1)
-    return w_res
+    return w_ret
 
 def list_remove__List_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.ob_size:
-        if space.eq_w(w_list.ob_item[i], w_any):
-            _del_slice(w_list, i, i+1)
+    items = w_list.wrappeditems
+    length = len(items)
+    while i < length:
+        if space.eq_w(items[i], w_any):
+            del items[i]
             return space.w_None
         i += 1
     raise OperationError(space.w_ValueError,
@@ -524,13 +359,14 @@
 
 def list_index__List_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
-    size = w_list.ob_size
+    items = w_list.wrappeditems
+    size = len(items)
     w_start = slicetype.adapt_bound(space, w_start, space.wrap(size))
     w_stop = slicetype.adapt_bound(space, w_stop, space.wrap(size))
     i = space.int_w(w_start)
     stop = space.int_w(w_stop)
-    while i < stop and i < w_list.ob_size:
-        if space.eq_w(w_list.ob_item[i], w_any):
+    while i < stop and i < len(items):
+        if space.eq_w(items[i], w_any):
             return space.wrap(i)
         i += 1
     raise OperationError(space.w_ValueError,
@@ -540,14 +376,22 @@
     # needs to be safe against eq_w() mutating the w_list behind our back
     count = 0
     i = 0
-    while i < w_list.ob_size:
-        if space.eq_w(w_list.ob_item[i], w_any):
+    items = w_list.wrappeditems
+    while i < len(items):
+        if space.eq_w(items[i], w_any):
             count += 1
         i += 1
     return space.wrap(count)
 
+def list_reverse__List(space, w_list):
+    w_list.wrappeditems.reverse()
+    return space.w_None
+
+# ____________________________________________________________
+# Sorting
+
 # Reverse a slice of a list in place, from lo up to (exclusive) hi.
-# (also used in sort, later)
+# (used in sort)
 
 def _reverse_slice(lis, lo, hi):
     hi -= 1
@@ -558,14 +402,6 @@
         lo += 1
         hi -= 1
 
-def list_reverse__List(space, w_list):
-    if w_list.ob_size > 1:
-        _reverse_slice(w_list.ob_item, 0, w_list.ob_size)
-    return space.w_None
-
-# ____________________________________________________________
-# Sorting
-
 class KeyContainer(baseobjspace.W_Root):
     def __init__(self, w_key, w_item):
         self.w_key = w_key
@@ -623,8 +459,8 @@
             sorterclass = CustomKeySort
         else: 
             sorterclass = SimpleSort
-            
-    sorter = sorterclass(w_list.ob_item, w_list.ob_size)
+    items = w_list.wrappeditems
+    sorter = sorterclass(items, len(items))
     sorter.space = space
     sorter.w_cmp = w_cmp
 
@@ -632,8 +468,8 @@
         # 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, since ob_item may change).
-        w_list.clear()
+        # core-dump factory, since wrappeditems may change).
+        w_list.wrappeditems = []
 
         # wrap each item in a KeyContainer if needed
         if has_key:
@@ -663,11 +499,10 @@
                     sorter.list[i] = w_obj.w_item
 
         # check if the user mucked with the list during the sort
-        mucked = len(w_list.ob_item) > 0
+        mucked = len(w_list.wrappeditems) > 0
 
         # put the items back into the list
-        w_list.ob_item = sorter.list
-        w_list.ob_size = sorter.listlength
+        w_list.wrappeditems = sorter.list
 
     if mucked:
         raise OperationError(space.w_ValueError,

Modified: pypy/dist/pypy/objspace/std/marshal_impl.py
==============================================================================
--- pypy/dist/pypy/objspace/std/marshal_impl.py	(original)
+++ pypy/dist/pypy/objspace/std/marshal_impl.py	Tue Sep  6 19:32:48 2005
@@ -318,7 +318,8 @@
 
 def marshal_w__Tuple(space, w_tuple, m):
     m.start(TYPE_TUPLE)
-    m.put_list_w(w_tuple.wrappeditems, len(w_tuple.wrappeditems))
+    items = w_tuple.wrappeditems
+    m.put_list_w(items, len(items))
 
 def unmarshal_Tuple(space, u, tc):
     items_w = u.get_list_w()
@@ -327,8 +328,8 @@
 
 def marshal_w__List(space, w_list, m):
     m.start(TYPE_LIST)
-    n = w_list.ob_size
-    m.put_list_w(w_list.ob_item, w_list.ob_size)
+    items = w_list.wrappeditems
+    m.put_list_w(items, len(items))
 
 def unmarshal_List(space, u, tc):
     items_w = u.get_list_w()
@@ -488,7 +489,6 @@
     w_lis = set_to_list(space, w_set)
     # cannot access this list directly, because it's
     # type is not exactly known through applevel.
-    # otherwise, I would access ob_item and ob_size, directly.
     lis_w = space.unpackiterable(w_lis)
     m.start(TYPE_SET)
     m.put_list_w(lis_w, len(lis_w))

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	Tue Sep  6 19:32:48 2005
@@ -341,27 +341,6 @@
         assert self.space.eq_w(self.space.le(w_list4, w_list3),
                            self.space.w_True)
 
-    def test_no_unneeded_refs(self):
-        space = self.space
-        w = space.wrap
-        w_empty = W_ListObject(space, [])
-
-        w_list = W_ListObject(space, [w(5), w(3), w(99)])
-        space.setitem(w_list, space.newslice(w(0), w(3), w(None)), w_empty)
-        assert w_list.ob_item == [None]*len(w_list.ob_item)
-
-        w_list = W_ListObject(space, [w(5), w(3), w(99)])
-        space.delitem(w_list, space.newslice(w(0), w(3), w(None)))
-        assert w_list.ob_item == [None]*len(w_list.ob_item)
-
-        w_list = W_ListObject(space, [w(5), w(3), w(99)])
-        space.call_method(w_list, 'pop')
-        assert w_list.ob_item[2] is None
-        space.call_method(w_list, 'pop')
-        assert w_list.ob_item[1] is None
-        space.call_method(w_list, 'pop')
-        assert w_list.ob_item == [None]*len(w_list.ob_item)
-
 class AppTestW_ListObject:
     def test_call_list(self):
         assert list('') == []

Modified: pypy/dist/pypy/rpython/rlist.py
==============================================================================
--- pypy/dist/pypy/rpython/rlist.py	(original)
+++ pypy/dist/pypy/rpython/rlist.py	Tue Sep  6 19:32:48 2005
@@ -93,7 +93,7 @@
     def get_eqfunc(self):
         return inputconst(Void, self.item_repr.get_ll_eq_function())
 
-    def rtype_bltn_list(self,hop):
+    def rtype_bltn_list(self, hop):
         v_lst = hop.inputarg(self, 0)
         return hop.gendirectcall(ll_copy, v_lst)
     
@@ -141,6 +141,11 @@
         hop.gendirectcall(ll_reverse,v_lst)
 
     def rtype_method_pop(self, hop):
+        if hop.has_implicit_exception(IndexError):
+            spec = dum_checkidx
+        else:
+            spec = dum_nocheck
+        v_func = hop.inputconst(Void, spec)
         if hop.nb_args == 2:
             args = hop.inputargs(self, Signed)
             assert hasattr(args[1], 'concretetype')
@@ -155,8 +160,8 @@
         else:
             args = hop.inputargs(self)
             llfn = ll_pop_default
-        hop.exception_cannot_occur()   # no IndexError support (yet?)
-        return hop.gendirectcall(llfn, *args)
+        hop.exception_is_here()
+        return hop.gendirectcall(llfn, v_func, *args)
 
     def make_iterator_repr(self):
         return ListIteratorRepr(self)
@@ -191,54 +196,57 @@
 class __extend__(pairtype(ListRepr, IntegerRepr)):
 
     def rtype_getitem((r_lst, r_int), hop):
-        v_lst, v_index = hop.inputargs(r_lst, Signed)
         if hop.has_implicit_exception(IndexError):
-            if hop.args_s[1].nonneg:
-                llfn = ll_getitem_nonneg_checked
-            else:
-                llfn = ll_getitem_checked
+            spec = dum_checkidx
         else:
-            if hop.args_s[1].nonneg:
-                llfn = ll_getitem_nonneg
-            else:
-                llfn = ll_getitem
+            spec = dum_nocheck
+        v_func = hop.inputconst(Void, spec)
+        v_lst, v_index = hop.inputargs(r_lst, Signed)
+        if hop.args_s[1].nonneg:
+            llfn = ll_getitem_nonneg
+        else:
+            llfn = ll_getitem
         hop.exception_is_here()
-        return hop.gendirectcall(llfn, v_lst, v_index)
-    
+        return hop.gendirectcall(llfn, v_func, v_lst, v_index)
+
     def rtype_setitem((r_lst, r_int), hop):
-        v_lst, v_index, v_item = hop.inputargs(r_lst, Signed, r_lst.item_repr)
         if hop.has_implicit_exception(IndexError):
-            if hop.args_s[1].nonneg:
-                llfn = ll_setitem_nonneg_checked
-            else:
-                llfn = ll_setitem_checked
+            spec = dum_checkidx
         else:
-            if hop.args_s[1].nonneg:
-                llfn = ll_setitem_nonneg
-            else:
-                llfn = ll_setitem
+            spec = dum_nocheck
+        v_func = hop.inputconst(Void, spec)
+        v_lst, v_index, v_item = hop.inputargs(r_lst, Signed, r_lst.item_repr)
+        if hop.args_s[1].nonneg:
+            llfn = ll_setitem_nonneg
+        else:
+            llfn = ll_setitem
         hop.exception_is_here()
-        return hop.gendirectcall(llfn, v_lst, v_index, v_item)
+        return hop.gendirectcall(llfn, v_func, v_lst, v_index, v_item)
 
     def rtype_delitem((r_lst, r_int), hop):
-        v_lst, v_index = hop.inputargs(r_lst, Signed)
         if hop.has_implicit_exception(IndexError):
-            if hop.args_s[1].nonneg:
-                llfn = ll_delitem_nonneg_checked
-            else:
-                llfn = ll_delitem_checked
+            spec = dum_checkidx
         else:
-            if hop.args_s[1].nonneg:
-                llfn = ll_delitem_nonneg
-            else:
-                llfn = ll_delitem
+            spec = dum_nocheck
+        v_func = hop.inputconst(Void, spec)
+        v_lst, v_index = hop.inputargs(r_lst, Signed)
+        if hop.args_s[1].nonneg:
+            llfn = ll_delitem_nonneg
+        else:
+            llfn = ll_delitem
         hop.exception_is_here()
-        return hop.gendirectcall(llfn, v_lst, v_index)
+        return hop.gendirectcall(llfn, v_func, v_lst, v_index)
 
     def rtype_mul((r_lst, r_int), hop):
+        v_func = hop.inputconst(Void, dum_newlist)
         v_lst, v_factor = hop.inputargs(r_lst, Signed)
-        return hop.gendirectcall(ll_mul, v_lst, v_factor)
-    
+        return hop.gendirectcall(ll_mul, v_func, v_lst, v_factor)
+
+    def rtype_inplace_mul((r_lst, r_int), hop):
+        v_func = hop.inputconst(Void, dum_inplace)
+        v_lst, v_factor = hop.inputargs(r_lst, Signed)
+        return hop.gendirectcall(ll_mul, v_func, v_lst, v_factor)
+
 class __extend__(pairtype(ListRepr, SliceRepr)):
 
     def rtype_getitem((r_lst, r_slic), hop):
@@ -417,13 +425,23 @@
         index += l.length
     ll_insert_nonneg(l, index, newitem)
 
-def ll_pop_nonneg(l, index):
+def dum_checkidx(): pass
+def dum_nocheck(): pass
+def dum_inplace():pass
+def dum_newlist():pass
+
+def ll_pop_nonneg(func, l, index):
+    if func is dum_checkidx and (index >= l.length):
+        raise IndexError
     res = l.items[index]
-    ll_delitem_nonneg(l, index)
+    ll_delitem_nonneg(dum_nocheck, l, index)
     return res
 
-def ll_pop_default(l):
-    index = l.length - 1
+def ll_pop_default(func, l):
+    length = l.length
+    if func is dum_checkidx and (length == 0):
+        raise IndexError
+    index = length - 1
     newlength = index
     items = l.items
     res = items[index]
@@ -433,8 +451,11 @@
     _ll_list_resize(l, newlength)
     return res
 
-def ll_pop_zero(l):
-    newlength = l.length - 1
+def ll_pop_zero(func, l):
+    length = l.length
+    if func is dum_checkidx and (length == 0):
+        raise IndexError
+    newlength = length - 1
     res = l.items[0]
     j = 0
     items = l.items
@@ -449,77 +470,60 @@
     _ll_list_resize(l, newlength)
     return res
 
-def ll_pop(l, index):
+def ll_pop(func, l, index):
+    length = l.length
     if index < 0:
-        index += l.length
+        index += length
+    if func is dum_checkidx and (index < 0 or index >= length):
+        raise IndexError
     res = l.items[index]
-    ll_delitem_nonneg(l, index)
+    ll_delitem_nonneg(dum_nocheck, l, index)
     return res
 
 def ll_reverse(l):
     length = l.length
-    len2 = length // 2
     i = 0
     items = l.items
     length_1_i = length-1-i
-    while i < len2:
+    while i < length_1_i:
         tmp = l.items[i]
         items[i] = items[length_1_i]
         items[length_1_i] = tmp
         i += 1
         length_1_i -= 1
 
-def ll_getitem_nonneg(l, i):
-    return l.items[i]
-
-def ll_getitem(l, i):
-    if i < 0:
-        i += l.length
-    return l.items[i]
-
-def ll_getitem_nonneg_checked(l, i):
-    if i >= l.length:
+def ll_getitem_nonneg(func, l, index):
+    if func is dum_checkidx and (index >= l.length):
         raise IndexError
-    else:
-        return l.items[i]
+    return l.items[index]
 
-def ll_getitem_checked(l, i):
-    if i < 0:
-        i += l.length
-    if i >= l.length or i < 0:
+def ll_getitem(func, l, index):
+    length = l.length
+    if index < 0:
+        index += length
+    if func is dum_checkidx and (index < 0 or index >= length):
         raise IndexError
-    else:
-        return l.items[i]
-
-def ll_setitem_nonneg(l, i, newitem):
-    l.items[i] = newitem
+    return l.items[index]
 
-def ll_setitem_nonneg_checked(l, i, newitem):
-    if i >= l.length:
+def ll_setitem_nonneg(func, l, index, newitem):
+    if func is dum_checkidx and (index >= l.length):
         raise IndexError
-    l.items[i] = newitem
+    l.items[index] = newitem
 
-def ll_setitem(l, i, newitem):
-    if i < 0:
-        i += l.length
-    l.items[i] = newitem
-
-def ll_setitem_checked(l, i, newitem):
-    if i < 0:
-        i += l.length
-    if i >= l.length or i < 0:
+def ll_setitem(func, l, index, newitem):
+    length = l.length
+    if index < 0:
+        index += length
+    if func is dum_checkidx and (index < 0 or index >= length):
         raise IndexError
-    else:
-        l.items[i] = newitem
+    l.items[index] = newitem
 
-def ll_delitem_nonneg_checked(l, i):
-    if i >= l.length:
+def ll_delitem_nonneg(func, l, index):
+    length = l.length
+    if func is dum_checkidx and (index < 0 or index >= length):
         raise IndexError
-    ll_delitem_nonneg(l, i)
-
-def ll_delitem_nonneg(l, i):
-    newlength = l.length - 1
-    j = i
+    newlength = length - 1
+    j = index
     items = l.items
     j1 = j+1
     while j < newlength:
@@ -531,17 +535,10 @@
         items[newlength] = nullptr(ITEM.TO)
     _ll_list_resize(l, newlength)
 
-def ll_delitem(l, i):
+def ll_delitem(func, l, i):
     if i < 0:
         i += l.length
-    ll_delitem_nonneg(l, i)
-
-def ll_delitem_checked(l, i):
-    if i < 0:
-        i += l.length
-    if i >= l.length or i < 0:
-        raise IndexError
-    ll_delitem_nonneg(l, i)
+    ll_delitem_nonneg(func, l, i)
 
 def ll_concat(l1, l2):
     len1 = l1.length
@@ -730,25 +727,30 @@
 
 TEMP = GcArray(Ptr(rstr.STR))
 
-def ll_mul(l, f):
-    items = l.items
+def ll_mul(func, l, factor):
+    source = l.items
     length = l.length
-    if length == 0 or f <= 0:
-        return ll_newlist(typeOf(l), 0)
-
-    resultlen = length * f
-    new_lst = ll_newlist(typeOf(l), resultlen)
+    if factor < 0:
+        factor = 0
+    resultlen = length * factor
+    if func is dum_inplace:
+        res = l
+        _ll_list_resize(res, resultlen)
+        j = length
+    else:
+        res = ll_newlist(typeOf(l), resultlen)
+        j = 0
     i = 0
-    new_items = new_lst.items
-    j = 0
+    target = res.items
     while j < resultlen:
         while i < length:
-            new_items[i + j] = items[i]
+            p = j + i
+            target[p] = source[i]
             i += 1
         j += length
-    return new_lst
-        
+    return res
         
+
 # ____________________________________________________________
 #
 #  Irregular operations.
@@ -775,10 +777,11 @@
     c1 = hop.inputconst(Void, r_list.lowleveltype)
     c2 = hop.inputconst(Signed, nb_args)
     v_result = hop.gendirectcall(ll_newlist, c1, c2)
+    v_func = hop.inputconst(Void, dum_nocheck)
     for i in range(nb_args):
         ci = hop.inputconst(Signed, i)
         v_item = hop.inputarg(r_listitem, arg=i)
-        hop.gendirectcall(ll_setitem_nonneg, v_result, ci, v_item)
+        hop.gendirectcall(ll_setitem_nonneg, v_func, v_result, ci, v_item)
     return v_result
 
 def ll_alloc_and_set(LISTPTR, count, item):

Modified: pypy/dist/pypy/rpython/rtuple.py
==============================================================================
--- pypy/dist/pypy/rpython/rtuple.py	(original)
+++ pypy/dist/pypy/rpython/rtuple.py	Tue Sep  6 19:32:48 2005
@@ -55,6 +55,7 @@
         c1 = inputconst(Void, hop.r_result.lowleveltype)
         c2 = inputconst(Signed, nitems)
         vlist = hop.gendirectcall(rlist.ll_newlist, c1, c2)
+        v_func = hop.inputconst(Void, rlist.dum_nocheck)
         for index in range(nitems):
             name = self.fieldnames[index]
             ritem = self.items_r[index]
@@ -62,7 +63,7 @@
             vitem = hop.genop('getfield', [vtup, cname], resulttype = ritem)
             vitem = hop.llops.convertvar(vitem, ritem, hop.r_result.item_repr)
             cindex = inputconst(Signed, index)
-            hop.gendirectcall(rlist.ll_setitem_nonneg, vlist, cindex, vitem)
+            hop.gendirectcall(rlist.ll_setitem_nonneg, v_func, vlist, cindex, vitem)
         return vlist
 
     def make_iterator_repr(self):

Modified: pypy/dist/pypy/rpython/test/test_rlist.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rlist.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rlist.py	Tue Sep  6 19:32:48 2005
@@ -6,6 +6,16 @@
 from pypy.rpython.rint import signed_repr
 from pypy.rpython.test.test_llinterp import interpret, interpret_raises
 
+# undo the specialization parameter
+for n1 in 'get set del'.split():
+    for n2 in '','_nonneg':
+        name = 'll_%sitem%s' % (n1, n2)
+        globals()['_'+name] = globals()[name]
+        exec """if 1:
+            def %s(*args):
+                return _%s(dum_checkidx, *args)
+""" % (name, name)
+del n1, n2, name
 
 def sample_list():    # [42, 43, 44, 45]
     rlist = ListRepr(signed_repr)
@@ -379,6 +389,22 @@
         res = interpret(fn, [arg])
         assert res == fn(arg)
 
+def test_list_inplace_multiply():
+    def fn(i):
+        lst = [i]
+        lst *= i
+        return len(lst)
+    for arg in (1, 9, 0, -1, -27):
+        res = interpret(fn, [arg])
+        assert res == fn(arg)
+    def fn(i):
+        lst = [i, i + 1]
+        lst *= i
+        return len(lst)
+    for arg in (1, 9, 0, -1, -27):
+        res = interpret(fn, [arg])
+        assert res == fn(arg)
+
 def test_indexerror():
     def fn(i):
         l = [5, 8, 3]
@@ -395,6 +421,33 @@
     res = interpret(fn, [-2])
     assert res._obj.value == "oups"
 
+def list_is_clear(lis, idx):
+    items = lis._obj.items._obj.items
+    for i in range(idx, len(items)):
+        if items[i]._obj is not None:
+            return False
+    return True
+
+def test_no_unneeded_refs():
+    def fndel(p, q):
+        lis = ["5", "3", "99"]
+        assert q >= 0
+        assert p >= 0
+        del lis[p:q]
+        return lis
+    def fnpop(n):
+        lis = ["5", "3", "99"]
+        while n:
+            lis.pop()
+            n -=1
+        return lis
+    for i in range(2, 3+1):
+        lis = interpret(fndel, [0, i])
+        assert list_is_clear(lis, 3-i)
+    for i in range(3):
+        lis = interpret(fnpop, [i])
+        assert list_is_clear(lis, 3-i)
+
 def test_list_basic_ops():
     def list_basic_ops(i=int, j=int):
         l = [1,2,3]

Modified: pypy/dist/pypy/translator/c/extfunc.py
==============================================================================
--- pypy/dist/pypy/translator/c/extfunc.py	(original)
+++ pypy/dist/pypy/translator/c/extfunc.py	Tue Sep  6 19:32:48 2005
@@ -93,7 +93,7 @@
     def _RPyListOfString_SetItem(l=p,
                                 index=lltype.Signed,
                                 newstring=lltype.Ptr(STR)):
-        rlist.ll_setitem_nonneg(l, index, newstring)
+        rlist.ll_setitem_nonneg(rlist.dum_nocheck, l, index, newstring)
 
     for fname, f in locals().items():
         if isinstance(f, types.FunctionType):



More information about the Pypy-commit mailing list