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