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

Delta Between Two Patch Sets: Objects/rangeobject.c

Issue 602: range: lean and mean (Closed) SVN Base: http://svn.python.org/view/*checkout*/python/branches/py3k/
Left Patch Set: Created 1 year, 7 months ago , Downloaded from: http://bugs.python.org/file10152/range_lean_and_mean.patch
Right Patch Set: address more concerns Created 1 year, 7 months ago , Downloaded from: http://bugs.python.org/file10183/range_lean_and_mean5.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:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
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;
17 PyObject *length; 18 PyObject *length;
mvloewis_gmail.com 2008/05/02 05:43:57 What is the purpose of caching the length in the r
GvR 2008/05/02 13:52:47 On 2008/05/02 05:43:57, mvloewis wrote: > What is
Benjamin 2008/05/02 16:56:18 On 2008/05/02 05:43:57, mvloewis wrote: > What is
18 } rangeobject; 19 } rangeobject;
19 20
20 /* Helper function for validating step. Always returns a new reference or 21 /* Helper function for validating step. Always returns a new reference or
21 NULL on error. 22 NULL on error.
22 */ 23 */
23 static PyObject * 24 static PyObject *
24 validate_step(PyObject *step) 25 validate_step(PyObject *step)
25 { 26 {
26 /* No step specified, use a step of 1. */ 27 /* No step specified, use a step of 1. */
27 if (!step) 28 if (!step)
(...skipping 10 matching lines...) Expand all
38 PyErr_SetString(PyExc_ValueError, 39 PyErr_SetString(PyExc_ValueError,
39 "range() arg 3 must not be zero"); 40 "range() arg 3 must not be zero");
40 Py_CLEAR(step); 41 Py_CLEAR(step);
41 } 42 }
42 } 43 }
43 44
44 return step; 45 return step;
45 } 46 }
46 47
47 static PyObject* range_compute_length(PyObject *start, 48 static PyObject* range_compute_length(PyObject *start,
48 » » » » PyObject *stop, PyObject *step); 49 PyObject *stop, PyObject *step);
GvR 2008/05/02 13:52:47 This line is indented one space too many.
49 50
50 /* 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?
51 range(-10) 52 range(-10)
52 range(0, -5) 53 range(0, -5)
53 range(0, 5, -1) 54 range(0, 5, -1)
54 */ 55 */
55 static PyObject * 56 static PyObject *
56 range_new(PyTypeObject *type, PyObject *args, PyObject *kw) 57 range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
57 { 58 {
58 rangeobject *obj = NULL; 59 rangeobject *obj = NULL;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 Py_XDECREF(start); 102 Py_XDECREF(start);
102 Py_XDECREF(stop); 103 Py_XDECREF(stop);
103 Py_XDECREF(step); 104 Py_XDECREF(step);
104 Py_XDECREF(length); 105 Py_XDECREF(length);
105 return NULL; 106 return NULL;
106 } 107 }
107 108
108 PyDoc_STRVAR(range_doc, 109 PyDoc_STRVAR(range_doc,
109 "range([start,] stop[, step]) -> range object\n\ 110 "range([start,] stop[, step]) -> range object\n\
110 \n\ 111 \n\
111 Returns a virtual sequence of numbers from start to stop by step."); 112 Return an arithmetic progression of numbers from start "
GvR 2008/05/02 13:52:47 I really don't want to use the word sequence here.
113 "to stop (exclusive) by step.");
112 114
113 static void 115 static void
114 range_dealloc(rangeobject *r) 116 range_dealloc(rangeobject *r)
115 { 117 {
116 Py_DECREF(r->start); 118 Py_DECREF(r->start);
117 Py_DECREF(r->stop); 119 Py_DECREF(r->stop);
118 Py_DECREF(r->step); 120 Py_DECREF(r->step);
119 Py_DECREF(r->length); 121 Py_DECREF(r->length);
120 PyObject_Del(r); 122 PyObject_Del(r);
121 } 123 }
122 124
123 /* Return number of items in range (lo, hi, step), when arguments are 125 /*Return number of items in range (lo, hi, step), when arguments are
124 * PyInt or PyLong objects. step > 0 required. Return a value < 0 if 126 * PyLong objects. step > 0 required. Return a PyLong with the length.
125 * & only if the true value is too large to fit in a signed long. 127 * Return NULL when there is an error.*/
126 * Arguments MUST return 1 with either PyLong_Check() or
127 * PyLong_Check(). Return -1 when there is an error.
GvR 2008/05/02 13:52:47 Not your fault, but this comment still references
128 */
129 static PyObject * 128 static PyObject *
130 range_compute_length(PyObject *start, PyObject *stop, PyObject *step) 129 range_compute_length(PyObject *start, PyObject *stop, PyObject *step)
131 { 130 {
132 /* ------------------------------------------------------------- 131 /* -------------------------------------------------------------
133 Algorithm is equal to that of get_len_of_range(), but it operates 132 Algorithm is equal to that of get_len_of_range(), but it operates
134 on PyObjects (which are assumed to be PyLong or PyInt objects). 133 on PyObjects (which are assumed to be PyLong or PyInt objects).
135 ---------------------------------------------------------------*/ 134 ---------------------------------------------------------------*/
136 int cmp_result, cmp_call; 135 int cmp_result, cmp_call;
137 PyObject *lo, *hi; 136 PyObject *lo, *hi;
138 PyObject *diff = NULL; 137 PyObject *diff = NULL;
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 PyErr_Clear(); 217 PyErr_Clear();
219 } 218 }
220 219
221 if (istep == 1) 220 if (istep == 1)
222 return PyUnicode_FromFormat("range(%R, %R)", r->start, r->stop); 221 return PyUnicode_FromFormat("range(%R, %R)", r->start, r->stop);
223 else 222 else
224 return PyUnicode_FromFormat("range(%R, %R, %R)", 223 return PyUnicode_FromFormat("range(%R, %R, %R)",
225 r->start, r->stop, r->step); 224 r->start, r->stop, r->step);
226 } 225 }
227 226
228 static PyObject * 227 static PyMemberDef range_members[] = {
229 range_getstart(rangeobject *obj) 228 {"start", T_OBJECT, offsetof(rangeobject, start), READONLY},
230 { 229 {"stop", T_OBJECT, offsetof(rangeobject, stop), READONLY},
231 return obj->start; 230 {"step", T_OBJECT, offsetof(rangeobject, step), READONLY},
232 } 231 {0}
233
234 static PyObject *
235 range_getstop(rangeobject *obj)
236 {
237 return obj->stop;
238 }
239
240 static PyObject *
241 range_getstep(rangeobject *obj)
242 {
243 return obj->step;
244 }
245
246 static PyGetSetDef range_getset[] = {
247 {"start", (getter)range_getstart, NULL, "The start of the range"},
248 {"stop", (getter)range_getstop, NULL, "Where the range stops."},
249 {"step", (getter)range_getstep, NULL, "How much the range jumps."},
250 {0},
251 };
252
253 static PySequenceMethods range_as_sequence = {
254 (lenfunc)range_length,» /* sq_length */
GvR 2008/05/02 13:52:47 The latest discussion on the list suggests to remo
255 0,» » » /* sq_concat */
256 0,» » » /* sq_repeat */
257 0, /* sq_item */
258 0,» » » /* sq_slice */
259 0, /* sq_ass_item */
260 0, /* sq_ass_slice */
261 0, /* sq_contains */
262 }; 232 };
263 233
264 static PyObject * range_iter(PyObject *seq); 234 static PyObject * range_iter(PyObject *seq);
265 static PyObject * range_reverse(PyObject *seq); 235 static PyObject * range_reverse(PyObject *seq);
266 236
267 PyDoc_STRVAR(reverse_doc, 237 PyDoc_STRVAR(reverse_doc,
268 "Returns a reverse iterator."); 238 "Returns a reverse iterator.");
239
240 static PySequenceMethods range_as_sequence = {
241 (lenfunc)range_length, /* sq_length */
242 0, /* sq_concat */
243 0, /* sq_repeat */
244 0, /* sq_item */
245 0, /* sq_slice */
246 0, /* sq_ass_item */
247 0, /* sq_ass_slice */
248 0, /* sq_contains */
249 0, /* sq_inplace_concat */
250 0, /* sq_inplace_repeat */
251 };
269 252
270 static PyMethodDef range_methods[] = { 253 static PyMethodDef range_methods[] = {
271 {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, 254 {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS,
272 reverse_doc}, 255 reverse_doc},
273 {NULL, NULL} /* sentinel */ 256 {NULL, NULL} /* sentinel */
274 }; 257 };
275 258
276 PyTypeObject PyRange_Type = { 259 PyTypeObject PyRange_Type = {
277 PyVarObject_HEAD_INIT(&PyType_Type, 0) 260 PyVarObject_HEAD_INIT(&PyType_Type, 0)
278 "range", /* Name of this type */ 261 "range", /* Name of this type */
279 sizeof(rangeobject), /* Basic object size */ 262 sizeof(rangeobject), /* Basic object size */
280 0, /* Item size for varobject */ 263 0, /* Item size for varobject */
281 (destructor)range_dealloc, /* tp_dealloc */ 264 (destructor)range_dealloc, /* tp_dealloc */
282 0, /* tp_print */ 265 0, /* tp_print */
283 0, /* tp_getattr */ 266 0, /* tp_getattr */
284 0, /* tp_setattr */ 267 0, /* tp_setattr */
285 0, /* tp_compare */ 268 0, /* tp_compare */
286 (reprfunc)range_repr, /* tp_repr */ 269 (reprfunc)range_repr, /* tp_repr */
287 0, /* tp_as_number */ 270 0, /* tp_as_number */
288 » &range_as_sequence,» /* tp_as_sequence */ 271 » &range_as_sequence, /* tp_as_sequence */
289 0, /* tp_as_mapping */ 272 0, /* tp_as_mapping */
290 0, /* tp_hash */ 273 0, /* tp_hash */
291 0, /* tp_call */ 274 0, /* tp_call */
292 0, /* tp_str */ 275 0, /* tp_str */
293 PyObject_GenericGetAttr, /* tp_getattro */ 276 PyObject_GenericGetAttr, /* tp_getattro */
294 0, /* tp_setattro */ 277 0, /* tp_setattro */
295 0, /* tp_as_buffer */ 278 0, /* tp_as_buffer */
296 Py_TPFLAGS_DEFAULT, /* tp_flags */ 279 Py_TPFLAGS_DEFAULT, /* tp_flags */
297 range_doc, /* tp_doc */ 280 range_doc, /* tp_doc */
298 0, /* tp_traverse */ 281 0, /* tp_traverse */
299 0, /* tp_clear */ 282 0, /* tp_clear */
300 0, /* tp_richcompare */ 283 0, /* tp_richcompare */
301 0, /* tp_weaklistoffset */ 284 0, /* tp_weaklistoffset */
302 range_iter, /* tp_iter */ 285 range_iter, /* tp_iter */
303 0, /* tp_iternext */ 286 0, /* tp_iternext */
304 range_methods, /* tp_methods */ 287 range_methods, /* tp_methods */
305 » 0,» » » /* tp_members */ 288 » range_members, /* tp_members */
306 » range_getset,» » /* tp_getset */ 289 » 0, /* tp_getset */
GvR 2008/05/02 13:52:47 Please use spaces to indent the comment.
307 0, /* tp_base */ 290 0, /* tp_base */
308 0, /* tp_dict */ 291 0, /* tp_dict */
309 0, /* tp_descr_get */ 292 0, /* tp_descr_get */
310 0, /* tp_descr_set */ 293 0, /* tp_descr_set */
311 0, /* tp_dictoffset */ 294 0, /* tp_dictoffset */
312 0, /* tp_init */ 295 0, /* tp_init */
313 0, /* tp_alloc */ 296 0, /* tp_alloc */
314 range_new, /* tp_new */ 297 range_new, /* tp_new */
315 }; 298 };
316 299
(...skipping 24 matching lines...) Expand all
341 rangeiter_len(rangeiterobject *r) 324 rangeiter_len(rangeiterobject *r)
342 { 325 {
343 return PyLong_FromLong(r->len - r->index); 326 return PyLong_FromLong(r->len - r->index);
344 } 327 }
345 328
346 typedef struct { 329 typedef struct {
347 PyObject_HEAD 330 PyObject_HEAD
348 PyObject *index; 331 PyObject *index;
349 PyObject *start; 332 PyObject *start;
350 PyObject *step; 333 PyObject *step;
351 PyObject *len; 334 PyObject *length;
352 } longrangeiterobject; 335 } longrangeiterobject;
353 336
354 static PyObject * 337 static PyObject *
355 longrangeiter_len(longrangeiterobject *r, PyObject *no_args) 338 longrangeiter_len(longrangeiterobject *r, PyObject *no_args)
356 { 339 {
357 return PyNumber_Subtract(r->len, r->index); 340 return PyNumber_Subtract(r->length, r->index);
358 } 341 }
359 342
360 static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw); 343 static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw);
361 344
362 PyDoc_STRVAR(length_hint_doc, 345 PyDoc_STRVAR(length_hint_doc,
363 "Private method returning an estimate of len(list(it))."); 346 "Private method returning an estimate of len(list(it)).");
364 347
365 static PyMethodDef rangeiter_methods[] = { 348 static PyMethodDef rangeiter_methods[] = {
366 {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS, 349 {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS,
367 length_hint_doc}, 350 length_hint_doc},
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 length_hint_doc}, 458 length_hint_doc},
476 {NULL, NULL} /* sentinel */ 459 {NULL, NULL} /* sentinel */
477 }; 460 };
478 461
479 static void 462 static void
480 longrangeiter_dealloc(longrangeiterobject *r) 463 longrangeiter_dealloc(longrangeiterobject *r)
481 { 464 {
482 Py_XDECREF(r->index); 465 Py_XDECREF(r->index);
483 Py_XDECREF(r->start); 466 Py_XDECREF(r->start);
484 Py_XDECREF(r->step); 467 Py_XDECREF(r->step);
485 Py_XDECREF(r->len); 468 Py_XDECREF(r->length);
486 PyObject_Del(r); 469 PyObject_Del(r);
487 } 470 }
488 471
489 static PyObject * 472 static PyObject *
490 longrangeiter_next(longrangeiterobject *r) 473 longrangeiter_next(longrangeiterobject *r)
491 { 474 {
492 PyObject *one, *product, *new_index, *result; 475 PyObject *one, *product, *new_index, *result;
493 if (PyObject_RichCompareBool(r->index, r->len, Py_LT) != 1) 476 if (PyObject_RichCompareBool(r->index, r->length, Py_LT) != 1)
494 return NULL; 477 return NULL;
495 478
496 one = PyLong_FromLong(1); 479 one = PyLong_FromLong(1);
497 if (!one) 480 if (!one)
498 return NULL; 481 return NULL;
499 482
500 product = PyNumber_Multiply(r->index, r->step); 483 product = PyNumber_Multiply(r->index, r->step);
501 if (!product) { 484 if (!product) {
502 Py_DECREF(one); 485 Py_DECREF(one);
503 return NULL; 486 return NULL;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
551 (iternextfunc)longrangeiter_next, /* tp_iternext */ 534 (iternextfunc)longrangeiter_next, /* tp_iternext */
552 longrangeiter_methods, /* tp_methods */ 535 longrangeiter_methods, /* tp_methods */
553 0, 536 0,
554 }; 537 };
555 538
556 static PyObject * 539 static PyObject *
557 range_iter(PyObject *seq) 540 range_iter(PyObject *seq)
558 { 541 {
559 rangeobject *r = (rangeobject *)seq; 542 rangeobject *r = (rangeobject *)seq;
560 longrangeiterobject *it; 543 longrangeiterobject *it;
561 PyObject *tmp, *len;
562 long lstart, lstop, lstep; 544 long lstart, lstop, lstep;
563 545
564 assert(PyRange_Check(seq)); 546 assert(PyRange_Check(seq));
565 547
566 /* If all three fields convert to long, use the int version */ 548 /* If all three fields convert to long, use the int version */
567 lstart = PyLong_AsLong(r->start); 549 lstart = PyLong_AsLong(r->start);
568 if (lstart != -1 || !PyErr_Occurred()) { 550 if (lstart != -1 || !PyErr_Occurred()) {
569 lstop = PyLong_AsLong(r->stop); 551 lstop = PyLong_AsLong(r->stop);
570 if (lstop != -1 || !PyErr_Occurred()) { 552 if (lstop != -1 || !PyErr_Occurred()) {
571 lstep = PyLong_AsLong(r->step); 553 lstep = PyLong_AsLong(r->step);
572 if (lstep != -1 || !PyErr_Occurred()) 554 if (lstep != -1 || !PyErr_Occurred())
573 return int_range_iter(lstart, lstop, lstep); 555 return int_range_iter(lstart, lstop, lstep);
574 } 556 }
575 } 557 }
576 /* Some conversion failed, so there is an error set. Clear it, 558 /* Some conversion failed, so there is an error set. Clear it,
577 and try again with a long range. */ 559 and try again with a long range. */
578 PyErr_Clear(); 560 PyErr_Clear();
579 561
580 it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type); 562 it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
581 if (it == NULL) 563 if (it == NULL)
582 return NULL; 564 return NULL;
583 565
584 /* Do all initialization here, so we can DECREF on failure. */ 566 /* Do all initialization here, so we can DECREF on failure. */
585 it->start = r->start; 567 it->start = r->start;
586 it->step = r->step; 568 it->step = r->step;
587 Py_INCREF(it->start); 569 Py_INCREF(it->start);
588 Py_INCREF(it->step); 570 Py_INCREF(it->step);
589 571
590 it->len = it->index = NULL; 572 Py_INCREF(r->length);
591 573 it->length = r->length;
592 /* Calculate length: (r->stop - r->start) / r->step */
593 tmp = PyNumber_Subtract(r->stop, r->start);
594 if (!tmp)
595 goto create_failure;
596 len = PyNumber_FloorDivide(tmp, r->step);
597 Py_DECREF(tmp);
598 if (!len)
599 goto create_failure;
600 it->len = len;
601 it->index = PyLong_FromLong(0); 574 it->index = PyLong_FromLong(0);
602 if (!it->index) 575 if (it->index == NULL)
603 goto create_failure; 576 goto create_failure;
604 577
605 return (PyObject *)it; 578 return (PyObject *)it;
606 579
607 create_failure: 580 create_failure:
608 Py_DECREF(it); 581 Py_DECREF(it);
609 return NULL; 582 return NULL;
610 } 583 }
611 584
612 static PyObject * 585 static PyObject *
(...skipping 28 matching lines...) Expand all
641 } 614 }
642 } 615 }
643 } 616 }
644 PyErr_Clear(); 617 PyErr_Clear();
645 618
646 it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type); 619 it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
647 if (it == NULL) 620 if (it == NULL)
648 return NULL; 621 return NULL;
649 622
650 /* start + (len - 1) * step */ 623 /* start + (len - 1) * step */
624 Py_INCREF(range->length);
651 len = range->length; 625 len = range->length;
652 626
653 one = PyLong_FromLong(1); 627 one = PyLong_FromLong(1);
654 if (!one) 628 if (!one)
655 goto create_failure; 629 goto create_failure;
656 630
657 diff = PyNumber_Subtract(len, one); 631 diff = PyNumber_Subtract(len, one);
658 Py_DECREF(one); 632 Py_DECREF(one);
659 if (!diff) 633 if (!diff)
660 goto create_failure; 634 goto create_failure;
661 635
662 product = PyNumber_Multiply(len, range->step); 636 product = PyNumber_Multiply(len, range->step);
663 if (!product) 637 if (!product)
664 goto create_failure; 638 goto create_failure;
665 639
666 sum = PyNumber_Add(range->start, product); 640 sum = PyNumber_Add(range->start, product);
667 Py_DECREF(product); 641 Py_DECREF(product);
668 it->start = sum; 642 it->start = sum;
669 if (!it->start) 643 if (!it->start)
670 goto create_failure; 644 goto create_failure;
671 it->step = PyNumber_Negative(range->step); 645 it->step = PyNumber_Negative(range->step);
672 if (!it->step) { 646 if (!it->step) {
673 Py_DECREF(it->start); 647 Py_DECREF(it->start);
674 PyObject_Del(it); 648 PyObject_Del(it);
675 return NULL; 649 return NULL;
676 } 650 }
677 651
678 /* Steal reference to len. */ 652 /* Steal reference to len. */
679 it->len = len; 653 it->length = len;
680 654
681 it->index = PyLong_FromLong(0); 655 it->index = PyLong_FromLong(0);
682 if (!it->index) { 656 if (!it->index) {
683 Py_DECREF(it); 657 Py_DECREF(it);
684 return NULL; 658 return NULL;
685 } 659 }
686 660
687 return (PyObject *)it; 661 return (PyObject *)it;
688 662
689 create_failure: 663 create_failure:
690 Py_XDECREF(len); 664 Py_XDECREF(len);
691 PyObject_Del(it); 665 PyObject_Del(it);
692 return NULL; 666 return NULL;
693 } 667 }
LEFTRIGHT

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