[Python-checkins] cpython (merge 3.6 -> default): Issue #27867: Function PySlice_GetIndicesEx() is deprecated and replaced with

serhiy.storchaka python-checkins at python.org
Wed Jan 25 06:29:16 EST 2017


https://hg.python.org/cpython/rev/6093ce8eed6c
changeset:   106314:6093ce8eed6c
parent:      106310:0fd4a3d8e32a
parent:      106313:b4457fe7fdb8
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Wed Jan 25 13:27:44 2017 +0200
summary:
  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().

files:
  Doc/c-api/slice.rst   |  37 ++++++++++++++
  Doc/whatsnew/3.7.rst  |   7 ++
  Include/sliceobject.h |  16 +++++-
  Misc/NEWS             |   5 +
  Objects/sliceobject.c |  78 +++++++++++++++++++++---------
  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
--- a/Doc/c-api/slice.rst
+++ b/Doc/c-api/slice.rst
@@ -56,3 +56,40 @@
    .. 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
--- a/Doc/whatsnew/3.7.rst
+++ b/Doc/whatsnew/3.7.rst
@@ -128,10 +128,17 @@
   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
--- a/Include/sliceobject.h
+++ b/Include/sliceobject.h
@@ -41,8 +41,20 @@
 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
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -623,6 +623,11 @@
 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
--- a/Objects/sliceobject.c
+++ b/Objects/sliceobject.c
@@ -191,15 +191,12 @@
 }
 
 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 @@
             *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
--- a/PC/python3.def
+++ b/PC/python3.def
@@ -531,10 +531,12 @@
   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

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list