PageRenderTime 40ms CodeModel.GetById 18ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/Objects/sliceobject.c

http://unladen-swallow.googlecode.com/
C | 361 lines | 292 code | 47 blank | 22 comment | 75 complexity | b52b82dcd5b5361746d057ee01dcde52 MD5 | raw file
  1/*
  2Written by Jim Hugunin and Chris Chase.
  3
  4This includes both the singular ellipsis object and slice objects.
  5
  6Guido, feel free to do whatever you want in the way of copyrights
  7for this file.
  8*/
  9
 10/* 
 11Py_Ellipsis encodes the '...' rubber index token. It is similar to
 12the Py_NoneStruct in that there is no way to create other objects of
 13this type and there is exactly one in existence.
 14*/
 15
 16#include "Python.h"
 17#include "structmember.h"
 18
 19static PyObject *
 20ellipsis_repr(PyObject *op)
 21{
 22	return PyString_FromString("Ellipsis");
 23}
 24
 25PyTypeObject 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
 48PyObject _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
 60PyObject *
 61PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
 62{
 63	PySliceObject *obj = PyObject_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	return (PyObject *) obj;
 80}
 81
 82PyObject *
 83_PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop)
 84{
 85	PyObject *start, *end, *slice;
 86	start = PyInt_FromSsize_t(istart);
 87	if (!start)
 88		return NULL;
 89	end = PyInt_FromSsize_t(istop);
 90	if (!end) {
 91		Py_DECREF(start);
 92		return NULL;
 93	}
 94
 95	slice = PySlice_New(start, end, NULL);
 96	Py_DECREF(start);
 97	Py_DECREF(end);
 98	return slice;
 99}
100
101int
102PySlice_GetIndices(PySliceObject *r, Py_ssize_t length,
103                   Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
104{
105	/* XXX support long ints */
106	if (r->step == Py_None) {
107		*step = 1;
108	} else {
109		if (!PyInt_Check(r->step) && !PyLong_Check(r->step)) return -1;
110		*step = PyInt_AsSsize_t(r->step);
111	}
112	if (r->start == Py_None) {
113		*start = *step < 0 ? length-1 : 0;
114	} else {
115		if (!PyInt_Check(r->start) && !PyLong_Check(r->step)) return -1;
116		*start = PyInt_AsSsize_t(r->start);
117		if (*start < 0) *start += length;
118	}
119	if (r->stop == Py_None) {
120		*stop = *step < 0 ? -1 : length;
121	} else {
122		if (!PyInt_Check(r->stop) && !PyLong_Check(r->step)) return -1;
123		*stop = PyInt_AsSsize_t(r->stop);
124		if (*stop < 0) *stop += length;
125	}
126	if (*stop > length) return -1;
127	if (*start >= length) return -1;
128	if (*step == 0) return -1;
129	return 0;
130}
131
132int
133PySlice_GetIndicesEx(PySliceObject *r, Py_ssize_t length,
134		     Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength)
135{
136	/* this is harder to get right than you might think */
137
138	Py_ssize_t defstart, defstop;
139
140	if (r->step == Py_None) {
141		*step = 1;
142	} 
143	else {
144		if (!_PyEval_SliceIndex(r->step, step)) return -1;
145		if (*step == 0) {
146			PyErr_SetString(PyExc_ValueError,
147					"slice step cannot be zero");
148			return -1;
149		}
150	}
151
152	defstart = *step < 0 ? length-1 : 0;
153	defstop = *step < 0 ? -1 : length;
154
155	if (r->start == Py_None) {
156		*start = defstart;
157	}
158	else {
159		if (!_PyEval_SliceIndex(r->start, start)) return -1;
160		if (*start < 0) *start += length;
161		if (*start < 0) *start = (*step < 0) ? -1 : 0;
162		if (*start >= length) 
163			*start = (*step < 0) ? length - 1 : length;
164	}
165
166	if (r->stop == Py_None) {
167		*stop = defstop;
168	}
169	else {
170		if (!_PyEval_SliceIndex(r->stop, stop)) return -1;
171		if (*stop < 0) *stop += length;
172		if (*stop < 0) *stop = (*step < 0) ? -1 : 0;
173		if (*stop >= length)
174			*stop = (*step < 0) ? length - 1 : length;
175	}
176
177	if ((*step < 0 && *stop >= *start) 
178	    || (*step > 0 && *start >= *stop)) {
179		*slicelength = 0;
180	}
181	else if (*step < 0) {
182		*slicelength = (*stop-*start+1)/(*step)+1;
183	}
184	else {
185		*slicelength = (*stop-*start-1)/(*step)+1;
186	}
187
188	return 0;
189}
190
191static PyObject *
192slice_new(PyTypeObject *type, PyObject *args, PyObject *kw)
193{
194	PyObject *start, *stop, *step;
195
196	start = stop = step = NULL;
197
198	if (!_PyArg_NoKeywords("slice()", kw))
199		return NULL;
200
201	if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step))
202		return NULL;
203
204	/* This swapping of stop and start is to maintain similarity with
205	   range(). */
206	if (stop == NULL) {
207		stop = start;
208		start = NULL;
209	}
210	return PySlice_New(start, stop, step);
211}
212
213PyDoc_STRVAR(slice_doc,
214"slice([start,] stop[, step])\n\
215\n\
216Create a slice object.  This is used for extended slicing (e.g. a[0:10:2]).");
217
218static void
219slice_dealloc(PySliceObject *r)
220{
221	Py_DECREF(r->step);
222	Py_DECREF(r->start);
223	Py_DECREF(r->stop);
224	PyObject_Del(r);
225}
226
227static PyObject *
228slice_repr(PySliceObject *r)
229{
230	PyObject *s, *comma;
231
232	s = PyString_FromString("slice(");
233	comma = PyString_FromString(", ");
234	PyString_ConcatAndDel(&s, PyObject_Repr(r->start));
235	PyString_Concat(&s, comma);
236	PyString_ConcatAndDel(&s, PyObject_Repr(r->stop));
237	PyString_Concat(&s, comma);
238	PyString_ConcatAndDel(&s, PyObject_Repr(r->step));
239	PyString_ConcatAndDel(&s, PyString_FromString(")"));
240	Py_DECREF(comma);
241	return s;
242}
243
244static PyMemberDef slice_members[] = {
245	{"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
246	{"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
247	{"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
248	{0}
249};
250
251static PyObject*
252slice_indices(PySliceObject* self, PyObject* len)
253{
254	Py_ssize_t ilen, start, stop, step, slicelength;
255
256	ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError);
257
258	if (ilen == -1 && PyErr_Occurred()) {
259		return NULL;
260	}
261
262	if (PySlice_GetIndicesEx(self, ilen, &start, &stop, 
263				 &step, &slicelength) < 0) {
264		return NULL;
265	}
266
267	return Py_BuildValue("(nnn)", start, stop, step);
268}
269
270PyDoc_STRVAR(slice_indices_doc,
271"S.indices(len) -> (start, stop, stride)\n\
272\n\
273Assuming a sequence of length len, calculate the start and stop\n\
274indices, and the stride length of the extended slice described by\n\
275S. Out of bounds indices are clipped in a manner consistent with the\n\
276handling of normal slices.");
277
278static PyObject *
279slice_reduce(PySliceObject* self)
280{
281	return Py_BuildValue("O(OOO)", Py_TYPE(self), self->start, self->stop, self->step);
282}
283
284PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
285
286static PyMethodDef slice_methods[] = {
287	{"indices",	(PyCFunction)slice_indices,
288	 METH_O,	slice_indices_doc},
289	{"__reduce__",	(PyCFunction)slice_reduce,
290	 METH_NOARGS,	reduce_doc},
291	{NULL, NULL}
292};
293
294static int
295slice_compare(PySliceObject *v, PySliceObject *w)
296{
297	int result = 0;
298
299        if (v == w)
300		return 0;
301
302	if (PyObject_Cmp(v->start, w->start, &result) < 0)
303	    return -2;
304	if (result != 0)
305		return result;
306	if (PyObject_Cmp(v->stop, w->stop, &result) < 0)
307	    return -2;
308	if (result != 0)
309		return result;
310	if (PyObject_Cmp(v->step, w->step, &result) < 0)
311	    return -2;
312	return result;
313}
314
315static long
316slice_hash(PySliceObject *v)
317{
318	PyErr_SetString(PyExc_TypeError, "unhashable type");
319	return -1L;
320}
321
322PyTypeObject PySlice_Type = {
323	PyVarObject_HEAD_INIT(&PyType_Type, 0)
324	"slice",		/* Name of this type */
325	sizeof(PySliceObject),	/* Basic object size */
326	0,			/* Item size for varobject */
327	(destructor)slice_dealloc,		/* tp_dealloc */
328	0,					/* tp_print */
329	0,					/* tp_getattr */
330	0,					/* tp_setattr */
331	(cmpfunc)slice_compare, 		/* tp_compare */
332	(reprfunc)slice_repr,   		/* tp_repr */
333	0,					/* tp_as_number */
334	0,	    				/* tp_as_sequence */
335	0,					/* tp_as_mapping */
336	(hashfunc)slice_hash,			/* tp_hash */
337	0,					/* tp_call */
338	0,					/* tp_str */
339	PyObject_GenericGetAttr,		/* tp_getattro */
340	0,					/* tp_setattro */
341	0,					/* tp_as_buffer */
342	Py_TPFLAGS_DEFAULT,			/* tp_flags */
343	slice_doc,				/* tp_doc */
344	0,					/* tp_traverse */
345	0,					/* tp_clear */
346	0,					/* tp_richcompare */
347	0,					/* tp_weaklistoffset */
348	0,					/* tp_iter */
349	0,					/* tp_iternext */
350	slice_methods,				/* tp_methods */
351	slice_members,				/* tp_members */
352	0,					/* tp_getset */
353	0,					/* tp_base */
354	0,					/* tp_dict */
355	0,					/* tp_descr_get */
356	0,					/* tp_descr_set */
357	0,					/* tp_dictoffset */
358	0,					/* tp_init */
359	0,					/* tp_alloc */
360	slice_new,				/* tp_new */
361};