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

cfbolz at codespeak.net cfbolz at codespeak.net
Thu Oct 19 19:38:22 CEST 2006


Author: cfbolz
Date: Thu Oct 19 19:38:20 2006
New Revision: 33473

Added:
   pypy/dist/pypy/objspace/std/rangeobject.py
   pypy/dist/pypy/objspace/std/test/test_rangeobject.py
Modified:
   pypy/dist/pypy/config/pypyoption.py
   pypy/dist/pypy/module/__builtin__/__init__.py
   pypy/dist/pypy/module/__builtin__/functional.py
   pypy/dist/pypy/objspace/std/model.py
   pypy/dist/pypy/objspace/std/strjoinobject.py
Log:
adding a special range list implementation that won't actually create the list
until it is mutated (but behaves completely like the full list).


Modified: pypy/dist/pypy/config/pypyoption.py
==============================================================================
--- pypy/dist/pypy/config/pypyoption.py	(original)
+++ pypy/dist/pypy/config/pypyoption.py	Thu Oct 19 19:38:20 2006
@@ -91,6 +91,12 @@
                        default=False,
                        requires=[("objspace.std.withmultidict", True)]),
 
+            BoolOption("withrangelist",
+                       "enable special range list implementation that does not "
+                       "actually create the full list until the resulting "
+                       "list is mutaged",
+                       default=False),
+
             BoolOption("oldstyle",
                        "specify whether the default metaclass should be classobj",
                        default=False, cmdline="--oldstyle"),

Modified: pypy/dist/pypy/module/__builtin__/__init__.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/__init__.py	(original)
+++ pypy/dist/pypy/module/__builtin__/__init__.py	Thu Oct 19 19:38:20 2006
@@ -140,6 +140,14 @@
        space.setitem(builtin.w_dict, space.wrap('None'), space.w_None)
        return builtin
 
+    def __init__(self, space, *args):
+        "NOT_RPYTHON: patches range if option withrangelist is set."
+        #XXX slightly strange that the __init__ changes a class attribute...
+        if (space.config.objspace.std.withrangelist and
+            space.config.objspace.name == "std"):
+            self.interpleveldefs["range"] = "functional.range_withrangelist"
+        MixedModule.__init__(self, space, *args)
+
     def setup_after_space_initialization(self):
         """NOT_RPYTHON"""
         space = self.space

Modified: pypy/dist/pypy/module/__builtin__/functional.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/functional.py	(original)
+++ pypy/dist/pypy/module/__builtin__/functional.py	Thu Oct 19 19:38:20 2006
@@ -92,3 +92,24 @@
 
 range_fallback = applevel(getsource(app_range), getfile(app_range)
                           ).interphook('range')
+
+def range_withrangelist(space, w_x, w_y=None, w_step=1):
+    """Return a list of integers in arithmetic position from start (defaults
+to zero) to stop - 1 by step (defaults to 1).  Use a negative step to
+get a list in decending order."""
+    # 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
+        else:
+            start, stop = x, space.int_w(w_y)
+        step = space.int_w(w_step)
+        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)
+range_withrangelist.unwrap_spec = [ObjSpace, W_Root, W_Root, W_Root]
+

Modified: pypy/dist/pypy/objspace/std/model.py
==============================================================================
--- pypy/dist/pypy/objspace/std/model.py	(original)
+++ pypy/dist/pypy/objspace/std/model.py	Thu Oct 19 19:38:20 2006
@@ -16,6 +16,8 @@
                         "dictstrobject.W_DictStrIterObject"],
     "withmultidict"  : ["dictmultiobject.W_DictMultiObject",
                         "dictmultiobject.W_DictMultiIterObject"],
+    "withrangelist"  : ["rangeobject.W_RangeListObject",
+                        "rangeobject.W_RangeIterObject"],
 }
 
 class StdTypeModel:
@@ -71,6 +73,7 @@
         from pypy.objspace.std import iterobject
         from pypy.objspace.std import unicodeobject
         from pypy.objspace.std import dictproxyobject
+        from pypy.objspace.std import rangeobject
         from pypy.objspace.std import fake
         import pypy.objspace.std.default # register a few catch-all multimethods
 
@@ -183,6 +186,11 @@
                 (unicodeobject.W_UnicodeObject,
                                        strjoinobject.delegate_join2unicode)
                 ]
+        if config.objspace.std.withrangelist:
+            self.typeorder[rangeobject.W_RangeListObject] += [
+                (listobject.W_ListObject,
+                                       rangeobject.delegate_range2list),
+                ]
 
         # put W_Root everywhere
         self.typeorder[W_Root] = []

Added: pypy/dist/pypy/objspace/std/rangeobject.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/objspace/std/rangeobject.py	Thu Oct 19 19:38:20 2006
@@ -0,0 +1,161 @@
+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.listobject import W_ListObject
+
+from pypy.objspace.std import slicetype
+from pypy.interpreter import gateway, baseobjspace
+
+def length(start, stop, step):
+    if step > 0:
+        if stop <= start:
+            return 0
+        return (stop - start + step - 1)/step
+
+    else:  # step must be < 0
+        if stop >= start:
+            return 0
+        return (start - stop - step  - 1)/-step
+
+
+class W_RangeListObject(W_Object):
+    from pypy.objspace.std.listtype import list_typedef as typedef
+    
+    def __init__(w_self, start, step, length):
+        assert step != 0
+        w_self.start = start
+        w_self.step = step
+        w_self.length = length
+        w_self.w_list = None
+
+    def force(w_self, space):
+        if w_self.w_list is not None:
+            return w_self.w_list
+        start = w_self.start
+        step = w_self.step
+        length = w_self.length
+        if not length:
+            w_self.w_list = space.newlist()
+            return w_self.w_list
+        
+        arr = [0] * length  # this is to avoid using append.
+
+        i = start
+        n = 0
+        while n < length:
+            arr[n] = i
+            i += step
+            n += 1
+
+        w_self.w_list = space.newlist([wrapint(space, element)
+                                           for element in arr])
+        return w_self.w_list
+
+    def getitem(w_self, i):
+        if i < 0:
+            i += w_self.length
+        if i >= w_self.length or i < 0:
+            raise IndexError
+        return w_self.start + i * w_self.step
+
+    def __repr__(w_self):
+        if w_self.w_list is None:
+            return "W_RangeListObject(%s, %s, %s)" % (
+                w_self.start, w_self.step, w_self.length)
+        else:
+            return "W_RangeListObject(%r)" % (w_self.w_list, )
+
+def delegate_range2list(space, w_rangelist):
+    return w_rangelist.force(space)
+
+def len__RangeList(space, w_rangelist):
+    if w_rangelist.w_list is not None:
+        return space.len(w_rangelist.w_list)
+    return wrapint(space, w_rangelist.length)
+
+
+def getitem__RangeList_ANY(space, w_rangelist, w_index):
+    if w_rangelist.w_list is not None:
+        return space.getitem(w_rangelist.w_list, w_index)
+    idx = space.int_w(w_index)
+    try:
+        return w_rangelist.getitem(idx)
+    except IndexError:
+        raise OperationError(space.w_IndexError,
+                             space.wrap("list index out of range"))
+
+def getitem__RangeList_Slice(space, w_rangelist, w_slice):
+    if w_rangelist.w_list is not None:
+        return space.getitem(w_rangelist.w_list, w_slice)
+    length = w_rangelist.length
+    start, stop, step, slicelength = w_slice.indices4(space, length)
+    assert slicelength >= 0
+    rangestart = w_rangelist.getitem(start)
+    rangestep = w_rangelist.step * step
+    return W_RangeListObject(rangestart, rangestep, slicelength)
+
+def iter__RangeList(space, w_rangelist):
+    from pypy.objspace.std import iterobject
+    return W_RangeIterObject(w_rangelist)
+
+def repr__RangeList(space, w_rangelist):
+    if w_rangelist.w_list is not None:
+        return space.repr(w_rangelist.w_list)
+    if w_rangelist.length == 0:
+        return space.wrap('[]')
+    result = [''] * w_rangelist.length
+    i = w_rangelist.start
+    n = 0
+    while n < w_rangelist.length:
+        result[n] = str(i)
+        i += w_rangelist.step
+        n += 1
+    return space.wrap("[" + ", ".join(result) + "]")
+
+class W_RangeIterObject(W_Object):
+    from pypy.objspace.std.itertype import iter_typedef as typedef
+
+    def __init__(w_self, w_rangelist, index=0):
+        w_self.w_rangelist = w_rangelist
+        w_self.index = index
+
+def iter__RangeIter(space, w_rangeiter):
+    return w_rangeiter
+
+def next__RangeIter(space, w_rangeiter):
+    if w_rangeiter.w_rangelist is None:
+        raise OperationError(space.w_StopIteration, space.w_None)
+    if w_rangeiter.w_rangelist.w_list is not None:
+        try:
+            w_item = space.getitem(w_rangeiter.w_rangelist.w_list,
+                                   wrapint(space, w_rangeiter.index))
+        except OperationError, e:
+            w_rangeiter.w_rangelist = None
+            if not e.match(space, space.w_IndexError):
+                raise
+            raise OperationError(space.w_StopIteration, space.w_None)
+    else:
+        try:
+            w_item = wrapint(
+                space,
+                w_rangeiter.w_rangelist.getitem(w_rangeiter.index))
+        except IndexError:
+            w_rangeiter.w_rangelist = None
+            raise OperationError(space.w_StopIteration, space.w_None)
+    w_rangeiter.index += 1
+    return w_item
+
+def len__RangeIter(space,  w_rangeiter):
+    if w_rangeiter.w_rangelist is None:
+        return wrapint(space, 0)
+    index = w_rangeiter.index
+    w_length = space.len(w_rangeiter.w_rangelist)
+    w_len = space.sub(w_length, wrapint(space, index))
+    if space.is_true(space.lt(w_len, wrapint(space, 0))):
+        w_len = wrapint(space, 0)
+    return w_len
+
+registerimplementation(W_RangeListObject)
+registerimplementation(W_RangeIterObject)
+
+register_all(vars())

Modified: pypy/dist/pypy/objspace/std/strjoinobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/strjoinobject.py	(original)
+++ pypy/dist/pypy/objspace/std/strjoinobject.py	Thu Oct 19 19:38:20 2006
@@ -56,6 +56,10 @@
     w_self.joined_strs.append(other)
     return W_StringJoinObject(w_self.joined_strs)
 
+#def add__String_StringJoin(space, w_other, w_self):
+#    other = space.str_w(w_other)
+#    return W_StringObject([other] + w_self.joined_strs)
+
 def str__StringJoin(space, w_str):
     if type(w_str) is W_StringJoinObject:
         return w_str

Added: pypy/dist/pypy/objspace/std/test/test_rangeobject.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/objspace/std/test/test_rangeobject.py	Thu Oct 19 19:38:20 2006
@@ -0,0 +1,28 @@
+import autopath, py
+
+from pypy.conftest import gettestobjspace
+
+class AppTestRangeListObject(object):
+
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withrangelist": True})
+
+    def test_simple(self):
+        result = []
+        for i in range(1, 8, 2):
+            result.append(i)
+        assert result == [1, 3, 5, 7]
+
+    def test_getitem_slice(self):
+        result = []
+        for i in range(1, 100, 2)[40:30:-2]:
+            result.append(i)
+        assert result == [81, 77, 73, 69, 65]
+
+    def test_repr(self):
+        assert repr(range(5)) == "[0, 1, 2, 3, 4]"
+
+    def test_force(self):
+        r = range(10)
+        r[0] = 42
+        assert r == [42, 1, 2, 3, 4, 5, 6, 7, 8, 9]



More information about the Pypy-commit mailing list