[Jython-checkins] jython: Fix slice indices computation and support slice pickling
jim.baker
jython-checkins at python.org
Tue Dec 9 02:45:40 CET 2014
https://hg.python.org/jython/rev/4191d2014781
changeset: 7437:4191d2014781
user: Jim Baker <jim.baker at rackspace.com>
date: Mon Dec 08 18:45:17 2014 -0700
summary:
Fix slice indices computation and support slice pickling
files:
Lib/test/test_slice.py | 137 -------------------
src/org/python/core/PySlice.java | 86 ++++++-----
2 files changed, 49 insertions(+), 174 deletions(-)
diff --git a/Lib/test/test_slice.py b/Lib/test/test_slice.py
deleted file mode 100644
--- a/Lib/test/test_slice.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# tests for slice objects; in particular the indices method.
-
-import unittest
-from test import test_support
-from cPickle import loads, dumps
-
-import sys
-
-class SliceTest(unittest.TestCase):
-
- def test_constructor(self):
- self.assertRaises(TypeError, slice)
- self.assertRaises(TypeError, slice, 1, 2, 3, 4)
-
- def test_repr(self):
- self.assertEqual(repr(slice(1, 2, 3)), "slice(1, 2, 3)")
-
- def test_hash(self):
- # Verify clearing of SF bug #800796
- self.assertRaises(TypeError, hash, slice(5))
- self.assertRaises(TypeError, slice(5).__hash__)
-
- def test_cmp(self):
- s1 = slice(1, 2, 3)
- s2 = slice(1, 2, 3)
- s3 = slice(1, 2, 4)
- self.assertEqual(s1, s2)
- self.assertNotEqual(s1, s3)
-
- class Exc(Exception):
- pass
-
- class BadCmp(object):
- def __eq__(self, other):
- raise Exc
- __hash__ = None # Silence Py3k warning
-
- s1 = slice(BadCmp())
- s2 = slice(BadCmp())
- self.assertRaises(Exc, cmp, s1, s2)
- self.assertEqual(s1, s1)
-
- s1 = slice(1, BadCmp())
- s2 = slice(1, BadCmp())
- self.assertEqual(s1, s1)
- self.assertRaises(Exc, cmp, s1, s2)
-
- s1 = slice(1, 2, BadCmp())
- s2 = slice(1, 2, BadCmp())
- self.assertEqual(s1, s1)
- self.assertRaises(Exc, cmp, s1, s2)
-
- def test_members(self):
- s = slice(1)
- self.assertEqual(s.start, None)
- self.assertEqual(s.stop, 1)
- self.assertEqual(s.step, None)
-
- s = slice(1, 2)
- self.assertEqual(s.start, 1)
- self.assertEqual(s.stop, 2)
- self.assertEqual(s.step, None)
-
- s = slice(1, 2, 3)
- self.assertEqual(s.start, 1)
- self.assertEqual(s.stop, 2)
- self.assertEqual(s.step, 3)
-
- class AnyClass:
- pass
-
- obj = AnyClass()
- s = slice(obj)
- self.assertTrue(s.stop is obj)
-
- def test_indices(self):
- self.assertEqual(slice(None ).indices(10), (0, 10, 1))
- self.assertEqual(slice(None, None, 2).indices(10), (0, 10, 2))
- self.assertEqual(slice(1, None, 2).indices(10), (1, 10, 2))
- self.assertEqual(slice(None, None, -1).indices(10), (9, -1, -1))
- self.assertEqual(slice(None, None, -2).indices(10), (9, -1, -2))
- self.assertEqual(slice(3, None, -2).indices(10), (3, -1, -2))
- # issue 3004 tests
- self.assertEqual(slice(None, -9).indices(10), (0, 1, 1))
- #FIXME: next two not correct on Jython
- #self.assertEqual(slice(None, -10).indices(10), (0, 0, 1))
- #self.assertEqual(slice(None, -11).indices(10), (0, 0, 1))
- self.assertEqual(slice(None, -10, -1).indices(10), (9, 0, -1))
- self.assertEqual(slice(None, -11, -1).indices(10), (9, -1, -1))
- self.assertEqual(slice(None, -12, -1).indices(10), (9, -1, -1))
- self.assertEqual(slice(None, 9).indices(10), (0, 9, 1))
- self.assertEqual(slice(None, 10).indices(10), (0, 10, 1))
- self.assertEqual(slice(None, 11).indices(10), (0, 10, 1))
- self.assertEqual(slice(None, 8, -1).indices(10), (9, 8, -1))
- self.assertEqual(slice(None, 9, -1).indices(10), (9, 9, -1))
- #FIXME: next not correct on Jython
- #self.assertEqual(slice(None, 10, -1).indices(10), (9, 9, -1))
-
- self.assertEqual(
- slice(-100, 100 ).indices(10),
- slice(None).indices(10)
- )
- self.assertEqual(
- slice(100, -100, -1).indices(10),
- slice(None, None, -1).indices(10)
- )
- self.assertEqual(slice(-100L, 100L, 2L).indices(10), (0, 10, 2))
-
- self.assertEqual(range(10)[::sys.maxint - 1], [0])
-
- self.assertRaises(OverflowError, slice(None).indices, 1L<<100)
-
- def test_setslice_without_getslice(self):
- tmp = []
- class X(object):
- def __setslice__(self, i, j, k):
- tmp.append((i, j, k))
-
- x = X()
- with test_support.check_py3k_warnings():
- x[1:2] = 42
- self.assertEqual(tmp, [(1, 2, 42)])
-
- @unittest.skipIf(test_support.is_jython, "FIXME: not working in Jython")
- def test_pickle(self):
- s = slice(10, 20, 3)
- for protocol in (0,1,2):
- t = loads(dumps(s, protocol))
- self.assertEqual(s, t)
- self.assertEqual(s.indices(15), t.indices(15))
- self.assertNotEqual(id(s), id(t))
-
-def test_main():
- test_support.run_unittest(SliceTest)
-
-if __name__ == "__main__":
- test_main()
diff --git a/src/org/python/core/PySlice.java b/src/org/python/core/PySlice.java
--- a/src/org/python/core/PySlice.java
+++ b/src/org/python/core/PySlice.java
@@ -113,62 +113,64 @@
* @return an array with the start at index 0, stop at index 1, step at index 2 and
* slicelength at index 3
*/
- public int[] indicesEx(int len) {
- int start;
- int stop;
- int step;
- int slicelength;
+ public int[] indicesEx(int length) {
+ /* The corresponding C code (PySlice_GetIndicesEx) states:
+ * "this is harder to get right than you might think"
+ * As a consequence, I have chosen to copy the code and translate to Java.
+ * Note *rstart, etc., become result_start - the usual changes we need
+ * when going from pointers to corresponding Java.
+ */
- if (getStep() == Py.None) {
- step = 1;
+ int defstart, defstop;
+ int result_start, result_stop, result_step, result_slicelength;
+
+ if (step == Py.None) {
+ result_step = 1;
} else {
- step = calculateSliceIndex(getStep());
- if (step == 0) {
+ result_step = calculateSliceIndex(step);
+ if (result_step == 0) {
throw Py.ValueError("slice step cannot be zero");
}
}
- if (getStart() == Py.None) {
- start = step < 0 ? len - 1 : 0;
+ defstart = result_step < 0 ? length - 1 : 0;
+ defstop = result_step < 0 ? -1 : length;
+
+ if (start == Py.None) {
+ result_start = defstart;
} else {
- start = calculateSliceIndex(getStart());
- if (start < 0) {
- start += len;
- }
- if (start < 0) {
- start = step < 0 ? -1 : 0;
- }
- if (start >= len) {
- start = step < 0 ? len - 1 : len;
+ result_start = calculateSliceIndex(start);
+ if (result_start < 0) result_start += length;
+ if (result_start < 0) result_start = (result_step < 0) ? -1 : 0;
+ if (result_start >= length) {
+ result_start = (result_step < 0) ? length - 1 : length;
}
}
- if (getStop() == Py.None) {
- stop = step < 0 ? -1 : len;
+ if (stop == Py.None) {
+ result_stop = defstop;
} else {
- stop = calculateSliceIndex(getStop());
- if (stop < 0) {
- stop += len;
- }
- if (stop < 0) {
- stop = -1;
- }
- if (stop > len) {
- stop = len;
+ result_stop = calculateSliceIndex(stop);
+ if (result_stop < 0) result_stop += length;
+ if (result_stop < 0) result_stop = (result_step < 0) ? -1 : 0;
+ if (result_stop >= length) {
+ result_stop = (result_step < 0) ? length - 1 : length;
}
}
- if ((step < 0 && stop >= start) || (step > 0 && start >= stop)) {
- slicelength = 0;
- } else if (step < 0) {
- slicelength = (stop - start + 1) / (step) + 1;
+ if ((result_step < 0 && result_stop >= result_start)
+ || (result_step > 0 && result_start >= result_stop)) {
+ result_slicelength = 0;
+ } else if (result_step < 0) {
+ result_slicelength = (result_stop - result_start + 1) / (result_step) + 1;
} else {
- slicelength = (stop - start - 1) / (step) + 1;
+ result_slicelength = (result_stop - result_start - 1) / (result_step) + 1;
}
- return new int[] {start, stop, step, slicelength};
+ return new int[]{result_start, result_stop, result_step, result_slicelength};
}
+
/**
* Calculate indices for the deprecated __get/set/delslice__ methods.
*
@@ -230,4 +232,14 @@
public final PyObject getStep() {
return step;
}
+
+ @ExposedMethod
+ final PyObject slice___reduce__() {
+ return new PyTuple(getType(), new PyTuple(start, stop, step));
+ }
+
+ @ExposedMethod(defaults = "Py.None")
+ final PyObject slice___reduce_ex__(PyObject protocol) {
+ return new PyTuple(getType(), new PyTuple(start, stop, step));
+ }
}
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list