• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
ellipsis_repr(PyObject * op)20 ellipsis_repr(PyObject *op)
21 {
22     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 *
PySlice_New(PyObject * start,PyObject * stop,PyObject * step)61 PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
62 {
63     PySliceObject *obj = PyObject_GC_New(PySliceObject, &PySlice_Type);
64 
65     if (obj == NULL)
66         return NULL;
67 
68     if (step == NULL) step = Py_None;
69     Py_INCREF(step);
70     if (start == NULL) start = Py_None;
71     Py_INCREF(start);
72     if (stop == NULL) stop = Py_None;
73     Py_INCREF(stop);
74 
75     obj->step = step;
76     obj->start = start;
77     obj->stop = stop;
78 
79     _PyObject_GC_TRACK(obj);
80     return (PyObject *) obj;
81 }
82 
83 PyObject *
_PySlice_FromIndices(Py_ssize_t istart,Py_ssize_t istop)84 _PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop)
85 {
86     PyObject *start, *end, *slice;
87     start = PyInt_FromSsize_t(istart);
88     if (!start)
89         return NULL;
90     end = PyInt_FromSsize_t(istop);
91     if (!end) {
92         Py_DECREF(start);
93         return NULL;
94     }
95 
96     slice = PySlice_New(start, end, NULL);
97     Py_DECREF(start);
98     Py_DECREF(end);
99     return slice;
100 }
101 
102 int
PySlice_GetIndices(PySliceObject * r,Py_ssize_t length,Py_ssize_t * start,Py_ssize_t * stop,Py_ssize_t * step)103 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     if (r->step == Py_None) {
108         *step = 1;
109     } else {
110         if (!PyInt_Check(r->step) && !PyLong_Check(r->step)) return -1;
111         *step = PyInt_AsSsize_t(r->step);
112     }
113     if (r->start == Py_None) {
114         *start = *step < 0 ? length-1 : 0;
115     } else {
116         if (!PyInt_Check(r->start) && !PyLong_Check(r->step)) return -1;
117         *start = PyInt_AsSsize_t(r->start);
118         if (*start < 0) *start += length;
119     }
120     if (r->stop == Py_None) {
121         *stop = *step < 0 ? -1 : length;
122     } else {
123         if (!PyInt_Check(r->stop) && !PyLong_Check(r->step)) return -1;
124         *stop = PyInt_AsSsize_t(r->stop);
125         if (*stop < 0) *stop += length;
126     }
127     if (*stop > length) return -1;
128     if (*start >= length) return -1;
129     if (*step == 0) return -1;
130     return 0;
131 }
132 
133 int
PySlice_GetIndicesEx(PySliceObject * r,Py_ssize_t length,Py_ssize_t * start,Py_ssize_t * stop,Py_ssize_t * step,Py_ssize_t * slicelength)134 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     if (r->step == Py_None) {
142         *step = 1;
143     }
144     else {
145         if (!_PyEval_SliceIndex(r->step, step)) return -1;
146         if (*step == 0) {
147             PyErr_SetString(PyExc_ValueError,
148                             "slice step cannot be zero");
149             return -1;
150         }
151     }
152 
153     defstart = *step < 0 ? length-1 : 0;
154     defstop = *step < 0 ? -1 : length;
155 
156     if (r->start == Py_None) {
157         *start = defstart;
158     }
159     else {
160         if (!_PyEval_SliceIndex(r->start, start)) return -1;
161         if (*start < 0) *start += length;
162         if (*start < 0) *start = (*step < 0) ? -1 : 0;
163         if (*start >= length)
164             *start = (*step < 0) ? length - 1 : length;
165     }
166 
167     if (r->stop == Py_None) {
168         *stop = defstop;
169     }
170     else {
171         if (!_PyEval_SliceIndex(r->stop, stop)) return -1;
172         if (*stop < 0) *stop += length;
173         if (*stop < 0) *stop = (*step < 0) ? -1 : 0;
174         if (*stop >= length)
175             *stop = (*step < 0) ? length - 1 : length;
176     }
177 
178     if ((*step < 0 && *stop >= *start)
179         || (*step > 0 && *start >= *stop)) {
180         *slicelength = 0;
181     }
182     else if (*step < 0) {
183         *slicelength = (*stop-*start+1)/(*step)+1;
184     }
185     else {
186         *slicelength = (*stop-*start-1)/(*step)+1;
187     }
188 
189     return 0;
190 }
191 
192 static PyObject *
slice_new(PyTypeObject * type,PyObject * args,PyObject * kw)193 slice_new(PyTypeObject *type, PyObject *args, PyObject *kw)
194 {
195     PyObject *start, *stop, *step;
196 
197     start = stop = step = NULL;
198 
199     if (!_PyArg_NoKeywords("slice()", kw))
200         return NULL;
201 
202     if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step))
203         return NULL;
204 
205     /* This swapping of stop and start is to maintain similarity with
206        range(). */
207     if (stop == NULL) {
208         stop = start;
209         start = NULL;
210     }
211     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
slice_dealloc(PySliceObject * r)221 slice_dealloc(PySliceObject *r)
222 {
223     _PyObject_GC_UNTRACK(r);
224     Py_DECREF(r->step);
225     Py_DECREF(r->start);
226     Py_DECREF(r->stop);
227     PyObject_GC_Del(r);
228 }
229 
230 static PyObject *
slice_repr(PySliceObject * r)231 slice_repr(PySliceObject *r)
232 {
233     PyObject *s, *comma;
234 
235     s = PyString_FromString("slice(");
236     comma = PyString_FromString(", ");
237     PyString_ConcatAndDel(&s, PyObject_Repr(r->start));
238     PyString_Concat(&s, comma);
239     PyString_ConcatAndDel(&s, PyObject_Repr(r->stop));
240     PyString_Concat(&s, comma);
241     PyString_ConcatAndDel(&s, PyObject_Repr(r->step));
242     PyString_ConcatAndDel(&s, PyString_FromString(")"));
243     Py_DECREF(comma);
244     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*
slice_indices(PySliceObject * self,PyObject * len)255 slice_indices(PySliceObject* self, PyObject* len)
256 {
257     Py_ssize_t ilen, start, stop, step, slicelength;
258 
259     ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError);
260 
261     if (ilen == -1 && PyErr_Occurred()) {
262         return NULL;
263     }
264 
265     if (PySlice_GetIndicesEx(self, ilen, &start, &stop,
266                              &step, &slicelength) < 0) {
267         return NULL;
268     }
269 
270     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 *
slice_reduce(PySliceObject * self)282 slice_reduce(PySliceObject* self)
283 {
284     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
slice_compare(PySliceObject * v,PySliceObject * w)298 slice_compare(PySliceObject *v, PySliceObject *w)
299 {
300     int result = 0;
301 
302     if (v == w)
303         return 0;
304 
305     if (PyObject_Cmp(v->start, w->start, &result) < 0)
306         return -2;
307     if (result != 0)
308         return result;
309     if (PyObject_Cmp(v->stop, w->stop, &result) < 0)
310         return -2;
311     if (result != 0)
312         return result;
313     if (PyObject_Cmp(v->step, w->step, &result) < 0)
314         return -2;
315     return result;
316 }
317 
318 static long
slice_hash(PySliceObject * v)319 slice_hash(PySliceObject *v)
320 {
321     PyErr_SetString(PyExc_TypeError, "unhashable type");
322     return -1L;
323 }
324 
325 static int
slice_traverse(PySliceObject * v,visitproc visit,void * arg)326 slice_traverse(PySliceObject *v, visitproc visit, void *arg)
327 {
328     Py_VISIT(v->start);
329     Py_VISIT(v->stop);
330     Py_VISIT(v->step);
331     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 };
374