[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