diff options
author | Christian Heimes <christian@cheimes.de> | 2008-02-29 14:57:44 (GMT) |
---|---|---|
committer | Christian Heimes <christian@cheimes.de> | 2008-02-29 14:57:44 (GMT) |
commit | f16baebf168a56afdc5c26c7ee195aed00a25617 (patch) | |
tree | 95acdaffa79ffe492a19e0db4268f5bd9f6d08f6 /Modules/itertoolsmodule.c | |
parent | 5524089fa1712a0f483bcacc7a8c3cd75bc3dc0c (diff) | |
download | cpython-f16baebf168a56afdc5c26c7ee195aed00a25617.zip cpython-f16baebf168a56afdc5c26c7ee195aed00a25617.tar.gz cpython-f16baebf168a56afdc5c26c7ee195aed00a25617.tar.bz2 |
Merged revisions 61038,61042-61045,61047,61050,61053,61055-61056,61061-61062,61066,61068,61070,61083,61085,61092-61097,61103-61104,61110-61112,61114-61115,61117-61125 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r61118 | raymond.hettinger | 2008-02-28 23:30:42 +0100 (Thu, 28 Feb 2008) | 1 line
Have itertools.chain() consume its inputs lazily instead of building a tuple of iterators at the outset.
........
r61119 | raymond.hettinger | 2008-02-28 23:46:41 +0100 (Thu, 28 Feb 2008) | 1 line
Add alternate constructor for itertools.chain().
........
r61123 | mark.dickinson | 2008-02-29 03:16:37 +0100 (Fri, 29 Feb 2008) | 2 lines
Add __format__ method to Decimal, to support PEP 3101
........
r61124 | raymond.hettinger | 2008-02-29 03:21:48 +0100 (Fri, 29 Feb 2008) | 1 line
Handle the repeat keyword argument for itertools.product().
........
r61125 | mark.dickinson | 2008-02-29 04:29:17 +0100 (Fri, 29 Feb 2008) | 2 lines
Fix docstring typo.
........
Diffstat (limited to 'Modules/itertoolsmodule.c')
-rw-r--r-- | Modules/itertoolsmodule.c | 158 |
1 files changed, 102 insertions, 56 deletions
diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index fa73605..12e862d 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -1571,92 +1571,104 @@ static PyTypeObject imap_type = { typedef struct { PyObject_HEAD - Py_ssize_t tuplesize; - Py_ssize_t iternum; /* which iterator is active */ - PyObject *ittuple; /* tuple of iterators */ + PyObject *source; /* Iterator over input iterables */ + PyObject *active; /* Currently running input iterator */ } chainobject; static PyTypeObject chain_type; +static PyObject * +chain_new_internal(PyTypeObject *type, PyObject *source) +{ + chainobject *lz; + + lz = (chainobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(source); + return NULL; + } + + lz->source = source; + lz->active = NULL; + return (PyObject *)lz; +} + static PyObject * chain_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - chainobject *lz; - Py_ssize_t tuplesize = PySequence_Length(args); - Py_ssize_t i; - PyObject *ittuple; + PyObject *source; if (type == &chain_type && !_PyArg_NoKeywords("chain()", kwds)) return NULL; - - /* obtain iterators */ - assert(PyTuple_Check(args)); - ittuple = PyTuple_New(tuplesize); - if (ittuple == NULL) + + source = PyObject_GetIter(args); + if (source == NULL) return NULL; - for (i=0; i < tuplesize; ++i) { - PyObject *item = PyTuple_GET_ITEM(args, i); - PyObject *it = PyObject_GetIter(item); - if (it == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - PyErr_Format(PyExc_TypeError, - "chain argument #%zd must support iteration", - i+1); - Py_DECREF(ittuple); - return NULL; - } - PyTuple_SET_ITEM(ittuple, i, it); - } - /* create chainobject structure */ - lz = (chainobject *)type->tp_alloc(type, 0); - if (lz == NULL) { - Py_DECREF(ittuple); - return NULL; - } + return chain_new_internal(type, source); +} - lz->ittuple = ittuple; - lz->iternum = 0; - lz->tuplesize = tuplesize; +static PyObject * +chain_new_from_iterable(PyTypeObject *type, PyObject *arg) +{ + PyObject *source; + + source = PyObject_GetIter(arg); + if (source == NULL) + return NULL; - return (PyObject *)lz; + return chain_new_internal(type, source); } static void chain_dealloc(chainobject *lz) { PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->ittuple); + Py_XDECREF(lz->active); + Py_XDECREF(lz->source); Py_TYPE(lz)->tp_free(lz); } static int chain_traverse(chainobject *lz, visitproc visit, void *arg) { - Py_VISIT(lz->ittuple); + Py_VISIT(lz->source); + Py_VISIT(lz->active); return 0; } static PyObject * chain_next(chainobject *lz) { - PyObject *it; PyObject *item; - while (lz->iternum < lz->tuplesize) { - it = PyTuple_GET_ITEM(lz->ittuple, lz->iternum); - item = PyIter_Next(it); - if (item != NULL) - return item; - if (PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_StopIteration)) - PyErr_Clear(); - else - return NULL; + if (lz->source == NULL) + return NULL; /* already stopped */ + + if (lz->active == NULL) { + PyObject *iterable = PyIter_Next(lz->source); + if (iterable == NULL) { + Py_CLEAR(lz->source); + return NULL; /* no more input sources */ + } + lz->active = PyObject_GetIter(iterable); + if (lz->active == NULL) { + Py_DECREF(iterable); + Py_CLEAR(lz->source); + return NULL; /* input not iterable */ } - lz->iternum++; } - return NULL; + item = PyIter_Next(lz->active); + if (item != NULL) + return item; + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_StopIteration)) + PyErr_Clear(); + else + return NULL; /* input raised an exception */ + } + Py_CLEAR(lz->active); + return chain_next(lz); /* recurse and use next active */ } PyDoc_STRVAR(chain_doc, @@ -1666,6 +1678,18 @@ Return a chain object whose .__next__() method returns elements from the\n\ first iterable until it is exhausted, then elements from the next\n\ iterable, until all of the iterables are exhausted."); +PyDoc_STRVAR(chain_from_iterable_doc, +"chain.from_iterable(iterable) --> chain object\n\ +\n\ +Alternate chain() contructor taking a single iterable argument\n\ +that evaluates lazily."); + +static PyMethodDef chain_methods[] = { + {"from_iterable", (PyCFunction) chain_new_from_iterable, METH_O | METH_CLASS, + chain_from_iterable_doc}, + {NULL, NULL} /* sentinel */ +}; + static PyTypeObject chain_type = { PyVarObject_HEAD_INIT(NULL, 0) "itertools.chain", /* tp_name */ @@ -1696,7 +1720,7 @@ static PyTypeObject chain_type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)chain_next, /* tp_iternext */ - 0, /* tp_methods */ + chain_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ @@ -1728,17 +1752,32 @@ static PyObject * product_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { productobject *lz; - Py_ssize_t npools; + Py_ssize_t nargs, npools, repeat=1; PyObject *pools = NULL; Py_ssize_t *maxvec = NULL; Py_ssize_t *indices = NULL; Py_ssize_t i; - if (type == &product_type && !_PyArg_NoKeywords("product()", kwds)) - return NULL; + if (kwds != NULL) { + char *kwlist[] = {"repeat", 0}; + PyObject *tmpargs = PyTuple_New(0); + if (tmpargs == NULL) + return NULL; + if (!PyArg_ParseTupleAndKeywords(tmpargs, kwds, "|n:product", kwlist, &repeat)) { + Py_DECREF(tmpargs); + return NULL; + } + Py_DECREF(tmpargs); + if (repeat < 0) { + PyErr_SetString(PyExc_ValueError, + "repeat argument cannot be negative"); + return NULL; + } + } assert(PyTuple_Check(args)); - npools = PyTuple_GET_SIZE(args); + nargs = (repeat == 0) ? 0 : PyTuple_GET_SIZE(args); + npools = nargs * repeat; maxvec = PyMem_Malloc(npools * sizeof(Py_ssize_t)); indices = PyMem_Malloc(npools * sizeof(Py_ssize_t)); @@ -1751,7 +1790,7 @@ product_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (pools == NULL) goto error; - for (i=0; i < npools; ++i) { + for (i=0; i < nargs ; ++i) { PyObject *item = PyTuple_GET_ITEM(args, i); PyObject *pool = PySequence_Tuple(item); if (pool == NULL) @@ -1761,6 +1800,13 @@ product_new(PyTypeObject *type, PyObject *args, PyObject *kwds) maxvec[i] = PyTuple_GET_SIZE(pool); indices[i] = 0; } + for ( ; i < npools; ++i) { + PyObject *pool = PyTuple_GET_ITEM(pools, i - nargs); + Py_INCREF(pool); + PyTuple_SET_ITEM(pools, i, pool); + maxvec[i] = maxvec[i - nargs]; + indices[i] = 0; + } /* create productobject structure */ lz = (productobject *)type->tp_alloc(type, 0); |