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_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
21 : {
22 0 : if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_Size(kwargs))) {
23 0 : PyErr_SetString(PyExc_TypeError, "EllipsisType takes no arguments");
24 0 : return NULL;
25 : }
26 0 : Py_INCREF(Py_Ellipsis);
27 0 : return Py_Ellipsis;
28 : }
29 :
30 : static PyObject *
31 0 : ellipsis_repr(PyObject *op)
32 : {
33 0 : return PyUnicode_FromString("Ellipsis");
34 : }
35 :
36 : PyTypeObject PyEllipsis_Type = {
37 : PyVarObject_HEAD_INIT(&PyType_Type, 0)
38 : "ellipsis", /* tp_name */
39 : 0, /* tp_basicsize */
40 : 0, /* tp_itemsize */
41 : 0, /*never called*/ /* tp_dealloc */
42 : 0, /* tp_print */
43 : 0, /* tp_getattr */
44 : 0, /* tp_setattr */
45 : 0, /* tp_reserved */
46 : ellipsis_repr, /* tp_repr */
47 : 0, /* tp_as_number */
48 : 0, /* tp_as_sequence */
49 : 0, /* tp_as_mapping */
50 : 0, /* tp_hash */
51 : 0, /* tp_call */
52 : 0, /* tp_str */
53 : PyObject_GenericGetAttr, /* tp_getattro */
54 : 0, /* tp_setattro */
55 : 0, /* tp_as_buffer */
56 : Py_TPFLAGS_DEFAULT, /* tp_flags */
57 : 0, /* tp_doc */
58 : 0, /* tp_traverse */
59 : 0, /* tp_clear */
60 : 0, /* tp_richcompare */
61 : 0, /* tp_weaklistoffset */
62 : 0, /* tp_iter */
63 : 0, /* tp_iternext */
64 : 0, /* tp_methods */
65 : 0, /* tp_members */
66 : 0, /* tp_getset */
67 : 0, /* tp_base */
68 : 0, /* tp_dict */
69 : 0, /* tp_descr_get */
70 : 0, /* tp_descr_set */
71 : 0, /* tp_dictoffset */
72 : 0, /* tp_init */
73 : 0, /* tp_alloc */
74 : ellipsis_new, /* tp_new */
75 : };
76 :
77 : PyObject _Py_EllipsisObject = {
78 : _PyObject_EXTRA_INIT
79 : 1, &PyEllipsis_Type
80 : };
81 :
82 :
83 : /* Slice object implementation */
84 :
85 : /* Using a cache is very effective since typically only a single slice is
86 : * created and then deleted again
87 : */
88 : static PySliceObject *slice_cache = NULL;
89 0 : void PySlice_Fini(void)
90 : {
91 0 : PySliceObject *obj = slice_cache;
92 0 : if (obj != NULL) {
93 0 : slice_cache = NULL;
94 0 : PyObject_Del(obj);
95 : }
96 0 : }
97 :
98 : /* start, stop, and step are python objects with None indicating no
99 : index is present.
100 : */
101 :
102 : PyObject *
103 16393 : PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
104 : {
105 : PySliceObject *obj;
106 16393 : if (slice_cache != NULL) {
107 16392 : obj = slice_cache;
108 16392 : slice_cache = NULL;
109 16392 : _Py_NewReference((PyObject *)obj);
110 : } else {
111 1 : obj = PyObject_New(PySliceObject, &PySlice_Type);
112 1 : if (obj == NULL)
113 0 : return NULL;
114 : }
115 :
116 16393 : if (step == NULL) step = Py_None;
117 16393 : Py_INCREF(step);
118 16393 : if (start == NULL) start = Py_None;
119 16393 : Py_INCREF(start);
120 16393 : if (stop == NULL) stop = Py_None;
121 16393 : Py_INCREF(stop);
122 :
123 16393 : obj->step = step;
124 16393 : obj->start = start;
125 16393 : obj->stop = stop;
126 :
127 16393 : return (PyObject *) obj;
128 : }
129 :
130 : PyObject *
131 18 : _PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop)
132 : {
133 : PyObject *start, *end, *slice;
134 18 : start = PyLong_FromSsize_t(istart);
135 18 : if (!start)
136 0 : return NULL;
137 18 : end = PyLong_FromSsize_t(istop);
138 18 : if (!end) {
139 0 : Py_DECREF(start);
140 0 : return NULL;
141 : }
142 :
143 18 : slice = PySlice_New(start, end, NULL);
144 18 : Py_DECREF(start);
145 18 : Py_DECREF(end);
146 18 : return slice;
147 : }
148 :
149 : int
150 0 : PySlice_GetIndices(PyObject *_r, Py_ssize_t length,
151 : Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
152 : {
153 0 : PySliceObject *r = (PySliceObject*)_r;
154 : /* XXX support long ints */
155 0 : if (r->step == Py_None) {
156 0 : *step = 1;
157 : } else {
158 0 : if (!PyLong_Check(r->step)) return -1;
159 0 : *step = PyLong_AsSsize_t(r->step);
160 : }
161 0 : if (r->start == Py_None) {
162 0 : *start = *step < 0 ? length-1 : 0;
163 : } else {
164 0 : if (!PyLong_Check(r->start)) return -1;
165 0 : *start = PyLong_AsSsize_t(r->start);
166 0 : if (*start < 0) *start += length;
167 : }
168 0 : if (r->stop == Py_None) {
169 0 : *stop = *step < 0 ? -1 : length;
170 : } else {
171 0 : if (!PyLong_Check(r->stop)) return -1;
172 0 : *stop = PyLong_AsSsize_t(r->stop);
173 0 : if (*stop < 0) *stop += length;
174 : }
175 0 : if (*stop > length) return -1;
176 0 : if (*start >= length) return -1;
177 0 : if (*step == 0) return -1;
178 0 : return 0;
179 : }
180 :
181 : int
182 16393 : PySlice_GetIndicesEx(PyObject *_r, Py_ssize_t length,
183 : Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step,
184 : Py_ssize_t *slicelength)
185 : {
186 16393 : PySliceObject *r = (PySliceObject*)_r;
187 : /* this is harder to get right than you might think */
188 :
189 : Py_ssize_t defstart, defstop;
190 :
191 16393 : if (r->step == Py_None) {
192 16393 : *step = 1;
193 : }
194 : else {
195 0 : if (!_PyEval_SliceIndex(r->step, step)) return -1;
196 0 : if (*step == 0) {
197 0 : PyErr_SetString(PyExc_ValueError,
198 : "slice step cannot be zero");
199 0 : return -1;
200 : }
201 : /* Here *step might be -PY_SSIZE_T_MAX-1; in this case we replace it
202 : * with -PY_SSIZE_T_MAX. This doesn't affect the semantics, and it
203 : * guards against later undefined behaviour resulting from code that
204 : * does "step = -step" as part of a slice reversal.
205 : */
206 0 : if (*step < -PY_SSIZE_T_MAX)
207 0 : *step = -PY_SSIZE_T_MAX;
208 : }
209 :
210 16393 : defstart = *step < 0 ? length-1 : 0;
211 16393 : defstop = *step < 0 ? -1 : length;
212 :
213 16393 : if (r->start == Py_None) {
214 692 : *start = defstart;
215 : }
216 : else {
217 15701 : if (!_PyEval_SliceIndex(r->start, start)) return -1;
218 15701 : if (*start < 0) *start += length;
219 15701 : if (*start < 0) *start = (*step < 0) ? -1 : 0;
220 15701 : if (*start >= length)
221 57 : *start = (*step < 0) ? length - 1 : length;
222 : }
223 :
224 16393 : if (r->stop == Py_None) {
225 799 : *stop = defstop;
226 : }
227 : else {
228 15594 : if (!_PyEval_SliceIndex(r->stop, stop)) return -1;
229 15594 : if (*stop < 0) *stop += length;
230 15594 : if (*stop < 0) *stop = (*step < 0) ? -1 : 0;
231 15594 : if (*stop >= length)
232 245 : *stop = (*step < 0) ? length - 1 : length;
233 : }
234 :
235 16393 : if ((*step < 0 && *stop >= *start)
236 16393 : || (*step > 0 && *start >= *stop)) {
237 579 : *slicelength = 0;
238 : }
239 15814 : else if (*step < 0) {
240 0 : *slicelength = (*stop-*start+1)/(*step)+1;
241 : }
242 : else {
243 15814 : *slicelength = (*stop-*start-1)/(*step)+1;
244 : }
245 :
246 16393 : return 0;
247 : }
248 :
249 : static PyObject *
250 0 : slice_new(PyTypeObject *type, PyObject *args, PyObject *kw)
251 : {
252 : PyObject *start, *stop, *step;
253 :
254 0 : start = stop = step = NULL;
255 :
256 0 : if (!_PyArg_NoKeywords("slice()", kw))
257 0 : return NULL;
258 :
259 0 : if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step))
260 0 : return NULL;
261 :
262 : /* This swapping of stop and start is to maintain similarity with
263 : range(). */
264 0 : if (stop == NULL) {
265 0 : stop = start;
266 0 : start = NULL;
267 : }
268 0 : return PySlice_New(start, stop, step);
269 : }
270 :
271 : PyDoc_STRVAR(slice_doc,
272 : "slice([start,] stop[, step])\n\
273 : \n\
274 : Create a slice object. This is used for extended slicing (e.g. a[0:10:2]).");
275 :
276 : static void
277 16393 : slice_dealloc(PySliceObject *r)
278 : {
279 16393 : Py_DECREF(r->step);
280 16393 : Py_DECREF(r->start);
281 16393 : Py_DECREF(r->stop);
282 16393 : if (slice_cache == NULL)
283 16393 : slice_cache = r;
284 : else
285 0 : PyObject_Del(r);
286 16393 : }
287 :
288 : static PyObject *
289 0 : slice_repr(PySliceObject *r)
290 : {
291 0 : return PyUnicode_FromFormat("slice(%R, %R, %R)", r->start, r->stop, r->step);
292 : }
293 :
294 : static PyMemberDef slice_members[] = {
295 : {"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
296 : {"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
297 : {"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
298 : {0}
299 : };
300 :
301 : static PyObject*
302 0 : slice_indices(PySliceObject* self, PyObject* len)
303 : {
304 : Py_ssize_t ilen, start, stop, step, slicelength;
305 :
306 0 : ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError);
307 :
308 0 : if (ilen == -1 && PyErr_Occurred()) {
309 0 : return NULL;
310 : }
311 :
312 0 : if (PySlice_GetIndicesEx((PyObject*)self, ilen, &start, &stop,
313 : &step, &slicelength) < 0) {
314 0 : return NULL;
315 : }
316 :
317 0 : return Py_BuildValue("(nnn)", start, stop, step);
318 : }
319 :
320 : PyDoc_STRVAR(slice_indices_doc,
321 : "S.indices(len) -> (start, stop, stride)\n\
322 : \n\
323 : Assuming a sequence of length len, calculate the start and stop\n\
324 : indices, and the stride length of the extended slice described by\n\
325 : S. Out of bounds indices are clipped in a manner consistent with the\n\
326 : handling of normal slices.");
327 :
328 : static PyObject *
329 0 : slice_reduce(PySliceObject* self)
330 : {
331 0 : return Py_BuildValue("O(OOO)", Py_TYPE(self), self->start, self->stop, self->step);
332 : }
333 :
334 : PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
335 :
336 : static PyMethodDef slice_methods[] = {
337 : {"indices", (PyCFunction)slice_indices,
338 : METH_O, slice_indices_doc},
339 : {"__reduce__", (PyCFunction)slice_reduce,
340 : METH_NOARGS, reduce_doc},
341 : {NULL, NULL}
342 : };
343 :
344 : static PyObject *
345 0 : slice_richcompare(PyObject *v, PyObject *w, int op)
346 : {
347 : PyObject *t1;
348 : PyObject *t2;
349 : PyObject *res;
350 :
351 0 : if (!PySlice_Check(v) || !PySlice_Check(w))
352 0 : Py_RETURN_NOTIMPLEMENTED;
353 :
354 0 : if (v == w) {
355 : /* XXX Do we really need this shortcut?
356 : There's a unit test for it, but is that fair? */
357 0 : switch (op) {
358 : case Py_EQ:
359 : case Py_LE:
360 : case Py_GE:
361 0 : res = Py_True;
362 0 : break;
363 : default:
364 0 : res = Py_False;
365 0 : break;
366 : }
367 0 : Py_INCREF(res);
368 0 : return res;
369 : }
370 :
371 0 : t1 = PyTuple_New(3);
372 0 : if (t1 == NULL)
373 0 : return NULL;
374 0 : t2 = PyTuple_New(3);
375 0 : if (t2 == NULL) {
376 0 : Py_DECREF(t1);
377 0 : return NULL;
378 : }
379 :
380 0 : PyTuple_SET_ITEM(t1, 0, ((PySliceObject *)v)->start);
381 0 : PyTuple_SET_ITEM(t1, 1, ((PySliceObject *)v)->stop);
382 0 : PyTuple_SET_ITEM(t1, 2, ((PySliceObject *)v)->step);
383 0 : PyTuple_SET_ITEM(t2, 0, ((PySliceObject *)w)->start);
384 0 : PyTuple_SET_ITEM(t2, 1, ((PySliceObject *)w)->stop);
385 0 : PyTuple_SET_ITEM(t2, 2, ((PySliceObject *)w)->step);
386 :
387 0 : res = PyObject_RichCompare(t1, t2, op);
388 :
389 0 : PyTuple_SET_ITEM(t1, 0, NULL);
390 0 : PyTuple_SET_ITEM(t1, 1, NULL);
391 0 : PyTuple_SET_ITEM(t1, 2, NULL);
392 0 : PyTuple_SET_ITEM(t2, 0, NULL);
393 0 : PyTuple_SET_ITEM(t2, 1, NULL);
394 0 : PyTuple_SET_ITEM(t2, 2, NULL);
395 :
396 0 : Py_DECREF(t1);
397 0 : Py_DECREF(t2);
398 :
399 0 : return res;
400 : }
401 :
402 : PyTypeObject PySlice_Type = {
403 : PyVarObject_HEAD_INIT(&PyType_Type, 0)
404 : "slice", /* Name of this type */
405 : sizeof(PySliceObject), /* Basic object size */
406 : 0, /* Item size for varobject */
407 : (destructor)slice_dealloc, /* tp_dealloc */
408 : 0, /* tp_print */
409 : 0, /* tp_getattr */
410 : 0, /* tp_setattr */
411 : 0, /* tp_reserved */
412 : (reprfunc)slice_repr, /* tp_repr */
413 : 0, /* tp_as_number */
414 : 0, /* tp_as_sequence */
415 : 0, /* tp_as_mapping */
416 : PyObject_HashNotImplemented, /* tp_hash */
417 : 0, /* tp_call */
418 : 0, /* tp_str */
419 : PyObject_GenericGetAttr, /* tp_getattro */
420 : 0, /* tp_setattro */
421 : 0, /* tp_as_buffer */
422 : Py_TPFLAGS_DEFAULT, /* tp_flags */
423 : slice_doc, /* tp_doc */
424 : 0, /* tp_traverse */
425 : 0, /* tp_clear */
426 : slice_richcompare, /* tp_richcompare */
427 : 0, /* tp_weaklistoffset */
428 : 0, /* tp_iter */
429 : 0, /* tp_iternext */
430 : slice_methods, /* tp_methods */
431 : slice_members, /* tp_members */
432 : 0, /* tp_getset */
433 : 0, /* tp_base */
434 : 0, /* tp_dict */
435 : 0, /* tp_descr_get */
436 : 0, /* tp_descr_set */
437 : 0, /* tp_dictoffset */
438 : 0, /* tp_init */
439 : 0, /* tp_alloc */
440 : slice_new, /* tp_new */
441 : };
|