[pypy-svn] r74560 - in pypy/branch/multilist/pypy: config objspace/std objspace/std/test

fijal at codespeak.net fijal at codespeak.net
Wed May 19 06:57:27 CEST 2010


Author: fijal
Date: Wed May 19 06:57:24 2010
New Revision: 74560

Added:
   pypy/branch/multilist/pypy/objspace/std/listmultiobject.py   (contents, props changed)
   pypy/branch/multilist/pypy/objspace/std/test/test_listmultiobject.py   (contents, props changed)
Modified:
   pypy/branch/multilist/pypy/config/pypyoption.py
   pypy/branch/multilist/pypy/objspace/std/model.py
Log:
Don't do anything, just boilerplate for now


Modified: pypy/branch/multilist/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/multilist/pypy/config/pypyoption.py	(original)
+++ pypy/branch/multilist/pypy/config/pypyoption.py	Wed May 19 06:57:24 2010
@@ -217,6 +217,8 @@
         BoolOption("withropeunicode", "use ropes for the unicode implementation",
                    default=False,
                    requires=[("objspace.std.withrope", True)]),
+        BoolOption("withmultilist", "use multilist implementation instead"
+                                    " of normal list", default=False),
 
         BoolOption("withcelldict",
                    "use dictionaries that are optimized for being used as module dicts",

Added: pypy/branch/multilist/pypy/objspace/std/listmultiobject.py
==============================================================================
--- (empty file)
+++ pypy/branch/multilist/pypy/objspace/std/listmultiobject.py	Wed May 19 06:57:24 2010
@@ -0,0 +1,538 @@
+from pypy.interpreter.argument import Signature
+from pypy.objspace.std.model import registerimplementation, W_Object
+from pypy.interpreter import gateway, baseobjspace
+from pypy.rlib.listsort import TimSort
+from pypy.objspace.std.register_all import register_all
+from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
+from pypy.objspace.std.listtype import get_list_index
+from pypy.objspace.std.inttype import wrapint
+
+class W_ListMultiObject(W_Object):
+    """ A multilist object. It works as normal W_ListObject (contains
+    wrappeditems as a list of W_Root), but if wrappeditems is None, we
+    fall back to fallbackimpl which implements some sort of interface.
+
+    That way we can have advantages of multilist with minimal overhead,
+    which can be neglected by the JIT
+    """
+
+    from pypy.objspace.std.listtype import list_typedef as typedef
+
+    def __init__(self, wrappeditems, fallbackimpl=None):
+        # invariant
+        if wrappeditems is None:
+            assert fallbackimpl is not None
+        else:
+            assert fallbackimpl is None
+        self.wrappeditems = wrappeditems
+        self.fallbackimpl = fallbackimpl
+
+    def __repr__(w_self):
+        """ representation for debugging purposes """
+        if w_self.wrappeditems is not None:
+            return "%s(%s)" % (w_self.__class__.__name__, w_self.wrappeditems)
+        else:
+            return "W_ListMultiObject(%r)" % self.fallbackimpl
+
+registerimplementation(W_ListMultiObject)
+
+
+init_signature = Signature(['sequence'], None, None)
+init_defaults = [None]
+
+def init__ListMulti(space, w_list, __args__):
+    # this is on the silly side
+    w_iterable, = __args__.parse_obj(
+            None, 'list', init_signature, init_defaults)
+    #
+    # this is the old version of the loop at the end of this function:
+    #
+    #   w_list.wrappeditems = space.unpackiterable(w_iterable)
+    #
+    # This is commented out to avoid assigning a new RPython list to
+    # 'wrappeditems', which defeats the W_FastSeqIterObject optimization.
+    #
+    items_w = w_list.wrappeditems
+    del items_w[:]
+    if w_iterable is not None:
+        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
+            items_w.append(w_item)
+
+def len__ListMulti(space, w_list):
+    result = len(w_list.wrappeditems)
+    return wrapint(space, result)
+
+def getitem__ListMulti_ANY(space, w_list, w_index):
+    try:
+        return w_list.wrappeditems[get_list_index(space, w_index)]
+    except IndexError:
+        raise OperationError(space.w_IndexError,
+                             space.wrap("list index out of range"))
+
+def getitem__ListMulti_Slice(space, w_list, w_slice):
+    # XXX consider to extend rlist's functionality?
+    length = len(w_list.wrappeditems)
+    start, stop, step, slicelength = w_slice.indices4(space, length)
+    assert slicelength >= 0
+    if step == 1 and 0 <= start <= stop:
+        return W_ListMultiObject(w_list.wrappeditems[start:stop])
+    w_res = W_ListMultiObject([None] * slicelength)
+    items_w = w_list.wrappeditems
+    subitems_w = w_res.wrappeditems
+    for i in range(slicelength):
+        subitems_w[i] = items_w[start]
+        start += step
+    return w_res
+
+def getslice__ListMulti_ANY_ANY(space, w_list, w_start, w_stop):
+    length = len(w_list.wrappeditems)
+    start, stop = normalize_simple_slice(space, length, w_start, w_stop)
+    return W_ListMultiObject(w_list.wrappeditems[start:stop])
+
+def setslice__ListMulti_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_sequence):
+    length = len(w_list.wrappeditems)
+    start, stop = normalize_simple_slice(space, length, w_start, w_stop)
+    _setitem_slice_helper(space, w_list, start, 1, stop-start, w_sequence)
+
+def delslice__ListMulti_ANY_ANY(space, w_list, w_start, w_stop):
+    length = len(w_list.wrappeditems)
+    start, stop = normalize_simple_slice(space, length, w_start, w_stop)
+    _delitem_slice_helper(space, w_list, start, 1, stop-start)
+
+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
+    items_w = w_list.wrappeditems
+    while i < len(items_w): # intentionally always calling len!
+        if space.eq_w(items_w[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_FastListIterObject(w_list, w_list.wrappeditems)
+
+def add__ListMulti_ListMulti(space, w_list1, w_list2):
+    return W_ListMultiObject(w_list1.wrappeditems + w_list2.wrappeditems)
+
+
+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.getindex_w(w_times, space.w_OverflowError)
+    except OperationError, e:
+        if e.match(space, space.w_TypeError):
+            raise FailedToImplement
+        raise
+    return W_ListMultiObject(w_list.wrappeditems * 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.getindex_w(w_times, space.w_OverflowError)
+    except OperationError, e:
+        if e.match(space, space.w_TypeError):
+            raise FailedToImplement
+        raise
+    w_list.wrappeditems *= 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
+    items1_w = w_list1.wrappeditems
+    items2_w = w_list2.wrappeditems
+    return equal_wrappeditems(space, items1_w, items2_w)
+
+def equal_wrappeditems(space, items1_w, items2_w):
+    if len(items1_w) != len(items2_w):
+        return space.w_False
+    i = 0
+    while i < len(items1_w) and i < len(items2_w):
+        if not space.eq_w(items1_w[i], items2_w[i]):
+            return space.w_False
+        i += 1
+    return space.w_True
+
+def lessthan_unwrappeditems(space, items1_w, items2_w):
+    # 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 < len(items1_w) and i < len(items2_w):
+        w_item1 = items1_w[i]
+        w_item2 = items2_w[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(len(items1_w) < len(items2_w))
+
+def greaterthan_unwrappeditems(space, items1_w, items2_w):
+    # 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 < len(items1_w) and i < len(items2_w):
+        w_item1 = items1_w[i]
+        w_item2 = items2_w[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(len(items1_w) > len(items2_w))
+
+def lt__ListMulti_ListMulti(space, w_list1, w_list2):
+    return lessthan_unwrappeditems(space, w_list1.wrappeditems,
+        w_list2.wrappeditems)
+
+def gt__ListMulti_ListMulti(space, w_list1, w_list2):
+    return greaterthan_unwrappeditems(space, w_list1.wrappeditems,
+        w_list2.wrappeditems)
+
+def delitem__ListMulti_ANY(space, w_list, w_idx):
+    idx = get_list_index(space, w_idx)
+    try:
+        del w_list.wrappeditems[idx]
+    except IndexError:
+        raise OperationError(space.w_IndexError,
+                             space.wrap("list deletion index out of range"))
+    return space.w_None
+
+
+def delitem__ListMulti_Slice(space, w_list, w_slice):
+    start, stop, step, slicelength = w_slice.indices4(space,
+                                                      len(w_list.wrappeditems))
+    _delitem_slice_helper(space, w_list, start, step, slicelength)
+
+def _delitem_slice_helper(space, w_list, start, step, slicelength):
+    if slicelength==0:
+        return
+
+    if step < 0:
+        start = start + step * (slicelength-1)
+        step = -step
+        
+    if step == 1:
+        assert start >= 0
+        assert slicelength >= 0
+        del w_list.wrappeditems[start:start+slicelength]
+    else:
+        items = w_list.wrappeditems
+        n = len(items)
+        i = start
+
+        for discard in range(1, slicelength):
+            j = i+1
+            i += step
+            while j < i:
+                items[j-discard] = items[j]
+                j += 1
+
+        j = i+1
+        while j < n:
+            items[j-slicelength] = items[j]
+            j += 1
+        start = n - slicelength
+        assert start >= 0 # annotator hint
+        del items[start:]
+
+def setitem__ListMulti_ANY_ANY(space, w_list, w_index, w_any):
+    idx = get_list_index(space, w_index)
+    try:
+        w_list.wrappeditems[idx] = w_any
+    except IndexError:
+        raise OperationError(space.w_IndexError,
+                             space.wrap("list index out of range"))
+    return space.w_None
+
+def setitem__ListMulti_Slice_ANY(space, w_list, w_slice, w_iterable):
+    oldsize = len(w_list.wrappeditems)
+    start, stop, step, slicelength = w_slice.indices4(space, oldsize)
+    _setitem_slice_helper(space, w_list, start, step, slicelength, w_iterable)
+
+def _setitem_slice_helper(space, w_list, start, step, slicelength, w_iterable):
+    sequence2 = space.listview(w_iterable)
+    assert slicelength >= 0
+    items = w_list.wrappeditems
+    oldsize = len(items)
+    len2 = len(sequence2)
+    if step == 1:  # Support list resizing for non-extended slices
+        delta = slicelength - len2
+        if delta < 0:
+            delta = -delta
+            newsize = oldsize + delta
+            # XXX support this in rlist!
+            items += [None] * delta
+            lim = start+len2
+            i = newsize - 1
+            while i >= lim:
+                items[i] = items[i-delta]
+                i -= 1
+        elif start >= 0:
+            del items[start:start+delta]
+        else:
+            assert delta==0
+    elif len2 != slicelength:  # No resize for extended slices
+        raise operationerrfmt(space.w_ValueError, "attempt to "
+              "assign sequence of size %d to extended slice of size %d",
+              len2, slicelength)
+
+    if sequence2 is items:
+        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:
+                items[start] = sequence2[i]
+                start -= step
+                i -= 1
+            return
+        else:
+            # Make a shallow copy to more easily handle the reversal case
+            sequence2 = list(sequence2)
+    for i in range(len2):
+        items[start] = sequence2[i]
+        start += step
+
+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 len(w_list.wrappeditems) == 0:
+        return space.wrap('[]')
+    ec = space.getexecutioncontext()
+    w_currently_in_repr = ec._py_repr
+    if w_currently_in_repr is None:
+        w_currently_in_repr = ec._py_repr = space.newdict()
+    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 = len(w_list.wrappeditems)
+    if where < 0:
+        where += length
+        if where < 0:
+            where = 0
+    elif where > length:
+        where = length
+    w_list.wrappeditems.insert(where, w_any)
+    return space.w_None
+
+def list_append__ListMulti_ANY(space, w_list, w_any):
+    w_list.wrappeditems.append(w_any)
+    return space.w_None
+
+def list_extend__ListMulti_ListMulti(space, w_list, w_other):
+    w_list.wrappeditems += w_other.wrappeditems
+    return space.w_None
+
+def list_extend__ListMulti_ANY(space, w_list, w_any):
+    w_list.wrappeditems += space.listview(w_any)
+    return space.w_None
+
+# note that the default value will come back wrapped!!!
+def list_pop__ListMulti_ANY(space, w_list, w_idx=-1):
+    items = w_list.wrappeditems
+    if len(items)== 0:
+        raise OperationError(space.w_IndexError,
+                             space.wrap("pop from empty list"))
+    idx = space.int_w(w_idx)
+    try:
+        return items.pop(idx)
+    except IndexError:
+        raise OperationError(space.w_IndexError,
+                             space.wrap("pop index out of range"))
+
+def list_remove__ListMulti_ANY(space, w_list, w_any):
+    # needs to be safe against eq_w() mutating the w_list behind our back
+    items = w_list.wrappeditems
+    i = 0
+    while i < len(items):
+        if space.eq_w(items[i], w_any):
+            if i < len(items): # if this is wrong the list was changed
+                del items[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
+    items = w_list.wrappeditems
+    size = len(items)
+    i = slicetype.adapt_bound(space, size, w_start)
+    stop = slicetype.adapt_bound(space, size, w_stop)
+    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,
+                         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
+    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__ListMulti(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.
+# (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
+    items = w_list.wrappeditems
+    sorter = sorterclass(items, len(items))
+    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, since wrappeditems may change).
+        w_list.wrappeditems = []
+
+        # 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 = len(w_list.wrappeditems) > 0
+
+        # put the items back into the list
+        w_list.wrappeditems = sorter.list
+
+    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/branch/multilist/pypy/objspace/std/model.py
==============================================================================
--- pypy/branch/multilist/pypy/objspace/std/model.py	(original)
+++ pypy/branch/multilist/pypy/objspace/std/model.py	Wed May 19 06:57:24 2010
@@ -26,6 +26,7 @@
                         "rangeobject.W_RangeIterObject"],
     "withtproxy" : ["proxyobject.W_TransparentList",
                     "proxyobject.W_TransparentDict"],
+    "withmultilist" : ["listmultiobject.W_ListMultiObject"],
 }
 
 class StdTypeModel:
@@ -69,6 +70,7 @@
         from pypy.objspace.std import smallintobject
         from pypy.objspace.std import tupleobject
         from pypy.objspace.std import listobject
+        from pypy.objspace.std import listmultiobject
         from pypy.objspace.std import dictmultiobject
         from pypy.objspace.std import stringobject
         from pypy.objspace.std import ropeobject

Added: pypy/branch/multilist/pypy/objspace/std/test/test_listmultiobject.py
==============================================================================
--- (empty file)
+++ pypy/branch/multilist/pypy/objspace/std/test/test_listmultiobject.py	Wed May 19 06:57:24 2010
@@ -0,0 +1,13 @@
+
+from pypy.conftest import gettestobjspace
+from pypy.objspace.std.test.test_listobject import TestW_ListObject,\
+     AppTestW_ListObject
+
+class TestW_ListMultiObject(TestW_ListObject):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{'objspace.std.withmultilist': True})
+
+class AppTestMultiList(AppTestW_ListObject):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{'objspace.std.withmultilist': True})
+    



More information about the Pypy-commit mailing list