sliceobject.c 8.33 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1 2 3
/*
Written by Jim Hugunin and Chris Chase.

4
This includes both the singular ellipsis object and slice objects.
Guido van Rossum's avatar
Guido van Rossum committed
5 6 7 8 9 10

Guido, feel free to do whatever you want in the way of copyrights
for this file.
*/

/* 
11
Py_Ellipsis encodes the '...' rubber index token. It is similar to
Guido van Rossum's avatar
Guido van Rossum committed
12 13 14 15 16
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"
17
#include "structmember.h"
Guido van Rossum's avatar
Guido van Rossum committed
18 19

static PyObject *
20
ellipsis_repr(PyObject *op)
Guido van Rossum's avatar
Guido van Rossum committed
21
{
22
	return PyString_FromString("Ellipsis");
Guido van Rossum's avatar
Guido van Rossum committed
23 24
}

25
static PyTypeObject PyEllipsis_Type = {
26
	PyVarObject_HEAD_INIT(&PyType_Type, 0)
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
	"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_compare */
	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 */
Guido van Rossum's avatar
Guido van Rossum committed
46 47
};

48
PyObject _Py_EllipsisObject = {
49 50
	_PyObject_EXTRA_INIT
	1, &PyEllipsis_Type
Guido van Rossum's avatar
Guido van Rossum committed
51 52 53 54 55 56 57 58 59 60
};


/* Slice object implementation

   start, stop, and step are python objects with None indicating no
   index is present.
*/

PyObject *
61
PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
Guido van Rossum's avatar
Guido van Rossum committed
62
{
63
	PySliceObject *obj = PyObject_New(PySliceObject, &PySlice_Type);
Guido van Rossum's avatar
Guido van Rossum committed
64

65 66 67
	if (obj == NULL)
		return NULL;

Guido van Rossum's avatar
Guido van Rossum committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81
	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;
}

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
PyObject *
_PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop)
{
	PyObject *start, *end, *slice;
	start = PyInt_FromSsize_t(istart);
	if (!start)
		return NULL;
	end = PyInt_FromSsize_t(istop);
	if (!end) {
		Py_DECREF(start);
		return NULL;
	}

	slice = PySlice_New(start, end, NULL);
	Py_DECREF(start);
	Py_DECREF(end);
	return slice;
}

Guido van Rossum's avatar
Guido van Rossum committed
101
int
Martin v. Löwis's avatar
Martin v. Löwis committed
102 103
PySlice_GetIndices(PySliceObject *r, Py_ssize_t length,
                   Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
Guido van Rossum's avatar
Guido van Rossum committed
104
{
Martin v. Löwis's avatar
Martin v. Löwis committed
105
	/* XXX support long ints */
Guido van Rossum's avatar
Guido van Rossum committed
106 107 108
	if (r->step == Py_None) {
		*step = 1;
	} else {
109
		if (!PyInt_Check(r->step) && !PyLong_Check(r->step)) return -1;
Neal Norwitz's avatar
Neal Norwitz committed
110
		*step = PyInt_AsSsize_t(r->step);
Guido van Rossum's avatar
Guido van Rossum committed
111 112 113 114
	}
	if (r->start == Py_None) {
		*start = *step < 0 ? length-1 : 0;
	} else {
115
		if (!PyInt_Check(r->start) && !PyLong_Check(r->step)) return -1;
Neal Norwitz's avatar
Neal Norwitz committed
116
		*start = PyInt_AsSsize_t(r->start);
Guido van Rossum's avatar
Guido van Rossum committed
117 118 119 120 121
		if (*start < 0) *start += length;
	}
	if (r->stop == Py_None) {
		*stop = *step < 0 ? -1 : length;
	} else {
122
		if (!PyInt_Check(r->stop) && !PyLong_Check(r->step)) return -1;
Neal Norwitz's avatar
Neal Norwitz committed
123
		*stop = PyInt_AsSsize_t(r->stop);
Guido van Rossum's avatar
Guido van Rossum committed
124 125 126 127 128 129 130 131
		if (*stop < 0) *stop += length;
	}
	if (*stop > length) return -1;
	if (*start >= length) return -1;
	if (*step == 0) return -1;
	return 0;
}

132
int
Martin v. Löwis's avatar
Martin v. Löwis committed
133 134
PySlice_GetIndicesEx(PySliceObject *r, Py_ssize_t length,
		     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

Martin v. Löwis's avatar
Martin v. Löwis committed
138
	Py_ssize_t defstart, defstop;
139 140 141

	if (r->step == Py_None) {
		*step = 1;
142 143
	} 
	else {
144 145
		if (!_PyEval_SliceIndex(r->step, step)) return -1;
		if (*step == 0) {
146 147 148 149 150 151 152 153 154 155 156
			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;
157 158
	}
	else {
159 160 161 162 163 164 165 166 167
		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;
168 169
	}
	else {
170 171
		if (!_PyEval_SliceIndex(r->stop, stop)) return -1;
		if (*stop < 0) *stop += length;
172 173 174
		if (*stop < 0) *stop = (*step < 0) ? -1 : 0;
		if (*stop >= length)
			*stop = (*step < 0) ? length - 1 : length;
175
	}
176 177 178

	if ((*step < 0 && *stop >= *start) 
	    || (*step > 0 && *start >= *stop)) {
179 180 181
		*slicelength = 0;
	}
	else if (*step < 0) {
182
		*slicelength = (*stop-*start+1)/(*step)+1;
183 184
	}
	else {
185 186 187 188 189 190
		*slicelength = (*stop-*start-1)/(*step)+1;
	}

	return 0;
}

191 192 193 194 195 196 197
static PyObject *
slice_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
	PyObject *start, *stop, *step;

	start = stop = step = NULL;

198 199 200
	if (!_PyArg_NoKeywords("slice()", kw))
		return NULL;

201
	if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step))
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
		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]).");

Guido van Rossum's avatar
Guido van Rossum committed
218
static void
219
slice_dealloc(PySliceObject *r)
Guido van Rossum's avatar
Guido van Rossum committed
220 221 222 223
{
	Py_DECREF(r->step);
	Py_DECREF(r->start);
	Py_DECREF(r->stop);
224
	PyObject_Del(r);
Guido van Rossum's avatar
Guido van Rossum committed
225 226 227
}

static PyObject *
228
slice_repr(PySliceObject *r)
Guido van Rossum's avatar
Guido van Rossum committed
229 230 231
{
	PyObject *s, *comma;

232 233 234 235 236 237 238 239
	s = PyString_FromString("slice(");
	comma = PyString_FromString(", ");
	PyString_ConcatAndDel(&s, PyObject_Repr(r->start));
	PyString_Concat(&s, comma);
	PyString_ConcatAndDel(&s, PyObject_Repr(r->stop));
	PyString_Concat(&s, comma);
	PyString_ConcatAndDel(&s, PyObject_Repr(r->step));
	PyString_ConcatAndDel(&s, PyString_FromString(")"));
Guido van Rossum's avatar
Guido van Rossum committed
240 241 242 243
	Py_DECREF(comma);
	return s;
}

244
static PyMemberDef slice_members[] = {
245 246 247 248 249
	{"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
	{"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
	{"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
	{0}
};
Guido van Rossum's avatar
Guido van Rossum committed
250

251 252 253
static PyObject*
slice_indices(PySliceObject* self, PyObject* len)
{
Martin v. Löwis's avatar
Martin v. Löwis committed
254
	Py_ssize_t ilen, start, stop, step, slicelength;
255

256
	ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError);
257 258 259 260 261 262 263 264 265 266

	if (ilen == -1 && PyErr_Occurred()) {
		return NULL;
	}

	if (PySlice_GetIndicesEx(self, ilen, &start, &stop, 
				 &step, &slicelength) < 0) {
		return NULL;
	}

Neal Norwitz's avatar
Neal Norwitz committed
267
	return Py_BuildValue("(nnn)", start, stop, step);
268 269 270 271 272 273 274 275 276 277
}

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.");

278 279 280
static PyObject *
slice_reduce(PySliceObject* self)
{
281
	return Py_BuildValue("O(OOO)", Py_TYPE(self), self->start, self->stop, self->step);
282 283 284 285
}

PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");

286
static PyMethodDef slice_methods[] = {
287
	{"indices",	(PyCFunction)slice_indices,
288
	 METH_O,	slice_indices_doc},
289 290
	{"__reduce__",	(PyCFunction)slice_reduce,
	 METH_NOARGS,	reduce_doc},
291 292 293
	{NULL, NULL}
};

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
static int
slice_compare(PySliceObject *v, PySliceObject *w)
{
	int result = 0;

        if (v == w)
		return 0;

	if (PyObject_Cmp(v->start, w->start, &result) < 0)
	    return -2;
	if (result != 0)
		return result;
	if (PyObject_Cmp(v->stop, w->stop, &result) < 0)
	    return -2;
	if (result != 0)
		return result;
	if (PyObject_Cmp(v->step, w->step, &result) < 0)
	    return -2;
	return result;
}
Guido van Rossum's avatar
Guido van Rossum committed
314

315 316 317 318 319 320 321
static long
slice_hash(PySliceObject *v)
{
	PyErr_SetString(PyExc_TypeError, "unhashable type");
	return -1L;
}

Guido van Rossum's avatar
Guido van Rossum committed
322
PyTypeObject PySlice_Type = {
323
	PyVarObject_HEAD_INIT(&PyType_Type, 0)
Guido van Rossum's avatar
Guido van Rossum committed
324 325 326
	"slice",		/* Name of this type */
	sizeof(PySliceObject),	/* Basic object size */
	0,			/* Item size for varobject */
327 328 329 330 331 332 333 334 335
	(destructor)slice_dealloc,		/* tp_dealloc */
	0,					/* tp_print */
	0,					/* tp_getattr */
	0,					/* tp_setattr */
	(cmpfunc)slice_compare, 		/* tp_compare */
	(reprfunc)slice_repr,   		/* tp_repr */
	0,					/* tp_as_number */
	0,	    				/* tp_as_sequence */
	0,					/* tp_as_mapping */
336
	(hashfunc)slice_hash,			/* tp_hash */
337 338 339 340 341 342
	0,					/* tp_call */
	0,					/* tp_str */
	PyObject_GenericGetAttr,		/* tp_getattro */
	0,					/* tp_setattro */
	0,					/* tp_as_buffer */
	Py_TPFLAGS_DEFAULT,			/* tp_flags */
343
	slice_doc,				/* tp_doc */
344 345 346 347 348 349
	0,					/* tp_traverse */
	0,					/* tp_clear */
	0,					/* tp_richcompare */
	0,					/* tp_weaklistoffset */
	0,					/* tp_iter */
	0,					/* tp_iternext */
350
	slice_methods,				/* tp_methods */
351 352 353 354
	slice_members,				/* tp_members */
	0,					/* tp_getset */
	0,					/* tp_base */
	0,					/* tp_dict */
355 356 357 358 359 360
	0,					/* tp_descr_get */
	0,					/* tp_descr_set */
	0,					/* tp_dictoffset */
	0,					/* tp_init */
	0,					/* tp_alloc */
	slice_new,				/* tp_new */
Guido van Rossum's avatar
Guido van Rossum committed
361
};