mirror of
https://github.com/python/cpython.git
synced 2025-10-10 00:43:41 +00:00
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). ........
This commit is contained in:
parent
598d98a7e8
commit
805365ee39
150 changed files with 1412 additions and 1320 deletions
|
@ -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 @@ PyDoc_STRVAR(reverse_doc,
|
|||
"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 @@ PyTypeObject PyRange_Type = {
|
|||
|
||||
/*********************** 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 @@ typedef struct {
|
|||
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 @@ static PyTypeObject Pyrangeiter_Type = {
|
|||
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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue