Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(213)

Side by Side Diff: Objects/rangeobject.c

Issue 602: range: lean and mean (Closed) SVN Base: http://svn.python.org/view/*checkout*/python/branches/py3k/
Patch Set: use PyMemberDef Created 5 months, 1 week ago , Downloaded from: http://bugs.python.org/file10155/range_lean_and_mean2.patch
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* Range object implementation */ 1 /* Range object implementation */
2 2
3 #include "Python.h" 3 #include "Python.h"
4 #include "structmember.h"
4 5
5 /* Support objects whose length is > PY_SSIZE_T_MAX. 6 /* Support objects whose length is > PY_SSIZE_T_MAX.
6 7
7 This could be sped up for small PyLongs if they fit in an Py_ssize_t. 8 This could be sped up for small PyLongs if they fit in an Py_ssize_t.
8 This only matters on Win64. Though we could use PY_LONG_LONG which 9 This only matters on Win64. Though we could use PY_LONG_LONG which
9 would presumably help perf. 10 would presumably help perf.
10 */ 11 */
11 12
12 typedef struct { 13 typedef struct {
13 PyObject_HEAD 14 PyObject_HEAD
14 PyObject *start; 15 PyObject *start;
15 PyObject *stop; 16 PyObject *stop;
16 PyObject *step; 17 PyObject *step;
18 PyObject *length;
17 } rangeobject; 19 } rangeobject;
18 20
19 /* Helper function for validating step. Always returns a new reference or 21 /* Helper function for validating step. Always returns a new reference or
20 NULL on error. 22 NULL on error.
21 */ 23 */
22 static PyObject * 24 static PyObject *
23 validate_step(PyObject *step) 25 validate_step(PyObject *step)
24 { 26 {
25 /* No step specified, use a step of 1. */ 27 /* No step specified, use a step of 1. */
26 if (!step) 28 if (!step)
27 return PyLong_FromLong(1); 29 return PyLong_FromLong(1);
28 30
29 step = PyNumber_Index(step); 31 step = PyNumber_Index(step);
30 if (step) { 32 if (step) {
31 Py_ssize_t istep = PyNumber_AsSsize_t(step, NULL); 33 Py_ssize_t istep = PyNumber_AsSsize_t(step, NULL);
32 if (istep == -1 && PyErr_Occurred()) { 34 if (istep == -1 && PyErr_Occurred()) {
33 /* Ignore OverflowError, we know the value isn't 0. */ 35 /* Ignore OverflowError, we know the value isn't 0. */
34 PyErr_Clear(); 36 PyErr_Clear();
35 } 37 }
36 else if (istep == 0) { 38 else if (istep == 0) {
37 PyErr_SetString(PyExc_ValueError, 39 PyErr_SetString(PyExc_ValueError,
38 "range() arg 3 must not be zero"); 40 "range() arg 3 must not be zero");
39 Py_CLEAR(step); 41 Py_CLEAR(step);
40 } 42 }
41 } 43 }
42 44
43 return step; 45 return step;
44 } 46 }
47
48 static PyObject* range_compute_length(PyObject *start,
49 PyObject *stop, PyObject *step);
45 50
46 /* XXX(nnorwitz): should we error check if the user passes any empty ranges? 51 /* XXX(nnorwitz): should we error check if the user passes any empty ranges?
47 range(-10) 52 range(-10)
48 range(0, -5) 53 range(0, -5)
49 range(0, 5, -1) 54 range(0, 5, -1)
50 */ 55 */
51 static PyObject * 56 static PyObject *
52 range_new(PyTypeObject *type, PyObject *args, PyObject *kw) 57 range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
53 { 58 {
54 rangeobject *obj = NULL; 59 rangeobject *obj = NULL;
55 PyObject *start = NULL, *stop = NULL, *step = NULL; 60 PyObject *start = NULL, *stop = NULL, *step = NULL, *length = NULL;
56 61
57 if (!_PyArg_NoKeywords("range()", kw)) 62 if (!_PyArg_NoKeywords("range()", kw))
58 return NULL; 63 return NULL;
59 64
60 if (PyTuple_Size(args) <= 1) { 65 if (PyTuple_Size(args) <= 1) {
61 if (!PyArg_UnpackTuple(args, "range", 1, 1, &stop)) 66 if (!PyArg_UnpackTuple(args, "range", 1, 1, &stop))
62 goto Fail; 67 goto Fail;
63 stop = PyNumber_Index(stop); 68 stop = PyNumber_Index(stop);
64 if (!stop) 69 if (!stop)
65 goto Fail; 70 goto Fail;
66 start = PyLong_FromLong(0); 71 start = PyLong_FromLong(0);
67 step = PyLong_FromLong(1); 72 step = PyLong_FromLong(1);
68 if (!start || !step) 73 if (!start || !step)
69 goto Fail; 74 goto Fail;
70 } 75 }
71 else { 76 else {
72 if (!PyArg_UnpackTuple(args, "range", 2, 3, 77 if (!PyArg_UnpackTuple(args, "range", 2, 3,
73 &start, &stop, &step)) 78 &start, &stop, &step))
74 goto Fail; 79 goto Fail;
75 80
76 /* Convert borrowed refs to owned refs */ 81 /* Convert borrowed refs to owned refs */
77 start = PyNumber_Index(start); 82 start = PyNumber_Index(start);
78 stop = PyNumber_Index(stop); 83 stop = PyNumber_Index(stop);
79 step = validate_step(step); 84 step = validate_step(step);
80 if (!start || !stop || !step) 85 if (!start || !stop || !step)
81 goto Fail; 86 goto Fail;
82 } 87 }
83 88
89 length = range_compute_length(start, stop, step);
90 if (length == NULL)
91 goto Fail;
84 obj = PyObject_New(rangeobject, &PyRange_Type); 92 obj = PyObject_New(rangeobject, &PyRange_Type);
85 if (obj == NULL) 93 if (obj == NULL)
86 goto Fail; 94 goto Fail;
87 obj->start = start; 95 obj->start = start;
88 obj->stop = stop; 96 obj->stop = stop;
89 obj->step = step; 97 obj->step = step;
98 obj->length = length;
90 return (PyObject *) obj; 99 return (PyObject *) obj;
91 100
92 Fail: 101 Fail:
93 Py_XDECREF(start); 102 Py_XDECREF(start);
94 Py_XDECREF(stop); 103 Py_XDECREF(stop);
95 Py_XDECREF(step); 104 Py_XDECREF(step);
105 Py_XDECREF(length);
96 return NULL; 106 return NULL;
97 } 107 }
98 108
99 PyDoc_STRVAR(range_doc, 109 PyDoc_STRVAR(range_doc,
100 "range([start,] stop[, step]) -> range object\n\ 110 "range([start,] stop[, step]) -> range object\n\
101 \n\ 111 \n\
102 Returns an iterator that generates the numbers in the range on demand."); 112 Returns a virtual sequence of numbers from start to stop by step.");
103 113
104 static void 114 static void
105 range_dealloc(rangeobject *r) 115 range_dealloc(rangeobject *r)
106 { 116 {
107 Py_DECREF(r->start); 117 Py_DECREF(r->start);
108 Py_DECREF(r->stop); 118 Py_DECREF(r->stop);
109 Py_DECREF(r->step); 119 Py_DECREF(r->step);
120 Py_DECREF(r->length);
110 PyObject_Del(r); 121 PyObject_Del(r);
111 } 122 }
112 123
113 /* Return number of items in range (lo, hi, step), when arguments are 124 /* Return number of items in range (lo, hi, step), when arguments are
114 * PyInt or PyLong objects. step > 0 required. Return a value < 0 if 125 * PyInt or PyLong objects. step > 0 required. Return a value < 0 if
115 * & only if the true value is too large to fit in a signed long. 126 * & only if the true value is too large to fit in a signed long.
116 * Arguments MUST return 1 with either PyLong_Check() or 127 * Arguments MUST return 1 with either PyLong_Check() or
117 * PyLong_Check(). Return -1 when there is an error. 128 * PyLong_Check(). Return -1 when there is an error.
118 */ 129 */
119 static PyObject* 130 static PyObject *
120 range_length_obj(rangeobject *r) 131 range_compute_length(PyObject *start, PyObject *stop, PyObject *step)
121 { 132 {
122 /* ------------------------------------------------------------- 133 /* -------------------------------------------------------------
123 Algorithm is equal to that of get_len_of_range(), but it operates 134 Algorithm is equal to that of get_len_of_range(), but it operates
124 on PyObjects (which are assumed to be PyLong or PyInt objects). 135 on PyObjects (which are assumed to be PyLong or PyInt objects).
125 ---------------------------------------------------------------*/ 136 ---------------------------------------------------------------*/
126 int cmp_result, cmp_call; 137 int cmp_result, cmp_call;
127 PyObject *lo, *hi; 138 PyObject *lo, *hi;
128 PyObject *step = NULL;
129 PyObject *diff = NULL; 139 PyObject *diff = NULL;
130 PyObject *one = NULL; 140 PyObject *one = NULL;
131 PyObject *tmp1 = NULL, *tmp2 = NULL, *result; 141 PyObject *tmp1 = NULL, *tmp2 = NULL, *result;
132 /* holds sub-expression evaluations */ 142 /* holds sub-expression evaluations */
133 143
134 PyObject *zero = PyLong_FromLong(0); 144 PyObject *zero = PyLong_FromLong(0);
135 if (zero == NULL) 145 if (zero == NULL)
136 return NULL; 146 return NULL;
137 cmp_call = PyObject_Cmp(r->step, zero, &cmp_result); 147 cmp_call = PyObject_Cmp(step, zero, &cmp_result);
138 Py_DECREF(zero); 148 Py_DECREF(zero);
139 if (cmp_call == -1) 149 if (cmp_call == -1)
140 return NULL; 150 return NULL;
141 151
142 assert(cmp_result != 0); 152 assert(cmp_result != 0);
143 if (cmp_result > 0) { 153 if (cmp_result > 0) {
144 lo = r->start; 154 lo = start;
145 hi = r->stop; 155 hi = stop;
146 step = r->step;
147 Py_INCREF(step); 156 Py_INCREF(step);
148 } else { 157 } else {
149 lo = r->stop; 158 lo = stop;
150 hi = r->start; 159 hi = start;
151 step = PyNumber_Negative(r->step); 160 step = PyNumber_Negative(step);
152 if (!step) 161 if (!step)
153 return NULL; 162 goto Fail;
154 } 163 }
155 164
156 /* if (lo >= hi), return length of 0. */ 165 /* if (lo >= hi), return length of 0. */
157 if (PyObject_Compare(lo, hi) >= 0) { 166 if (PyObject_Compare(lo, hi) >= 0) {
158 Py_XDECREF(step); 167 Py_XDECREF(step);
159 return PyLong_FromLong(0); 168 return PyLong_FromLong(0);
160 } 169 }
161 170
162 if ((one = PyLong_FromLong(1L)) == NULL) 171 if ((one = PyLong_FromLong(1L)) == NULL)
163 goto Fail; 172 goto Fail;
(...skipping 22 matching lines...) Show 10 above Show 10 below
186 Py_XDECREF(diff); 195 Py_XDECREF(diff);
187 Py_XDECREF(step); 196 Py_XDECREF(step);
188 Py_XDECREF(tmp1); 197 Py_XDECREF(tmp1);
189 Py_XDECREF(one); 198 Py_XDECREF(one);
190 return NULL; 199 return NULL;
191 } 200 }
192 201
193 static Py_ssize_t 202 static Py_ssize_t
194 range_length(rangeobject *r) 203 range_length(rangeobject *r)
195 { 204 {
196 PyObject *len = range_length_obj(r); 205 return PyLong_AsSsize_t(r->length);
197 Py_ssize_t result = -1;
198 if (len) {
199 result = PyLong_AsSsize_t(len);
200 Py_DECREF(len);
201 }
202 return result;
203 } 206 }
204 207
205 /* range(...)[x] is necessary for: seq[:] = range(...) */
206
207 static PyObject *
208 range_item(rangeobject *r, Py_ssize_t i)
209 {
210 Py_ssize_t len = range_length(r);
211 PyObject *rem, *incr, *result;
212
213 /* XXX(nnorwitz): should negative indices be supported? */
214 /* XXX(nnorwitz): should support range[x] where x > PY_SSIZE_T_MAX? */
215 if (i < 0 || i >= len) {
216 if (!PyErr_Occurred())
217 PyErr_SetString(PyExc_IndexError,
218 "range object index out of range");
219 return NULL;
220 }
221
222 /* XXX(nnorwitz): optimize for short ints. */
223 rem = PyLong_FromSsize_t(i);
224 if (!rem)
225 return NULL;
226 incr = PyNumber_Multiply(rem, r->step);
227 Py_DECREF(rem);
228 if (!incr)
229 return NULL;
230 result = PyNumber_Add(r->start, incr);
231 Py_DECREF(incr);
232 return result;
233 }
234 208
235 static PyObject * 209 static PyObject *
236 range_repr(rangeobject *r) 210 range_repr(rangeobject *r)
237 { 211 {
238 Py_ssize_t istep; 212 Py_ssize_t istep;
239 213
240 /* Check for special case values for printing. We don't always 214 /* Check for special case values for printing. We don't always
241 need the step value. We don't care about errors 215 need the step value. We don't care about errors
242 (it means overflow), so clear the errors. */ 216 (it means overflow), so clear the errors. */
243 istep = PyNumber_AsSsize_t(r->step, NULL); 217 istep = PyNumber_AsSsize_t(r->step, NULL);
244 if (istep != 1 || (istep == -1 && PyErr_Occurred())) { 218 if (istep != 1 || (istep == -1 && PyErr_Occurred())) {
245 PyErr_Clear(); 219 PyErr_Clear();
246 } 220 }
247 221
248 if (istep == 1) 222 if (istep == 1)
249 return PyUnicode_FromFormat("range(%R, %R)", r->start, r->stop); 223 return PyUnicode_FromFormat("range(%R, %R)", r->start, r->stop);
250 else 224 else
251 return PyUnicode_FromFormat("range(%R, %R, %R)", 225 return PyUnicode_FromFormat("range(%R, %R, %R)",
252 r->start, r->stop, r->step); 226 r->start, r->stop, r->step);
253 } 227 }
254 228
229 static PyMemberDef range_members[] = {
230 {"start", T_OBJECT, offsetof(rangeobject, start), READONLY},
231 {"stop", T_OBJECT, offsetof(rangeobject, stop), READONLY},
232 {"step", T_OBJECT, offsetof(rangeobject, step), READONLY},
233 {0}
234 };
235
255 static PySequenceMethods range_as_sequence = { 236 static PySequenceMethods range_as_sequence = {
256 (lenfunc)range_length, /* sq_length */ 237 (lenfunc)range_length, /* sq_length */
257 0, /* sq_concat */ 238 0, /* sq_concat */
258 0, /* sq_repeat */ 239 0, /* sq_repeat */
259 (ssizeargfunc)range_item, /* sq_item */ 240 0, /* sq_item */
260 0, /* sq_slice */ 241 0, /* sq_slice */
242 0, /* sq_ass_item */
243 0, /* sq_ass_slice */
244 0, /* sq_contains */
261 }; 245 };
262 246
263 static PyObject * range_iter(PyObject *seq); 247 static PyObject * range_iter(PyObject *seq);
264 static PyObject * range_reverse(PyObject *seq); 248 static PyObject * range_reverse(PyObject *seq);
265 249
266 PyDoc_STRVAR(reverse_doc, 250 PyDoc_STRVAR(reverse_doc,
267 "Returns a reverse iterator."); 251 "Returns a reverse iterator.");
268 252
269 static PyMethodDef range_methods[] = { 253 static PyMethodDef range_methods[] = {
270 {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, 254 {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS,
271 reverse_doc}, 255 reverse_doc},
272 {NULL, NULL} /* sentinel */ 256 {NULL, NULL} /* sentinel */
273 }; 257 };
274 258
275 PyTypeObject PyRange_Type = { 259 PyTypeObject PyRange_Type = {
276 PyVarObject_HEAD_INIT(&PyType_Type, 0) 260 PyVarObject_HEAD_INIT(&PyType_Type, 0)
277 "range", /* Name of this type */ 261 "range", /* Name of this type */
278 sizeof(rangeobject), /* Basic object size */ 262 sizeof(rangeobject), /* Basic object size */
279 0, /* Item size for varobject */ 263 0, /* Item size for varobject */
280 (destructor)range_dealloc, /* tp_dealloc */ 264 (destructor)range_dealloc, /* tp_dealloc */
281 0, /* tp_print */ 265 0, /* tp_print */
282 0, /* tp_getattr */ 266 0, /* tp_getattr */
283 0, /* tp_setattr */ 267 0, /* tp_setattr */
284 0, /* tp_compare */ 268 0, /* tp_compare */
285 (reprfunc)range_repr, /* tp_repr */ 269 (reprfunc)range_repr, /* tp_repr */
286 0, /* tp_as_number */ 270 0, /* tp_as_number */
287 &range_as_sequence, /* tp_as_sequence */ 271 &range_as_sequence, /* tp_as_sequence */
288 0, /* tp_as_mapping */ 272 0, /* tp_as_mapping */
289 0, /* tp_hash */ 273 0, /* tp_hash */
290 0, /* tp_call */ 274 0, /* tp_call */
291 0, /* tp_str */ 275 0, /* tp_str */
292 PyObject_GenericGetAttr, /* tp_getattro */ 276 PyObject_GenericGetAttr, /* tp_getattro */
293 0, /* tp_setattro */ 277 0, /* tp_setattro */
294 0, /* tp_as_buffer */ 278 0, /* tp_as_buffer */
295 Py_TPFLAGS_DEFAULT, /* tp_flags */ 279 Py_TPFLAGS_DEFAULT, /* tp_flags */
296 range_doc, /* tp_doc */ 280 range_doc, /* tp_doc */
297 0, /* tp_traverse */ 281 0, /* tp_traverse */
298 0, /* tp_clear */ 282 0, /* tp_clear */
299 0, /* tp_richcompare */ 283 0, /* tp_richcompare */
300 0, /* tp_weaklistoffset */ 284 0, /* tp_weaklistoffset */
301 range_iter, /* tp_iter */ 285 range_iter, /* tp_iter */
302 0, /* tp_iternext */ 286 0, /* tp_iternext */
303 range_methods, /* tp_methods */ 287 range_methods, /* tp_methods */
304 0, »»/* tp_members */ 288 range_members,»»/* tp_members */
mvloewis 2008/05/02 20:17:20 Carrying forward from the previous patch set: this
305 0, /* tp_getset */ 289 0, /* tp_getset */
306 0, /* tp_base */ 290 0, /* tp_base */
307 0, /* tp_dict */ 291 0, /* tp_dict */
308 0, /* tp_descr_get */ 292 0, /* tp_descr_get */
309 0, /* tp_descr_set */ 293 0, /* tp_descr_set */
310 0, /* tp_dictoffset */ 294 0, /* tp_dictoffset */
311 0, /* tp_init */ 295 0, /* tp_init */
312 0, /* tp_alloc */ 296 0, /* tp_alloc */
313 range_new, /* tp_new */ 297 range_new, /* tp_new */
314 }; 298 };
315 299
(...skipping 324 matching lines...) Show 10 above Show 10 below
640 } 624 }
641 } 625 }
642 } 626 }
643 PyErr_Clear(); 627 PyErr_Clear();
644 628
645 it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type); 629 it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
646 if (it == NULL) 630 if (it == NULL)
647 return NULL; 631 return NULL;
648 632
649 /* start + (len - 1) * step */ 633 /* start + (len - 1) * step */
650 len = range_length_obj(range); 634 len = range->length;
mvloewis 2008/05/02 20:17:20 You need to INCREF, since you are a) going to DECR
651 if (!len)
652 goto create_failure;
653 635
654 one = PyLong_FromLong(1); 636 one = PyLong_FromLong(1);
655 if (!one) 637 if (!one)
656 goto create_failure; 638 goto create_failure;
657 639
658 diff = PyNumber_Subtract(len, one); 640 diff = PyNumber_Subtract(len, one);
659 Py_DECREF(one); 641 Py_DECREF(one);
660 if (!diff) 642 if (!diff)
661 goto create_failure; 643 goto create_failure;
662 644
(...skipping 22 matching lines...) Show 10 above Show 10 below
685 return NULL; 667 return NULL;
686 } 668 }
687 669
688 return (PyObject *)it; 670 return (PyObject *)it;
689 671
690 create_failure: 672 create_failure:
691 Py_XDECREF(len); 673 Py_XDECREF(len);
692 PyObject_Del(it); 674 PyObject_Del(it);
693 return NULL; 675 return NULL;
694 } 676 }
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld r338