Merged revisions 55007-55179 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/branches/p3yk

........
  r55077 | guido.van.rossum | 2007-05-02 11:54:37 -0700 (Wed, 02 May 2007) | 2 lines

  Use the new print syntax, at least.
........
  r55142 | fred.drake | 2007-05-04 21:27:30 -0700 (Fri, 04 May 2007) | 1 line

  remove old cruftiness
........
  r55143 | fred.drake | 2007-05-04 21:52:16 -0700 (Fri, 04 May 2007) | 1 line

  make this work with the new Python
........
  r55162 | neal.norwitz | 2007-05-06 22:29:18 -0700 (Sun, 06 May 2007) | 1 line

  Get asdl code gen working with Python 2.3.  Should continue to work with 3.0
........
  r55164 | neal.norwitz | 2007-05-07 00:00:38 -0700 (Mon, 07 May 2007) | 1 line

  Verify checkins to p3yk (sic) branch go to 3000 list.
........
  r55166 | neal.norwitz | 2007-05-07 00:12:35 -0700 (Mon, 07 May 2007) | 1 line

  Fix this test so it runs again by importing warnings_test properly.
........
  r55167 | neal.norwitz | 2007-05-07 01:03:22 -0700 (Mon, 07 May 2007) | 8 lines

  So long xrange.  range() now supports values that are outside
  -sys.maxint to sys.maxint.  floats raise a TypeError.

  This has been sitting for a long time.  It probably has some problems and
  needs cleanup.  Objects/rangeobject.c now uses 4-space indents since
  it is almost completely new.
........
  r55171 | guido.van.rossum | 2007-05-07 10:21:26 -0700 (Mon, 07 May 2007) | 4 lines

  Fix two tests that were previously depending on significant spaces
  at the end of a line (and before that on Python 2.x print behavior
  that has no exact equivalent in 3.0).
........
diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c
index c48bee0..f38935b 100644
--- a/Objects/rangeobject.c
+++ b/Objects/rangeobject.c
@@ -2,139 +2,292 @@
 
 #include "Python.h"
 
+/* Support objects whose length is > PY_SSIZE_T_MAX.
+
+   This could be sped up for small PyLongs if they fit in an Py_ssize_t.
+   This only matters on Win64.  Though we could use PY_LONG_LONG which
+   would presumably help perf.
+*/
+
 typedef struct {
-	PyObject_HEAD
-	long	start;
-	long	step;
-	long	len;
+    PyObject_HEAD
+    PyObject *start;
+    PyObject *stop;
+    PyObject *step;
 } rangeobject;
 
-/* Return number of items in range/xrange (lo, hi, step).  step > 0
- * required.  Return a value < 0 if & only if the true value is too
- * large to fit in a signed long.
- */
-static long
-get_len_of_range(long lo, long hi, long step)
+/* Helper function for validating step.  Always returns a new reference or
+   NULL on error. 
+*/
+static PyObject *
+validate_step(PyObject *step)
 {
-	/* -------------------------------------------------------------
-	If lo >= hi, the range is empty.
-	Else if n values are in the range, the last one is
-	lo + (n-1)*step, which must be <= hi-1.  Rearranging,
-	n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
-	the proper value.  Since lo < hi in this case, hi-lo-1 >= 0, so
-	the RHS is non-negative and so truncation is the same as the
-	floor.  Letting M be the largest positive long, the worst case
-	for the RHS numerator is hi=M, lo=-M-1, and then
-	hi-lo-1 = M-(-M-1)-1 = 2*M.  Therefore unsigned long has enough
-	precision to compute the RHS exactly.
-	---------------------------------------------------------------*/
-	long n = 0;
-	if (lo < hi) {
-		unsigned long uhi = (unsigned long)hi;
-		unsigned long ulo = (unsigned long)lo;
-		unsigned long diff = uhi - ulo - 1;
-		n = (long)(diff / (unsigned long)step + 1);
-	}
-	return n;
+    /* No step specified, use a step of 1. */
+    if (!step)
+        return PyInt_FromLong(1);
+
+    step = PyNumber_Index(step);
+    if (step) {
+        Py_ssize_t istep = PyNumber_AsSsize_t(step, NULL);
+        if (istep == -1 && PyErr_Occurred()) {
+            /* Ignore OverflowError, we know the value isn't 0. */
+            PyErr_Clear();
+        }
+        else if (istep == 0) {
+            PyErr_SetString(PyExc_ValueError,
+                            "range() arg 3 must not be zero");
+            Py_CLEAR(step);
+        }
+    }
+
+    return step;
 }
 
+/* XXX(nnorwitz): should we error check if the user passes any empty ranges?
+   range(-10)
+   range(0, -5)
+   range(0, 5, -1)
+*/
 static PyObject *
 range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 {
-	rangeobject *obj;
-	long ilow = 0, ihigh = 0, istep = 1;
-	long n;
+    rangeobject *obj = NULL;
+    PyObject *start = NULL, *stop = NULL, *step = NULL;
 
-	if (!_PyArg_NoKeywords("xrange()", kw))
-		return NULL;
+    if (!_PyArg_NoKeywords("range()", kw))
+        return NULL;
 
-	if (PyTuple_Size(args) <= 1) {
-		if (!PyArg_ParseTuple(args,
-				"l;xrange() requires 1-3 int arguments",
-				&ihigh))
-			return NULL;
-	}
-	else {
-		if (!PyArg_ParseTuple(args,
-				"ll|l;xrange() requires 1-3 int arguments",
-				&ilow, &ihigh, &istep))
-			return NULL;
-	}
-	if (istep == 0) {
-		PyErr_SetString(PyExc_ValueError, "xrange() arg 3 must not be zero");
-		return NULL;
-	}
-	if (istep > 0)
-		n = get_len_of_range(ilow, ihigh, istep);
-	else
-		n = get_len_of_range(ihigh, ilow, -istep);
-	if (n < 0) {
-		PyErr_SetString(PyExc_OverflowError,
-				"xrange() result has too many items");
-		return NULL;
-	}
+    if (PyTuple_Size(args) <= 1) {
+        if (!PyArg_UnpackTuple(args, "range", 1, 1, &stop))
+            goto Fail;
+        stop = PyNumber_Index(stop);
+        if (!stop)
+            goto Fail;
+        start = PyInt_FromLong(0);
+        step = PyInt_FromLong(1);
+        if (!start || !step)
+            goto Fail;
+    }
+    else {
+        if (!PyArg_UnpackTuple(args, "range", 2, 3,
+                               &start, &stop, &step))
+            goto Fail;
 
-	obj = PyObject_New(rangeobject, &PyRange_Type);
-	if (obj == NULL)
-		return NULL;
-	obj->start = ilow;
-	obj->len   = n;
-	obj->step  = istep;
-	return (PyObject *) obj;
+        /* Convert borrowed refs to owned refs */
+        start = PyNumber_Index(start);
+        stop = PyNumber_Index(stop);
+        step = validate_step(step);
+        if (!start || !stop || !step)
+            goto Fail;
+    }
+
+    obj = PyObject_New(rangeobject, &PyRange_Type);
+    if (obj == NULL)
+        goto Fail;
+    obj->start = start;
+    obj->stop = stop;
+    obj->step = step;
+    return (PyObject *) obj;
+
+Fail:
+    Py_XDECREF(start);
+    Py_XDECREF(stop);
+    Py_XDECREF(step);
+    return NULL;
 }
 
 PyDoc_STRVAR(range_doc,
-"xrange([start,] stop[, step]) -> xrange object\n\
+"range([start,] stop[, step]) -> range object\n\
 \n\
-Like range(), but instead of returning a list, returns an object that\n\
-generates the numbers in the range on demand.  For looping, this is \n\
-slightly faster than range() and more memory efficient.");
+Returns an iterator that generates the numbers in the range on demand.");
 
-static PyObject *
-range_item(rangeobject *r, Py_ssize_t i)
+static void
+range_dealloc(rangeobject *r)
 {
-	if (i < 0 || i >= r->len) {
-		PyErr_SetString(PyExc_IndexError,
-				"xrange object index out of range");
-		return NULL;
-	}
-	return PyInt_FromSsize_t(r->start + (i % r->len) * r->step);
+    Py_DECREF(r->start);
+    Py_DECREF(r->stop);
+    Py_DECREF(r->step);
+}
+
+/* Return number of items in range (lo, hi, step), when arguments are
+ * PyInt or PyLong objects.  step > 0 required.  Return a value < 0 if
+ * & only if the true value is too large to fit in a signed long.
+ * Arguments MUST return 1 with either PyInt_Check() or
+ * PyLong_Check().  Return -1 when there is an error.
+ */
+static PyObject*
+range_length_obj(rangeobject *r)
+{
+    /* -------------------------------------------------------------
+    Algorithm is equal to that of get_len_of_range(), but it operates
+    on PyObjects (which are assumed to be PyLong or PyInt objects).
+    ---------------------------------------------------------------*/
+    int cmp_result, cmp_call;
+    PyObject *lo, *hi;
+    PyObject *step = NULL;
+    PyObject *diff = NULL;
+    PyObject *one = NULL;
+    PyObject *tmp1 = NULL, *tmp2 = NULL, *result;
+                /* holds sub-expression evaluations */
+
+    PyObject *zero = PyLong_FromLong(0);
+    if (zero == NULL)
+        return NULL;
+    cmp_call = PyObject_Cmp(r->step, zero, &cmp_result);
+    Py_DECREF(zero);
+    if (cmp_call == -1)
+        return NULL;
+
+    assert(cmp_result != 0);
+    if (cmp_result > 0) {
+        lo = r->start;
+        hi = r->stop;
+        step = r->step;
+        Py_INCREF(step);
+    } else {
+        lo = r->stop;
+        hi = r->start;
+        step = PyNumber_Negative(r->step);
+        if (!step)
+            return NULL;
+    }
+
+    /* if (lo >= hi), return length of 0. */
+    if (PyObject_Compare(lo, hi) >= 0) {
+        Py_XDECREF(step);
+        return PyLong_FromLong(0);
+    }
+
+    if ((one = PyLong_FromLong(1L)) == NULL)
+        goto Fail;
+
+    if ((tmp1 = PyNumber_Subtract(hi, lo)) == NULL)
+        goto Fail;
+
+    if ((diff = PyNumber_Subtract(tmp1, one)) == NULL)
+        goto Fail;
+
+    if ((tmp2 = PyNumber_FloorDivide(diff, step)) == NULL)
+        goto Fail;
+
+    if ((result = PyNumber_Add(tmp2, one)) == NULL)
+        goto Fail;
+
+    Py_DECREF(tmp2);
+    Py_DECREF(diff);
+    Py_DECREF(step);
+    Py_DECREF(tmp1);
+    Py_DECREF(one);
+    return result;
+
+  Fail:
+    Py_XDECREF(tmp2);
+    Py_XDECREF(diff);
+    Py_XDECREF(step);
+    Py_XDECREF(tmp1);
+    Py_XDECREF(one);
+    return NULL;
 }
 
 static Py_ssize_t
 range_length(rangeobject *r)
 {
-	return (Py_ssize_t)(r->len);
+    PyObject *len = range_length_obj(r);
+    Py_ssize_t result = -1;
+    if (len) {
+        result = PyLong_AsSsize_t(len);
+        Py_DECREF(len);
+    }
+    return result;
+}
+
+/* range(...)[x] is necessary for:  seq[:] = range(...) */
+
+static PyObject *
+range_item(rangeobject *r, Py_ssize_t i)
+{
+    Py_ssize_t len = range_length(r);
+    PyObject *rem, *incr, *result;
+
+    /* XXX(nnorwitz): should negative indices be supported? */
+    /* XXX(nnorwitz): should support range[x] where x > PY_SSIZE_T_MAX? */
+    if (i < 0 || i >= len) {
+        if (!PyErr_Occurred())
+            PyErr_SetString(PyExc_IndexError,
+                            "xrange object index out of range");
+            return NULL;
+        }
+
+    /* XXX(nnorwitz): optimize for short ints. */
+    rem = PyLong_FromSsize_t(i % len);
+    if (!rem)
+        return NULL;
+    incr = PyNumber_Multiply(rem, r->step);
+    Py_DECREF(rem);
+    if (!incr)
+        return NULL;
+    result = PyNumber_Add(r->start, incr);
+    Py_DECREF(incr);
+    return result;
 }
 
 static PyObject *
 range_repr(rangeobject *r)
 {
-	PyObject *rtn;
+    PyObject *start_str = NULL, *stop_str = NULL, *step_str = NULL;
+    PyObject *result = NULL;
+    Py_ssize_t istart, istep;
 
-	if (r->start == 0 && r->step == 1)
-		rtn = PyString_FromFormat("xrange(%ld)",
-					  r->start + r->len * r->step);
+    /* We always need the stop value. */
+    stop_str = PyObject_Str(r->stop);
+    if (!stop_str)
+        return NULL;
 
-	else if (r->step == 1)
-		rtn = PyString_FromFormat("xrange(%ld, %ld)",
-					  r->start,
-					  r->start + r->len * r->step);
+    /* XXX(nnorwitz): should we use PyObject_Repr instead of str? */
 
-	else
-		rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)",
-					  r->start,
-					  r->start + r->len * r->step,
-					  r->step);
-	return rtn;
+    /* Check for special case values for printing.  We don't always
+       need the start or step values.  We don't care about errors
+       (it means overflow), so clear the errors. */
+    istart = PyNumber_AsSsize_t(r->start, NULL);
+    if (istart != 0 || (istart == -1 && PyErr_Occurred())) {
+        PyErr_Clear();
+        start_str = PyObject_Str(r->start);
+    }
+
+    istep = PyNumber_AsSsize_t(r->step, NULL);
+    if (istep != 1 || (istep == -1 && PyErr_Occurred())) {
+        PyErr_Clear();
+        step_str = PyObject_Str(r->step);
+    }
+
+    if (istart == 0 && istep == 1)
+        result = PyString_FromFormat("range(%s)",
+                                     PyString_AS_STRING(stop_str));
+    else if (istep == 1) {
+        if (start_str)
+            result = PyString_FromFormat("range(%s, %s)",
+                                         PyString_AS_STRING(start_str),
+                                         PyString_AS_STRING(stop_str));
+    }
+    else if (start_str && step_str)
+        result = PyString_FromFormat("range(%s, %s, %s)",
+                                     PyString_AS_STRING(start_str),
+                                     PyString_AS_STRING(stop_str),
+                                     PyString_AS_STRING(step_str));
+    /* else result is NULL and an error should already be set. */
+
+    Py_XDECREF(start_str);
+    Py_XDECREF(stop_str);
+    Py_XDECREF(step_str);
+    return result;
 }
 
 static PySequenceMethods range_as_sequence = {
-	(lenfunc)range_length,	/* sq_length */
-	0,			/* sq_concat */
-	0,			/* sq_repeat */
-	(ssizeargfunc)range_item, /* sq_item */
-	0,			/* sq_slice */
+    (lenfunc)range_length,	/* sq_length */
+    0,			/* sq_concat */
+    0,			/* sq_repeat */
+    (ssizeargfunc)range_item, /* sq_item */
+    0,			/* sq_slice */
 };
 
 static PyObject * range_iter(PyObject *seq);
@@ -144,17 +297,18 @@
 "Returns a reverse iterator.");
 
 static PyMethodDef range_methods[] = {
-	{"__reversed__",	(PyCFunction)range_reverse, METH_NOARGS, reverse_doc},
- 	{NULL,		NULL}		/* sentinel */
+    {"__reversed__",	(PyCFunction)range_reverse, METH_NOARGS,
+	reverse_doc},
+    {NULL,		NULL}		/* sentinel */
 };
 
 PyTypeObject PyRange_Type = {
 	PyObject_HEAD_INIT(&PyType_Type)
 	0,			/* Number of items for varobject */
-	"xrange",		/* Name of this type */
+	"range",		/* Name of this type */
 	sizeof(rangeobject),	/* Basic object size */
 	0,			/* Item size for varobject */
-	(destructor)PyObject_Del, /* tp_dealloc */
+	(destructor)range_dealloc, /* tp_dealloc */
 	0,			/* tp_print */
 	0,			/* tp_getattr */
 	0,			/* tp_setattr */
@@ -192,6 +346,11 @@
 
 /*********************** Xrange Iterator **************************/
 
+/* There are 2 types of iterators, one for C longs, the other for
+   Python longs (ie, PyObjects).  This should make iteration fast
+   in the normal case, but possible for any numeric value.
+*/
+
 typedef struct {
 	PyObject_HEAD
 	long	index;
@@ -203,25 +362,42 @@
 static PyObject *
 rangeiter_next(rangeiterobject *r)
 {
-	if (r->index < r->len)
-		return PyInt_FromLong(r->start + (r->index++) * r->step);
-	return NULL;
+    if (r->index < r->len)
+        return PyInt_FromLong(r->start + (r->index++) * r->step);
+    return NULL;
 }
 
 static PyObject *
 rangeiter_len(rangeiterobject *r)
 {
-	return PyInt_FromLong(r->len - r->index);
+    return PyInt_FromLong(r->len - r->index);
 }
 
-PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
+typedef struct {
+    PyObject_HEAD
+    PyObject *index;
+    PyObject *start;
+    PyObject *step;
+    PyObject *len;
+} longrangeiterobject;
+
+static PyObject *
+longrangeiter_len(longrangeiterobject *r, PyObject *no_args)
+{
+    return PyNumber_Subtract(r->len, r->index);
+}
+static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw);
+
+PyDoc_STRVAR(length_hint_doc,
+             "Private method returning an estimate of len(list(it)).");
 
 static PyMethodDef rangeiter_methods[] = {
-	{"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS, length_hint_doc},
- 	{NULL,		NULL}		/* sentinel */
+    {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS,
+	length_hint_doc},
+    {NULL,		NULL}		/* sentinel */
 };
 
-static PyTypeObject Pyrangeiter_Type = {
+PyTypeObject Pyrangeiter_Type = {
 	PyObject_HEAD_INIT(&PyType_Type)
 	0,                                      /* ob_size */
 	"rangeiterator",                        /* tp_name */
@@ -252,50 +428,279 @@
 	PyObject_SelfIter,			/* tp_iter */
 	(iternextfunc)rangeiter_next,		/* tp_iternext */
 	rangeiter_methods,			/* tp_methods */
+	0,					/* tp_members */
+	0,					/* tp_getset */
+	0,					/* tp_base */
+	0,					/* tp_dict */
+	0,					/* tp_descr_get */
+	0,					/* tp_descr_set */
+	0,					/* tp_dictoffset */
+	0,					/* tp_init */
+	0,					/* tp_alloc */
+	rangeiter_new,				/* tp_new */
+};
+
+/* Return number of items in range/xrange (lo, hi, step).  step > 0
+ * required.  Return a value < 0 if & only if the true value is too
+ * large to fit in a signed long.
+ */
+static long
+get_len_of_range(long lo, long hi, long step)
+{
+    /* -------------------------------------------------------------
+    If lo >= hi, the range is empty.
+    Else if n values are in the range, the last one is
+    lo + (n-1)*step, which must be <= hi-1.  Rearranging,
+    n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
+    the proper value.  Since lo < hi in this case, hi-lo-1 >= 0, so
+    the RHS is non-negative and so truncation is the same as the
+    floor.  Letting M be the largest positive long, the worst case
+    for the RHS numerator is hi=M, lo=-M-1, and then
+    hi-lo-1 = M-(-M-1)-1 = 2*M.  Therefore unsigned long has enough
+    precision to compute the RHS exactly.
+    ---------------------------------------------------------------*/
+    long n = 0;
+    if (lo < hi) {
+        unsigned long uhi = (unsigned long)hi;
+        unsigned long ulo = (unsigned long)lo;
+        unsigned long diff = uhi - ulo - 1;
+        n = (long)(diff / (unsigned long)step + 1);
+    }
+    return n;
+}
+
+static PyObject *
+int_range_iter(long start, long stop, long step)
+{
+    rangeiterobject *it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);
+    if (it == NULL)
+        return NULL;
+    it->start = start;
+    it->step = step;
+    if (step > 0)
+        it->len = get_len_of_range(start, stop, step);
+    else
+        it->len = get_len_of_range(stop, start, -step);
+    it->index = 0;
+    return (PyObject *)it;
+}
+
+static PyObject *
+rangeiter_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+{
+    long start, stop, step;
+
+    if (!_PyArg_NoKeywords("rangeiter()", kw))
+        return NULL;
+
+    if (!PyArg_ParseTuple(args, "lll;rangeiter() requires 3 int arguments",
+                          &start, &stop, &step))
+        return NULL;
+
+    return int_range_iter(start, stop, step);
+}
+
+static PyMethodDef longrangeiter_methods[] = {
+    {"__length_hint__", (PyCFunction)longrangeiter_len, METH_NOARGS,
+	length_hint_doc},
+    {NULL,		NULL}		/* sentinel */
+};
+
+static void
+longrangeiter_dealloc(longrangeiterobject *r)
+{
+    Py_XDECREF(r->index);
+    Py_DECREF(r->start);
+    Py_DECREF(r->step);
+    Py_DECREF(r->len);
+}
+
+static PyObject *
+longrangeiter_next(longrangeiterobject *r)
+{
+    PyObject *one, *product, *new_index, *result;
+    if (PyObject_RichCompareBool(r->index, r->len, Py_LT) != 1)
+        return NULL;
+
+    one = PyLong_FromLong(1);
+    if (!one)
+        return NULL;
+
+    product = PyNumber_Multiply(r->index, r->step);
+    if (!product) {
+        Py_DECREF(one);
+        return NULL;
+    }
+
+    new_index = PyNumber_Add(r->index, one);
+    Py_DECREF(one);
+    if (!new_index) {
+        Py_DECREF(product);
+        return NULL;
+    }
+
+    result = PyNumber_Add(r->start, product);
+    Py_DECREF(product);
+    if (result) {
+        Py_DECREF(r->index);
+        r->index = new_index;
+    }
+
+    return result;
+}
+
+static PyTypeObject Pylongrangeiter_Type = {
+	PyObject_HEAD_INIT(&PyType_Type)
+	0,                                      /* ob_size */
+	"rangeiterator",                        /* tp_name */
+	sizeof(longrangeiterobject),            /* tp_basicsize */
+	0,                                      /* tp_itemsize */
+	/* methods */
+	(destructor)longrangeiter_dealloc,	/* tp_dealloc */
+	0,                                      /* tp_print */
+	0,                                      /* tp_getattr */
+	0,                                      /* tp_setattr */
+	0,                                      /* tp_compare */
+	0,                                      /* tp_repr */
+	0,                                      /* tp_as_number */
+	0,					/* 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 */
+	PyObject_SelfIter,			/* tp_iter */
+	(iternextfunc)longrangeiter_next,	/* tp_iternext */
+	longrangeiter_methods,			/* tp_methods */
 	0,
 };
 
 static PyObject *
 range_iter(PyObject *seq)
 {
-	rangeiterobject *it;
+    rangeobject *r = (rangeobject *)seq;
+    longrangeiterobject *it;
+    PyObject *tmp, *len;
 
-	if (!PyRange_Check(seq)) {
-		PyErr_BadInternalCall();
-		return NULL;
-	}
-	it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);
-	if (it == NULL)
-		return NULL;
-	it->index = 0;
-	it->start = ((rangeobject *)seq)->start;
-	it->step = ((rangeobject *)seq)->step;
-	it->len = ((rangeobject *)seq)->len;
-	return (PyObject *)it;
+    assert(PyRange_Check(seq));
+    if (_PyLong_FitsInLong(r->start) &&
+        _PyLong_FitsInLong(r->stop) &&
+        _PyLong_FitsInLong(r->step))
+        return int_range_iter(PyLong_AsLong(r->start),
+                      PyLong_AsLong(r->stop),
+                      PyLong_AsLong(r->step));
+
+    it = PyObject_New(longrangeiterobject, &Pylongrangeiter_Type);
+    if (it == NULL)
+        return NULL;
+    it->start = r->start;
+    /* Calculate length: (r->stop - r->start) / r->step */
+    tmp = PyNumber_Subtract(r->stop, r->start);
+    if (!tmp)
+        goto create_failure;
+    len = PyNumber_FloorDivide(tmp, r->step);
+    Py_DECREF(tmp);
+    if (!len)
+        goto create_failure;
+    it->len = len;
+    it->step = r->step;
+    it->index = PyLong_FromLong(0);
+    if (!it->index)
+        goto create_failure;
+
+    Py_INCREF(it->start);
+    Py_INCREF(it->step);
+    Py_INCREF(it->len);
+    return (PyObject *)it;
+
+create_failure:
+    PyObject_Del(it);
+    return NULL;
 }
 
 static PyObject *
 range_reverse(PyObject *seq)
 {
-	rangeiterobject *it;
-	long start, step, len;
+    rangeobject *range = (rangeobject*) seq;
+    longrangeiterobject *it;
+    PyObject *one, *sum, *diff, *len = NULL, *product;
 
-	if (!PyRange_Check(seq)) {
-		PyErr_BadInternalCall();
-		return NULL;
-	}
-	it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);
-	if (it == NULL)
-		return NULL;
+    /* XXX(nnorwitz): do the calc for the new start/stop first,
+        then if they fit, call the proper iter()?
+    */
+    assert(PyRange_Check(seq));
+    if (_PyLong_FitsInLong(range->start) &&
+        _PyLong_FitsInLong(range->stop) &&
+        _PyLong_FitsInLong(range->step)) {
+        long start = PyLong_AsLong(range->start);
+        long step = PyLong_AsLong(range->step);
+        long stop = PyLong_AsLong(range->stop);
+        /* XXX(nnorwitz): need to check for overflow and simplify. */
+        long len = get_len_of_range(start, stop, step);
+        long new_start = start + (len - 1) * step;
+        long new_stop = start;
+        if (step > 0)
+            new_stop -= 1;
+        else
+            new_stop += 1;
+        return int_range_iter(new_start, new_stop, -step);
+    }
 
-	start = ((rangeobject *)seq)->start;
-	step = ((rangeobject *)seq)->step;
-	len = ((rangeobject *)seq)->len;
+    it = PyObject_New(longrangeiterobject, &Pylongrangeiter_Type);
+    if (it == NULL)
+        return NULL;
 
-	it->index = 0;
-	it->start = start + (len-1) * step;
-	it->step = -step;
-	it->len = len;
+    /* start + (len - 1) * step */
+    len = range_length_obj(range);
+    if (!len)
+        goto create_failure;
 
-	return (PyObject *)it;
+    one = PyLong_FromLong(1);
+    if (!one)
+        goto create_failure;
+
+    diff = PyNumber_Subtract(len, one);
+    Py_DECREF(one);
+    if (!diff)
+        goto create_failure;
+
+    product = PyNumber_Multiply(len, range->step);
+    if (!product)
+        goto create_failure;
+
+    sum = PyNumber_Add(range->start, product);
+    Py_DECREF(product);
+    it->start = sum;
+    if (!it->start)
+        goto create_failure;
+    it->step = PyNumber_Negative(range->step);
+    if (!it->step) {
+        Py_DECREF(it->start);
+        PyObject_Del(it);
+        return NULL;
+    }
+
+    /* Steal reference to len. */
+    it->len = len;
+
+    it->index = PyLong_FromLong(0);
+    if (!it->index) {
+        Py_DECREF(it);
+        return NULL;
+    }
+
+    return (PyObject *)it;
+
+create_failure:
+    Py_XDECREF(len);
+    PyObject_Del(it);
+    return NULL;
 }