summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2010-05-07 13:23:18 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2010-05-07 13:23:18 (GMT)
commite02c9d22f6d0c1cbe5a65096cd454c4c0b36304c (patch)
tree1a973790ee5844a5259813c075dac4dc13af3a19 /Python
parentcdf48a8ec24a121ae8e17f63d08a6955f8f4ed0d (diff)
downloadcpython-e02c9d22f6d0c1cbe5a65096cd454c4c0b36304c.zip
cpython-e02c9d22f6d0c1cbe5a65096cd454c4c0b36304c.tar.gz
cpython-e02c9d22f6d0c1cbe5a65096cd454c4c0b36304c.tar.bz2
Merged revisions 80758 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r80758 | mark.dickinson | 2010-05-04 17:18:25 +0100 (Tue, 04 May 2010) | 9 lines Issue #1533: fix inconsistency in range function argument processing: any non-float non-integer argument is now converted to an integer (if possible) using its __int__ method. Previously, only small arguments were treated this way; larger arguments (those whose __int__ was outside the range of a C long) would produce a TypeError. Patch by Alexander Belopolsky (with minor modifications). ........
Diffstat (limited to 'Python')
-rw-r--r--Python/bltinmodule.c117
1 files changed, 72 insertions, 45 deletions
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 4b5a062..08cc8b3 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -1745,15 +1745,54 @@ get_len_of_range_longs(PyObject *lo, PyObject *hi, PyObject *step)
return -1;
}
+/* Helper function for handle_range_longs. If arg is int or long
+ object, returns it with incremented reference count. If arg is
+ float, raises type error. As a last resort, creates a new int by
+ calling arg type's nb_int method if it is defined. Returns NULL
+ and sets exception on error.
+
+ Returns a new reference to an int object. */
+static PyObject *
+get_range_long_argument(PyObject *arg, const char *name)
+{
+ PyObject *v;
+ PyNumberMethods *nb;
+ if (PyInt_Check(arg) || PyLong_Check(arg)) {
+ Py_INCREF(arg);
+ return arg;
+ }
+ if (PyFloat_Check(arg) ||
+ (nb = Py_TYPE(arg)->tp_as_number) == NULL ||
+ nb->nb_int == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "range() integer %s argument expected, got %s.",
+ name, arg->ob_type->tp_name);
+ return NULL;
+ }
+ v = nb->nb_int(arg);
+ if (v == NULL)
+ return NULL;
+ if (PyInt_Check(v) || PyLong_Check(v))
+ return v;
+ Py_DECREF(v);
+ PyErr_SetString(PyExc_TypeError,
+ "__int__ should return int object");
+ return NULL;
+}
+
/* An extension of builtin_range() that handles the case when PyLong
* arguments are given. */
static PyObject *
handle_range_longs(PyObject *self, PyObject *args)
{
- PyObject *ilow;
+ PyObject *ilow = NULL;
PyObject *ihigh = NULL;
PyObject *istep = NULL;
+ PyObject *low = NULL;
+ PyObject *high = NULL;
+ PyObject *step = NULL;
+
PyObject *curnum = NULL;
PyObject *v = NULL;
long bign;
@@ -1772,7 +1811,7 @@ handle_range_longs(PyObject *self, PyObject *args)
/* Figure out which way we were called, supply defaults, and be
* sure to incref everything so that the decrefs at the end
- * are correct.
+ * are correct. NB: ilow, ihigh and istep are borrowed references.
*/
assert(ilow != NULL);
if (ihigh == NULL) {
@@ -1780,47 +1819,35 @@ handle_range_longs(PyObject *self, PyObject *args)
ihigh = ilow;
ilow = NULL;
}
+
+ /* convert ihigh if necessary */
assert(ihigh != NULL);
- Py_INCREF(ihigh);
+ high = get_range_long_argument(ihigh, "end");
+ if (high == NULL)
+ goto Fail;
/* ihigh correct now; do ilow */
- if (ilow == NULL)
- ilow = zero;
- Py_INCREF(ilow);
-
- /* ilow and ihigh correct now; do istep */
- if (istep == NULL) {
- istep = PyLong_FromLong(1L);
- if (istep == NULL)
- goto Fail;
+ if (ilow == NULL) {
+ Py_INCREF(zero);
+ low = zero;
}
else {
- Py_INCREF(istep);
- }
-
- if (!PyInt_Check(ilow) && !PyLong_Check(ilow)) {
- PyErr_Format(PyExc_TypeError,
- "range() integer start argument expected, got %s.",
- ilow->ob_type->tp_name);
- goto Fail;
+ low = get_range_long_argument(ilow, "start");
+ if (low == NULL)
+ goto Fail;
}
- if (!PyInt_Check(ihigh) && !PyLong_Check(ihigh)) {
- PyErr_Format(PyExc_TypeError,
- "range() integer end argument expected, got %s.",
- ihigh->ob_type->tp_name);
+ /* ilow and ihigh correct now; do istep */
+ if (istep == NULL)
+ step = PyLong_FromLong(1);
+ else
+ step = get_range_long_argument(istep, "step");
+ if (step == NULL)
goto Fail;
- }
- if (!PyInt_Check(istep) && !PyLong_Check(istep)) {
- PyErr_Format(PyExc_TypeError,
- "range() integer step argument expected, got %s.",
- istep->ob_type->tp_name);
+ if (PyObject_Cmp(step, zero, &cmp_result) == -1)
goto Fail;
- }
- if (PyObject_Cmp(istep, zero, &cmp_result) == -1)
- goto Fail;
if (cmp_result == 0) {
PyErr_SetString(PyExc_ValueError,
"range() step argument must not be zero");
@@ -1828,13 +1855,13 @@ handle_range_longs(PyObject *self, PyObject *args)
}
if (cmp_result > 0)
- bign = get_len_of_range_longs(ilow, ihigh, istep);
+ bign = get_len_of_range_longs(low, high, step);
else {
- PyObject *neg_istep = PyNumber_Negative(istep);
- if (neg_istep == NULL)
+ PyObject *neg_step = PyNumber_Negative(step);
+ if (neg_step == NULL)
goto Fail;
- bign = get_len_of_range_longs(ihigh, ilow, neg_istep);
- Py_DECREF(neg_istep);
+ bign = get_len_of_range_longs(high, low, neg_step);
+ Py_DECREF(neg_step);
}
n = (int)bign;
@@ -1848,7 +1875,7 @@ handle_range_longs(PyObject *self, PyObject *args)
if (v == NULL)
goto Fail;
- curnum = ilow;
+ curnum = low;
Py_INCREF(curnum);
for (i = 0; i < n; i++) {
@@ -1859,24 +1886,24 @@ handle_range_longs(PyObject *self, PyObject *args)
PyList_SET_ITEM(v, i, w);
- tmp_num = PyNumber_Add(curnum, istep);
+ tmp_num = PyNumber_Add(curnum, step);
if (tmp_num == NULL)
goto Fail;
Py_DECREF(curnum);
curnum = tmp_num;
}
- Py_DECREF(ilow);
- Py_DECREF(ihigh);
- Py_DECREF(istep);
+ Py_DECREF(low);
+ Py_DECREF(high);
+ Py_DECREF(step);
Py_DECREF(zero);
Py_DECREF(curnum);
return v;
Fail:
- Py_DECREF(ilow);
- Py_DECREF(ihigh);
- Py_XDECREF(istep);
+ Py_XDECREF(low);
+ Py_XDECREF(high);
+ Py_XDECREF(step);
Py_DECREF(zero);
Py_XDECREF(curnum);
Py_XDECREF(v);