diff options
Diffstat (limited to 'Objects/sliceobject.c')
| -rw-r--r-- | Objects/sliceobject.c | 204 | 
1 files changed, 195 insertions, 9 deletions
| diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 1593335263..104952333a 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -33,6 +33,17 @@ ellipsis_repr(PyObject *op)      return PyUnicode_FromString("Ellipsis");  } +static PyObject * +ellipsis_reduce(PyObject *op) +{ +    return PyUnicode_FromString("Ellipsis"); +} + +static PyMethodDef ellipsis_methods[] = { +    {"__reduce__", (PyCFunction)ellipsis_reduce, METH_NOARGS, NULL}, +    {NULL, NULL} +}; +  PyTypeObject PyEllipsis_Type = {      PyVarObject_HEAD_INIT(&PyType_Type, 0)      "ellipsis",                         /* tp_name */ @@ -61,7 +72,7 @@ PyTypeObject PyEllipsis_Type = {      0,                                  /* tp_weaklistoffset */      0,                                  /* tp_iter */      0,                                  /* tp_iternext */ -    0,                                  /* tp_methods */ +    ellipsis_methods,                   /* tp_methods */      0,                                  /* tp_members */      0,                                  /* tp_getset */      0,                                  /* tp_base */ @@ -299,23 +310,198 @@ 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) +{ +    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; +    } +} + +/* Compute slice indices given a slice and length.  Return -1 on failure.  Used +   by slice.indices and rangeobject slicing.  Assumes that `len` is a +   nonnegative instance of PyLong. */ + +int +_PySlice_GetLongIndices(PySliceObject *self, PyObject *length, +                        PyObject **start_ptr, PyObject **stop_ptr, +                        PyObject **step_ptr)  { -    Py_ssize_t ilen, start, stop, step, slicelength; +    PyObject *start=NULL, *stop=NULL, *step=NULL; +    PyObject *upper=NULL, *lower=NULL; +    int step_is_negative, cmp_result; + +    /* Convert step to an integer; raise for zero step. */ +    if (self->step == Py_None) { +        step = PyLong_FromLong(1L); +        if (step == NULL) +            goto error; +        step_is_negative = 0; +    } +    else { +        int step_sign; +        step = evaluate_slice_index(self->step); +        if (step == NULL) +            goto error; +        step_sign = _PyLong_Sign(step); +        if (step_sign == 0) { +            PyErr_SetString(PyExc_ValueError, +                            "slice step cannot be zero"); +            goto error; +        } +        step_is_negative = step_sign < 0; +    } -    ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError); +    /* Find lower and upper bounds for start and stop. */ +    if (step_is_negative) { +        lower = PyLong_FromLong(-1L); +        if (lower == NULL) +            goto error; -    if (ilen == -1 && PyErr_Occurred()) { -        return NULL; +        upper = PyNumber_Add(length, lower); +        if (upper == NULL) +            goto error;      } +    else { +        lower = PyLong_FromLong(0L); +        if (lower == NULL) +            goto error; -    if (PySlice_GetIndicesEx((PyObject*)self, ilen, &start, &stop, -                             &step, &slicelength) < 0) { +        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; + +        if (_PyLong_Sign(start) < 0) { +            /* start += length */ +            PyObject *tmp = PyNumber_Add(start, length); +            Py_DECREF(start); +            start = tmp; +            if (start == NULL) +                goto error; + +            cmp_result = PyObject_RichCompareBool(start, lower, Py_LT); +            if (cmp_result < 0) +                goto error; +            if (cmp_result) { +                Py_INCREF(lower); +                Py_DECREF(start); +                start = lower; +            } +        } +        else { +            cmp_result = PyObject_RichCompareBool(start, upper, Py_GT); +            if (cmp_result < 0) +                goto error; +            if (cmp_result) { +                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; + +        if (_PyLong_Sign(stop) < 0) { +            /* stop += length */ +            PyObject *tmp = PyNumber_Add(stop, length); +            Py_DECREF(stop); +            stop = tmp; +            if (stop == NULL) +                goto error; + +            cmp_result = PyObject_RichCompareBool(stop, lower, Py_LT); +            if (cmp_result < 0) +                goto error; +            if (cmp_result) { +                Py_INCREF(lower); +                Py_DECREF(stop); +                stop = lower; +            } +        } +        else { +            cmp_result = PyObject_RichCompareBool(stop, upper, Py_GT); +            if (cmp_result < 0) +                goto error; +            if (cmp_result) { +                Py_INCREF(upper); +                Py_DECREF(stop); +                stop = upper; +            } +        } +    } + +    *start_ptr = start; +    *stop_ptr = stop; +    *step_ptr = step; +    Py_DECREF(upper); +    Py_DECREF(lower); +    return 0; + +  error: +    *start_ptr = *stop_ptr = *step_ptr = NULL; +    Py_XDECREF(start); +    Py_XDECREF(stop); +    Py_XDECREF(step); +    Py_XDECREF(upper); +    Py_XDECREF(lower); +    return -1; +} + +/* Implementation of slice.indices. */ + +static PyObject* +slice_indices(PySliceObject* self, PyObject* len) +{ +    PyObject *start, *stop, *step; +    PyObject *length; +    int error; + +    /* Convert length to an integer if necessary; raise for negative length. */ +    length = PyNumber_Index(len); +    if (length == NULL) +        return NULL; + +    if (_PyLong_Sign(length) < 0) { +        PyErr_SetString(PyExc_ValueError, +                        "length should not be negative"); +        Py_DECREF(length);          return NULL;      } -    return Py_BuildValue("(nnn)", start, stop, step); +    error = _PySlice_GetLongIndices(self, length, &start, &stop, &step); +    Py_DECREF(length); +    if (error == -1) +        return NULL; +    else +        return Py_BuildValue("(NNN)", start, stop, step);  }  PyDoc_STRVAR(slice_indices_doc, | 
