mirror of
				https://github.com/python/cpython.git
				synced 2025-10-26 11:14:33 +00:00 
			
		
		
		
	 7f14f0d8a0
			
		
	
	
		7f14f0d8a0
		
	
	
	
	
		
			
			svn+ssh://pythondev@svn.python.org/python/branches/py3k
................
  r81032 | antoine.pitrou | 2010-05-09 17:52:27 +0200 (dim., 09 mai 2010) | 9 lines
  Recorded merge of revisions 81029 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk
  ........
    r81029 | antoine.pitrou | 2010-05-09 16:46:46 +0200 (dim., 09 mai 2010) | 3 lines
    Untabify C files. Will watch buildbots.
  ........
................
		
	
			
		
			
				
	
	
		
			385 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			385 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
| Written by Jim Hugunin and Chris Chase.
 | |
| 
 | |
| This includes both the singular ellipsis object and slice objects.
 | |
| 
 | |
| Guido, feel free to do whatever you want in the way of copyrights
 | |
| for this file.
 | |
| */
 | |
| 
 | |
| /*
 | |
| Py_Ellipsis encodes the '...' rubber index token. It is similar to
 | |
| the Py_NoneStruct in that there is no way to create other objects of
 | |
| this type and there is exactly one in existence.
 | |
| */
 | |
| 
 | |
| #include "Python.h"
 | |
| #include "structmember.h"
 | |
| 
 | |
| static PyObject *
 | |
| ellipsis_repr(PyObject *op)
 | |
| {
 | |
|     return PyUnicode_FromString("Ellipsis");
 | |
| }
 | |
| 
 | |
| PyTypeObject PyEllipsis_Type = {
 | |
|     PyVarObject_HEAD_INIT(&PyType_Type, 0)
 | |
|     "ellipsis",                         /* tp_name */
 | |
|     0,                                  /* tp_basicsize */
 | |
|     0,                                  /* tp_itemsize */
 | |
|     0, /*never called*/                 /* tp_dealloc */
 | |
|     0,                                  /* tp_print */
 | |
|     0,                                  /* tp_getattr */
 | |
|     0,                                  /* tp_setattr */
 | |
|     0,                                  /* tp_reserved */
 | |
|     ellipsis_repr,                      /* tp_repr */
 | |
|     0,                                  /* tp_as_number */
 | |
|     0,                                  /* tp_as_sequence */
 | |
|     0,                                  /* tp_as_mapping */
 | |
|     0,                                  /* tp_hash */
 | |
|     0,                                  /* tp_call */
 | |
|     0,                                  /* tp_str */
 | |
|     PyObject_GenericGetAttr,            /* tp_getattro */
 | |
|     0,                                  /* tp_setattro */
 | |
|     0,                                  /* tp_as_buffer */
 | |
|     Py_TPFLAGS_DEFAULT,                 /* tp_flags */
 | |
| };
 | |
| 
 | |
| PyObject _Py_EllipsisObject = {
 | |
|     _PyObject_EXTRA_INIT
 | |
|     1, &PyEllipsis_Type
 | |
| };
 | |
| 
 | |
| 
 | |
| /* Slice object implementation
 | |
| 
 | |
|    start, stop, and step are python objects with None indicating no
 | |
|    index is present.
 | |
| */
 | |
| 
 | |
| PyObject *
 | |
| PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
 | |
| {
 | |
|     PySliceObject *obj = PyObject_New(PySliceObject, &PySlice_Type);
 | |
| 
 | |
|     if (obj == NULL)
 | |
|         return NULL;
 | |
| 
 | |
|     if (step == NULL) step = Py_None;
 | |
|     Py_INCREF(step);
 | |
|     if (start == NULL) start = Py_None;
 | |
|     Py_INCREF(start);
 | |
|     if (stop == NULL) stop = Py_None;
 | |
|     Py_INCREF(stop);
 | |
| 
 | |
|     obj->step = step;
 | |
|     obj->start = start;
 | |
|     obj->stop = stop;
 | |
| 
 | |
|     return (PyObject *) obj;
 | |
| }
 | |
| 
 | |
| PyObject *
 | |
| _PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop)
 | |
| {
 | |
|     PyObject *start, *end, *slice;
 | |
|     start = PyLong_FromSsize_t(istart);
 | |
|     if (!start)
 | |
|         return NULL;
 | |
|     end = PyLong_FromSsize_t(istop);
 | |
|     if (!end) {
 | |
|         Py_DECREF(start);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     slice = PySlice_New(start, end, NULL);
 | |
|     Py_DECREF(start);
 | |
|     Py_DECREF(end);
 | |
|     return slice;
 | |
| }
 | |
| 
 | |
| int
 | |
| PySlice_GetIndices(PySliceObject *r, Py_ssize_t length,
 | |
|                    Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
 | |
| {
 | |
|     /* XXX support long ints */
 | |
|     if (r->step == Py_None) {
 | |
|         *step = 1;
 | |
|     } else {
 | |
|         if (!PyLong_Check(r->step)) return -1;
 | |
|         *step = PyLong_AsSsize_t(r->step);
 | |
|     }
 | |
|     if (r->start == Py_None) {
 | |
|         *start = *step < 0 ? length-1 : 0;
 | |
|     } else {
 | |
|         if (!PyLong_Check(r->start)) return -1;
 | |
|         *start = PyLong_AsSsize_t(r->start);
 | |
|         if (*start < 0) *start += length;
 | |
|     }
 | |
|     if (r->stop == Py_None) {
 | |
|         *stop = *step < 0 ? -1 : length;
 | |
|     } else {
 | |
|         if (!PyLong_Check(r->stop)) return -1;
 | |
|         *stop = PyLong_AsSsize_t(r->stop);
 | |
|         if (*stop < 0) *stop += length;
 | |
|     }
 | |
|     if (*stop > length) return -1;
 | |
|     if (*start >= length) return -1;
 | |
|     if (*step == 0) return -1;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 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)
 | |
| {
 | |
|     /* this is harder to get right than you might think */
 | |
| 
 | |
|     Py_ssize_t defstart, defstop;
 | |
| 
 | |
|     if (r->step == Py_None) {
 | |
|         *step = 1;
 | |
|     }
 | |
|     else {
 | |
|         if (!_PyEval_SliceIndex(r->step, step)) return -1;
 | |
|         if (*step == 0) {
 | |
|             PyErr_SetString(PyExc_ValueError,
 | |
|                             "slice step cannot be zero");
 | |
|             return -1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     defstart = *step < 0 ? length-1 : 0;
 | |
|     defstop = *step < 0 ? -1 : length;
 | |
| 
 | |
|     if (r->start == Py_None) {
 | |
|         *start = defstart;
 | |
|     }
 | |
|     else {
 | |
|         if (!_PyEval_SliceIndex(r->start, start)) return -1;
 | |
|         if (*start < 0) *start += length;
 | |
|         if (*start < 0) *start = (*step < 0) ? -1 : 0;
 | |
|         if (*start >= length)
 | |
|             *start = (*step < 0) ? length - 1 : length;
 | |
|     }
 | |
| 
 | |
|     if (r->stop == Py_None) {
 | |
|         *stop = defstop;
 | |
|     }
 | |
|     else {
 | |
|         if (!_PyEval_SliceIndex(r->stop, stop)) return -1;
 | |
|         if (*stop < 0) *stop += length;
 | |
|         if (*stop < 0) *stop = (*step < 0) ? -1 : 0;
 | |
|         if (*stop >= length)
 | |
|             *stop = (*step < 0) ? length - 1 : length;
 | |
|     }
 | |
| 
 | |
|     if ((*step < 0 && *stop >= *start)
 | |
|         || (*step > 0 && *start >= *stop)) {
 | |
|         *slicelength = 0;
 | |
|     }
 | |
|     else if (*step < 0) {
 | |
|         *slicelength = (*stop-*start+1)/(*step)+1;
 | |
|     }
 | |
|     else {
 | |
|         *slicelength = (*stop-*start-1)/(*step)+1;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| slice_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 | |
| {
 | |
|     PyObject *start, *stop, *step;
 | |
| 
 | |
|     start = stop = step = NULL;
 | |
| 
 | |
|     if (!_PyArg_NoKeywords("slice()", kw))
 | |
|         return NULL;
 | |
| 
 | |
|     if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step))
 | |
|         return NULL;
 | |
| 
 | |
|     /* This swapping of stop and start is to maintain similarity with
 | |
|        range(). */
 | |
|     if (stop == NULL) {
 | |
|         stop = start;
 | |
|         start = NULL;
 | |
|     }
 | |
|     return PySlice_New(start, stop, step);
 | |
| }
 | |
| 
 | |
| PyDoc_STRVAR(slice_doc,
 | |
| "slice([start,] stop[, step])\n\
 | |
| \n\
 | |
| Create a slice object.  This is used for extended slicing (e.g. a[0:10:2]).");
 | |
| 
 | |
| static void
 | |
| slice_dealloc(PySliceObject *r)
 | |
| {
 | |
|     Py_DECREF(r->step);
 | |
|     Py_DECREF(r->start);
 | |
|     Py_DECREF(r->stop);
 | |
|     PyObject_Del(r);
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| slice_repr(PySliceObject *r)
 | |
| {
 | |
|     return PyUnicode_FromFormat("slice(%R, %R, %R)", r->start, r->stop, r->step);
 | |
| }
 | |
| 
 | |
| static PyMemberDef slice_members[] = {
 | |
|     {"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
 | |
|     {"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
 | |
|     {"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
 | |
|     {0}
 | |
| };
 | |
| 
 | |
| static PyObject*
 | |
| slice_indices(PySliceObject* self, PyObject* len)
 | |
| {
 | |
|     Py_ssize_t ilen, start, stop, step, slicelength;
 | |
| 
 | |
|     ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError);
 | |
| 
 | |
|     if (ilen == -1 && PyErr_Occurred()) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (PySlice_GetIndicesEx(self, ilen, &start, &stop,
 | |
|                              &step, &slicelength) < 0) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     return Py_BuildValue("(nnn)", start, stop, step);
 | |
| }
 | |
| 
 | |
| PyDoc_STRVAR(slice_indices_doc,
 | |
| "S.indices(len) -> (start, stop, stride)\n\
 | |
| \n\
 | |
| Assuming a sequence of length len, calculate the start and stop\n\
 | |
| indices, and the stride length of the extended slice described by\n\
 | |
| S. Out of bounds indices are clipped in a manner consistent with the\n\
 | |
| handling of normal slices.");
 | |
| 
 | |
| static PyObject *
 | |
| slice_reduce(PySliceObject* self)
 | |
| {
 | |
|     return Py_BuildValue("O(OOO)", Py_TYPE(self), self->start, self->stop, self->step);
 | |
| }
 | |
| 
 | |
| PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
 | |
| 
 | |
| static PyMethodDef slice_methods[] = {
 | |
|     {"indices",         (PyCFunction)slice_indices,
 | |
|      METH_O,            slice_indices_doc},
 | |
|     {"__reduce__",      (PyCFunction)slice_reduce,
 | |
|      METH_NOARGS,       reduce_doc},
 | |
|     {NULL, NULL}
 | |
| };
 | |
| 
 | |
| static PyObject *
 | |
| slice_richcompare(PyObject *v, PyObject *w, int op)
 | |
| {
 | |
|     PyObject *t1;
 | |
|     PyObject *t2;
 | |
|     PyObject *res;
 | |
| 
 | |
|     if (!PySlice_Check(v) || !PySlice_Check(w)) {
 | |
|         Py_INCREF(Py_NotImplemented);
 | |
|         return Py_NotImplemented;
 | |
|     }
 | |
| 
 | |
|     if (v == w) {
 | |
|         /* XXX Do we really need this shortcut?
 | |
|            There's a unit test for it, but is that fair? */
 | |
|         switch (op) {
 | |
|         case Py_EQ:
 | |
|         case Py_LE:
 | |
|         case Py_GE:
 | |
|             res = Py_True;
 | |
|             break;
 | |
|         default:
 | |
|             res = Py_False;
 | |
|             break;
 | |
|         }
 | |
|         Py_INCREF(res);
 | |
|         return res;
 | |
|     }
 | |
| 
 | |
|     t1 = PyTuple_New(3);
 | |
|     t2 = PyTuple_New(3);
 | |
|     if (t1 == NULL || t2 == NULL)
 | |
|         return NULL;
 | |
| 
 | |
|     PyTuple_SET_ITEM(t1, 0, ((PySliceObject *)v)->start);
 | |
|     PyTuple_SET_ITEM(t1, 1, ((PySliceObject *)v)->stop);
 | |
|     PyTuple_SET_ITEM(t1, 2, ((PySliceObject *)v)->step);
 | |
|     PyTuple_SET_ITEM(t2, 0, ((PySliceObject *)w)->start);
 | |
|     PyTuple_SET_ITEM(t2, 1, ((PySliceObject *)w)->stop);
 | |
|     PyTuple_SET_ITEM(t2, 2, ((PySliceObject *)w)->step);
 | |
| 
 | |
|     res = PyObject_RichCompare(t1, t2, op);
 | |
| 
 | |
|     PyTuple_SET_ITEM(t1, 0, NULL);
 | |
|     PyTuple_SET_ITEM(t1, 1, NULL);
 | |
|     PyTuple_SET_ITEM(t1, 2, NULL);
 | |
|     PyTuple_SET_ITEM(t2, 0, NULL);
 | |
|     PyTuple_SET_ITEM(t2, 1, NULL);
 | |
|     PyTuple_SET_ITEM(t2, 2, NULL);
 | |
| 
 | |
|     Py_DECREF(t1);
 | |
|     Py_DECREF(t2);
 | |
| 
 | |
|     return res;
 | |
| }
 | |
| 
 | |
| static long
 | |
| slice_hash(PySliceObject *v)
 | |
| {
 | |
|     PyErr_SetString(PyExc_TypeError, "unhashable type");
 | |
|     return -1L;
 | |
| }
 | |
| 
 | |
| PyTypeObject PySlice_Type = {
 | |
|     PyVarObject_HEAD_INIT(&PyType_Type, 0)
 | |
|     "slice",                    /* Name of this type */
 | |
|     sizeof(PySliceObject),      /* Basic object size */
 | |
|     0,                          /* Item size for varobject */
 | |
|     (destructor)slice_dealloc,                  /* tp_dealloc */
 | |
|     0,                                          /* tp_print */
 | |
|     0,                                          /* tp_getattr */
 | |
|     0,                                          /* tp_setattr */
 | |
|     0,                                          /* tp_reserved */
 | |
|     (reprfunc)slice_repr,                       /* tp_repr */
 | |
|     0,                                          /* tp_as_number */
 | |
|     0,                                          /* tp_as_sequence */
 | |
|     0,                                          /* tp_as_mapping */
 | |
|     (hashfunc)slice_hash,                       /* tp_hash */
 | |
|     0,                                          /* tp_call */
 | |
|     0,                                          /* tp_str */
 | |
|     PyObject_GenericGetAttr,                    /* tp_getattro */
 | |
|     0,                                          /* tp_setattro */
 | |
|     0,                                          /* tp_as_buffer */
 | |
|     Py_TPFLAGS_DEFAULT,                         /* tp_flags */
 | |
|     slice_doc,                                  /* tp_doc */
 | |
|     0,                                          /* tp_traverse */
 | |
|     0,                                          /* tp_clear */
 | |
|     slice_richcompare,                          /* tp_richcompare */
 | |
|     0,                                          /* tp_weaklistoffset */
 | |
|     0,                                          /* tp_iter */
 | |
|     0,                                          /* tp_iternext */
 | |
|     slice_methods,                              /* tp_methods */
 | |
|     slice_members,                              /* tp_members */
 | |
|     0,                                          /* tp_getset */
 | |
|     0,                                          /* tp_base */
 | |
|     0,                                          /* tp_dict */
 | |
|     0,                                          /* tp_descr_get */
 | |
|     0,                                          /* tp_descr_set */
 | |
|     0,                                          /* tp_dictoffset */
 | |
|     0,                                          /* tp_init */
 | |
|     0,                                          /* tp_alloc */
 | |
|     slice_new,                                  /* tp_new */
 | |
| };
 |