diff options
author | Mark Dickinson <mdickinson@enthought.com> | 2012-11-10 14:52:10 (GMT) |
---|---|---|
committer | Mark Dickinson <mdickinson@enthought.com> | 2012-11-10 14:52:10 (GMT) |
commit | c8a6967ea8d983358e5e5e4965b6071daede62b3 (patch) | |
tree | 45caf669971af0d5ac431f14a060dfe5996da23a /Objects/sliceobject.c | |
parent | ff3d515952aa6eabdb82a90b9fe6f9dc33a406e5 (diff) | |
download | cpython-c8a6967ea8d983358e5e5e4965b6071daede62b3.zip cpython-c8a6967ea8d983358e5e5e4965b6071daede62b3.tar.gz cpython-c8a6967ea8d983358e5e5e4965b6071daede62b3.tar.bz2 |
Issue #14794: slice.indices no longer returns OverflowError for out-of-range start, stop, step or length.
Diffstat (limited to 'Objects/sliceobject.c')
-rw-r--r-- | Objects/sliceobject.c | 183 |
1 files changed, 175 insertions, 8 deletions
diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 1593335..4b31f23 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -299,25 +299,192 @@ static PyMemberDef slice_members[] = { {0} }; +/* Helper function to convert a slice argument to a PyLong, and raise TypeError + with a suitable message on failure. */ + static PyObject* -slice_indices(PySliceObject* self, PyObject* len) +evaluate_slice_index(PyObject *v) { - Py_ssize_t ilen, start, stop, step, slicelength; + if (PyIndex_Check(v)) { + return PyNumber_Index(v); + } + else { + PyErr_SetString(PyExc_TypeError, + "slice indices must be integers or " + "None or have an __index__ method"); + return NULL; + } +} - ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError); +/* Implementation of slice.indices. */ + +static PyObject* +slice_indices(PySliceObject* self, PyObject* len) +{ + PyObject *start=NULL, *stop=NULL, *step=NULL; + PyObject *length=NULL, *upper=NULL, *lower=NULL, *zero=NULL; + int step_is_negative, cmp; - if (ilen == -1 && PyErr_Occurred()) { + zero = PyLong_FromLong(0L); + if (zero == NULL) return NULL; + + /* Compute step and length as integers. */ + length = PyNumber_Index(len); + if (length == NULL) + goto error; + + if (self->step == Py_None) + step = PyLong_FromLong(1L); + else + step = evaluate_slice_index(self->step); + if (step == NULL) + goto error; + + /* Raise ValueError for negative length or zero step. */ + cmp = PyObject_RichCompareBool(length, zero, Py_LT); + if (cmp < 0) { + goto error; + } + if (cmp) { + PyErr_SetString(PyExc_ValueError, + "length should not be negative"); + goto error; } - if (PySlice_GetIndicesEx((PyObject*)self, ilen, &start, &stop, - &step, &slicelength) < 0) { - return NULL; + cmp = PyObject_RichCompareBool(step, zero, Py_EQ); + if (cmp < 0) { + goto error; + } + if (cmp) { + PyErr_SetString(PyExc_ValueError, + "slice step cannot be zero"); + goto error; } - return Py_BuildValue("(nnn)", start, stop, step); + /* Find lower and upper bounds for start and stop. */ + step_is_negative = PyObject_RichCompareBool(step, zero, Py_LT); + if (step_is_negative < 0) { + goto error; + } + if (step_is_negative) { + lower = PyLong_FromLong(-1L); + if (lower == NULL) + goto error; + + upper = PyNumber_Add(length, lower); + if (upper == NULL) + goto error; + } + else { + lower = zero; + Py_INCREF(lower); + upper = length; + Py_INCREF(upper); + } + + /* Compute start. */ + if (self->start == Py_None) { + start = step_is_negative ? upper : lower; + Py_INCREF(start); + } + else { + start = evaluate_slice_index(self->start); + if (start == NULL) + goto error; + + cmp = PyObject_RichCompareBool(start, zero, Py_LT); + if (cmp < 0) + goto error; + if (cmp) { + /* start += length */ + PyObject *tmp = PyNumber_Add(start, length); + Py_DECREF(start); + start = tmp; + if (start == NULL) + goto error; + + cmp = PyObject_RichCompareBool(start, lower, Py_LT); + if (cmp < 0) + goto error; + if (cmp) { + Py_INCREF(lower); + Py_DECREF(start); + start = lower; + } + } + else { + cmp = PyObject_RichCompareBool(start, upper, Py_GT); + if (cmp < 0) + goto error; + if (cmp) { + Py_INCREF(upper); + Py_DECREF(start); + start = upper; + } + } + } + + /* Compute stop. */ + if (self->stop == Py_None) { + stop = step_is_negative ? lower : upper; + Py_INCREF(stop); + } + else { + stop = evaluate_slice_index(self->stop); + if (stop == NULL) + goto error; + + cmp = PyObject_RichCompareBool(stop, zero, Py_LT); + if (cmp < 0) + goto error; + if (cmp) { + /* stop += length */ + PyObject *tmp = PyNumber_Add(stop, length); + Py_DECREF(stop); + stop = tmp; + if (stop == NULL) + goto error; + + cmp = PyObject_RichCompareBool(stop, lower, Py_LT); + if (cmp < 0) + goto error; + if (cmp) { + Py_INCREF(lower); + Py_DECREF(stop); + stop = lower; + } + } + else { + cmp = PyObject_RichCompareBool(stop, upper, Py_GT); + if (cmp < 0) + goto error; + if (cmp) { + Py_INCREF(upper); + Py_DECREF(stop); + stop = upper; + } + } + } + + Py_DECREF(upper); + Py_DECREF(lower); + Py_DECREF(length); + Py_DECREF(zero); + return Py_BuildValue("(NNN)", start, stop, step); + + error: + Py_XDECREF(start); + Py_XDECREF(stop); + Py_XDECREF(step); + Py_XDECREF(upper); + Py_XDECREF(lower); + Py_XDECREF(length); + Py_XDECREF(zero); + return NULL; } + PyDoc_STRVAR(slice_indices_doc, "S.indices(len) -> (start, stop, stride)\n\ \n\ |