[pypy-commit] pypy py3k: Implement range slices, and test getitem with large numbers
amauryfa
noreply at buildbot.pypy.org
Tue Dec 20 01:32:43 CET 2011
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3k
Changeset: r50738:9e845f84d41f
Date: 2011-12-19 22:49 +0100
http://bitbucket.org/pypy/pypy/changeset/9e845f84d41f/
Log: Implement range slices, and test getitem with large numbers
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
@@ -49,6 +49,60 @@
w_len = space.newint(0)
return w_len
+def compute_slice_indices3(space, w_slice, w_length):
+ "An W_Object version of W_SliceObject.indices3"
+ from pypy.objspace.std.sliceobject import W_SliceObject
+ assert isinstance(w_slice, W_SliceObject)
+ w_0 = space.newint(0)
+ w_1 = space.newint(1)
+ if space.is_w(w_slice.w_step, space.w_None):
+ w_step = w_1
+ else:
+ w_step = space.index(w_slice.w_step)
+ if space.is_true(space.eq(w_step, w_0)):
+ raise OperationError(space.w_ValueError,
+ space.wrap("slice step cannot be zero"))
+ negative_step = space.is_true(space.lt(w_step, w_0))
+ if space.is_w(w_slice.w_start, space.w_None):
+ if negative_step:
+ w_start = space.sub(w_length, w_1)
+ else:
+ w_start = w_0
+ else:
+ w_start = space.index(w_slice.w_start)
+ if space.is_true(space.lt(w_start, w_0)):
+ w_start = space.add(w_start, w_length)
+ if space.is_true(space.lt(w_start, w_0)):
+ if negative_step:
+ w_start = space.newint(-1)
+ else:
+ w_start = w_0
+ elif space.is_true(space.ge(w_start, w_length)):
+ if negative_step:
+ w_start = space.sub(w_length, w_1)
+ else:
+ w_start = w_length
+ if space.is_w(w_slice.w_stop, space.w_None):
+ if negative_step:
+ w_stop = space.newint(-1)
+ else:
+ w_stop = w_length
+ else:
+ w_stop = space.index(w_slice.w_stop)
+ if space.is_true(space.lt(w_stop, w_0)):
+ w_stop = space.add(w_stop, w_length)
+ if space.is_true(space.lt(w_stop, w_0)):
+ if negative_step:
+ w_stop = space.newint(-1)
+ else:
+ w_stop = w_0
+ elif space.is_true(space.ge(w_stop, w_length)):
+ if negative_step:
+ w_stop = space.sub(w_length, w_1)
+ else:
+ w_stop = w_length
+ return w_start, w_stop, w_step
+
@specialize.arg(2)
@jit.look_inside_iff(lambda space, args, implementation_of:
@@ -270,10 +324,41 @@
def descr_len(self):
return self.w_length
- def descr_getitem(self, space, w_index):
- # range does NOT support slicing
+ def _compute_item0(self, space, w_index):
+ "Get a range item, when known to be inside bounds"
# return self.start + (i * self.step)
return space.add(self.w_start, space.mul(w_index, self.w_step))
+
+ def _compute_item(self, space, w_index):
+ if space.is_true(space.lt(w_index, space.newint(0))):
+ w_index = space.add(w_index, self.w_length)
+ if space.is_true(space.ge(w_index, self.w_length)):
+ raise OperationError(space.w_IndexError, space.wrap(
+ "range object index out of range"))
+ return self._compute_item0(space, w_index)
+
+ def _compute_slice(self, space, w_slice):
+ w_start, w_stop, w_step = compute_slice_indices3(
+ space, w_slice, self.w_length)
+
+ w_substep = space.mul(self.w_step, w_step)
+ w_substart = self._compute_item0(space, w_start)
+ if w_stop:
+ w_substop = self._compute_item0(space, w_stop)
+ else:
+ w_substop = w_substart
+
+ w_length = compute_range_length(space, w_substart, w_substop, w_substep)
+ obj = W_Range(w_substart, w_substop, w_substep, w_length)
+ return space.wrap(obj)
+
+ def descr_getitem(self, space, w_index):
+ # Cannot use the usual space.decode_index methods, because
+ # numbers might not fit in longs.
+ if space.isinstance_w(w_index, space.w_slice):
+ return self._compute_slice(space, w_index)
+ else:
+ return self._compute_item(space, w_index)
def descr_iter(self, space):
return space.wrap(W_RangeIterator(
diff --git a/pypy/module/__builtin__/test/test_range.py b/pypy/module/__builtin__/test/test_range.py
--- a/pypy/module/__builtin__/test/test_range.py
+++ b/pypy/module/__builtin__/test/test_range.py
@@ -127,3 +127,31 @@
assert range(0, 5, 2).count(3) == 0
assert range(5).count(3.0) == 1
assert range(5).count('3') == 0
+
+ def test_range_getitem(self):
+ assert range(6)[3] == 3
+ assert range(6)[-1] == 5
+ raises(IndexError, range(6).__getitem__, 6)
+
+ def test_range_slice(self):
+ # range objects don't implement equality in 3.2, use the repr
+ assert repr(range(6)[2:5]) == 'range(2, 5)'
+ assert repr(range(6)[-1:-3:-2]) == 'range(5, 3, -2)'
+
+ def test_large_range(self):
+ import sys
+ def _range_len(x):
+ try:
+ length = len(x)
+ except OverflowError:
+ step = x[1] - x[0]
+ length = 1 + ((x[-1] - x[0]) // step)
+ return length
+ a = -sys.maxsize
+ b = sys.maxsize
+ expected_len = b - a
+ x = range(a, b)
+ assert a in x
+ assert b not in x
+ raises(OverflowError, len, x)
+ assert _range_len(x) == expected_len
More information about the pypy-commit
mailing list