rangeobject.c 6.97 KB
Newer Older
1 2 3

/* Range object implementation */

4
#include "Python.h"
5 6
#include "structmember.h"
#include <string.h>
7

8 9 10
#define WARN(msg) if (PyErr_Warn(PyExc_DeprecationWarning, msg) < 0) \
			return NULL;

11
typedef struct {
12
	PyObject_HEAD
13 14 15
	long	start;
	long	step;
	long	len;
16 17
	int	reps;
	long	totlen;
18 19
} rangeobject;

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
static int
long_mul(long i, long j, long *kk)
{
	PyObject *a;
	PyObject *b;
	PyObject *c;
	
	if ((a = PyInt_FromLong(i)) == NULL)
		return 0;
	
	if ((b = PyInt_FromLong(j)) == NULL)
		return 0;
	
	c = PyNumber_Multiply(a, b);
	
	Py_DECREF(a);
	Py_DECREF(b);
	
	if (c == NULL)
		return 0;

41 42 43 44 45
	if (!PyInt_Check(c)) {
		Py_DECREF(c);
		goto overflow;
	}

46 47 48 49
	*kk = PyInt_AS_LONG(c);
	Py_DECREF(c);

	if (*kk > INT_MAX) {
50
	  overflow:
51 52 53 54 55 56 57 58
		PyErr_SetString(PyExc_OverflowError,
				"integer multiplication");
		return 0;
	}
	else
		return 1;
}

59
PyObject *
60
PyRange_New(long start, long len, long step, int reps)
61
{
62
	long totlen = -1;
63
	rangeobject *obj = PyObject_New(rangeobject, &PyRange_Type);
64

65 66
	if (obj == NULL)
		return NULL;
67 68 69
		
	if (reps != 1)
		WARN("PyRange_New's 'repetitions' argument is deprecated");
70

71
	if (len == 0 || reps <= 0) {
72 73 74
		start = 0;
		len = 0;
		step = 1;
75 76
		reps = 1;
		totlen = 0;
77 78 79 80
	}
	else {
		long last = start + (len - 1) * step;
		if ((step > 0) ?
81 82
		    (last > (PyInt_GetMax() - step)) : 
		    (last < (-1 - PyInt_GetMax() - step))) {
83 84 85
			PyErr_SetString(PyExc_OverflowError,
					"integer addition");
			return NULL;
86 87 88 89 90 91
		}			
		if (! long_mul(len, (long) reps, &totlen)) {
			if(!PyErr_ExceptionMatches(PyExc_OverflowError))
				return NULL;
			PyErr_Clear();
			totlen = -1;
92 93 94
		}
	}

95 96 97
	obj->start = start;
	obj->len   = len;
	obj->step  = step;
98 99
	obj->reps  = reps;
	obj->totlen = totlen;
100

101
	return (PyObject *) obj;
102 103 104
}

static void
105
range_dealloc(rangeobject *r)
106
{
107
	PyObject_Del(r);
108 109
}

110
static PyObject *
111
range_item(rangeobject *r, int i)
112
{
113 114 115
	if (i < 0 || i >= r->totlen)
		if (r->totlen!=-1) {
			PyErr_SetString(PyExc_IndexError,
116
				"xrange object index out of range");
117 118
			return NULL;
		}
119

120
	return PyInt_FromLong(r->start + (i % r->len) * r->step);
121 122 123
}

static int
124
range_length(rangeobject *r)
125
{
126 127 128 129
	if (r->totlen == -1)
		PyErr_SetString(PyExc_OverflowError,
				"xrange object has too many items");
	return r->totlen;
130 131
}

132
static PyObject *
133
range_repr(rangeobject *r)
134
{
135 136
	PyObject *rtn;
	
137
	if (r->start == 0 && r->step == 1)
138 139
		rtn = PyString_FromFormat("xrange(%ld)",
					  r->start + r->len * r->step);
140 141

	else if (r->step == 1)
142 143 144
		rtn = PyString_FromFormat("xrange(%ld, %ld)",
					  r->start,
					  r->start + r->len * r->step);
145 146

	else
147 148 149 150 151 152 153 154 155 156 157 158
		rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)",
					  r->start,
					  r->start + r->len * r->step,
					  r->step);
	if (r->reps != 1) {
		PyObject *extra = PyString_FromFormat(
			"(%s * %d)",
			PyString_AS_STRING(rtn), r->reps);
		Py_DECREF(rtn);
		rtn = extra;
	}
	return rtn;
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
}

static PyObject *
range_repeat(rangeobject *r, int n)
{
	long lreps = 0;

	WARN("xrange object multiplication is deprecated; "
	     "convert to list instead");

	if (n <= 0)
		return (PyObject *) PyRange_New(0, 0, 1, 1);

	else if (n == 1) {
		Py_INCREF(r);
		return (PyObject *) r;
	}

	else if (! long_mul((long) r->reps, (long) n, &lreps))
		return NULL;
	
	else
		return (PyObject *) PyRange_New(
						r->start,
						r->len,
						r->step,
						(int) lreps);
}

static int
range_compare(rangeobject *r1, rangeobject *r2)
{

        if (PyErr_Warn(PyExc_DeprecationWarning,
193
        	       "xrange object comparison is deprecated; "
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
        	       "convert to list instead") < 0)
        	return -1;

	if (r1->start != r2->start)
		return r1->start - r2->start;

	else if (r1->step != r2->step)
		return r1->step - r2->step;

	else if (r1->len != r2->len)
		return r1->len - r2->len;

	else
		return r1->reps - r2->reps;
}

static PyObject *
range_slice(rangeobject *r, int low, int high)
{
	WARN("xrange object slicing is deprecated; "
	     "convert to list instead");

	if (r->reps != 1) {
		PyErr_SetString(PyExc_TypeError,
				"cannot slice a replicated xrange");
		return NULL;
	}
	if (low < 0)
		low = 0;
	else if (low > r->len)
		low = r->len;
	if (high < 0)
		high = 0;
	if (high < low)
		high = low;
	else if (high > r->len)
		high = r->len;

	if (low == 0 && high == r->len) {
		Py_INCREF(r);
		return (PyObject *) r;
	}

	return (PyObject *) PyRange_New(
				low * r->step + r->start,
				high - low,
				r->step,
				1);
}

static PyObject *
range_tolist(rangeobject *self, PyObject *args)
{
	PyObject *thelist;
	int j;

	WARN("xrange.tolist() is deprecated; use list(xrange) instead");

	if (self->totlen == -1)
		return PyErr_NoMemory();

	if ((thelist = PyList_New(self->totlen)) == NULL)
		return NULL;

	for (j = 0; j < self->totlen; ++j)
		if ((PyList_SetItem(thelist, j, (PyObject *) PyInt_FromLong(
			self->start + (j % self->len) * self->step))) < 0)
			return NULL;

	return thelist;
}

static PyObject *
range_getattr(rangeobject *r, char *name)
{
	PyObject *result;

	static PyMethodDef range_methods[] = {
272
		{"tolist",	(PyCFunction)range_tolist, METH_NOARGS,
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
                 "tolist() -> list\n"
                 "Return a list object with the same values.\n"
                 "(This method is deprecated; use list() instead.)"},
		{NULL,		NULL}
	};
	static struct memberlist range_members[] = {
		{"step",  T_LONG, offsetof(rangeobject, step), RO},
		{"start", T_LONG, offsetof(rangeobject, start), RO},
		{"stop",  T_LONG, 0, RO},
		{NULL, 0, 0, 0}
	};

	result = Py_FindMethod(range_methods, (PyObject *) r, name);
	if (result == NULL) {
		PyErr_Clear();
		if (strcmp("stop", name) == 0)
			result = PyInt_FromLong(r->start + (r->len * r->step));
		else
			result = PyMember_Get((char *)r, range_members, name);
		if (result)
			WARN("xrange object's 'start', 'stop' and 'step' "
			     "attributes are deprecated");
	}
	return result;
297 298
}

299
static PySequenceMethods range_as_sequence = {
300
	(inquiry)range_length,	/*sq_length*/
301
	0,			/*sq_concat*/
302 303 304
	(intargfunc)range_repeat, /*sq_repeat*/
	(intargfunc)range_item, /*sq_item*/
	(intintargfunc)range_slice, /*sq_slice*/
305 306
	0,			/*sq_ass_item*/
	0,			/*sq_ass_slice*/
307
	0, 			/*sq_contains*/
308 309
};

310 311
PyTypeObject PyRange_Type = {
	PyObject_HEAD_INIT(&PyType_Type)
312
	0,			/* Number of items for varobject */
313
	"xrange",		/* Name of this type */
314 315
	sizeof(rangeobject),	/* Basic object size */
	0,			/* Item size for varobject */
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
	(destructor)range_dealloc,		/*tp_dealloc*/
	0,					/*tp_print*/
	(getattrfunc)range_getattr,		/*tp_getattr*/
	0,					/*tp_setattr*/
	(cmpfunc)range_compare,			/*tp_compare*/
	(reprfunc)range_repr,			/*tp_repr*/
	0,					/*tp_as_number*/
	&range_as_sequence,			/*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*/
	0,					/* tp_doc */
	0,					/* tp_traverse */
	0,					/* tp_clear */
	0,					/* tp_richcompare */
	0,					/* tp_weaklistoffset */
	0,					/* tp_iter */
	0,					/* tp_iternext */
	0,					/* tp_methods */
	0,					/* tp_members */
	0,					/* tp_getset */
	0,					/* tp_base */
	0,					/* tp_dict */
344
};
345 346

#undef WARN