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

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: use PyMemberDef Created 1 year, 6 months ago , Downloaded from: http://bugs.python.org/file10155/range_lean_and_mean2.patch
Right Patch Set: address more concerns Created 1 year, 6 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 #include "structmember.h"
5 5
6 /* Support objects whose length is > PY_SSIZE_T_MAX. 6 /* Support objects whose length is > PY_SSIZE_T_MAX.
7 7
8 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.
9 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
10 would presumably help perf. 10 would presumably help perf.
(...skipping 28 matching lines...) Expand all
39 PyErr_SetString(PyExc_ValueError, 39 PyErr_SetString(PyExc_ValueError,
40 "range() arg 3 must not be zero"); 40 "range() arg 3 must not be zero");
41 Py_CLEAR(step); 41 Py_CLEAR(step);
42 } 42 }
43 } 43 }
44 44
45 return step; 45 return step;
46 } 46 }
47 47
48 static PyObject* range_compute_length(PyObject *start, 48 static PyObject* range_compute_length(PyObject *start,
49 » » » » PyObject *stop, PyObject *step); 49 PyObject *stop, PyObject *step);
50 50
51 /* 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?
52 range(-10) 52 range(-10)
53 range(0, -5) 53 range(0, -5)
54 range(0, 5, -1) 54 range(0, 5, -1)
55 */ 55 */
56 static PyObject * 56 static PyObject *
57 range_new(PyTypeObject *type, PyObject *args, PyObject *kw) 57 range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
58 { 58 {
59 rangeobject *obj = NULL; 59 rangeobject *obj = NULL;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 Py_XDECREF(start); 102 Py_XDECREF(start);
103 Py_XDECREF(stop); 103 Py_XDECREF(stop);
104 Py_XDECREF(step); 104 Py_XDECREF(step);
105 Py_XDECREF(length); 105 Py_XDECREF(length);
106 return NULL; 106 return NULL;
107 } 107 }
108 108
109 PyDoc_STRVAR(range_doc, 109 PyDoc_STRVAR(range_doc,
110 "range([start,] stop[, step]) -> range object\n\ 110 "range([start,] stop[, step]) -> range object\n\
111 \n\ 111 \n\
112 Returns a virtual sequence of numbers from start to stop by step."); 112 Return an arithmetic progression of numbers from start "
113 "to stop (exclusive) by step.");
113 114
114 static void 115 static void
115 range_dealloc(rangeobject *r) 116 range_dealloc(rangeobject *r)
116 { 117 {
117 Py_DECREF(r->start); 118 Py_DECREF(r->start);
118 Py_DECREF(r->stop); 119 Py_DECREF(r->stop);
119 Py_DECREF(r->step); 120 Py_DECREF(r->step);
120 Py_DECREF(r->length); 121 Py_DECREF(r->length);
121 PyObject_Del(r); 122 PyObject_Del(r);
122 } 123 }
123 124
124 /* 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
125 * PyInt or PyLong objects. step > 0 required. Return a value < 0 if 126 * PyLong objects. step > 0 required. Return a PyLong with the length.
126 * & only if the true value is too large to fit in a signed long. 127 * Return NULL when there is an error.*/
127 * Arguments MUST return 1 with either PyLong_Check() or
128 * PyLong_Check(). Return -1 when there is an error.
129 */
130 static PyObject * 128 static PyObject *
131 range_compute_length(PyObject *start, PyObject *stop, PyObject *step) 129 range_compute_length(PyObject *start, PyObject *stop, PyObject *step)
132 { 130 {
133 /* ------------------------------------------------------------- 131 /* -------------------------------------------------------------
134 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
135 on PyObjects (which are assumed to be PyLong or PyInt objects). 133 on PyObjects (which are assumed to be PyLong or PyInt objects).
136 ---------------------------------------------------------------*/ 134 ---------------------------------------------------------------*/
137 int cmp_result, cmp_call; 135 int cmp_result, cmp_call;
138 PyObject *lo, *hi; 136 PyObject *lo, *hi;
139 PyObject *diff = NULL; 137 PyObject *diff = NULL;
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 r->start, r->stop, r->step); 224 r->start, r->stop, r->step);
227 } 225 }
228 226
229 static PyMemberDef range_members[] = { 227 static PyMemberDef range_members[] = {
230 {"start", T_OBJECT, offsetof(rangeobject, start), READONLY}, 228 {"start", T_OBJECT, offsetof(rangeobject, start), READONLY},
231 {"stop", T_OBJECT, offsetof(rangeobject, stop), READONLY}, 229 {"stop", T_OBJECT, offsetof(rangeobject, stop), READONLY},
232 {"step", T_OBJECT, offsetof(rangeobject, step), READONLY}, 230 {"step", T_OBJECT, offsetof(rangeobject, step), READONLY},
233 {0} 231 {0}
234 }; 232 };
235 233
236 static PySequenceMethods range_as_sequence = {
237 (lenfunc)range_length, /* sq_length */
238 0, /* sq_concat */
239 0, /* sq_repeat */
240 0, /* sq_item */
241 0, /* sq_slice */
242 0, /* sq_ass_item */
243 0, /* sq_ass_slice */
244 0, /* sq_contains */
245 };
246
247 static PyObject * range_iter(PyObject *seq); 234 static PyObject * range_iter(PyObject *seq);
248 static PyObject * range_reverse(PyObject *seq); 235 static PyObject * range_reverse(PyObject *seq);
249 236
250 PyDoc_STRVAR(reverse_doc, 237 PyDoc_STRVAR(reverse_doc,
251 "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 };
252 252
253 static PyMethodDef range_methods[] = { 253 static PyMethodDef range_methods[] = {
254 {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, 254 {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS,
255 reverse_doc}, 255 reverse_doc},
256 {NULL, NULL} /* sentinel */ 256 {NULL, NULL} /* sentinel */
257 }; 257 };
258 258
259 PyTypeObject PyRange_Type = { 259 PyTypeObject PyRange_Type = {
260 PyVarObject_HEAD_INIT(&PyType_Type, 0) 260 PyVarObject_HEAD_INIT(&PyType_Type, 0)
261 "range", /* Name of this type */ 261 "range", /* Name of this type */
262 sizeof(rangeobject), /* Basic object size */ 262 sizeof(rangeobject), /* Basic object size */
263 0, /* Item size for varobject */ 263 0, /* Item size for varobject */
264 (destructor)range_dealloc, /* tp_dealloc */ 264 (destructor)range_dealloc, /* tp_dealloc */
265 0, /* tp_print */ 265 0, /* tp_print */
266 0, /* tp_getattr */ 266 0, /* tp_getattr */
267 0, /* tp_setattr */ 267 0, /* tp_setattr */
268 0, /* tp_compare */ 268 0, /* tp_compare */
269 (reprfunc)range_repr, /* tp_repr */ 269 (reprfunc)range_repr, /* tp_repr */
270 0, /* tp_as_number */ 270 0, /* tp_as_number */
271 » &range_as_sequence,» /* tp_as_sequence */ 271 » &range_as_sequence, /* tp_as_sequence */
272 0, /* tp_as_mapping */ 272 0, /* tp_as_mapping */
273 0, /* tp_hash */ 273 0, /* tp_hash */
274 0, /* tp_call */ 274 0, /* tp_call */
275 0, /* tp_str */ 275 0, /* tp_str */
276 PyObject_GenericGetAttr, /* tp_getattro */ 276 PyObject_GenericGetAttr, /* tp_getattro */
277 0, /* tp_setattro */ 277 0, /* tp_setattro */
278 0, /* tp_as_buffer */ 278 0, /* tp_as_buffer */
279 Py_TPFLAGS_DEFAULT, /* tp_flags */ 279 Py_TPFLAGS_DEFAULT, /* tp_flags */
280 range_doc, /* tp_doc */ 280 range_doc, /* tp_doc */
281 0, /* tp_traverse */ 281 0, /* tp_traverse */
282 0, /* tp_clear */ 282 0, /* tp_clear */
283 0, /* tp_richcompare */ 283 0, /* tp_richcompare */
284 0, /* tp_weaklistoffset */ 284 0, /* tp_weaklistoffset */
285 range_iter, /* tp_iter */ 285 range_iter, /* tp_iter */
286 0, /* tp_iternext */ 286 0, /* tp_iternext */
287 range_methods, /* tp_methods */ 287 range_methods, /* tp_methods */
288 » range_members,» » /* tp_members */ 288 » range_members, /* tp_members */
mvloewis_gmail.com 2008/05/02 20:17:20 Carrying forward from the previous patch set: this
289 0, /* tp_getset */ 289 0, /* tp_getset */
290 0, /* tp_base */ 290 0, /* tp_base */
291 0, /* tp_dict */ 291 0, /* tp_dict */
292 0, /* tp_descr_get */ 292 0, /* tp_descr_get */
293 0, /* tp_descr_set */ 293 0, /* tp_descr_set */
294 0, /* tp_dictoffset */ 294 0, /* tp_dictoffset */
295 0, /* tp_init */ 295 0, /* tp_init */
296 0, /* tp_alloc */ 296 0, /* tp_alloc */
297 range_new, /* tp_new */ 297 range_new, /* tp_new */
298 }; 298 };
(...skipping 25 matching lines...) Expand all
324 rangeiter_len(rangeiterobject *r) 324 rangeiter_len(rangeiterobject *r)
325 { 325 {
326 return PyLong_FromLong(r->len - r->index); 326 return PyLong_FromLong(r->len - r->index);
327 } 327 }
328 328
329 typedef struct { 329 typedef struct {
330 PyObject_HEAD 330 PyObject_HEAD
331 PyObject *index; 331 PyObject *index;
332 PyObject *start; 332 PyObject *start;
333 PyObject *step; 333 PyObject *step;
334 PyObject *len; 334 PyObject *length;
335 } longrangeiterobject; 335 } longrangeiterobject;
336 336
337 static PyObject * 337 static PyObject *
338 longrangeiter_len(longrangeiterobject *r, PyObject *no_args) 338 longrangeiter_len(longrangeiterobject *r, PyObject *no_args)
339 { 339 {
340 return PyNumber_Subtract(r->len, r->index); 340 return PyNumber_Subtract(r->length, r->index);
341 } 341 }
342 342
343 static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw); 343 static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw);
344 344
345 PyDoc_STRVAR(length_hint_doc, 345 PyDoc_STRVAR(length_hint_doc,
346 "Private method returning an estimate of len(list(it))."); 346 "Private method returning an estimate of len(list(it)).");
347 347
348 static PyMethodDef rangeiter_methods[] = { 348 static PyMethodDef rangeiter_methods[] = {
349 {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS, 349 {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS,
350 length_hint_doc}, 350 length_hint_doc},
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 length_hint_doc}, 458 length_hint_doc},
459 {NULL, NULL} /* sentinel */ 459 {NULL, NULL} /* sentinel */
460 }; 460 };
461 461
462 static void 462 static void
463 longrangeiter_dealloc(longrangeiterobject *r) 463 longrangeiter_dealloc(longrangeiterobject *r)
464 { 464 {
465 Py_XDECREF(r->index); 465 Py_XDECREF(r->index);
466 Py_XDECREF(r->start); 466 Py_XDECREF(r->start);
467 Py_XDECREF(r->step); 467 Py_XDECREF(r->step);
468 Py_XDECREF(r->len); 468 Py_XDECREF(r->length);
469 PyObject_Del(r); 469 PyObject_Del(r);
470 } 470 }
471 471
472 static PyObject * 472 static PyObject *
473 longrangeiter_next(longrangeiterobject *r) 473 longrangeiter_next(longrangeiterobject *r)
474 { 474 {
475 PyObject *one, *product, *new_index, *result; 475 PyObject *one, *product, *new_index, *result;
476 if (PyObject_RichCompareBool(r->index, r->len, Py_LT) != 1) 476 if (PyObject_RichCompareBool(r->index, r->length, Py_LT) != 1)
477 return NULL; 477 return NULL;
478 478
479 one = PyLong_FromLong(1); 479 one = PyLong_FromLong(1);
480 if (!one) 480 if (!one)
481 return NULL; 481 return NULL;
482 482
483 product = PyNumber_Multiply(r->index, r->step); 483 product = PyNumber_Multiply(r->index, r->step);
484 if (!product) { 484 if (!product) {
485 Py_DECREF(one); 485 Py_DECREF(one);
486 return NULL; 486 return NULL;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 (iternextfunc)longrangeiter_next, /* tp_iternext */ 534 (iternextfunc)longrangeiter_next, /* tp_iternext */
535 longrangeiter_methods, /* tp_methods */ 535 longrangeiter_methods, /* tp_methods */
536 0, 536 0,
537 }; 537 };
538 538
539 static PyObject * 539 static PyObject *
540 range_iter(PyObject *seq) 540 range_iter(PyObject *seq)
541 { 541 {
542 rangeobject *r = (rangeobject *)seq; 542 rangeobject *r = (rangeobject *)seq;
543 longrangeiterobject *it; 543 longrangeiterobject *it;
544 PyObject *tmp, *len;
545 long lstart, lstop, lstep; 544 long lstart, lstop, lstep;
546 545
547 assert(PyRange_Check(seq)); 546 assert(PyRange_Check(seq));
548 547
549 /* If all three fields convert to long, use the int version */ 548 /* If all three fields convert to long, use the int version */
550 lstart = PyLong_AsLong(r->start); 549 lstart = PyLong_AsLong(r->start);
551 if (lstart != -1 || !PyErr_Occurred()) { 550 if (lstart != -1 || !PyErr_Occurred()) {
552 lstop = PyLong_AsLong(r->stop); 551 lstop = PyLong_AsLong(r->stop);
553 if (lstop != -1 || !PyErr_Occurred()) { 552 if (lstop != -1 || !PyErr_Occurred()) {
554 lstep = PyLong_AsLong(r->step); 553 lstep = PyLong_AsLong(r->step);
555 if (lstep != -1 || !PyErr_Occurred()) 554 if (lstep != -1 || !PyErr_Occurred())
556 return int_range_iter(lstart, lstop, lstep); 555 return int_range_iter(lstart, lstop, lstep);
557 } 556 }
558 } 557 }
559 /* Some conversion failed, so there is an error set. Clear it, 558 /* Some conversion failed, so there is an error set. Clear it,
560 and try again with a long range. */ 559 and try again with a long range. */
561 PyErr_Clear(); 560 PyErr_Clear();
562 561
563 it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type); 562 it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
564 if (it == NULL) 563 if (it == NULL)
565 return NULL; 564 return NULL;
566 565
567 /* Do all initialization here, so we can DECREF on failure. */ 566 /* Do all initialization here, so we can DECREF on failure. */
568 it->start = r->start; 567 it->start = r->start;
569 it->step = r->step; 568 it->step = r->step;
570 Py_INCREF(it->start); 569 Py_INCREF(it->start);
571 Py_INCREF(it->step); 570 Py_INCREF(it->step);
572 571
573 it->len = it->index = NULL; 572 Py_INCREF(r->length);
574 573 it->length = r->length;
575 /* Calculate length: (r->stop - r->start) / r->step */
576 tmp = PyNumber_Subtract(r->stop, r->start);
577 if (!tmp)
578 goto create_failure;
579 len = PyNumber_FloorDivide(tmp, r->step);
580 Py_DECREF(tmp);
581 if (!len)
582 goto create_failure;
583 it->len = len;
584 it->index = PyLong_FromLong(0); 574 it->index = PyLong_FromLong(0);
585 if (!it->index) 575 if (it->index == NULL)
586 goto create_failure; 576 goto create_failure;
587 577
588 return (PyObject *)it; 578 return (PyObject *)it;
589 579
590 create_failure: 580 create_failure:
591 Py_DECREF(it); 581 Py_DECREF(it);
592 return NULL; 582 return NULL;
593 } 583 }
594 584
595 static PyObject * 585 static PyObject *
(...skipping 28 matching lines...) Expand all
624 } 614 }
625 } 615 }
626 } 616 }
627 PyErr_Clear(); 617 PyErr_Clear();
628 618
629 it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type); 619 it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
630 if (it == NULL) 620 if (it == NULL)
631 return NULL; 621 return NULL;
632 622
633 /* start + (len - 1) * step */ 623 /* start + (len - 1) * step */
624 Py_INCREF(range->length);
634 len = range->length; 625 len = range->length;
mvloewis_gmail.com 2008/05/02 20:17:20 You need to INCREF, since you are a) going to DECR
635 626
636 one = PyLong_FromLong(1); 627 one = PyLong_FromLong(1);
637 if (!one) 628 if (!one)
638 goto create_failure; 629 goto create_failure;
639 630
640 diff = PyNumber_Subtract(len, one); 631 diff = PyNumber_Subtract(len, one);
641 Py_DECREF(one); 632 Py_DECREF(one);
642 if (!diff) 633 if (!diff)
643 goto create_failure; 634 goto create_failure;
644 635
645 product = PyNumber_Multiply(len, range->step); 636 product = PyNumber_Multiply(len, range->step);
646 if (!product) 637 if (!product)
647 goto create_failure; 638 goto create_failure;
648 639
649 sum = PyNumber_Add(range->start, product); 640 sum = PyNumber_Add(range->start, product);
650 Py_DECREF(product); 641 Py_DECREF(product);
651 it->start = sum; 642 it->start = sum;
652 if (!it->start) 643 if (!it->start)
653 goto create_failure; 644 goto create_failure;
654 it->step = PyNumber_Negative(range->step); 645 it->step = PyNumber_Negative(range->step);
655 if (!it->step) { 646 if (!it->step) {
656 Py_DECREF(it->start); 647 Py_DECREF(it->start);
657 PyObject_Del(it); 648 PyObject_Del(it);
658 return NULL; 649 return NULL;
659 } 650 }
660 651
661 /* Steal reference to len. */ 652 /* Steal reference to len. */
662 it->len = len; 653 it->length = len;
663 654
664 it->index = PyLong_FromLong(0); 655 it->index = PyLong_FromLong(0);
665 if (!it->index) { 656 if (!it->index) {
666 Py_DECREF(it); 657 Py_DECREF(it);
667 return NULL; 658 return NULL;
668 } 659 }
669 660
670 return (PyObject *)it; 661 return (PyObject *)it;
671 662
672 create_failure: 663 create_failure:
673 Py_XDECREF(len); 664 Py_XDECREF(len);
674 PyObject_Del(it); 665 PyObject_Del(it);
675 return NULL; 666 return NULL;
676 } 667 }
LEFTRIGHT

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