Index: Python/bltinmodule.c =================================================================== --- Python/bltinmodule.c (revision 51572) +++ Python/bltinmodule.c (working copy) @@ -1855,22 +1855,10 @@ static PyObject* builtin_zip(PyObject *self, PyObject *args) { - PyObject *itertools = NULL, *izip = NULL, *result = NULL; + /* args must be a tuple */ + assert(PyTuple_Check(args)); - itertools = PyImport_ImportModule("itertools"); - if (itertools == NULL) - return NULL; - - izip = PyObject_GetAttrString(itertools, "izip"); - if (izip == NULL) - goto done; - - result = PyObject_Call(izip, args, NULL); - - done: - Py_XDECREF(itertools); - Py_XDECREF(izip); - return result; + return _PyZip_CreateIter(args); } Index: Include/iterobject.h =================================================================== --- Include/iterobject.h (revision 51572) +++ Include/iterobject.h (working copy) @@ -16,6 +16,9 @@ #define PyCallIter_Check(op) ((op)->ob_type == &PyCallIter_Type) PyAPI_FUNC(PyObject *) PyCallIter_New(PyObject *, PyObject *); + +PyObject* _PyZip_CreateIter(PyObject* args); + #ifdef __cplusplus } #endif Index: Objects/iterobject.c =================================================================== --- Objects/iterobject.c (revision 51572) +++ Objects/iterobject.c (working copy) @@ -230,3 +230,169 @@ (iternextfunc)calliter_iternext, /* tp_iternext */ 0, /* tp_methods */ }; + + +/*********************** Zip Iterator **************************/ + +typedef struct zipiterobject_t { + PyObject_HEAD + PyTupleObject *it_tuple; /* Set to NULL when iterator is exhausted */ + Py_ssize_t resultsize; + PyTupleObject *result; /* Reusable tuple for optimization */ +} zipiterobject; + +static void zipiter_dealloc(zipiterobject *); +static int zipiter_traverse(zipiterobject *, visitproc, void *); +static PyObject *zipiter_next(zipiterobject *); +static PyObject *zipiter_len(zipiterobject *); + +PyTypeObject PyZipIter_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "zipiterator", /* tp_name */ + sizeof(zipiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)zipiter_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 | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)zipiter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weakzipoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)zipiter_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ +}; + + +PyObject * +_PyZip_CreateIter(PyObject* args) +{ + Py_ssize_t i; + Py_ssize_t tuplesize = PySequence_Length((PyObject*) args); + PyObject* ziptuple; + PyObject* result; + struct zipiterobject_t* zipiter; + + assert(PyTuple_Check(args)); + + ziptuple = PyTuple_New(tuplesize); + if (ziptuple == NULL) + return NULL; + + for(i=0; i < tuplesize; i++) { + PyObject *o = PyTuple_GET_ITEM(args, i); + PyObject *it = PyObject_GetIter(o); + if (it == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, + "zip argument #%zd must support iteration", + i+1); + Py_DECREF(ziptuple); + return NULL; + } + PyTuple_SET_ITEM(ziptuple, i, it); + } + + /* create a reusable result holder */ + result = PyTuple_New(tuplesize); + if (result == NULL) { + Py_DECREF(ziptuple); + return NULL; + } + for (i=0 ; i < tuplesize ; i++) { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(result, i, Py_None); + } + + zipiter = PyObject_GC_New(zipiterobject, &PyZipIter_Type); + if (zipiter == NULL) { + Py_DECREF(ziptuple); + Py_DECREF(result); + return NULL; + } + + zipiter->result = (PyTupleObject*) result; + zipiter->resultsize = tuplesize; + Py_INCREF(ziptuple); + zipiter->it_tuple = (PyTupleObject *) ziptuple; + _PyObject_GC_TRACK(zipiter); + return (PyObject *)zipiter; +} + +static void +zipiter_dealloc(zipiterobject *it) +{ + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->it_tuple); + Py_XDECREF(it->result); + PyObject_GC_Del(it); +} + +static int +zipiter_traverse(zipiterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->it_tuple); + Py_VISIT(it->result); + return 0; +} + +static PyObject * +zipiter_next(zipiterobject *zit) +{ + Py_ssize_t i; + Py_ssize_t tuplesize = zit->resultsize; + PyObject *result = (PyObject*) zit->result; + PyObject *olditem; + + if (tuplesize == 0) + return NULL; + + if (result->ob_refcnt == 1) { + Py_INCREF(result); + for (i=0 ; i < tuplesize ; i++) { + PyObject *it = PyTuple_GET_ITEM(zit->it_tuple, i); + assert(PyIter_Check(it)); + PyObject *item = (*it->ob_type->tp_iternext)(it); + if (item == NULL) { + Py_DECREF(result); + return NULL; + } + olditem = PyTuple_GET_ITEM(result, i); + PyTuple_SET_ITEM(result, i, item); + Py_DECREF(olditem); + } + } else { + result = PyTuple_New(tuplesize); + if (result == NULL) + return NULL; + for (i=0 ; i < tuplesize ; i++) { + PyObject *it = PyTuple_GET_ITEM(zit->it_tuple, i); + assert(PyIter_Check(it)); + PyObject *item = (*it->ob_type->tp_iternext)(it); + if (item == NULL) { + Py_DECREF(result); + return NULL; + } + PyTuple_SET_ITEM(result, i, item); + } + } + return result; +} +