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 "pycore_abstract.h" // _PyIndex_Check()
18 #include "pycore_long.h" // _PyLong_GetZero()
19 #include "pycore_object.h" // _PyObject_GC_TRACK()
20 #include "structmember.h" // PyMemberDef
21
22 static PyObject *
ellipsis_new(PyTypeObject * type,PyObject * args,PyObject * kwargs)23 ellipsis_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
24 {
25 if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_GET_SIZE(kwargs))) {
26 PyErr_SetString(PyExc_TypeError, "EllipsisType takes no arguments");
27 return NULL;
28 }
29 Py_INCREF(Py_Ellipsis);
30 return Py_Ellipsis;
31 }
32
33 static PyObject *
ellipsis_repr(PyObject * op)34 ellipsis_repr(PyObject *op)
35 {
36 return PyUnicode_FromString("Ellipsis");
37 }
38
39 static PyObject *
ellipsis_reduce(PyObject * op,PyObject * Py_UNUSED (ignored))40 ellipsis_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
41 {
42 return PyUnicode_FromString("Ellipsis");
43 }
44
45 static PyMethodDef ellipsis_methods[] = {
46 {"__reduce__", ellipsis_reduce, METH_NOARGS, NULL},
47 {NULL, NULL}
48 };
49
50 PyTypeObject PyEllipsis_Type = {
51 PyVarObject_HEAD_INIT(&PyType_Type, 0)
52 "ellipsis", /* tp_name */
53 0, /* tp_basicsize */
54 0, /* tp_itemsize */
55 0, /*never called*/ /* tp_dealloc */
56 0, /* tp_vectorcall_offset */
57 0, /* tp_getattr */
58 0, /* tp_setattr */
59 0, /* tp_as_async */
60 ellipsis_repr, /* tp_repr */
61 0, /* tp_as_number */
62 0, /* tp_as_sequence */
63 0, /* tp_as_mapping */
64 0, /* tp_hash */
65 0, /* tp_call */
66 0, /* tp_str */
67 PyObject_GenericGetAttr, /* tp_getattro */
68 0, /* tp_setattro */
69 0, /* tp_as_buffer */
70 Py_TPFLAGS_DEFAULT, /* tp_flags */
71 0, /* tp_doc */
72 0, /* tp_traverse */
73 0, /* tp_clear */
74 0, /* tp_richcompare */
75 0, /* tp_weaklistoffset */
76 0, /* tp_iter */
77 0, /* tp_iternext */
78 ellipsis_methods, /* tp_methods */
79 0, /* tp_members */
80 0, /* tp_getset */
81 0, /* tp_base */
82 0, /* tp_dict */
83 0, /* tp_descr_get */
84 0, /* tp_descr_set */
85 0, /* tp_dictoffset */
86 0, /* tp_init */
87 0, /* tp_alloc */
88 ellipsis_new, /* tp_new */
89 };
90
91 PyObject _Py_EllipsisObject = {
92 _PyObject_EXTRA_INIT
93 1, &PyEllipsis_Type
94 };
95
96
97 /* Slice object implementation */
98
99
_PySlice_Fini(PyInterpreterState * interp)100 void _PySlice_Fini(PyInterpreterState *interp)
101 {
102 PySliceObject *obj = interp->slice_cache;
103 if (obj != NULL) {
104 interp->slice_cache = NULL;
105 PyObject_GC_Del(obj);
106 }
107 }
108
109 /* start, stop, and step are python objects with None indicating no
110 index is present.
111 */
112
113 PyObject *
PySlice_New(PyObject * start,PyObject * stop,PyObject * step)114 PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
115 {
116 if (step == NULL) {
117 step = Py_None;
118 }
119 if (start == NULL) {
120 start = Py_None;
121 }
122 if (stop == NULL) {
123 stop = Py_None;
124 }
125
126 PyInterpreterState *interp = _PyInterpreterState_GET();
127 PySliceObject *obj;
128 if (interp->slice_cache != NULL) {
129 obj = interp->slice_cache;
130 interp->slice_cache = NULL;
131 _Py_NewReference((PyObject *)obj);
132 }
133 else {
134 obj = PyObject_GC_New(PySliceObject, &PySlice_Type);
135 if (obj == NULL) {
136 return NULL;
137 }
138 }
139
140 Py_INCREF(step);
141 obj->step = step;
142 Py_INCREF(start);
143 obj->start = start;
144 Py_INCREF(stop);
145 obj->stop = stop;
146
147 _PyObject_GC_TRACK(obj);
148 return (PyObject *) obj;
149 }
150
151 PyObject *
_PySlice_FromIndices(Py_ssize_t istart,Py_ssize_t istop)152 _PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop)
153 {
154 PyObject *start, *end, *slice;
155 start = PyLong_FromSsize_t(istart);
156 if (!start)
157 return NULL;
158 end = PyLong_FromSsize_t(istop);
159 if (!end) {
160 Py_DECREF(start);
161 return NULL;
162 }
163
164 slice = PySlice_New(start, end, NULL);
165 Py_DECREF(start);
166 Py_DECREF(end);
167 return slice;
168 }
169
170 int
PySlice_GetIndices(PyObject * _r,Py_ssize_t length,Py_ssize_t * start,Py_ssize_t * stop,Py_ssize_t * step)171 PySlice_GetIndices(PyObject *_r, Py_ssize_t length,
172 Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
173 {
174 PySliceObject *r = (PySliceObject*)_r;
175 /* XXX support long ints */
176 if (r->step == Py_None) {
177 *step = 1;
178 } else {
179 if (!PyLong_Check(r->step)) return -1;
180 *step = PyLong_AsSsize_t(r->step);
181 }
182 if (r->start == Py_None) {
183 *start = *step < 0 ? length-1 : 0;
184 } else {
185 if (!PyLong_Check(r->start)) return -1;
186 *start = PyLong_AsSsize_t(r->start);
187 if (*start < 0) *start += length;
188 }
189 if (r->stop == Py_None) {
190 *stop = *step < 0 ? -1 : length;
191 } else {
192 if (!PyLong_Check(r->stop)) return -1;
193 *stop = PyLong_AsSsize_t(r->stop);
194 if (*stop < 0) *stop += length;
195 }
196 if (*stop > length) return -1;
197 if (*start >= length) return -1;
198 if (*step == 0) return -1;
199 return 0;
200 }
201
202 int
PySlice_Unpack(PyObject * _r,Py_ssize_t * start,Py_ssize_t * stop,Py_ssize_t * step)203 PySlice_Unpack(PyObject *_r,
204 Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
205 {
206 PySliceObject *r = (PySliceObject*)_r;
207 /* this is harder to get right than you might think */
208
209 static_assert(PY_SSIZE_T_MIN + 1 <= -PY_SSIZE_T_MAX,
210 "-PY_SSIZE_T_MAX < PY_SSIZE_T_MIN + 1");
211
212 if (r->step == Py_None) {
213 *step = 1;
214 }
215 else {
216 if (!_PyEval_SliceIndex(r->step, step)) return -1;
217 if (*step == 0) {
218 PyErr_SetString(PyExc_ValueError,
219 "slice step cannot be zero");
220 return -1;
221 }
222 /* Here *step might be -PY_SSIZE_T_MAX-1; in this case we replace it
223 * with -PY_SSIZE_T_MAX. This doesn't affect the semantics, and it
224 * guards against later undefined behaviour resulting from code that
225 * does "step = -step" as part of a slice reversal.
226 */
227 if (*step < -PY_SSIZE_T_MAX)
228 *step = -PY_SSIZE_T_MAX;
229 }
230
231 if (r->start == Py_None) {
232 *start = *step < 0 ? PY_SSIZE_T_MAX : 0;
233 }
234 else {
235 if (!_PyEval_SliceIndex(r->start, start)) return -1;
236 }
237
238 if (r->stop == Py_None) {
239 *stop = *step < 0 ? PY_SSIZE_T_MIN : PY_SSIZE_T_MAX;
240 }
241 else {
242 if (!_PyEval_SliceIndex(r->stop, stop)) return -1;
243 }
244
245 return 0;
246 }
247
248 Py_ssize_t
PySlice_AdjustIndices(Py_ssize_t length,Py_ssize_t * start,Py_ssize_t * stop,Py_ssize_t step)249 PySlice_AdjustIndices(Py_ssize_t length,
250 Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t step)
251 {
252 /* this is harder to get right than you might think */
253
254 assert(step != 0);
255 assert(step >= -PY_SSIZE_T_MAX);
256
257 if (*start < 0) {
258 *start += length;
259 if (*start < 0) {
260 *start = (step < 0) ? -1 : 0;
261 }
262 }
263 else if (*start >= length) {
264 *start = (step < 0) ? length - 1 : length;
265 }
266
267 if (*stop < 0) {
268 *stop += length;
269 if (*stop < 0) {
270 *stop = (step < 0) ? -1 : 0;
271 }
272 }
273 else if (*stop >= length) {
274 *stop = (step < 0) ? length - 1 : length;
275 }
276
277 if (step < 0) {
278 if (*stop < *start) {
279 return (*start - *stop - 1) / (-step) + 1;
280 }
281 }
282 else {
283 if (*start < *stop) {
284 return (*stop - *start - 1) / step + 1;
285 }
286 }
287 return 0;
288 }
289
290 #undef PySlice_GetIndicesEx
291
292 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)293 PySlice_GetIndicesEx(PyObject *_r, Py_ssize_t length,
294 Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step,
295 Py_ssize_t *slicelength)
296 {
297 if (PySlice_Unpack(_r, start, stop, step) < 0)
298 return -1;
299 *slicelength = PySlice_AdjustIndices(length, start, stop, *step);
300 return 0;
301 }
302
303 static PyObject *
slice_new(PyTypeObject * type,PyObject * args,PyObject * kw)304 slice_new(PyTypeObject *type, PyObject *args, PyObject *kw)
305 {
306 PyObject *start, *stop, *step;
307
308 start = stop = step = NULL;
309
310 if (!_PyArg_NoKeywords("slice", kw))
311 return NULL;
312
313 if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step))
314 return NULL;
315
316 /* This swapping of stop and start is to maintain similarity with
317 range(). */
318 if (stop == NULL) {
319 stop = start;
320 start = NULL;
321 }
322 return PySlice_New(start, stop, step);
323 }
324
325 PyDoc_STRVAR(slice_doc,
326 "slice(stop)\n\
327 slice(start, stop[, step])\n\
328 \n\
329 Create a slice object. This is used for extended slicing (e.g. a[0:10:2]).");
330
331 static void
slice_dealloc(PySliceObject * r)332 slice_dealloc(PySliceObject *r)
333 {
334 PyInterpreterState *interp = _PyInterpreterState_GET();
335 _PyObject_GC_UNTRACK(r);
336 Py_DECREF(r->step);
337 Py_DECREF(r->start);
338 Py_DECREF(r->stop);
339 if (interp->slice_cache == NULL) {
340 interp->slice_cache = r;
341 }
342 else {
343 PyObject_GC_Del(r);
344 }
345 }
346
347 static PyObject *
slice_repr(PySliceObject * r)348 slice_repr(PySliceObject *r)
349 {
350 return PyUnicode_FromFormat("slice(%R, %R, %R)", r->start, r->stop, r->step);
351 }
352
353 static PyMemberDef slice_members[] = {
354 {"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
355 {"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
356 {"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
357 {0}
358 };
359
360 /* Helper function to convert a slice argument to a PyLong, and raise TypeError
361 with a suitable message on failure. */
362
363 static PyObject*
evaluate_slice_index(PyObject * v)364 evaluate_slice_index(PyObject *v)
365 {
366 if (_PyIndex_Check(v)) {
367 return PyNumber_Index(v);
368 }
369 else {
370 PyErr_SetString(PyExc_TypeError,
371 "slice indices must be integers or "
372 "None or have an __index__ method");
373 return NULL;
374 }
375 }
376
377 /* Compute slice indices given a slice and length. Return -1 on failure. Used
378 by slice.indices and rangeobject slicing. Assumes that `len` is a
379 nonnegative instance of PyLong. */
380
381 int
_PySlice_GetLongIndices(PySliceObject * self,PyObject * length,PyObject ** start_ptr,PyObject ** stop_ptr,PyObject ** step_ptr)382 _PySlice_GetLongIndices(PySliceObject *self, PyObject *length,
383 PyObject **start_ptr, PyObject **stop_ptr,
384 PyObject **step_ptr)
385 {
386 PyObject *start=NULL, *stop=NULL, *step=NULL;
387 PyObject *upper=NULL, *lower=NULL;
388 int step_is_negative, cmp_result;
389
390 /* Convert step to an integer; raise for zero step. */
391 if (self->step == Py_None) {
392 step = _PyLong_GetOne();
393 Py_INCREF(step);
394 step_is_negative = 0;
395 }
396 else {
397 int step_sign;
398 step = evaluate_slice_index(self->step);
399 if (step == NULL)
400 goto error;
401 step_sign = _PyLong_Sign(step);
402 if (step_sign == 0) {
403 PyErr_SetString(PyExc_ValueError,
404 "slice step cannot be zero");
405 goto error;
406 }
407 step_is_negative = step_sign < 0;
408 }
409
410 /* Find lower and upper bounds for start and stop. */
411 if (step_is_negative) {
412 lower = PyLong_FromLong(-1L);
413 if (lower == NULL)
414 goto error;
415
416 upper = PyNumber_Add(length, lower);
417 if (upper == NULL)
418 goto error;
419 }
420 else {
421 lower = _PyLong_GetZero();
422 Py_INCREF(lower);
423 upper = length;
424 Py_INCREF(upper);
425 }
426
427 /* Compute start. */
428 if (self->start == Py_None) {
429 start = step_is_negative ? upper : lower;
430 Py_INCREF(start);
431 }
432 else {
433 start = evaluate_slice_index(self->start);
434 if (start == NULL)
435 goto error;
436
437 if (_PyLong_Sign(start) < 0) {
438 /* start += length */
439 PyObject *tmp = PyNumber_Add(start, length);
440 Py_DECREF(start);
441 start = tmp;
442 if (start == NULL)
443 goto error;
444
445 cmp_result = PyObject_RichCompareBool(start, lower, Py_LT);
446 if (cmp_result < 0)
447 goto error;
448 if (cmp_result) {
449 Py_INCREF(lower);
450 Py_DECREF(start);
451 start = lower;
452 }
453 }
454 else {
455 cmp_result = PyObject_RichCompareBool(start, upper, Py_GT);
456 if (cmp_result < 0)
457 goto error;
458 if (cmp_result) {
459 Py_INCREF(upper);
460 Py_DECREF(start);
461 start = upper;
462 }
463 }
464 }
465
466 /* Compute stop. */
467 if (self->stop == Py_None) {
468 stop = step_is_negative ? lower : upper;
469 Py_INCREF(stop);
470 }
471 else {
472 stop = evaluate_slice_index(self->stop);
473 if (stop == NULL)
474 goto error;
475
476 if (_PyLong_Sign(stop) < 0) {
477 /* stop += length */
478 PyObject *tmp = PyNumber_Add(stop, length);
479 Py_DECREF(stop);
480 stop = tmp;
481 if (stop == NULL)
482 goto error;
483
484 cmp_result = PyObject_RichCompareBool(stop, lower, Py_LT);
485 if (cmp_result < 0)
486 goto error;
487 if (cmp_result) {
488 Py_INCREF(lower);
489 Py_DECREF(stop);
490 stop = lower;
491 }
492 }
493 else {
494 cmp_result = PyObject_RichCompareBool(stop, upper, Py_GT);
495 if (cmp_result < 0)
496 goto error;
497 if (cmp_result) {
498 Py_INCREF(upper);
499 Py_DECREF(stop);
500 stop = upper;
501 }
502 }
503 }
504
505 *start_ptr = start;
506 *stop_ptr = stop;
507 *step_ptr = step;
508 Py_DECREF(upper);
509 Py_DECREF(lower);
510 return 0;
511
512 error:
513 *start_ptr = *stop_ptr = *step_ptr = NULL;
514 Py_XDECREF(start);
515 Py_XDECREF(stop);
516 Py_XDECREF(step);
517 Py_XDECREF(upper);
518 Py_XDECREF(lower);
519 return -1;
520 }
521
522 /* Implementation of slice.indices. */
523
524 static PyObject*
slice_indices(PySliceObject * self,PyObject * len)525 slice_indices(PySliceObject* self, PyObject* len)
526 {
527 PyObject *start, *stop, *step;
528 PyObject *length;
529 int error;
530
531 /* Convert length to an integer if necessary; raise for negative length. */
532 length = PyNumber_Index(len);
533 if (length == NULL)
534 return NULL;
535
536 if (_PyLong_Sign(length) < 0) {
537 PyErr_SetString(PyExc_ValueError,
538 "length should not be negative");
539 Py_DECREF(length);
540 return NULL;
541 }
542
543 error = _PySlice_GetLongIndices(self, length, &start, &stop, &step);
544 Py_DECREF(length);
545 if (error == -1)
546 return NULL;
547 else
548 return Py_BuildValue("(NNN)", start, stop, step);
549 }
550
551 PyDoc_STRVAR(slice_indices_doc,
552 "S.indices(len) -> (start, stop, stride)\n\
553 \n\
554 Assuming a sequence of length len, calculate the start and stop\n\
555 indices, and the stride length of the extended slice described by\n\
556 S. Out of bounds indices are clipped in a manner consistent with the\n\
557 handling of normal slices.");
558
559 static PyObject *
slice_reduce(PySliceObject * self,PyObject * Py_UNUSED (ignored))560 slice_reduce(PySliceObject* self, PyObject *Py_UNUSED(ignored))
561 {
562 return Py_BuildValue("O(OOO)", Py_TYPE(self), self->start, self->stop, self->step);
563 }
564
565 PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
566
567 static PyMethodDef slice_methods[] = {
568 {"indices", (PyCFunction)slice_indices,
569 METH_O, slice_indices_doc},
570 {"__reduce__", (PyCFunction)slice_reduce,
571 METH_NOARGS, reduce_doc},
572 {NULL, NULL}
573 };
574
575 static PyObject *
slice_richcompare(PyObject * v,PyObject * w,int op)576 slice_richcompare(PyObject *v, PyObject *w, int op)
577 {
578 if (!PySlice_Check(v) || !PySlice_Check(w))
579 Py_RETURN_NOTIMPLEMENTED;
580
581 if (v == w) {
582 PyObject *res;
583 /* XXX Do we really need this shortcut?
584 There's a unit test for it, but is that fair? */
585 switch (op) {
586 case Py_EQ:
587 case Py_LE:
588 case Py_GE:
589 res = Py_True;
590 break;
591 default:
592 res = Py_False;
593 break;
594 }
595 Py_INCREF(res);
596 return res;
597 }
598
599
600 PyObject *t1 = PyTuple_Pack(3,
601 ((PySliceObject *)v)->start,
602 ((PySliceObject *)v)->stop,
603 ((PySliceObject *)v)->step);
604 if (t1 == NULL) {
605 return NULL;
606 }
607
608 PyObject *t2 = PyTuple_Pack(3,
609 ((PySliceObject *)w)->start,
610 ((PySliceObject *)w)->stop,
611 ((PySliceObject *)w)->step);
612 if (t2 == NULL) {
613 Py_DECREF(t1);
614 return NULL;
615 }
616
617 PyObject *res = PyObject_RichCompare(t1, t2, op);
618 Py_DECREF(t1);
619 Py_DECREF(t2);
620 return res;
621 }
622
623 static int
slice_traverse(PySliceObject * v,visitproc visit,void * arg)624 slice_traverse(PySliceObject *v, visitproc visit, void *arg)
625 {
626 Py_VISIT(v->start);
627 Py_VISIT(v->stop);
628 Py_VISIT(v->step);
629 return 0;
630 }
631
632 PyTypeObject PySlice_Type = {
633 PyVarObject_HEAD_INIT(&PyType_Type, 0)
634 "slice", /* Name of this type */
635 sizeof(PySliceObject), /* Basic object size */
636 0, /* Item size for varobject */
637 (destructor)slice_dealloc, /* tp_dealloc */
638 0, /* tp_vectorcall_offset */
639 0, /* tp_getattr */
640 0, /* tp_setattr */
641 0, /* tp_as_async */
642 (reprfunc)slice_repr, /* tp_repr */
643 0, /* tp_as_number */
644 0, /* tp_as_sequence */
645 0, /* tp_as_mapping */
646 PyObject_HashNotImplemented, /* tp_hash */
647 0, /* tp_call */
648 0, /* tp_str */
649 PyObject_GenericGetAttr, /* tp_getattro */
650 0, /* tp_setattro */
651 0, /* tp_as_buffer */
652 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
653 slice_doc, /* tp_doc */
654 (traverseproc)slice_traverse, /* tp_traverse */
655 0, /* tp_clear */
656 slice_richcompare, /* tp_richcompare */
657 0, /* tp_weaklistoffset */
658 0, /* tp_iter */
659 0, /* tp_iternext */
660 slice_methods, /* tp_methods */
661 slice_members, /* tp_members */
662 0, /* tp_getset */
663 0, /* tp_base */
664 0, /* tp_dict */
665 0, /* tp_descr_get */
666 0, /* tp_descr_set */
667 0, /* tp_dictoffset */
668 0, /* tp_init */
669 0, /* tp_alloc */
670 slice_new, /* tp_new */
671 };
672