[pypy-commit] pypy py3.5: slice.indices() is rewritten, duplicating functionality instead of reusing it

arigo pypy.commits at gmail.com
Tue Aug 16 14:06:30 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: py3.5
Changeset: r86227:5e6b9a703f80
Date: 2016-08-16 13:33 +0200
http://bitbucket.org/pypy/pypy/changeset/5e6b9a703f80/

Log:	slice.indices() is rewritten, duplicating functionality instead of
	reusing it

diff --git a/pypy/objspace/std/sliceobject.py b/pypy/objspace/std/sliceobject.py
--- a/pypy/objspace/std/sliceobject.py
+++ b/pypy/objspace/std/sliceobject.py
@@ -153,10 +153,12 @@
         S. Out of bounds indices are clipped in a manner consistent with the
         handling of normal slices.
         """
-        length = space.getindex_w(w_length, space.w_OverflowError)
-        start, stop, step = self.indices3(space, length)
-        return space.newtuple([space.wrap(start), space.wrap(stop),
-                               space.wrap(step)])
+        # like CPython 3.5, we duplicate this whole functionality for
+        # this rarely-used method instead of using the existing logic
+        # in indices3(), just to support 'slice(a,b,c).indices(d)' where
+        # all of a, b, c and d are very large integers.
+        return app_indices(space, self.w_start, self.w_stop,
+                           self.w_step, w_length)
 
 
 def slicewprop(name):
@@ -248,3 +250,68 @@
     elif start > stop:
         start = stop
     return start, stop
+
+
+app = gateway.applevel("""
+    from operator import index
+
+    def evaluate_slice_index(x):
+        try:
+            return index(x)
+        except TypeError:
+            raise TypeError("slice indices must be integers or "
+                            "None or have an __index__ method")
+
+    def _getlongindices(start, stop, step, length):
+        if step is None:
+            step = 1
+        else:
+            step = evaluate_slice_index(step)
+            if step == 0:
+                raise ValueError("slice step cannot be zero")
+
+        # Find lower and upper bounds for start and stop.
+        if step < 0:
+            lower = -1
+            upper = length - 1
+        else:
+            lower = 0
+            upper = length
+
+        # Compute start.
+        if start is None:
+            start = upper if step < 0 else lower
+        else:
+            start = evaluate_slice_index(start)
+            if start < 0:
+                start += length
+                if start < lower:
+                    start = lower
+            else:
+                if start > upper:
+                    start = upper
+
+        # Compute stop.
+        if stop is None:
+            stop = lower if step < 0 else upper
+        else:
+            stop = evaluate_slice_index(stop)
+            if stop < 0:
+                stop += length
+                if stop < lower:
+                    stop = lower
+            else:
+                if stop > upper:
+                    stop = upper
+
+        return (start, stop, step)
+
+    def indices(start, stop, step, length):
+        length = index(length)
+        if length < 0:
+            raise ValueError("length should not be negative")
+        return _getlongindices(start, stop, step, length)
+
+""", filename=__file__)
+
+app_indices = app.interphook("indices")
diff --git a/pypy/objspace/std/test/test_sliceobject.py b/pypy/objspace/std/test/test_sliceobject.py
--- a/pypy/objspace/std/test/test_sliceobject.py
+++ b/pypy/objspace/std/test/test_sliceobject.py
@@ -111,11 +111,11 @@
         assert slice(-2 ** 200, -2 ** 100, 1).indices(1000) == (0, 0, 1)
         assert slice(2 ** 100, 0, -1).indices(1000) == (999, 0, -1)
         assert slice(2 ** 100, -2 ** 100, -1).indices(1000) == (999, -1, -1)
-        start, stop, step = slice(0, 1000, 2 ** 200).indices(1000)
-        assert start == 0
-        assert stop == 1000
-        assert step >= 1000
-        raises(OverflowError, "slice(0, 1000, 1).indices(2 ** 100)")
+        assert slice(0, 1000, 2 ** 200).indices(1000) == (0, 1000, 2 ** 200)
+        assert slice(0, 1000, 1).indices(2 ** 100) == (0, 1000, 1)
 
     def test_reduce(self):
         assert slice(1, 2, 3).__reduce__() == (slice, (1, 2, 3))
+
+    def test_indices_negative_length(self):
+        raises(ValueError, "slice(0, 1000, 1).indices(-1)")


More information about the pypy-commit mailing list