Author: Hakan Ardo <[email protected]>
Branch: 
Changeset: r55040:b380d1325ae0
Date: 2012-05-11 14:44 +0200
http://bitbucket.org/pypy/pypy/changeset/b380d1325ae0/

Log:    Merge step-one-xrange. It introduces a slightly more efficient
        xrange iterator for the case when the step is not specified and can
        thus safely be promoted.

diff --git a/pypy/module/__builtin__/functional.py 
b/pypy/module/__builtin__/functional.py
--- a/pypy/module/__builtin__/functional.py
+++ b/pypy/module/__builtin__/functional.py
@@ -312,22 +312,28 @@
 
 
 class W_XRange(Wrappable):
-    def __init__(self, space, start, len, step):
+    def __init__(self, space, start, len, step, promote_step=False):
         self.space = space
         self.start = start
         self.len   = len
         self.step  = step
+        self.promote_step = promote_step
 
-    def descr_new(space, w_subtype, w_start, w_stop=None, w_step=1):
+    def descr_new(space, w_subtype, w_start, w_stop=None, w_step=None):
         start = _toint(space, w_start)
-        step  = _toint(space, w_step)
+        if space.is_w(w_step, space.w_None):  # no step argument provided
+            step = 1
+            promote_step = True
+        else:
+            step  = _toint(space, w_step)
+            promote_step = False
         if space.is_w(w_stop, space.w_None):  # only 1 argument provided
             start, stop = 0, start
         else:
             stop = _toint(space, w_stop)
         howmany = get_len_of_range(space, start, stop, step)
         obj = space.allocate_instance(W_XRange, w_subtype)
-        W_XRange.__init__(obj, space, start, howmany, step)
+        W_XRange.__init__(obj, space, start, howmany, step, promote_step)
         return space.wrap(obj)
 
     def descr_repr(self):
@@ -356,8 +362,14 @@
                              space.wrap("xrange object index out of range"))
 
     def descr_iter(self):
-        return self.space.wrap(W_XRangeIterator(self.space, self.start,
-                                                self.len, self.step))
+        if self.promote_step and self.step == 1:
+            stop = self.start + self.len
+            return self.space.wrap(W_XRangeStepOneIterator(self.space,
+                                                           self.start,
+                                                           stop))
+        else:
+            return self.space.wrap(W_XRangeIterator(self.space, self.start,
+                                                    self.len, self.step))
 
     def descr_reversed(self):
         lastitem = self.start + (self.len-1) * self.step
@@ -399,6 +411,9 @@
         return self.space.wrap(self)
 
     def descr_next(self):
+        return self.next()
+    
+    def next(self):
         if self.remaining > 0:
             item = self.current
             self.current = item + self.step
@@ -418,9 +433,12 @@
         w        = space.wrap
         nt = space.newtuple
 
-        tup = [w(self.current), w(self.remaining), w(self.step)]
+        tup = [w(self.current), w(self.get_remaining()), w(self.step)]
         return nt([new_inst, nt(tup)])
 
+    def get_remaining(self):
+        return self.remaining
+
 W_XRangeIterator.typedef = TypeDef("rangeiterator",
     __iter__        = interp2app(W_XRangeIterator.descr_iter),
 # XXX __length_hint__()
@@ -428,3 +446,20 @@
     next            = interp2app(W_XRangeIterator.descr_next),
     __reduce__      = interp2app(W_XRangeIterator.descr_reduce),
 )
+
+class W_XRangeStepOneIterator(W_XRangeIterator):
+    def __init__(self, space, start, stop):
+        self.space = space
+        self.current = start
+        self.stop = stop
+        self.step = 1
+
+    def next(self):
+        if self.current < self.stop:
+            item = self.current
+            self.current = item + 1
+            return self.space.wrap(item)
+        raise OperationError(self.space.w_StopIteration, self.space.w_None)
+
+    def get_remaining(self):
+        return self.stop - self.current
diff --git a/pypy/module/__builtin__/test/test_functional.py 
b/pypy/module/__builtin__/test/test_functional.py
--- a/pypy/module/__builtin__/test/test_functional.py
+++ b/pypy/module/__builtin__/test/test_functional.py
@@ -164,6 +164,25 @@
       y = callable(*args)
       assert list(y) == list(x)
 
+   def test_xrange_iter_reduce(self):
+      x = iter(xrange(2, 9, 3))
+      x.next()
+      callable, args = x.__reduce__()
+      y = callable(*args)
+      assert list(y) == list(x)
+
+   def test_xrange_iter_reduce_one(self):
+      x = iter(xrange(2, 9))
+      x.next()
+      callable, args = x.__reduce__()
+      y = callable(*args)
+      assert list(y) == list(x)
+
+   def test_lib_python_xrange_optimization(self):
+      x = xrange(1)
+      assert type(reversed(x)) == type(iter(x))
+
+
 class AppTestReversed:
    def test_reversed(self):
       r = reversed("hello")
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py 
b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -131,6 +131,36 @@
             jump(..., descr=...)
             """)
 
+    def test_xrange_iter(self):
+        def main(n):
+            def g(n):
+                return xrange(n)
+            s = 0
+            for i in xrange(n):  # ID: for
+                tmp = g(n)
+                s += tmp[i]     # ID: getitem
+                a = 0
+            return s
+        #
+        log = self.run(main, [1000])
+        assert log.result == 1000 * 999 / 2
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match("""
+        i15 = int_lt(i10, i11)
+        guard_true(i15, descr=...)
+        i17 = int_add(i10, 1)
+        i18 = force_token()
+        setfield_gc(p9, i17, descr=<.* .*W_XRangeIterator.inst_current .*>)
+        guard_not_invalidated(descr=...)
+        i21 = int_lt(i10, 0)
+        guard_false(i21, descr=...)
+        i22 = int_lt(i10, i14)
+        guard_true(i22, descr=...)
+        i23 = int_add_ovf(i6, i10)
+        guard_no_overflow(descr=...)
+        --TICK--
+        jump(..., descr=...)
+        """)
 
     def test_range_iter(self):
         def main(n):
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to