diff options
-rw-r--r-- | Doc/c-api/slice.rst | 37 | ||||
-rw-r--r-- | Doc/whatsnew/3.7.rst | 7 | ||||
-rw-r--r-- | Include/sliceobject.h | 16 | ||||
-rw-r--r-- | Misc/NEWS | 5 | ||||
-rw-r--r-- | Objects/sliceobject.c | 78 | ||||
-rw-r--r-- | PC/python3.def | 2 |
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 } @@ -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 |