LCOV - code coverage report
Current view: top level - Objects - sliceobject.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 56 138 40.6 %
Date: 2017-04-19 Functions: 4 13 30.8 %

          Line data    Source code
       1             : /*
       2             : Written by Jim Hugunin and Chris Chase.
       3             : 
       4             : This includes both the singular ellipsis object and slice objects.
       5             : 
       6             : Guido, feel free to do whatever you want in the way of copyrights
       7             : for this file.
       8             : */
       9             : 
      10             : /*
      11             : Py_Ellipsis encodes the '...' rubber index token. It is similar to
      12             : the Py_NoneStruct in that there is no way to create other objects of
      13             : this type and there is exactly one in existence.
      14             : */
      15             : 
      16             : #include "Python.h"
      17             : #include "structmember.h"
      18             : 
      19             : static PyObject *
      20           0 : ellipsis_repr(PyObject *op)
      21             : {
      22           0 :     return PyString_FromString("Ellipsis");
      23             : }
      24             : 
      25             : PyTypeObject PyEllipsis_Type = {
      26             :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
      27             :     "ellipsis",                         /* tp_name */
      28             :     0,                                  /* tp_basicsize */
      29             :     0,                                  /* tp_itemsize */
      30             :     0, /*never called*/                 /* tp_dealloc */
      31             :     0,                                  /* tp_print */
      32             :     0,                                  /* tp_getattr */
      33             :     0,                                  /* tp_setattr */
      34             :     0,                                  /* tp_compare */
      35             :     ellipsis_repr,                      /* tp_repr */
      36             :     0,                                  /* tp_as_number */
      37             :     0,                                  /* tp_as_sequence */
      38             :     0,                                  /* tp_as_mapping */
      39             :     0,                                  /* tp_hash */
      40             :     0,                                  /* tp_call */
      41             :     0,                                  /* tp_str */
      42             :     PyObject_GenericGetAttr,            /* tp_getattro */
      43             :     0,                                  /* tp_setattro */
      44             :     0,                                  /* tp_as_buffer */
      45             :     Py_TPFLAGS_DEFAULT,                 /* tp_flags */
      46             : };
      47             : 
      48             : PyObject _Py_EllipsisObject = {
      49             :     _PyObject_EXTRA_INIT
      50             :     1, &PyEllipsis_Type
      51             : };
      52             : 
      53             : 
      54             : /* Slice object implementation
      55             : 
      56             :    start, stop, and step are python objects with None indicating no
      57             :    index is present.
      58             : */
      59             : 
      60             : PyObject *
      61         768 : PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
      62             : {
      63         768 :     PySliceObject *obj = PyObject_GC_New(PySliceObject, &PySlice_Type);
      64             : 
      65         768 :     if (obj == NULL)
      66           0 :         return NULL;
      67             : 
      68         768 :     if (step == NULL) step = Py_None;
      69         768 :     Py_INCREF(step);
      70         768 :     if (start == NULL) start = Py_None;
      71         768 :     Py_INCREF(start);
      72         768 :     if (stop == NULL) stop = Py_None;
      73         768 :     Py_INCREF(stop);
      74             : 
      75         768 :     obj->step = step;
      76         768 :     obj->start = start;
      77         768 :     obj->stop = stop;
      78             : 
      79         768 :     _PyObject_GC_TRACK(obj);
      80         768 :     return (PyObject *) obj;
      81             : }
      82             : 
      83             : PyObject *
      84         570 : _PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop)
      85             : {
      86             :     PyObject *start, *end, *slice;
      87         570 :     start = PyInt_FromSsize_t(istart);
      88         570 :     if (!start)
      89           0 :         return NULL;
      90         570 :     end = PyInt_FromSsize_t(istop);
      91         570 :     if (!end) {
      92           0 :         Py_DECREF(start);
      93           0 :         return NULL;
      94             :     }
      95             : 
      96         570 :     slice = PySlice_New(start, end, NULL);
      97         570 :     Py_DECREF(start);
      98         570 :     Py_DECREF(end);
      99         570 :     return slice;
     100             : }
     101             : 
     102             : int
     103           0 : PySlice_GetIndices(PySliceObject *r, Py_ssize_t length,
     104             :                    Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
     105             : {
     106             :     /* XXX support long ints */
     107           0 :     if (r->step == Py_None) {
     108           0 :         *step = 1;
     109             :     } else {
     110           0 :         if (!PyInt_Check(r->step) && !PyLong_Check(r->step)) return -1;
     111           0 :         *step = PyInt_AsSsize_t(r->step);
     112             :     }
     113           0 :     if (r->start == Py_None) {
     114           0 :         *start = *step < 0 ? length-1 : 0;
     115             :     } else {
     116           0 :         if (!PyInt_Check(r->start) && !PyLong_Check(r->step)) return -1;
     117           0 :         *start = PyInt_AsSsize_t(r->start);
     118           0 :         if (*start < 0) *start += length;
     119             :     }
     120           0 :     if (r->stop == Py_None) {
     121           0 :         *stop = *step < 0 ? -1 : length;
     122             :     } else {
     123           0 :         if (!PyInt_Check(r->stop) && !PyLong_Check(r->step)) return -1;
     124           0 :         *stop = PyInt_AsSsize_t(r->stop);
     125           0 :         if (*stop < 0) *stop += length;
     126             :     }
     127           0 :     if (*stop > length) return -1;
     128           0 :     if (*start >= length) return -1;
     129           0 :     if (*step == 0) return -1;
     130           0 :     return 0;
     131             : }
     132             : 
     133             : int
     134         768 : PySlice_GetIndicesEx(PySliceObject *r, Py_ssize_t length,
     135             :                      Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength)
     136             : {
     137             :     /* this is harder to get right than you might think */
     138             : 
     139             :     Py_ssize_t defstart, defstop;
     140             : 
     141         768 :     if (r->step == Py_None) {
     142         570 :         *step = 1;
     143             :     }
     144             :     else {
     145         198 :         if (!_PyEval_SliceIndex(r->step, step)) return -1;
     146         198 :         if (*step == 0) {
     147           0 :             PyErr_SetString(PyExc_ValueError,
     148             :                             "slice step cannot be zero");
     149           0 :             return -1;
     150             :         }
     151             :     }
     152             : 
     153         768 :     defstart = *step < 0 ? length-1 : 0;
     154         768 :     defstop = *step < 0 ? -1 : length;
     155             : 
     156         768 :     if (r->start == Py_None) {
     157         198 :         *start = defstart;
     158             :     }
     159             :     else {
     160         570 :         if (!_PyEval_SliceIndex(r->start, start)) return -1;
     161         570 :         if (*start < 0) *start += length;
     162         570 :         if (*start < 0) *start = (*step < 0) ? -1 : 0;
     163         570 :         if (*start >= length)
     164           0 :             *start = (*step < 0) ? length - 1 : length;
     165             :     }
     166             : 
     167         768 :     if (r->stop == Py_None) {
     168         198 :         *stop = defstop;
     169             :     }
     170             :     else {
     171         570 :         if (!_PyEval_SliceIndex(r->stop, stop)) return -1;
     172         570 :         if (*stop < 0) *stop += length;
     173         570 :         if (*stop < 0) *stop = (*step < 0) ? -1 : 0;
     174         570 :         if (*stop >= length)
     175         570 :             *stop = (*step < 0) ? length - 1 : length;
     176             :     }
     177             : 
     178         768 :     if ((*step < 0 && *stop >= *start)
     179         768 :         || (*step > 0 && *start >= *stop)) {
     180           0 :         *slicelength = 0;
     181             :     }
     182         768 :     else if (*step < 0) {
     183         198 :         *slicelength = (*stop-*start+1)/(*step)+1;
     184             :     }
     185             :     else {
     186         570 :         *slicelength = (*stop-*start-1)/(*step)+1;
     187             :     }
     188             : 
     189         768 :     return 0;
     190             : }
     191             : 
     192             : static PyObject *
     193           0 : slice_new(PyTypeObject *type, PyObject *args, PyObject *kw)
     194             : {
     195             :     PyObject *start, *stop, *step;
     196             : 
     197           0 :     start = stop = step = NULL;
     198             : 
     199           0 :     if (!_PyArg_NoKeywords("slice()", kw))
     200           0 :         return NULL;
     201             : 
     202           0 :     if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step))
     203           0 :         return NULL;
     204             : 
     205             :     /* This swapping of stop and start is to maintain similarity with
     206             :        range(). */
     207           0 :     if (stop == NULL) {
     208           0 :         stop = start;
     209           0 :         start = NULL;
     210             :     }
     211           0 :     return PySlice_New(start, stop, step);
     212             : }
     213             : 
     214             : PyDoc_STRVAR(slice_doc,
     215             : "slice(stop)\n\
     216             : slice(start, stop[, step])\n\
     217             : \n\
     218             : Create a slice object.  This is used for extended slicing (e.g. a[0:10:2]).");
     219             : 
     220             : static void
     221         768 : slice_dealloc(PySliceObject *r)
     222             : {
     223         768 :     _PyObject_GC_UNTRACK(r);
     224         768 :     Py_DECREF(r->step);
     225         768 :     Py_DECREF(r->start);
     226         768 :     Py_DECREF(r->stop);
     227         768 :     PyObject_GC_Del(r);
     228         768 : }
     229             : 
     230             : static PyObject *
     231           0 : slice_repr(PySliceObject *r)
     232             : {
     233             :     PyObject *s, *comma;
     234             : 
     235           0 :     s = PyString_FromString("slice(");
     236           0 :     comma = PyString_FromString(", ");
     237           0 :     PyString_ConcatAndDel(&s, PyObject_Repr(r->start));
     238           0 :     PyString_Concat(&s, comma);
     239           0 :     PyString_ConcatAndDel(&s, PyObject_Repr(r->stop));
     240           0 :     PyString_Concat(&s, comma);
     241           0 :     PyString_ConcatAndDel(&s, PyObject_Repr(r->step));
     242           0 :     PyString_ConcatAndDel(&s, PyString_FromString(")"));
     243           0 :     Py_DECREF(comma);
     244           0 :     return s;
     245             : }
     246             : 
     247             : static PyMemberDef slice_members[] = {
     248             :     {"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
     249             :     {"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
     250             :     {"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
     251             :     {0}
     252             : };
     253             : 
     254             : static PyObject*
     255           0 : slice_indices(PySliceObject* self, PyObject* len)
     256             : {
     257             :     Py_ssize_t ilen, start, stop, step, slicelength;
     258             : 
     259           0 :     ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError);
     260             : 
     261           0 :     if (ilen == -1 && PyErr_Occurred()) {
     262           0 :         return NULL;
     263             :     }
     264             : 
     265           0 :     if (PySlice_GetIndicesEx(self, ilen, &start, &stop,
     266             :                              &step, &slicelength) < 0) {
     267           0 :         return NULL;
     268             :     }
     269             : 
     270           0 :     return Py_BuildValue("(nnn)", start, stop, step);
     271             : }
     272             : 
     273             : PyDoc_STRVAR(slice_indices_doc,
     274             : "S.indices(len) -> (start, stop, stride)\n\
     275             : \n\
     276             : Assuming a sequence of length len, calculate the start and stop\n\
     277             : indices, and the stride length of the extended slice described by\n\
     278             : S. Out of bounds indices are clipped in a manner consistent with the\n\
     279             : handling of normal slices.");
     280             : 
     281             : static PyObject *
     282           0 : slice_reduce(PySliceObject* self)
     283             : {
     284           0 :     return Py_BuildValue("O(OOO)", Py_TYPE(self), self->start, self->stop, self->step);
     285             : }
     286             : 
     287             : PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
     288             : 
     289             : static PyMethodDef slice_methods[] = {
     290             :     {"indices",         (PyCFunction)slice_indices,
     291             :      METH_O,            slice_indices_doc},
     292             :     {"__reduce__",      (PyCFunction)slice_reduce,
     293             :      METH_NOARGS,       reduce_doc},
     294             :     {NULL, NULL}
     295             : };
     296             : 
     297             : static int
     298           0 : slice_compare(PySliceObject *v, PySliceObject *w)
     299             : {
     300           0 :     int result = 0;
     301             : 
     302           0 :     if (v == w)
     303           0 :         return 0;
     304             : 
     305           0 :     if (PyObject_Cmp(v->start, w->start, &result) < 0)
     306           0 :         return -2;
     307           0 :     if (result != 0)
     308           0 :         return result;
     309           0 :     if (PyObject_Cmp(v->stop, w->stop, &result) < 0)
     310           0 :         return -2;
     311           0 :     if (result != 0)
     312           0 :         return result;
     313           0 :     if (PyObject_Cmp(v->step, w->step, &result) < 0)
     314           0 :         return -2;
     315           0 :     return result;
     316             : }
     317             : 
     318             : static long
     319           0 : slice_hash(PySliceObject *v)
     320             : {
     321           0 :     PyErr_SetString(PyExc_TypeError, "unhashable type");
     322           0 :     return -1L;
     323             : }
     324             : 
     325             : static int
     326           0 : slice_traverse(PySliceObject *v, visitproc visit, void *arg)
     327             : {
     328           0 :     Py_VISIT(v->start);
     329           0 :     Py_VISIT(v->stop);
     330           0 :     Py_VISIT(v->step);
     331           0 :     return 0;
     332             : }
     333             : 
     334             : PyTypeObject PySlice_Type = {
     335             :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
     336             :     "slice",                    /* Name of this type */
     337             :     sizeof(PySliceObject),      /* Basic object size */
     338             :     0,                          /* Item size for varobject */
     339             :     (destructor)slice_dealloc,                  /* tp_dealloc */
     340             :     0,                                          /* tp_print */
     341             :     0,                                          /* tp_getattr */
     342             :     0,                                          /* tp_setattr */
     343             :     (cmpfunc)slice_compare,                     /* tp_compare */
     344             :     (reprfunc)slice_repr,                       /* tp_repr */
     345             :     0,                                          /* tp_as_number */
     346             :     0,                                          /* tp_as_sequence */
     347             :     0,                                          /* tp_as_mapping */
     348             :     (hashfunc)slice_hash,                       /* tp_hash */
     349             :     0,                                          /* tp_call */
     350             :     0,                                          /* tp_str */
     351             :     PyObject_GenericGetAttr,                    /* tp_getattro */
     352             :     0,                                          /* tp_setattro */
     353             :     0,                                          /* tp_as_buffer */
     354             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
     355             :     slice_doc,                                  /* tp_doc */
     356             :     (traverseproc)slice_traverse,               /* tp_traverse */
     357             :     0,                                          /* tp_clear */
     358             :     0,                                          /* tp_richcompare */
     359             :     0,                                          /* tp_weaklistoffset */
     360             :     0,                                          /* tp_iter */
     361             :     0,                                          /* tp_iternext */
     362             :     slice_methods,                              /* tp_methods */
     363             :     slice_members,                              /* tp_members */
     364             :     0,                                          /* tp_getset */
     365             :     0,                                          /* tp_base */
     366             :     0,                                          /* tp_dict */
     367             :     0,                                          /* tp_descr_get */
     368             :     0,                                          /* tp_descr_set */
     369             :     0,                                          /* tp_dictoffset */
     370             :     0,                                          /* tp_init */
     371             :     0,                                          /* tp_alloc */
     372             :     slice_new,                                  /* tp_new */
     373             : };

Generated by: LCOV version 1.10