summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/c-api/slice.rst37
-rw-r--r--Doc/whatsnew/3.7.rst7
-rw-r--r--Include/sliceobject.h16
-rw-r--r--Misc/NEWS5
-rw-r--r--Objects/sliceobject.c78
-rw-r--r--PC/python3.def2
6 files changed, 119 insertions, 26 deletions
diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst
index a825164..5606ae4 100644
--- a/Doc/c-api/slice.rst
+++ b/Doc/c-api/slice.rst
@@ -56,3 +56,40 @@ Slice Objects
.. versionchanged:: 3.2
The parameter type for the *slice* parameter was ``PySliceObject*``
before.
+
+ .. versionchanged:: 3.6.1
+ If ``Py_LIMITED_API`` is not set or set to the value between ``0x03050400``
+ and ``0x03060000`` (not including) or ``0x03060100`` or higher
+ :c:func:`!PySlice_GetIndicesEx` is implemented as a macro using
+ :c:func:`PySlice_Unpack` and :c:func:`PySlice_AdjustIndices`.
+ Arguments *start*, *stop* and *step* are evaluated more than once.
+
+ .. deprecated:: 3.6.1
+ If ``Py_LIMITED_API`` is set to the value less than ``0x03050400`` or
+ between ``0x03060000`` and ``0x03060100`` (not including)
+ :c:func:`!PySlice_GetIndicesEx` is a deprecated function.
+
+
+.. c:function:: int PySlice_Unpack(PyObject *slice, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
+
+ Extract the start, stop and step data members from a slice object as
+ C integers. Silently reduce values larger than ``PY_SSIZE_T_MAX`` to
+ ``PY_SSIZE_T_MAX``, silently boost the start and stop values less than
+ ``-PY_SSIZE_T_MAX-1`` to ``-PY_SSIZE_T_MAX-1``, and silently boost the step
+ values less than ``-PY_SSIZE_T_MAX`` to ``-PY_SSIZE_T_MAX``.
+
+ Return ``-1`` on error, ``0`` on success.
+
+ .. versionadded:: 3.6.1
+
+
+.. c:function:: Py_ssize_t PySlice_AdjustIndices(Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t step)
+
+ Adjust start/end slice indices assuming a sequence of the specified length.
+ Out of bounds indices are clipped in a manner consistent with the handling
+ of normal slices.
+
+ Return the length of the slice. Always successful. Doesn't call Python
+ code.
+
+ .. versionadded:: 3.6.1
diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst
index 129d4d4..81ad4f9 100644
--- a/Doc/whatsnew/3.7.rst
+++ b/Doc/whatsnew/3.7.rst
@@ -128,10 +128,17 @@ Build and C API Changes
is now of type ``const char *`` rather of ``char *``.
(Contributed by Serhiy Storchaka in :issue:`28769`.)
+* Added functions :c:func:`PySlice_Unpack` and :c:func:`PySlice_AdjustIndices`.
+ (Contributed by Serhiy Storchaka in :issue:`27867`.)
+
Deprecated
==========
+- Function :c:func:`PySlice_GetIndicesEx` is deprecated and replaced with
+ a macro if ``Py_LIMITED_API`` is not set or set to the value between
+ ``0x03050400`` and ``0x03060000`` (not including) or ``0x03060100`` or
+ higher. (Contributed by Serhiy Storchaka in :issue:`27867`.)
Removed
diff --git a/Include/sliceobject.h b/Include/sliceobject.h
index 26370e0..edd14c5 100644
--- a/Include/sliceobject.h
+++ b/Include/sliceobject.h
@@ -41,8 +41,20 @@ PyAPI_FUNC(int) _PySlice_GetLongIndices(PySliceObject *self, PyObject *length,
PyAPI_FUNC(int) PySlice_GetIndices(PyObject *r, Py_ssize_t length,
Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step);
PyAPI_FUNC(int) PySlice_GetIndicesEx(PyObject *r, Py_ssize_t length,
- Py_ssize_t *start, Py_ssize_t *stop,
- Py_ssize_t *step, Py_ssize_t *slicelength);
+ Py_ssize_t *start, Py_ssize_t *stop,
+ Py_ssize_t *step, Py_ssize_t *slicelength) Py_DEPRECATED(3.7);
+
+#if !defined(Py_LIMITED_API) || (Py_LIMITED_API+0 >= 0x03050400 && Py_LIMITED_API+0 < 0x03060000) || Py_LIMITED_API+0 >= 0x03060100
+#define PySlice_GetIndicesEx(slice, length, start, stop, step, slicelen) ( \
+ PySlice_Unpack((slice), (start), (stop), (step)) < 0 ? -1 : \
+ ((*slicelen = PySlice_AdjustIndices((length), (start), (stop), *(step))), \
+ 0))
+PyAPI_FUNC(int) PySlice_Unpack(PyObject *slice,
+ Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step);
+PyAPI_FUNC(Py_ssize_t) PySlice_AdjustIndices(Py_ssize_t length,
+ Py_ssize_t *start, Py_ssize_t *stop,
+ Py_ssize_t step);
+#endif
#ifdef __cplusplus
}
diff --git a/Misc/NEWS b/Misc/NEWS
index 34d4565..137de9d 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -623,6 +623,11 @@ Windows
C API
-----
+- Issue #27867: Function PySlice_GetIndicesEx() is deprecated and replaced with
+ a macro if Py_LIMITED_API is not set or set to the value between 0x03050400
+ and 0x03060000 (not including) or 0x03060100 or higher. Added functions
+ PySlice_Unpack() and PySlice_AdjustIndices().
+
- Issue #29083: Fixed the declaration of some public API functions.
PyArg_VaParse() and PyArg_VaParseTupleAndKeywords() were not available in
limited API. PyArg_ValidateKeywordArguments(), PyArg_UnpackTuple() and
diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c
index 1dc7e4e..d41ac10 100644
--- a/Objects/sliceobject.c
+++ b/Objects/sliceobject.c
@@ -191,15 +191,12 @@ PySlice_GetIndices(PyObject *_r, Py_ssize_t length,
}
int
-PySlice_GetIndicesEx(PyObject *_r, Py_ssize_t length,
- Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step,
- Py_ssize_t *slicelength)
+PySlice_Unpack(PyObject *_r,
+ Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
{
PySliceObject *r = (PySliceObject*)_r;
/* this is harder to get right than you might think */
- Py_ssize_t defstart, defstop;
-
if (r->step == Py_None) {
*step = 1;
}
@@ -219,42 +216,75 @@ PySlice_GetIndicesEx(PyObject *_r, Py_ssize_t length,
*step = -PY_SSIZE_T_MAX;
}
- defstart = *step < 0 ? length-1 : 0;
- defstop = *step < 0 ? -1 : length;
-
if (r->start == Py_None) {
- *start = defstart;
+ *start = *step < 0 ? PY_SSIZE_T_MAX-1 : 0;;
}
else {
if (!_PyEval_SliceIndex(r->start, start)) return -1;
- if (*start < 0) *start += length;
- if (*start < 0) *start = (*step < 0) ? -1 : 0;
- if (*start >= length)
- *start = (*step < 0) ? length - 1 : length;
}
if (r->stop == Py_None) {
- *stop = defstop;
+ *stop = *step < 0 ? -PY_SSIZE_T_MAX : PY_SSIZE_T_MAX;
}
else {
if (!_PyEval_SliceIndex(r->stop, stop)) return -1;
- if (*stop < 0) *stop += length;
- if (*stop < 0) *stop = (*step < 0) ? -1 : 0;
- if (*stop >= length)
- *stop = (*step < 0) ? length - 1 : length;
}
- if ((*step < 0 && *stop >= *start)
- || (*step > 0 && *start >= *stop)) {
- *slicelength = 0;
+ return 0;
+}
+
+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 (*step < 0) {
- *slicelength = (*stop-*start+1)/(*step)+1;
+ 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 {
- *slicelength = (*stop-*start-1)/(*step)+1;
+ if (*start < *stop) {
+ return (*stop - *start - 1) / step + 1;
+ }
}
+ return 0;
+}
+
+#undef PySlice_GetIndicesEx
+int
+PySlice_GetIndicesEx(PyObject *_r, Py_ssize_t length,
+ Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step,
+ Py_ssize_t *slicelength)
+{
+ if (PySlice_Unpack(_r, start, stop, step) < 0)
+ return -1;
+ *slicelength = PySlice_AdjustIndices(length, start, stop, *step);
return 0;
}
diff --git a/PC/python3.def b/PC/python3.def
index a513b2a..bb3ca88 100644
--- a/PC/python3.def
+++ b/PC/python3.def
@@ -531,10 +531,12 @@ EXPORTS
PySet_Pop=python37.PySet_Pop
PySet_Size=python37.PySet_Size
PySet_Type=python37.PySet_Type DATA
+ PySlice_AdjustIndices=python37.PySlice_AdjustIndices
PySlice_GetIndices=python37.PySlice_GetIndices
PySlice_GetIndicesEx=python37.PySlice_GetIndicesEx
PySlice_New=python37.PySlice_New
PySlice_Type=python37.PySlice_Type DATA
+ PySlice_Unpack=python37.PySlice_Unpack
PySortWrapper_Type=python37.PySortWrapper_Type DATA
PyState_AddModule=python37.PyState_AddModule
PyState_FindModule=python37.PyState_FindModule