[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