Author: Armin Rigo <[email protected]>
Branch: py3.6
Changeset: r97957:5b94ae9bcf6d
Date: 2019-11-05 17:12 +0100
http://bitbucket.org/pypy/pypy/changeset/5b94ae9bcf6d/
Log: add the 3.6.1 new functions PySlice_Unpack() and
PySlice_AdjustIndices()
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -1528,6 +1528,7 @@
source_dir / "object.c",
source_dir / "typeobject.c",
source_dir / "tupleobject.c",
+ source_dir / "sliceobject.c",
]
def build_eci(code, use_micronumpy=False, translating=False):
diff --git a/pypy/module/cpyext/include/sliceobject.h
b/pypy/module/cpyext/include/sliceobject.h
--- a/pypy/module/cpyext/include/sliceobject.h
+++ b/pypy/module/cpyext/include/sliceobject.h
@@ -18,7 +18,10 @@
} PySliceObject;
#define PySlice_Check(op) ((op)->ob_type == &PySlice_Type)
-
+
+PyAPI_FUNC(Py_ssize_t) PySlice_AdjustIndices(Py_ssize_t length,
+ Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t step);
+
#ifdef __cplusplus
}
#endif
diff --git a/pypy/module/cpyext/sliceobject.py
b/pypy/module/cpyext/sliceobject.py
--- a/pypy/module/cpyext/sliceobject.py
+++ b/pypy/module/cpyext/sliceobject.py
@@ -1,3 +1,4 @@
+import sys
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (
cpython_api, cpython_struct, bootstrap_function, build_type_checkers,
@@ -5,7 +6,7 @@
from pypy.module.cpyext.pyobject import (
decref, PyObject, make_ref, make_typedescr)
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import oefmt
from pypy.objspace.std.sliceobject import W_SliceObject
# Slice objects directly expose their members as PyObject.
@@ -75,7 +76,7 @@
Returns 0 on success and -1 on error with exception set."""
if not isinstance(w_slice, W_SliceObject):
- PyErr_BadInternalCall(space)
+ raise PyErr_BadInternalCall(space)
start_p[0], stop_p[0], step_p[0], slicelength_p[0] = \
w_slice.indices4(space, length)
return 0
@@ -96,7 +97,37 @@
incorporate the source of PySlice_GetIndicesEx(), suitably renamed,
in the source of your extension."""
if not isinstance(w_slice, W_SliceObject):
- PyErr_BadInternalCall(space)
+ raise PyErr_BadInternalCall(space)
start_p[0], stop_p[0], step_p[0] = \
w_slice.indices3(space, length)
return 0
+
+@cpython_api([PyObject, Py_ssize_tP, Py_ssize_tP, Py_ssize_tP],
+ rffi.INT_real, error=-1)
+def PySlice_Unpack(space, w_slice, start_p, stop_p, step_p):
+ if not isinstance(w_slice, W_SliceObject):
+ raise PyErr_BadInternalCall(space)
+
+ if space.is_none(w_slice.w_step):
+ step = 1
+ else:
+ step = W_SliceObject.eval_slice_index(space, w_slice.w_step)
+ if step == 0:
+ raise oefmt(space.w_ValueError, "slice step cannot be zero")
+ if step < -sys.maxint:
+ step = -sys.maxint
+ step_p[0] = step
+
+ if space.is_none(w_slice.w_start):
+ start = sys.maxint if step < 0 else 0
+ else:
+ start = W_SliceObject.eval_slice_index(space, w_slice.w_start)
+ start_p[0] = start
+
+ if space.is_none(w_slice.w_stop):
+ stop = -sys.maxint-1 if step < 0 else sys.maxint
+ else:
+ stop = W_SliceObject.eval_slice_index(space, w_slice.w_stop)
+ stop_p[0] = stop
+
+ return 0
diff --git a/pypy/module/cpyext/src/sliceobject.c
b/pypy/module/cpyext/src/sliceobject.c
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/src/sliceobject.c
@@ -0,0 +1,43 @@
+#include "Python.h"
+
+Py_ssize_t
+PySlice_AdjustIndices(Py_ssize_t length,
+ Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t step)
+{
+ /* this is harder to get right than you might think */
+
+ assert(step != 0);
+ assert(step >= -PY_SSIZE_T_MAX);
+
+ if (*start < 0) {
+ *start += length;
+ if (*start < 0) {
+ *start = (step < 0) ? -1 : 0;
+ }
+ }
+ else if (*start >= length) {
+ *start = (step < 0) ? length - 1 : length;
+ }
+
+ if (*stop < 0) {
+ *stop += length;
+ if (*stop < 0) {
+ *stop = (step < 0) ? -1 : 0;
+ }
+ }
+ else if (*stop >= length) {
+ *stop = (step < 0) ? length - 1 : length;
+ }
+
+ if (step < 0) {
+ if (*stop < *start) {
+ return (*start - *stop - 1) / (-step) + 1;
+ }
+ }
+ else {
+ if (*start < *stop) {
+ return (*stop - *start - 1) / step + 1;
+ }
+ }
+ return 0;
+}
diff --git a/pypy/module/cpyext/test/test_sliceobject.py
b/pypy/module/cpyext/test/test_sliceobject.py
--- a/pypy/module/cpyext/test/test_sliceobject.py
+++ b/pypy/module/cpyext/test/test_sliceobject.py
@@ -1,3 +1,4 @@
+import sys
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
@@ -84,3 +85,47 @@
])
s = slice(10, 20, 30)
assert module.check(s)
+
+ def test_Unpack(self):
+ from sys import maxsize as M
+ module = self.import_extension('foo', [
+ ("check", "METH_O",
+ """
+ Py_ssize_t start, stop, step;
+ if (PySlice_Unpack(args, &start, &stop, &step) != 0)
+ return NULL;
+ return Py_BuildValue("nnn", start, stop, step);
+ """),
+ ])
+ assert module.check(slice(10, 20, 1)) == (10, 20, 1)
+ assert module.check(slice(None, 20, 1)) == (0, 20, 1)
+ assert module.check(slice(10, None, 3)) == (10, M, 3)
+ assert module.check(slice(10, 20, None)) == (10, 20, 1)
+ assert module.check(slice(20, 5, 1)) == (20, 5, 1)
+ assert module.check(slice(None, None, None)) == (0, M, 1)
+
+ assert module.check(slice(20, 10, -1)) == (20, 10, -1)
+ assert module.check(slice(None, 20, -1)) == (M, 20, -1)
+ assert module.check(slice(10, None, -1)) == (10, -M-1, -1)
+
+ assert module.check(slice(M*2, M*3, 1)) == (M, M, 1)
+ assert module.check(slice(M*2, -123, 1)) == (M, -123, 1)
+ assert module.check(slice(-M*2, -M*3, 1)) == (-M-1, -M-1, 1)
+ assert module.check(slice(-M*2, 123, -2)) == (-M-1, 123, -2)
+
+ with raises(ValueError):
+ module.check(slice(2, 3, 0))
+ assert module.check(slice(2, 3, -M-1)) == (2, 3, -M)
+ assert module.check(slice(2, 3, -M-10)) == (2, 3, -M)
+ assert module.check(slice(2, 3, M+10)) == (2, 3, M)
+
+ def test_AdjustIndices(self):
+ module = self.import_extension('foo', [
+ ("check", "METH_NOARGS",
+ """
+ Py_ssize_t start = -35, stop = 99999, step = 10, result;
+ result = PySlice_AdjustIndices(100, &start, &stop, step);
+ return Py_BuildValue("nnnn", result, start, stop, step);
+ """),
+ ])
+ assert module.check() == (4, 65, 100, 10)
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
@@ -172,6 +172,11 @@
return app_indices(space, self.w_start, self.w_stop,
self.w_step, w_length)
+ @staticmethod
+ def eval_slice_index(space, w_int):
+ """Helper for cpyext"""
+ return _eval_slice_index(space, w_int)
+
def slicewprop(name):
def fget(space, w_obj):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit