Author: Philip Jenvey <[email protected]>
Branch: py3k
Changeset: r72096:addd0f2aa776
Date: 2014-06-17 18:20 -0700
http://bitbucket.org/pypy/pypy/changeset/addd0f2aa776/

Log:    specialize range iterators when the ranges fit into machine sized
        integers and further specialize when step is not specified (like the
        default branch does)

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
@@ -6,7 +6,8 @@
 
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError, oefmt
-from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
+from pypy.interpreter.gateway import (
+    interp2app, interpindirect2app, unwrap_spec)
 from pypy.interpreter.typedef import TypeDef
 from rpython.rlib import jit
 from rpython.rlib.objectmodel import specialize
@@ -307,15 +308,19 @@
 
 
 class W_Range(W_Root):
-    def __init__(self, w_start, w_stop, w_step, w_length):
+    def __init__(self, w_start, w_stop, w_step, w_length, promote_step=False):
         self.w_start = w_start
         self.w_stop  = w_stop
         self.w_step  = w_step
         self.w_length = w_length
+        self.promote_step = promote_step
 
-    @unwrap_spec(w_step = WrappedDefault(1))
     def descr_new(space, w_subtype, w_start, w_stop=None, w_step=None):
         w_start = space.index(w_start)
+        promote_step = False
+        if space.is_none(w_step):  # no step argument provided
+            w_step = space.wrap(1)
+            promote_step = True
         if space.is_none(w_stop):  # only 1 argument provided
             w_start, w_stop = space.newint(0), w_start
         else:
@@ -331,7 +336,7 @@
                         "step argument must not be zero"))
         w_length = compute_range_length(space, w_start, w_stop, w_step)
         obj = space.allocate_instance(W_Range, w_subtype)
-        W_Range.__init__(obj, w_start, w_stop, w_step, w_length)
+        W_Range.__init__(obj, w_start, w_stop, w_step, w_length, promote_step)
         return space.wrap(obj)
 
     def descr_repr(self, space):
@@ -386,8 +391,19 @@
             return self._compute_item(space, w_index)
 
     def descr_iter(self, space):
-        return space.wrap(W_RangeIterator(
-                space, self.w_start, self.w_step, self.w_length))
+        try:
+            start = space.int_w(self.w_start)
+            stop = space.int_w(self.w_stop)
+            step = space.int_w(self.w_step)
+            length = space.int_w(self.w_length)
+        except OperationError as e:
+            pass
+        else:
+            if self.promote_step:
+                return W_IntRangeStepOneIterator(space, start, stop)
+            return W_IntRangeIterator(space, start, length, step)
+        return W_LongRangeIterator(space, self.w_start, self.w_step,
+                                   self.w_length)
 
     def descr_reversed(self, space):
         # lastitem = self.start + (self.length-1) * self.step
@@ -395,7 +411,7 @@
             self.w_start,
             space.mul(space.sub(self.w_length, space.newint(1)),
                       self.w_step))
-        return space.wrap(W_RangeIterator(
+        return space.wrap(W_LongRangeIterator(
                 space, w_lastitem, space.neg(self.w_step), self.w_length))
 
     def descr_reduce(self, space):
@@ -463,7 +479,22 @@
 W_Range.typedef.acceptable_as_base_class = False
 
 
-class W_RangeIterator(W_Root):
+class W_AbstractRangeIterator(W_Root):
+
+    def descr_iter(self, space):
+        return space.wrap(self)
+
+    def descr_len(self, space):
+        raise NotImplementedError
+
+    def descr_next(self, space):
+        raise NotImplementedError
+
+    def descr_reduce(self, space):
+        raise NotImplementedError
+
+
+class W_LongRangeIterator(W_AbstractRangeIterator):
     def __init__(self, space, w_start, w_step, w_len, w_index=None):
         self.w_start = w_start
         self.w_step = w_step
@@ -472,9 +503,6 @@
             w_index = space.newint(0)
         self.w_index = w_index
 
-    def descr_iter(self, space):
-        return space.wrap(self)
-
     def descr_next(self, space):
         if space.is_true(space.lt(self.w_index, self.w_len)):
             w_index = space.add(self.w_index, space.newint(1))
@@ -489,23 +517,75 @@
 
     def descr_reduce(self, space):
         from pypy.interpreter.mixedmodule import MixedModule
+        w_mod = space.getbuiltinmodule('_pickle_support')
+        mod = space.interp_w(MixedModule, w_mod)
+        w_args = space.newtuple([self.w_start, self.w_step, self.w_len,
+                                 self.w_index])
+        return space.newtuple([mod.get('longrangeiter_new'), w_args])
+
+
+class W_IntRangeIterator(W_AbstractRangeIterator):
+
+    def __init__(self, space, current, remaining, step):
+        self.current = current
+        self.remaining = remaining
+        self.step = step
+
+    def descr_next(self, space):
+        return self.next(space)
+
+    def next(self, space):
+        if self.remaining > 0:
+            item = self.current
+            self.current = item + self.step
+            self.remaining -= 1
+            return space.wrap(item)
+        raise OperationError(space.w_StopIteration, space.w_None)
+
+    def descr_len(self, space):
+        return self.get_remaining(space)
+
+    def descr_reduce(self, space):
+        from pypy.interpreter.mixedmodule import MixedModule
         w_mod    = space.getbuiltinmodule('_pickle_support')
         mod      = space.interp_w(MixedModule, w_mod)
+        new_inst = mod.get('intrangeiter_new')
+        w        = space.wrap
+        nt = space.newtuple
 
-        return space.newtuple(
-            [mod.get('rangeiter_new'),
-             space.newtuple([self.w_start, self.w_step,
-                             self.w_len, self.w_index]),
-             ])
+        tup = [w(self.current), self.get_remaining(space), w(self.step)]
+        return nt([new_inst, nt(tup)])
 
+    def get_remaining(self, space):
+        return space.wrap(self.remaining)
 
-W_RangeIterator.typedef = TypeDef("rangeiterator",
-    __iter__        = interp2app(W_RangeIterator.descr_iter),
-    __length_hint__ = interp2app(W_RangeIterator.descr_len),
-    __next__        = interp2app(W_RangeIterator.descr_next),
-    __reduce__      = interp2app(W_RangeIterator.descr_reduce),
+
+class W_IntRangeStepOneIterator(W_IntRangeIterator):
+    _immutable_fields_ = ['stop']
+
+    def __init__(self, space, start, stop):
+        self.current = start
+        self.stop = stop
+        self.step = 1
+
+    def next(self, space):
+        if self.current < self.stop:
+            item = self.current
+            self.current = item + 1
+            return space.wrap(item)
+        raise OperationError(space.w_StopIteration, space.w_None)
+
+    def get_remaining(self, space):
+        return space.wrap(self.stop - self.current)
+
+
+W_AbstractRangeIterator.typedef = TypeDef("rangeiterator",
+    __iter__        = interp2app(W_AbstractRangeIterator.descr_iter),
+    __length_hint__ = interpindirect2app(W_AbstractRangeIterator.descr_len),
+    __next__        = interpindirect2app(W_AbstractRangeIterator.descr_next),
+    __reduce__      = interpindirect2app(W_AbstractRangeIterator.descr_reduce),
 )
-W_RangeIterator.typedef.acceptable_as_base_class = False
+W_AbstractRangeIterator.typedef.acceptable_as_base_class = False
 
 
 class W_Map(W_Root):
diff --git a/pypy/module/_pickle_support/__init__.py 
b/pypy/module/_pickle_support/__init__.py
--- a/pypy/module/_pickle_support/__init__.py
+++ b/pypy/module/_pickle_support/__init__.py
@@ -19,7 +19,8 @@
         'frame_new'    : 'maker.frame_new',
         'traceback_new' : 'maker.traceback_new',
         'generator_new' : 'maker.generator_new',
-        'rangeiter_new': 'maker.rangeiter_new',
+        'longrangeiter_new': 'maker.longrangeiter_new',
+        'intrangeiter_new': 'maker.intrangeiter_new',
         'builtin_code': 'maker.builtin_code',
         'builtin_function' : 'maker.builtin_function',
         'enumerate_new': 'maker.enumerate_new',
diff --git a/pypy/module/_pickle_support/maker.py 
b/pypy/module/_pickle_support/maker.py
--- a/pypy/module/_pickle_support/maker.py
+++ b/pypy/module/_pickle_support/maker.py
@@ -62,9 +62,15 @@
     new_generator = instantiate(GeneratorIteratorWithDel)
     return space.wrap(new_generator)
 
-def rangeiter_new(space, w_start, w_step, w_len, w_index):
-    from pypy.module.__builtin__.functional import W_RangeIterator
-    new_iter = W_RangeIterator(space, w_start, w_step, w_len, w_index)
+def longrangeiter_new(space, w_start, w_step, w_len, w_index):
+    from pypy.module.__builtin__.functional import W_LongRangeIterator
+    new_iter = W_LongRangeIterator(space, w_start, w_step, w_len, w_index)
+    return space.wrap(new_iter)
+
+@unwrap_spec(current=int, remaining=int, step=int)
+def intrangeiter_new(space, current, remaining, step):
+    from pypy.module.__builtin__.functional import W_IntRangeIterator
+    new_iter = W_IntRangeIterator(space, current, remaining, step)
     return space.wrap(new_iter)
 
 def operationerror_new(space):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to