*** itertoolsmodule.c.orig Tue Jun 17 15:52:32 2003 --- itertoolsmodule.c Tue Jun 17 17:19:09 2003 *************** *** 1781,1786 **** --- 1781,2116 ---- }; + /* roundrobin object ********************************************************/ + + typedef struct { + PyObject_HEAD + long iternum; /* which iterator is active */ + PyObject *itlist; /* list of iterators */ + } roundrobinobject; + + PyTypeObject roundrobin_type; + + static PyObject * + roundrobin_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + { + roundrobinobject *lz; + int listsize = PySequence_Length(args); + int i; + PyObject *itlist; + char *error_msg = "roundrobin argument #%d must support iteration"; + + /* obtain iterators */ + assert(PyTuple_Check(args)); + itlist = PyList_New(listsize); + if(itlist == NULL) + return NULL; + for (i=0; i < listsize; ++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, error_msg, i+1); + Py_DECREF(itlist); + return NULL; + } + PyList_SET_ITEM(itlist, i, it); + } + + /* create roundrobinobject structure */ + lz = (roundrobinobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(itlist); + return NULL; + } + + lz->itlist = itlist; + lz->iternum = 0; + + return (PyObject *)lz; + } + + static void + roundrobin_dealloc(roundrobinobject *lz) + { + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->itlist); + lz->ob_type->tp_free(lz); + } + + static int + roundrobin_traverse(roundrobinobject *lz, visitproc visit, void *arg) + { + if (lz->itlist) + return visit(lz->itlist, arg); + return 0; + } + + static PyObject * + roundrobin_next(roundrobinobject *lz) + { + PyObject *it; + PyObject *item; + long listsize; + + + while ((listsize = PyList_GET_SIZE(lz->itlist))) { + lz->iternum = lz->iternum % listsize; + it = PyList_GET_ITEM(lz->itlist, lz->iternum); + item = PyIter_Next(it); + if (item == NULL) { + /* the iterator is finished, remove */ + PyList_SetSlice(lz->itlist, lz->iternum, + lz->iternum + 1, (PyObject *)NULL); + } else { + lz->iternum++; + return item; + } + } + return NULL; + } + + PyDoc_STRVAR(roundrobin_doc, + "roundrobin(*iterables) --> roundrobin object\n\ + \n\ + Return a roundrobin object whose .next() method returns elements from each\n\ + iterable in turn. If an iterator is exhausted during its turn it is\n\ + removed from the list. We continue unti all iterators are exhausted"); + + PyTypeObject roundrobin_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.roundrobin", /* tp_name */ + sizeof(roundrobinobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)roundrobin_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 | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + roundrobin_doc, /* tp_doc */ + (traverseproc)roundrobin_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)roundrobin_next, /* tp_iternext */ + 0, /* 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 */ + roundrobin_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ + }; + + + /* window object ********************************************************/ + + typedef struct { + PyObject_HEAD + int window; /* the size of the window */ + PyObject *curr_list; /* the current items in the window */ + PyObject *it; /* the iterator we are using */ + } windowobject; + + PyTypeObject window_type; + + static PyObject * + window_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + { + windowobject *lz; + int window_size = 0; + PyObject *iterable; + PyObject *it; + + if (!PyArg_ParseTuple(args, "Oi:window", &iterable, &window_size)) + return NULL; + + /* Get iterator. */ + it = PyObject_GetIter(iterable); + if (it == NULL) + return NULL; + + /* check window size */ + if (window_size <= 0) { + Py_DECREF(it); + if (PyErr_Occurred()) + PyErr_Clear(); + PyErr_SetString(PyExc_ValueError, + "window size must be positive\n"); + return NULL; + } + + /* create window structure */ + lz = (windowobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(it); + return NULL; + } + + lz->it = it; + lz->window = window_size; + lz->curr_list = NULL; + + return (PyObject *)lz; + } + + static void + window_dealloc(windowobject *lz) + { + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->it); + Py_XDECREF(lz->curr_list); + lz->ob_type->tp_free(lz); + } + + static int + window_traverse(windowobject *lz, visitproc visit, void *arg) + { + int err; + if (lz->it) { + err = visit(lz->it, arg); + if (err) + return err; + } + if (lz->curr_list) { + err = visit(lz->curr_list, arg); + if (err) + return err; + } + return 0; + } + + static PyObject * + window_next(windowobject *lz) + { + PyObject *tup; + PyObject *item; + int remove = 1; + int add = 1; + int copy = lz->window - 1; + int i; + + tup = PyTuple_New(lz->window); + if (tup == NULL) + return NULL; + + /* first call, create our copy of the window */ + if (lz->curr_list == NULL) { + lz->curr_list = PyList_New(0); + if (lz->curr_list == NULL) { + Py_DECREF(tup); + return NULL; + } + remove = 0; + add = lz->window; + copy = 0; + } + /* remove items from the last list */ + if (remove > 0) { + PyList_SetSlice(lz->curr_list, 0, remove, (PyObject *)NULL); + } + + /* copy the existing items from the list to the tuple */ + for (i = 0; i < copy; i++) { + item = PyList_GET_ITEM(lz->curr_list, i); + Py_INCREF(item); + PyTuple_SET_ITEM(tup, i, item); + } + + /* add items to the tuple and the curr_list */ + while (add > 0) { + item = PyIter_Next(lz->it); + if (item == NULL) { + /* the iterator is finished, cleanup and leave */ + Py_DECREF(tup); + return NULL; + } else { + PyTuple_SET_ITEM(tup, lz->window - add, item); + if (PyList_Append(lz->curr_list, item)) { + Py_DECREF(tup); + return NULL; + } + } + add--; + } + + return tup; + } + + PyDoc_STRVAR(window_doc, + "window(iterable, windowsize) --> window object\n\ + \n\ + Return a window object whose .next() method returns tuples of elements\n\ + of size windowszie starting with the first windowsize elements from the\n\ + iterable and ending with the last windowsize elements from the iterable.\n\ + "); + + PyTypeObject window_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.window", /* tp_name */ + sizeof(windowobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)window_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 | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + window_doc, /* tp_doc */ + (traverseproc)window_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)window_next, /* tp_iternext */ + 0, /* 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 */ + window_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ + }; + + /* module level code ********************************************************/ PyDoc_STRVAR(module_doc, *************** *** 1800,1807 **** --- 2130,2139 ---- imap(fun, p, q, ...) --> fun(p0, q0), fun(p1, q1), ...\n\ starmap(fun, seq) --> fun(*seq[0]), fun(*seq[1]), ...\n\ chain(p, q, ...) --> p0, p1, ... plast, q0, q1, ... \n\ + roundrobin(p, q, ...) -> p0, q0, ... plast, qlast\n\ takewhile(pred, seq) --> seq[0], seq[1], until pred fails\n\ dropwhile(pred, seq) --> seq[n], seq[n+1], starting when pred fails\n\ + window(p, size) --> ((p0, p1 .. psize), (p1, p2 .. psize), ...)\n\ "); *************** *** 1824,1829 **** --- 2156,2163 ---- &count_type, &izip_type, &repeat_type, + &roundrobin_type, + &window_type, NULL };