[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