mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			388 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			388 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
Written by Jim Hugunin and Chris Chase.
 | 
						|
 | 
						|
This includes both the singular ellipsis object and slice objects.
 | 
						|
 | 
						|
Guido, feel free to do whatever you want in the way of copyrights
 | 
						|
for this file.
 | 
						|
*/
 | 
						|
 | 
						|
/*
 | 
						|
Py_Ellipsis encodes the '...' rubber index token. It is similar to
 | 
						|
the Py_NoneStruct in that there is no way to create other objects of
 | 
						|
this type and there is exactly one in existence.
 | 
						|
*/
 | 
						|
 | 
						|
#include "Python.h"
 | 
						|
#include "structmember.h"
 | 
						|
 | 
						|
static PyObject *
 | 
						|
ellipsis_repr(PyObject *op)
 | 
						|
{
 | 
						|
    return PyUnicode_FromString("Ellipsis");
 | 
						|
}
 | 
						|
 | 
						|
PyTypeObject PyEllipsis_Type = {
 | 
						|
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
 | 
						|
    "ellipsis",                         /* tp_name */
 | 
						|
    0,                                  /* tp_basicsize */
 | 
						|
    0,                                  /* tp_itemsize */
 | 
						|
    0, /*never called*/                 /* tp_dealloc */
 | 
						|
    0,                                  /* tp_print */
 | 
						|
    0,                                  /* tp_getattr */
 | 
						|
    0,                                  /* tp_setattr */
 | 
						|
    0,                                  /* tp_reserved */
 | 
						|
    ellipsis_repr,                      /* tp_repr */
 | 
						|
    0,                                  /* tp_as_number */
 | 
						|
    0,                                  /* tp_as_sequence */
 | 
						|
    0,                                  /* tp_as_mapping */
 | 
						|
    0,                                  /* tp_hash */
 | 
						|
    0,                                  /* tp_call */
 | 
						|
    0,                                  /* tp_str */
 | 
						|
    PyObject_GenericGetAttr,            /* tp_getattro */
 | 
						|
    0,                                  /* tp_setattro */
 | 
						|
    0,                                  /* tp_as_buffer */
 | 
						|
    Py_TPFLAGS_DEFAULT,                 /* tp_flags */
 | 
						|
};
 | 
						|
 | 
						|
PyObject _Py_EllipsisObject = {
 | 
						|
    _PyObject_EXTRA_INIT
 | 
						|
    1, &PyEllipsis_Type
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/* Slice object implementation
 | 
						|
 | 
						|
   start, stop, and step are python objects with None indicating no
 | 
						|
   index is present.
 | 
						|
*/
 | 
						|
 | 
						|
PyObject *
 | 
						|
PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
 | 
						|
{
 | 
						|
    PySliceObject *obj = PyObject_New(PySliceObject, &PySlice_Type);
 | 
						|
 | 
						|
    if (obj == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    if (step == NULL) step = Py_None;
 | 
						|
    Py_INCREF(step);
 | 
						|
    if (start == NULL) start = Py_None;
 | 
						|
    Py_INCREF(start);
 | 
						|
    if (stop == NULL) stop = Py_None;
 | 
						|
    Py_INCREF(stop);
 | 
						|
 | 
						|
    obj->step = step;
 | 
						|
    obj->start = start;
 | 
						|
    obj->stop = stop;
 | 
						|
 | 
						|
    return (PyObject *) obj;
 | 
						|
}
 | 
						|
 | 
						|
PyObject *
 | 
						|
_PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop)
 | 
						|
{
 | 
						|
    PyObject *start, *end, *slice;
 | 
						|
    start = PyLong_FromSsize_t(istart);
 | 
						|
    if (!start)
 | 
						|
        return NULL;
 | 
						|
    end = PyLong_FromSsize_t(istop);
 | 
						|
    if (!end) {
 | 
						|
        Py_DECREF(start);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    slice = PySlice_New(start, end, NULL);
 | 
						|
    Py_DECREF(start);
 | 
						|
    Py_DECREF(end);
 | 
						|
    return slice;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
PySlice_GetIndices(PyObject *_r, Py_ssize_t length,
 | 
						|
                   Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
 | 
						|
{
 | 
						|
    PySliceObject *r = (PySliceObject*)_r;
 | 
						|
    /* XXX support long ints */
 | 
						|
    if (r->step == Py_None) {
 | 
						|
        *step = 1;
 | 
						|
    } else {
 | 
						|
        if (!PyLong_Check(r->step)) return -1;
 | 
						|
        *step = PyLong_AsSsize_t(r->step);
 | 
						|
    }
 | 
						|
    if (r->start == Py_None) {
 | 
						|
        *start = *step < 0 ? length-1 : 0;
 | 
						|
    } else {
 | 
						|
        if (!PyLong_Check(r->start)) return -1;
 | 
						|
        *start = PyLong_AsSsize_t(r->start);
 | 
						|
        if (*start < 0) *start += length;
 | 
						|
    }
 | 
						|
    if (r->stop == Py_None) {
 | 
						|
        *stop = *step < 0 ? -1 : length;
 | 
						|
    } else {
 | 
						|
        if (!PyLong_Check(r->stop)) return -1;
 | 
						|
        *stop = PyLong_AsSsize_t(r->stop);
 | 
						|
        if (*stop < 0) *stop += length;
 | 
						|
    }
 | 
						|
    if (*stop > length) return -1;
 | 
						|
    if (*start >= length) return -1;
 | 
						|
    if (*step == 0) return -1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
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)
 | 
						|
{
 | 
						|
    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;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        if (!_PyEval_SliceIndex(r->step, step)) return -1;
 | 
						|
        if (*step == 0) {
 | 
						|
            PyErr_SetString(PyExc_ValueError,
 | 
						|
                            "slice step cannot be zero");
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
        /* Here *step might be -PY_SSIZE_T_MAX-1; in this case we replace it
 | 
						|
         * with -PY_SSIZE_T_MAX.  This doesn't affect the semantics, and it
 | 
						|
         * guards against later undefined behaviour resulting from code that
 | 
						|
         * does "step = -step" as part of a slice reversal.
 | 
						|
         */
 | 
						|
        if (*step < -PY_SSIZE_T_MAX)
 | 
						|
            *step = -PY_SSIZE_T_MAX;
 | 
						|
    }
 | 
						|
 | 
						|
    defstart = *step < 0 ? length-1 : 0;
 | 
						|
    defstop = *step < 0 ? -1 : length;
 | 
						|
 | 
						|
    if (r->start == Py_None) {
 | 
						|
        *start = defstart;
 | 
						|
    }
 | 
						|
    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;
 | 
						|
    }
 | 
						|
    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;
 | 
						|
    }
 | 
						|
    else if (*step < 0) {
 | 
						|
        *slicelength = (*stop-*start+1)/(*step)+1;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        *slicelength = (*stop-*start-1)/(*step)+1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
slice_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 | 
						|
{
 | 
						|
    PyObject *start, *stop, *step;
 | 
						|
 | 
						|
    start = stop = step = NULL;
 | 
						|
 | 
						|
    if (!_PyArg_NoKeywords("slice()", kw))
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step))
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    /* This swapping of stop and start is to maintain similarity with
 | 
						|
       range(). */
 | 
						|
    if (stop == NULL) {
 | 
						|
        stop = start;
 | 
						|
        start = NULL;
 | 
						|
    }
 | 
						|
    return PySlice_New(start, stop, step);
 | 
						|
}
 | 
						|
 | 
						|
PyDoc_STRVAR(slice_doc,
 | 
						|
"slice([start,] stop[, step])\n\
 | 
						|
\n\
 | 
						|
Create a slice object.  This is used for extended slicing (e.g. a[0:10:2]).");
 | 
						|
 | 
						|
static void
 | 
						|
slice_dealloc(PySliceObject *r)
 | 
						|
{
 | 
						|
    Py_DECREF(r->step);
 | 
						|
    Py_DECREF(r->start);
 | 
						|
    Py_DECREF(r->stop);
 | 
						|
    PyObject_Del(r);
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
slice_repr(PySliceObject *r)
 | 
						|
{
 | 
						|
    return PyUnicode_FromFormat("slice(%R, %R, %R)", r->start, r->stop, r->step);
 | 
						|
}
 | 
						|
 | 
						|
static PyMemberDef slice_members[] = {
 | 
						|
    {"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
 | 
						|
    {"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
 | 
						|
    {"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
 | 
						|
    {0}
 | 
						|
};
 | 
						|
 | 
						|
static PyObject*
 | 
						|
slice_indices(PySliceObject* self, PyObject* len)
 | 
						|
{
 | 
						|
    Py_ssize_t ilen, start, stop, step, slicelength;
 | 
						|
 | 
						|
    ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError);
 | 
						|
 | 
						|
    if (ilen == -1 && PyErr_Occurred()) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (PySlice_GetIndicesEx((PyObject*)self, ilen, &start, &stop,
 | 
						|
                             &step, &slicelength) < 0) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    return Py_BuildValue("(nnn)", start, stop, step);
 | 
						|
}
 | 
						|
 | 
						|
PyDoc_STRVAR(slice_indices_doc,
 | 
						|
"S.indices(len) -> (start, stop, stride)\n\
 | 
						|
\n\
 | 
						|
Assuming a sequence of length len, calculate the start and stop\n\
 | 
						|
indices, and the stride length of the extended slice described by\n\
 | 
						|
S. Out of bounds indices are clipped in a manner consistent with the\n\
 | 
						|
handling of normal slices.");
 | 
						|
 | 
						|
static PyObject *
 | 
						|
slice_reduce(PySliceObject* self)
 | 
						|
{
 | 
						|
    return Py_BuildValue("O(OOO)", Py_TYPE(self), self->start, self->stop, self->step);
 | 
						|
}
 | 
						|
 | 
						|
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
 | 
						|
 | 
						|
static PyMethodDef slice_methods[] = {
 | 
						|
    {"indices",         (PyCFunction)slice_indices,
 | 
						|
     METH_O,            slice_indices_doc},
 | 
						|
    {"__reduce__",      (PyCFunction)slice_reduce,
 | 
						|
     METH_NOARGS,       reduce_doc},
 | 
						|
    {NULL, NULL}
 | 
						|
};
 | 
						|
 | 
						|
static PyObject *
 | 
						|
slice_richcompare(PyObject *v, PyObject *w, int op)
 | 
						|
{
 | 
						|
    PyObject *t1;
 | 
						|
    PyObject *t2;
 | 
						|
    PyObject *res;
 | 
						|
 | 
						|
    if (!PySlice_Check(v) || !PySlice_Check(w)) {
 | 
						|
        Py_INCREF(Py_NotImplemented);
 | 
						|
        return Py_NotImplemented;
 | 
						|
    }
 | 
						|
 | 
						|
    if (v == w) {
 | 
						|
        /* XXX Do we really need this shortcut?
 | 
						|
           There's a unit test for it, but is that fair? */
 | 
						|
        switch (op) {
 | 
						|
        case Py_EQ:
 | 
						|
        case Py_LE:
 | 
						|
        case Py_GE:
 | 
						|
            res = Py_True;
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            res = Py_False;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        Py_INCREF(res);
 | 
						|
        return res;
 | 
						|
    }
 | 
						|
 | 
						|
    t1 = PyTuple_New(3);
 | 
						|
    t2 = PyTuple_New(3);
 | 
						|
    if (t1 == NULL || t2 == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    PyTuple_SET_ITEM(t1, 0, ((PySliceObject *)v)->start);
 | 
						|
    PyTuple_SET_ITEM(t1, 1, ((PySliceObject *)v)->stop);
 | 
						|
    PyTuple_SET_ITEM(t1, 2, ((PySliceObject *)v)->step);
 | 
						|
    PyTuple_SET_ITEM(t2, 0, ((PySliceObject *)w)->start);
 | 
						|
    PyTuple_SET_ITEM(t2, 1, ((PySliceObject *)w)->stop);
 | 
						|
    PyTuple_SET_ITEM(t2, 2, ((PySliceObject *)w)->step);
 | 
						|
 | 
						|
    res = PyObject_RichCompare(t1, t2, op);
 | 
						|
 | 
						|
    PyTuple_SET_ITEM(t1, 0, NULL);
 | 
						|
    PyTuple_SET_ITEM(t1, 1, NULL);
 | 
						|
    PyTuple_SET_ITEM(t1, 2, NULL);
 | 
						|
    PyTuple_SET_ITEM(t2, 0, NULL);
 | 
						|
    PyTuple_SET_ITEM(t2, 1, NULL);
 | 
						|
    PyTuple_SET_ITEM(t2, 2, NULL);
 | 
						|
 | 
						|
    Py_DECREF(t1);
 | 
						|
    Py_DECREF(t2);
 | 
						|
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
PyTypeObject PySlice_Type = {
 | 
						|
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
 | 
						|
    "slice",                    /* Name of this type */
 | 
						|
    sizeof(PySliceObject),      /* Basic object size */
 | 
						|
    0,                          /* Item size for varobject */
 | 
						|
    (destructor)slice_dealloc,                  /* tp_dealloc */
 | 
						|
    0,                                          /* tp_print */
 | 
						|
    0,                                          /* tp_getattr */
 | 
						|
    0,                                          /* tp_setattr */
 | 
						|
    0,                                          /* tp_reserved */
 | 
						|
    (reprfunc)slice_repr,                       /* tp_repr */
 | 
						|
    0,                                          /* tp_as_number */
 | 
						|
    0,                                          /* tp_as_sequence */
 | 
						|
    0,                                          /* tp_as_mapping */
 | 
						|
    PyObject_HashNotImplemented,                /* tp_hash */
 | 
						|
    0,                                          /* tp_call */
 | 
						|
    0,                                          /* tp_str */
 | 
						|
    PyObject_GenericGetAttr,                    /* tp_getattro */
 | 
						|
    0,                                          /* tp_setattro */
 | 
						|
    0,                                          /* tp_as_buffer */
 | 
						|
    Py_TPFLAGS_DEFAULT,                         /* tp_flags */
 | 
						|
    slice_doc,                                  /* tp_doc */
 | 
						|
    0,                                          /* tp_traverse */
 | 
						|
    0,                                          /* tp_clear */
 | 
						|
    slice_richcompare,                          /* tp_richcompare */
 | 
						|
    0,                                          /* tp_weaklistoffset */
 | 
						|
    0,                                          /* tp_iter */
 | 
						|
    0,                                          /* tp_iternext */
 | 
						|
    slice_methods,                              /* tp_methods */
 | 
						|
    slice_members,                              /* tp_members */
 | 
						|
    0,                                          /* tp_getset */
 | 
						|
    0,                                          /* tp_base */
 | 
						|
    0,                                          /* tp_dict */
 | 
						|
    0,                                          /* tp_descr_get */
 | 
						|
    0,                                          /* tp_descr_set */
 | 
						|
    0,                                          /* tp_dictoffset */
 | 
						|
    0,                                          /* tp_init */
 | 
						|
    0,                                          /* tp_alloc */
 | 
						|
    slice_new,                                  /* tp_new */
 | 
						|
};
 |