]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
SF patch 1546297 (with some tweaks):
authorGuido van Rossum <guido@python.org>
Fri, 25 Aug 2006 23:26:40 +0000 (23:26 +0000)
committerGuido van Rossum <guido@python.org>
Fri, 25 Aug 2006 23:26:40 +0000 (23:26 +0000)
Create a real zip iterator object; not using itertools.izip
(Brian Holmes).

Include/iterobject.h
Objects/iterobject.c
Python/bltinmodule.c

index c078ebb28b092cc8fbed35417b1c361b16204687..69deb45de3a1035909d8959007ab2c255faad928 100644 (file)
@@ -16,6 +16,9 @@ PyAPI_DATA(PyTypeObject) PyCallIter_Type;
 #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 cf839f47816d59f49c0f2a398f5c1ecaf5d49df3..dc4c5835ca0f5d36831827c4027d6ec86a52b789 100644 (file)
@@ -230,3 +230,174 @@ PyTypeObject PyCallIter_Type = {
        (iternextfunc)calliter_iternext,        /* tp_iternext */
        0,                                      /* tp_methods */
 };
+
+
+/*********************** Zip Iterator **************************/
+/* Largely copied from itertools.c by Brian Holmes */
+
+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 PyTypeObject PyZipIter_Type; /* Forward */
+
+PyObject *
+_PyZip_CreateIter(PyObject* args)
+{
+       Py_ssize_t i;
+        Py_ssize_t tuplesize;
+       PyObject* ziptuple;
+       PyObject* result;
+       struct zipiterobject_t* zipiter;
+        
+        assert(PyTuple_Check(args));
+
+       if (PyZipIter_Type.ob_type == NULL) {
+               if (PyType_Ready(&PyZipIter_Type) < 0)
+                       return NULL;
+       }
+
+       tuplesize = PySequence_Length((PyObject*) 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) {
+                       /* XXX Should we do this?
+                       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;
+}
+
+static PyTypeObject PyZipIter_Type = {
+       PyObject_HEAD_INIT(0)
+       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 */
+};
index 6ca2a283d4a3c998bc3c2d5517764a8cccc47c6c..200ec26f22235b3e155a93eb573605bc59142e7e 100644 (file)
@@ -1855,22 +1855,10 @@ is a shortcut for issubclass(X, A) or issubclass(X, B) or ... (etc.).");
 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);
 }