mirror of
https://github.com/python/cpython.git
synced 2024-11-28 04:15:11 +08:00
7c2bb5bc57
the itertoolsmodule. * Taught itertools.repeat(obj, n) to treat negative repeat counts as zero. This behavior matches that for sequences and prevents infinite loops.
1841 lines
40 KiB
C
1841 lines
40 KiB
C
|
|
#include "Python.h"
|
|
|
|
/* Itertools module written and maintained
|
|
by Raymond D. Hettinger <python@rcn.com>
|
|
Copyright (c) 2003 Python Software Foundation.
|
|
All rights reserved.
|
|
*/
|
|
|
|
/* cycle object **********************************************************/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyObject *it;
|
|
PyObject *saved;
|
|
int firstpass;
|
|
} cycleobject;
|
|
|
|
PyTypeObject cycle_type;
|
|
|
|
static PyObject *
|
|
cycle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
PyObject *it;
|
|
PyObject *iterable;
|
|
PyObject *saved;
|
|
cycleobject *lz;
|
|
|
|
if (!PyArg_UnpackTuple(args, "cycle", 1, 1, &iterable))
|
|
return NULL;
|
|
|
|
/* Get iterator. */
|
|
it = PyObject_GetIter(iterable);
|
|
if (it == NULL)
|
|
return NULL;
|
|
|
|
saved = PyList_New(0);
|
|
if (saved == NULL) {
|
|
Py_DECREF(it);
|
|
return NULL;
|
|
}
|
|
|
|
/* create cycleobject structure */
|
|
lz = (cycleobject *)type->tp_alloc(type, 0);
|
|
if (lz == NULL) {
|
|
Py_DECREF(it);
|
|
Py_DECREF(saved);
|
|
return NULL;
|
|
}
|
|
lz->it = it;
|
|
lz->saved = saved;
|
|
lz->firstpass = 0;
|
|
|
|
return (PyObject *)lz;
|
|
}
|
|
|
|
static void
|
|
cycle_dealloc(cycleobject *lz)
|
|
{
|
|
PyObject_GC_UnTrack(lz);
|
|
Py_XDECREF(lz->saved);
|
|
Py_XDECREF(lz->it);
|
|
lz->ob_type->tp_free(lz);
|
|
}
|
|
|
|
static int
|
|
cycle_traverse(cycleobject *lz, visitproc visit, void *arg)
|
|
{
|
|
int err;
|
|
|
|
if (lz->it) {
|
|
err = visit(lz->it, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
if (lz->saved) {
|
|
err = visit(lz->saved, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
cycle_next(cycleobject *lz)
|
|
{
|
|
PyObject *item;
|
|
PyObject *it;
|
|
|
|
while (1) {
|
|
item = PyIter_Next(lz->it);
|
|
if (item != NULL) {
|
|
if (!lz->firstpass)
|
|
PyList_Append(lz->saved, item);
|
|
return item;
|
|
}
|
|
if (PyList_Size(lz->saved) == 0)
|
|
return NULL;
|
|
it = PyObject_GetIter(lz->saved);
|
|
if (it == NULL)
|
|
return NULL;
|
|
Py_DECREF(lz->it);
|
|
lz->it = it;
|
|
lz->firstpass = 1;
|
|
}
|
|
}
|
|
|
|
PyDoc_STRVAR(cycle_doc,
|
|
"cycle(iterable) --> cycle object\n\
|
|
\n\
|
|
Return elements from the iterable until it is exhausted.\n\
|
|
Then repeat the sequence indefinitely.");
|
|
|
|
PyTypeObject cycle_type = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"itertools.cycle", /* tp_name */
|
|
sizeof(cycleobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)cycle_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 */
|
|
cycle_doc, /* tp_doc */
|
|
(traverseproc)cycle_traverse, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)cycle_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 */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
cycle_new, /* tp_new */
|
|
PyObject_GC_Del, /* tp_free */
|
|
};
|
|
|
|
|
|
/* dropwhile object **********************************************************/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyObject *func;
|
|
PyObject *it;
|
|
long start;
|
|
} dropwhileobject;
|
|
|
|
PyTypeObject dropwhile_type;
|
|
|
|
static PyObject *
|
|
dropwhile_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
PyObject *func, *seq;
|
|
PyObject *it;
|
|
dropwhileobject *lz;
|
|
|
|
if (!PyArg_UnpackTuple(args, "dropwhile", 2, 2, &func, &seq))
|
|
return NULL;
|
|
|
|
/* Get iterator. */
|
|
it = PyObject_GetIter(seq);
|
|
if (it == NULL)
|
|
return NULL;
|
|
|
|
/* create dropwhileobject structure */
|
|
lz = (dropwhileobject *)type->tp_alloc(type, 0);
|
|
if (lz == NULL) {
|
|
Py_DECREF(it);
|
|
return NULL;
|
|
}
|
|
Py_INCREF(func);
|
|
lz->func = func;
|
|
lz->it = it;
|
|
lz->start = 0;
|
|
|
|
return (PyObject *)lz;
|
|
}
|
|
|
|
static void
|
|
dropwhile_dealloc(dropwhileobject *lz)
|
|
{
|
|
PyObject_GC_UnTrack(lz);
|
|
Py_XDECREF(lz->func);
|
|
Py_XDECREF(lz->it);
|
|
lz->ob_type->tp_free(lz);
|
|
}
|
|
|
|
static int
|
|
dropwhile_traverse(dropwhileobject *lz, visitproc visit, void *arg)
|
|
{
|
|
int err;
|
|
|
|
if (lz->it) {
|
|
err = visit(lz->it, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
if (lz->func) {
|
|
err = visit(lz->func, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
dropwhile_next(dropwhileobject *lz)
|
|
{
|
|
PyObject *item, *good;
|
|
PyObject *it = lz->it;
|
|
long ok;
|
|
|
|
for (;;) {
|
|
assert(PyIter_Check(it));
|
|
item = (*it->ob_type->tp_iternext)(it);
|
|
if (item == NULL)
|
|
return NULL;
|
|
if (lz->start == 1)
|
|
return item;
|
|
|
|
good = PyObject_CallFunctionObjArgs(lz->func, item, NULL);
|
|
if (good == NULL) {
|
|
Py_DECREF(item);
|
|
return NULL;
|
|
}
|
|
ok = PyObject_IsTrue(good);
|
|
Py_DECREF(good);
|
|
if (!ok) {
|
|
lz->start = 1;
|
|
return item;
|
|
}
|
|
Py_DECREF(item);
|
|
}
|
|
}
|
|
|
|
PyDoc_STRVAR(dropwhile_doc,
|
|
"dropwhile(predicate, iterable) --> dropwhile object\n\
|
|
\n\
|
|
Drop items from the iterable while predicate(item) is true.\n\
|
|
Afterwards, return every element until the iterable is exhausted.");
|
|
|
|
PyTypeObject dropwhile_type = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"itertools.dropwhile", /* tp_name */
|
|
sizeof(dropwhileobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)dropwhile_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 */
|
|
dropwhile_doc, /* tp_doc */
|
|
(traverseproc)dropwhile_traverse, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)dropwhile_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 */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
dropwhile_new, /* tp_new */
|
|
PyObject_GC_Del, /* tp_free */
|
|
};
|
|
|
|
|
|
/* takewhile object **********************************************************/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyObject *func;
|
|
PyObject *it;
|
|
long stop;
|
|
} takewhileobject;
|
|
|
|
PyTypeObject takewhile_type;
|
|
|
|
static PyObject *
|
|
takewhile_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
PyObject *func, *seq;
|
|
PyObject *it;
|
|
takewhileobject *lz;
|
|
|
|
if (!PyArg_UnpackTuple(args, "takewhile", 2, 2, &func, &seq))
|
|
return NULL;
|
|
|
|
/* Get iterator. */
|
|
it = PyObject_GetIter(seq);
|
|
if (it == NULL)
|
|
return NULL;
|
|
|
|
/* create takewhileobject structure */
|
|
lz = (takewhileobject *)type->tp_alloc(type, 0);
|
|
if (lz == NULL) {
|
|
Py_DECREF(it);
|
|
return NULL;
|
|
}
|
|
Py_INCREF(func);
|
|
lz->func = func;
|
|
lz->it = it;
|
|
lz->stop = 0;
|
|
|
|
return (PyObject *)lz;
|
|
}
|
|
|
|
static void
|
|
takewhile_dealloc(takewhileobject *lz)
|
|
{
|
|
PyObject_GC_UnTrack(lz);
|
|
Py_XDECREF(lz->func);
|
|
Py_XDECREF(lz->it);
|
|
lz->ob_type->tp_free(lz);
|
|
}
|
|
|
|
static int
|
|
takewhile_traverse(takewhileobject *lz, visitproc visit, void *arg)
|
|
{
|
|
int err;
|
|
|
|
if (lz->it) {
|
|
err = visit(lz->it, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
if (lz->func) {
|
|
err = visit(lz->func, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
takewhile_next(takewhileobject *lz)
|
|
{
|
|
PyObject *item, *good;
|
|
PyObject *it = lz->it;
|
|
long ok;
|
|
|
|
if (lz->stop == 1)
|
|
return NULL;
|
|
|
|
assert(PyIter_Check(it));
|
|
item = (*it->ob_type->tp_iternext)(it);
|
|
if (item == NULL)
|
|
return NULL;
|
|
|
|
good = PyObject_CallFunctionObjArgs(lz->func, item, NULL);
|
|
if (good == NULL) {
|
|
Py_DECREF(item);
|
|
return NULL;
|
|
}
|
|
ok = PyObject_IsTrue(good);
|
|
Py_DECREF(good);
|
|
if (ok)
|
|
return item;
|
|
Py_DECREF(item);
|
|
lz->stop = 1;
|
|
return NULL;
|
|
}
|
|
|
|
PyDoc_STRVAR(takewhile_doc,
|
|
"takewhile(predicate, iterable) --> takewhile object\n\
|
|
\n\
|
|
Return successive entries from an iterable as long as the \n\
|
|
predicate evaluates to true for each entry.");
|
|
|
|
PyTypeObject takewhile_type = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"itertools.takewhile", /* tp_name */
|
|
sizeof(takewhileobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)takewhile_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 */
|
|
takewhile_doc, /* tp_doc */
|
|
(traverseproc)takewhile_traverse, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)takewhile_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 */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
takewhile_new, /* tp_new */
|
|
PyObject_GC_Del, /* tp_free */
|
|
};
|
|
|
|
|
|
/* islice object ************************************************************/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyObject *it;
|
|
long next;
|
|
long stop;
|
|
long step;
|
|
long cnt;
|
|
} isliceobject;
|
|
|
|
PyTypeObject islice_type;
|
|
|
|
static PyObject *
|
|
islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
PyObject *seq;
|
|
long start=0, stop=-1, step=1;
|
|
PyObject *it, *a1=NULL, *a2=NULL;
|
|
int numargs;
|
|
isliceobject *lz;
|
|
|
|
numargs = PyTuple_Size(args);
|
|
if (!PyArg_ParseTuple(args, "OO|Ol:islice", &seq, &a1, &a2, &step))
|
|
return NULL;
|
|
|
|
if (numargs == 2) {
|
|
if (a1 != Py_None) {
|
|
stop = PyInt_AsLong(a1);
|
|
if (stop == -1) {
|
|
if (PyErr_Occurred())
|
|
PyErr_Clear();
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"Stop argument must be an integer or None.");
|
|
return NULL;
|
|
}
|
|
}
|
|
} else {
|
|
start = PyInt_AsLong(a1);
|
|
if (start == -1 && PyErr_Occurred()) {
|
|
PyErr_Clear();
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"Start argument must be an integer.");
|
|
return NULL;
|
|
}
|
|
if (a2 != Py_None) {
|
|
stop = PyInt_AsLong(a2);
|
|
if (stop == -1) {
|
|
if (PyErr_Occurred())
|
|
PyErr_Clear();
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"Stop argument must be an integer or None.");
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (start<0 || stop<-1) {
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"Indices for islice() must be positive.");
|
|
return NULL;
|
|
}
|
|
|
|
if (step<1) {
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"Step must be one or larger for islice().");
|
|
return NULL;
|
|
}
|
|
|
|
/* Get iterator. */
|
|
it = PyObject_GetIter(seq);
|
|
if (it == NULL)
|
|
return NULL;
|
|
|
|
/* create isliceobject structure */
|
|
lz = (isliceobject *)type->tp_alloc(type, 0);
|
|
if (lz == NULL) {
|
|
Py_DECREF(it);
|
|
return NULL;
|
|
}
|
|
lz->it = it;
|
|
lz->next = start;
|
|
lz->stop = stop;
|
|
lz->step = step;
|
|
lz->cnt = 0L;
|
|
|
|
return (PyObject *)lz;
|
|
}
|
|
|
|
static void
|
|
islice_dealloc(isliceobject *lz)
|
|
{
|
|
PyObject_GC_UnTrack(lz);
|
|
Py_XDECREF(lz->it);
|
|
lz->ob_type->tp_free(lz);
|
|
}
|
|
|
|
static int
|
|
islice_traverse(isliceobject *lz, visitproc visit, void *arg)
|
|
{
|
|
if (lz->it)
|
|
return visit(lz->it, arg);
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
islice_next(isliceobject *lz)
|
|
{
|
|
PyObject *item;
|
|
PyObject *it = lz->it;
|
|
long oldnext;
|
|
|
|
while (lz->cnt < lz->next) {
|
|
assert(PyIter_Check(it));
|
|
item = (*it->ob_type->tp_iternext)(it);
|
|
if (item == NULL)
|
|
return NULL;
|
|
Py_DECREF(item);
|
|
lz->cnt++;
|
|
}
|
|
if (lz->stop != -1 && lz->cnt >= lz->stop)
|
|
return NULL;
|
|
assert(PyIter_Check(it));
|
|
item = (*it->ob_type->tp_iternext)(it);
|
|
if (item == NULL)
|
|
return NULL;
|
|
lz->cnt++;
|
|
oldnext = lz->next;
|
|
lz->next += lz->step;
|
|
if (lz->next < oldnext) /* Check for overflow */
|
|
lz->next = lz->stop;
|
|
return item;
|
|
}
|
|
|
|
PyDoc_STRVAR(islice_doc,
|
|
"islice(iterable, [start,] stop [, step]) --> islice object\n\
|
|
\n\
|
|
Return an iterator whose next() method returns selected values from an\n\
|
|
iterable. If start is specified, will skip all preceding elements;\n\
|
|
otherwise, start defaults to zero. Step defaults to one. If\n\
|
|
specified as another value, step determines how many values are \n\
|
|
skipped between successive calls. Works like a slice() on a list\n\
|
|
but returns an iterator.");
|
|
|
|
PyTypeObject islice_type = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"itertools.islice", /* tp_name */
|
|
sizeof(isliceobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)islice_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 */
|
|
islice_doc, /* tp_doc */
|
|
(traverseproc)islice_traverse, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)islice_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 */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
islice_new, /* tp_new */
|
|
PyObject_GC_Del, /* tp_free */
|
|
};
|
|
|
|
|
|
/* starmap object ************************************************************/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyObject *func;
|
|
PyObject *it;
|
|
} starmapobject;
|
|
|
|
PyTypeObject starmap_type;
|
|
|
|
static PyObject *
|
|
starmap_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
PyObject *func, *seq;
|
|
PyObject *it;
|
|
starmapobject *lz;
|
|
|
|
if (!PyArg_UnpackTuple(args, "starmap", 2, 2, &func, &seq))
|
|
return NULL;
|
|
|
|
/* Get iterator. */
|
|
it = PyObject_GetIter(seq);
|
|
if (it == NULL)
|
|
return NULL;
|
|
|
|
/* create starmapobject structure */
|
|
lz = (starmapobject *)type->tp_alloc(type, 0);
|
|
if (lz == NULL) {
|
|
Py_DECREF(it);
|
|
return NULL;
|
|
}
|
|
Py_INCREF(func);
|
|
lz->func = func;
|
|
lz->it = it;
|
|
|
|
return (PyObject *)lz;
|
|
}
|
|
|
|
static void
|
|
starmap_dealloc(starmapobject *lz)
|
|
{
|
|
PyObject_GC_UnTrack(lz);
|
|
Py_XDECREF(lz->func);
|
|
Py_XDECREF(lz->it);
|
|
lz->ob_type->tp_free(lz);
|
|
}
|
|
|
|
static int
|
|
starmap_traverse(starmapobject *lz, visitproc visit, void *arg)
|
|
{
|
|
int err;
|
|
|
|
if (lz->it) {
|
|
err = visit(lz->it, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
if (lz->func) {
|
|
err = visit(lz->func, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
starmap_next(starmapobject *lz)
|
|
{
|
|
PyObject *args;
|
|
PyObject *result;
|
|
PyObject *it = lz->it;
|
|
|
|
assert(PyIter_Check(it));
|
|
args = (*it->ob_type->tp_iternext)(it);
|
|
if (args == NULL)
|
|
return NULL;
|
|
if (!PyTuple_CheckExact(args)) {
|
|
Py_DECREF(args);
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"iterator must return a tuple");
|
|
return NULL;
|
|
}
|
|
result = PyObject_Call(lz->func, args, NULL);
|
|
Py_DECREF(args);
|
|
return result;
|
|
}
|
|
|
|
PyDoc_STRVAR(starmap_doc,
|
|
"starmap(function, sequence) --> starmap object\n\
|
|
\n\
|
|
Return an iterator whose values are returned from the function evaluated\n\
|
|
with a argument tuple taken from the given sequence.");
|
|
|
|
PyTypeObject starmap_type = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"itertools.starmap", /* tp_name */
|
|
sizeof(starmapobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)starmap_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 */
|
|
starmap_doc, /* tp_doc */
|
|
(traverseproc)starmap_traverse, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)starmap_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 */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
starmap_new, /* tp_new */
|
|
PyObject_GC_Del, /* tp_free */
|
|
};
|
|
|
|
|
|
/* imap object ************************************************************/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyObject *iters;
|
|
PyObject *func;
|
|
} imapobject;
|
|
|
|
PyTypeObject imap_type;
|
|
|
|
static PyObject *
|
|
imap_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
PyObject *it, *iters, *func;
|
|
imapobject *lz;
|
|
int numargs, i;
|
|
|
|
numargs = PyTuple_Size(args);
|
|
if (numargs < 2) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"imap() must have at least two arguments.");
|
|
return NULL;
|
|
}
|
|
|
|
iters = PyTuple_New(numargs-1);
|
|
if (iters == NULL)
|
|
return NULL;
|
|
|
|
for (i=1 ; i<numargs ; i++) {
|
|
/* Get iterator. */
|
|
it = PyObject_GetIter(PyTuple_GET_ITEM(args, i));
|
|
if (it == NULL) {
|
|
Py_DECREF(iters);
|
|
return NULL;
|
|
}
|
|
PyTuple_SET_ITEM(iters, i-1, it);
|
|
}
|
|
|
|
/* create imapobject structure */
|
|
lz = (imapobject *)type->tp_alloc(type, 0);
|
|
if (lz == NULL) {
|
|
Py_DECREF(iters);
|
|
return NULL;
|
|
}
|
|
lz->iters = iters;
|
|
func = PyTuple_GET_ITEM(args, 0);
|
|
Py_INCREF(func);
|
|
lz->func = func;
|
|
|
|
return (PyObject *)lz;
|
|
}
|
|
|
|
static void
|
|
imap_dealloc(imapobject *lz)
|
|
{
|
|
PyObject_GC_UnTrack(lz);
|
|
Py_XDECREF(lz->iters);
|
|
Py_XDECREF(lz->func);
|
|
lz->ob_type->tp_free(lz);
|
|
}
|
|
|
|
static int
|
|
imap_traverse(imapobject *lz, visitproc visit, void *arg)
|
|
{
|
|
int err;
|
|
|
|
if (lz->iters) {
|
|
err = visit(lz->iters, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
if (lz->func) {
|
|
err = visit(lz->func, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
imap() is an iterator version of __builtins__.map() except that it does
|
|
not have the None fill-in feature. That was intentionally left out for
|
|
the following reasons:
|
|
|
|
1) Itertools are designed to be easily combined and chained together.
|
|
Having all tools stop with the shortest input is a unifying principle
|
|
that makes it easier to combine finite iterators (supplying data) with
|
|
infinite iterators like count() and repeat() (for supplying sequential
|
|
or constant arguments to a function).
|
|
|
|
2) In typical use cases for combining itertools, having one finite data
|
|
supplier run out before another is likely to be an error condition which
|
|
should not pass silently by automatically supplying None.
|
|
|
|
3) The use cases for automatic None fill-in are rare -- not many functions
|
|
do something useful when a parameter suddenly switches type and becomes
|
|
None.
|
|
|
|
4) If a need does arise, it can be met by __builtins__.map() or by
|
|
writing a generator.
|
|
|
|
5) Similar toolsets in Haskell and SML do not have automatic None fill-in.
|
|
*/
|
|
|
|
static PyObject *
|
|
imap_next(imapobject *lz)
|
|
{
|
|
PyObject *val;
|
|
PyObject *argtuple;
|
|
PyObject *result;
|
|
int numargs, i;
|
|
|
|
numargs = PyTuple_Size(lz->iters);
|
|
argtuple = PyTuple_New(numargs);
|
|
if (argtuple == NULL)
|
|
return NULL;
|
|
|
|
for (i=0 ; i<numargs ; i++) {
|
|
val = PyIter_Next(PyTuple_GET_ITEM(lz->iters, i));
|
|
if (val == NULL) {
|
|
Py_DECREF(argtuple);
|
|
return NULL;
|
|
}
|
|
PyTuple_SET_ITEM(argtuple, i, val);
|
|
}
|
|
if (lz->func == Py_None)
|
|
return argtuple;
|
|
result = PyObject_Call(lz->func, argtuple, NULL);
|
|
Py_DECREF(argtuple);
|
|
return result;
|
|
}
|
|
|
|
PyDoc_STRVAR(imap_doc,
|
|
"imap(func, *iterables) --> imap object\n\
|
|
\n\
|
|
Make an iterator that computes the function using arguments from\n\
|
|
each of the iterables. Like map() except that it returns\n\
|
|
an iterator instead of a list and that it stops when the shortest\n\
|
|
iterable is exhausted instead of filling in None for shorter\n\
|
|
iterables.");
|
|
|
|
PyTypeObject imap_type = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"itertools.imap", /* tp_name */
|
|
sizeof(imapobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)imap_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 */
|
|
imap_doc, /* tp_doc */
|
|
(traverseproc)imap_traverse, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)imap_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 */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
imap_new, /* tp_new */
|
|
PyObject_GC_Del, /* tp_free */
|
|
};
|
|
|
|
|
|
/* chain object ************************************************************/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
long tuplesize;
|
|
long iternum; /* which iterator is active */
|
|
PyObject *ittuple; /* tuple of iterators */
|
|
} chainobject;
|
|
|
|
PyTypeObject chain_type;
|
|
|
|
static PyObject *
|
|
chain_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
chainobject *lz;
|
|
int tuplesize = PySequence_Length(args);
|
|
int i;
|
|
PyObject *ittuple;
|
|
|
|
/* obtain iterators */
|
|
assert(PyTuple_Check(args));
|
|
ittuple = PyTuple_New(tuplesize);
|
|
if(ittuple == 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 #%d 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)
|
|
return NULL;
|
|
|
|
lz->ittuple = ittuple;
|
|
lz->iternum = 0;
|
|
lz->tuplesize = tuplesize;
|
|
|
|
return (PyObject *)lz;
|
|
}
|
|
|
|
static void
|
|
chain_dealloc(chainobject *lz)
|
|
{
|
|
PyObject_GC_UnTrack(lz);
|
|
Py_XDECREF(lz->ittuple);
|
|
lz->ob_type->tp_free(lz);
|
|
}
|
|
|
|
static int
|
|
chain_traverse(chainobject *lz, visitproc visit, void *arg)
|
|
{
|
|
if (lz->ittuple)
|
|
return visit(lz->ittuple, arg);
|
|
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;
|
|
lz->iternum++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
PyDoc_STRVAR(chain_doc,
|
|
"chain(*iterables) --> chain object\n\
|
|
\n\
|
|
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.");
|
|
|
|
PyTypeObject chain_type = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"itertools.chain", /* tp_name */
|
|
sizeof(chainobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)chain_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 */
|
|
chain_doc, /* tp_doc */
|
|
(traverseproc)chain_traverse, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)chain_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 */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
chain_new, /* tp_new */
|
|
PyObject_GC_Del, /* tp_free */
|
|
};
|
|
|
|
|
|
/* ifilter object ************************************************************/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyObject *func;
|
|
PyObject *it;
|
|
} ifilterobject;
|
|
|
|
PyTypeObject ifilter_type;
|
|
|
|
static PyObject *
|
|
ifilter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
PyObject *func, *seq;
|
|
PyObject *it;
|
|
ifilterobject *lz;
|
|
|
|
if (!PyArg_UnpackTuple(args, "ifilter", 2, 2, &func, &seq))
|
|
return NULL;
|
|
|
|
/* Get iterator. */
|
|
it = PyObject_GetIter(seq);
|
|
if (it == NULL)
|
|
return NULL;
|
|
|
|
/* create ifilterobject structure */
|
|
lz = (ifilterobject *)type->tp_alloc(type, 0);
|
|
if (lz == NULL) {
|
|
Py_DECREF(it);
|
|
return NULL;
|
|
}
|
|
Py_INCREF(func);
|
|
lz->func = func;
|
|
lz->it = it;
|
|
|
|
return (PyObject *)lz;
|
|
}
|
|
|
|
static void
|
|
ifilter_dealloc(ifilterobject *lz)
|
|
{
|
|
PyObject_GC_UnTrack(lz);
|
|
Py_XDECREF(lz->func);
|
|
Py_XDECREF(lz->it);
|
|
lz->ob_type->tp_free(lz);
|
|
}
|
|
|
|
static int
|
|
ifilter_traverse(ifilterobject *lz, visitproc visit, void *arg)
|
|
{
|
|
int err;
|
|
|
|
if (lz->it) {
|
|
err = visit(lz->it, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
if (lz->func) {
|
|
err = visit(lz->func, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
ifilter_next(ifilterobject *lz)
|
|
{
|
|
PyObject *item;
|
|
PyObject *it = lz->it;
|
|
long ok;
|
|
|
|
for (;;) {
|
|
assert(PyIter_Check(it));
|
|
item = (*it->ob_type->tp_iternext)(it);
|
|
if (item == NULL)
|
|
return NULL;
|
|
|
|
if (lz->func == Py_None) {
|
|
ok = PyObject_IsTrue(item);
|
|
} else {
|
|
PyObject *good;
|
|
good = PyObject_CallFunctionObjArgs(lz->func,
|
|
item, NULL);
|
|
if (good == NULL) {
|
|
Py_DECREF(item);
|
|
return NULL;
|
|
}
|
|
ok = PyObject_IsTrue(good);
|
|
Py_DECREF(good);
|
|
}
|
|
if (ok)
|
|
return item;
|
|
Py_DECREF(item);
|
|
}
|
|
}
|
|
|
|
PyDoc_STRVAR(ifilter_doc,
|
|
"ifilter(function or None, sequence) --> ifilter object\n\
|
|
\n\
|
|
Return those items of sequence for which function(item) is true.\n\
|
|
If function is None, return the items that are true.");
|
|
|
|
PyTypeObject ifilter_type = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"itertools.ifilter", /* tp_name */
|
|
sizeof(ifilterobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)ifilter_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 */
|
|
ifilter_doc, /* tp_doc */
|
|
(traverseproc)ifilter_traverse, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)ifilter_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 */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
ifilter_new, /* tp_new */
|
|
PyObject_GC_Del, /* tp_free */
|
|
};
|
|
|
|
|
|
/* ifilterfalse object ************************************************************/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyObject *func;
|
|
PyObject *it;
|
|
} ifilterfalseobject;
|
|
|
|
PyTypeObject ifilterfalse_type;
|
|
|
|
static PyObject *
|
|
ifilterfalse_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
PyObject *func, *seq;
|
|
PyObject *it;
|
|
ifilterfalseobject *lz;
|
|
|
|
if (!PyArg_UnpackTuple(args, "ifilterfalse", 2, 2, &func, &seq))
|
|
return NULL;
|
|
|
|
/* Get iterator. */
|
|
it = PyObject_GetIter(seq);
|
|
if (it == NULL)
|
|
return NULL;
|
|
|
|
/* create ifilterfalseobject structure */
|
|
lz = (ifilterfalseobject *)type->tp_alloc(type, 0);
|
|
if (lz == NULL) {
|
|
Py_DECREF(it);
|
|
return NULL;
|
|
}
|
|
Py_INCREF(func);
|
|
lz->func = func;
|
|
lz->it = it;
|
|
|
|
return (PyObject *)lz;
|
|
}
|
|
|
|
static void
|
|
ifilterfalse_dealloc(ifilterfalseobject *lz)
|
|
{
|
|
PyObject_GC_UnTrack(lz);
|
|
Py_XDECREF(lz->func);
|
|
Py_XDECREF(lz->it);
|
|
lz->ob_type->tp_free(lz);
|
|
}
|
|
|
|
static int
|
|
ifilterfalse_traverse(ifilterfalseobject *lz, visitproc visit, void *arg)
|
|
{
|
|
int err;
|
|
|
|
if (lz->it) {
|
|
err = visit(lz->it, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
if (lz->func) {
|
|
err = visit(lz->func, arg);
|
|
if (err)
|
|
return err;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
ifilterfalse_next(ifilterfalseobject *lz)
|
|
{
|
|
PyObject *item;
|
|
PyObject *it = lz->it;
|
|
long ok;
|
|
|
|
for (;;) {
|
|
assert(PyIter_Check(it));
|
|
item = (*it->ob_type->tp_iternext)(it);
|
|
if (item == NULL)
|
|
return NULL;
|
|
|
|
if (lz->func == Py_None) {
|
|
ok = PyObject_IsTrue(item);
|
|
} else {
|
|
PyObject *good;
|
|
good = PyObject_CallFunctionObjArgs(lz->func,
|
|
item, NULL);
|
|
if (good == NULL) {
|
|
Py_DECREF(item);
|
|
return NULL;
|
|
}
|
|
ok = PyObject_IsTrue(good);
|
|
Py_DECREF(good);
|
|
}
|
|
if (!ok)
|
|
return item;
|
|
Py_DECREF(item);
|
|
}
|
|
}
|
|
|
|
PyDoc_STRVAR(ifilterfalse_doc,
|
|
"ifilterfalse(function or None, sequence) --> ifilterfalse object\n\
|
|
\n\
|
|
Return those items of sequence for which function(item) is false.\n\
|
|
If function is None, return the items that are false.");
|
|
|
|
PyTypeObject ifilterfalse_type = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"itertools.ifilterfalse", /* tp_name */
|
|
sizeof(ifilterfalseobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)ifilterfalse_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 */
|
|
ifilterfalse_doc, /* tp_doc */
|
|
(traverseproc)ifilterfalse_traverse, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)ifilterfalse_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 */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
ifilterfalse_new, /* tp_new */
|
|
PyObject_GC_Del, /* tp_free */
|
|
};
|
|
|
|
|
|
/* count object ************************************************************/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
long cnt;
|
|
} countobject;
|
|
|
|
PyTypeObject count_type;
|
|
|
|
static PyObject *
|
|
count_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
countobject *lz;
|
|
long cnt = 0;
|
|
|
|
if (!PyArg_ParseTuple(args, "|l:count", &cnt))
|
|
return NULL;
|
|
|
|
/* create countobject structure */
|
|
lz = (countobject *)PyObject_New(countobject, &count_type);
|
|
if (lz == NULL)
|
|
return NULL;
|
|
lz->cnt = cnt;
|
|
|
|
return (PyObject *)lz;
|
|
}
|
|
|
|
static PyObject *
|
|
count_next(countobject *lz)
|
|
{
|
|
return PyInt_FromLong(lz->cnt++);
|
|
}
|
|
|
|
PyDoc_STRVAR(count_doc,
|
|
"count([firstval]) --> count object\n\
|
|
\n\
|
|
Return a count object whose .next() method returns consecutive\n\
|
|
integers starting from zero or, if specified, from firstval.");
|
|
|
|
PyTypeObject count_type = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"itertools.count", /* tp_name */
|
|
sizeof(countobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)PyObject_Del, /* 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 */
|
|
count_doc, /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)count_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 */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
count_new, /* tp_new */
|
|
};
|
|
|
|
|
|
/* izip object ************************************************************/
|
|
|
|
#include "Python.h"
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
long tuplesize;
|
|
PyObject *ittuple; /* tuple of iterators */
|
|
PyObject *result;
|
|
} izipobject;
|
|
|
|
PyTypeObject izip_type;
|
|
|
|
static PyObject *
|
|
izip_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
izipobject *lz;
|
|
int i;
|
|
PyObject *ittuple; /* tuple of iterators */
|
|
PyObject *result;
|
|
int tuplesize = PySequence_Length(args);
|
|
|
|
if (tuplesize < 1) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"izip() requires at least one sequence");
|
|
return NULL;
|
|
}
|
|
|
|
/* args must be a tuple */
|
|
assert(PyTuple_Check(args));
|
|
|
|
/* obtain iterators */
|
|
ittuple = PyTuple_New(tuplesize);
|
|
if(ittuple == 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,
|
|
"izip argument #%d must support iteration",
|
|
i+1);
|
|
Py_DECREF(ittuple);
|
|
return NULL;
|
|
}
|
|
PyTuple_SET_ITEM(ittuple, i, it);
|
|
}
|
|
|
|
/* create a result holder */
|
|
result = PyTuple_New(tuplesize);
|
|
if (result == NULL) {
|
|
Py_DECREF(ittuple);
|
|
return NULL;
|
|
}
|
|
for (i=0 ; i < tuplesize ; i++) {
|
|
Py_INCREF(Py_None);
|
|
PyTuple_SET_ITEM(result, i, Py_None);
|
|
}
|
|
|
|
/* create izipobject structure */
|
|
lz = (izipobject *)type->tp_alloc(type, 0);
|
|
if (lz == NULL) {
|
|
Py_DECREF(ittuple);
|
|
Py_DECREF(result);
|
|
return NULL;
|
|
}
|
|
lz->ittuple = ittuple;
|
|
lz->tuplesize = tuplesize;
|
|
lz->result = result;
|
|
|
|
return (PyObject *)lz;
|
|
}
|
|
|
|
static void
|
|
izip_dealloc(izipobject *lz)
|
|
{
|
|
PyObject_GC_UnTrack(lz);
|
|
Py_XDECREF(lz->ittuple);
|
|
Py_XDECREF(lz->result);
|
|
lz->ob_type->tp_free(lz);
|
|
}
|
|
|
|
static int
|
|
izip_traverse(izipobject *lz, visitproc visit, void *arg)
|
|
{
|
|
if (lz->ittuple)
|
|
return visit(lz->ittuple, arg);
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
izip_next(izipobject *lz)
|
|
{
|
|
int i;
|
|
long tuplesize = lz->tuplesize;
|
|
PyObject *result = lz->result;
|
|
PyObject *it;
|
|
PyObject *item;
|
|
|
|
if (result->ob_refcnt == 1) {
|
|
for (i=0 ; i < tuplesize ; i++) {
|
|
it = PyTuple_GET_ITEM(lz->ittuple, i);
|
|
assert(PyIter_Check(it));
|
|
item = (*it->ob_type->tp_iternext)(it);
|
|
if (item == NULL)
|
|
return NULL;
|
|
Py_DECREF(PyTuple_GET_ITEM(result, i));
|
|
PyTuple_SET_ITEM(result, i, item);
|
|
}
|
|
Py_INCREF(result);
|
|
} else {
|
|
result = PyTuple_New(tuplesize);
|
|
if (result == NULL)
|
|
return NULL;
|
|
for (i=0 ; i < tuplesize ; i++) {
|
|
it = PyTuple_GET_ITEM(lz->ittuple, i);
|
|
assert(PyIter_Check(it));
|
|
item = (*it->ob_type->tp_iternext)(it);
|
|
if (item == NULL) {
|
|
Py_DECREF(result);
|
|
return NULL;
|
|
}
|
|
PyTuple_SET_ITEM(result, i, item);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
PyDoc_STRVAR(izip_doc,
|
|
"izip(iter1 [,iter2 [...]]) --> izip object\n\
|
|
\n\
|
|
Return a izip object whose .next() method returns a tuple where\n\
|
|
the i-th element comes from the i-th iterable argument. The .next()\n\
|
|
method continues until the shortest iterable in the argument sequence\n\
|
|
is exhausted and then it raises StopIteration. Works like the zip()\n\
|
|
function but consumes less memory by returning an iterator instead of\n\
|
|
a list.");
|
|
|
|
PyTypeObject izip_type = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"itertools.izip", /* tp_name */
|
|
sizeof(izipobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)izip_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 */
|
|
izip_doc, /* tp_doc */
|
|
(traverseproc)izip_traverse, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)izip_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 */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
izip_new, /* tp_new */
|
|
PyObject_GC_Del, /* tp_free */
|
|
};
|
|
|
|
|
|
/* repeat object ************************************************************/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyObject *element;
|
|
long cnt;
|
|
} repeatobject;
|
|
|
|
PyTypeObject repeat_type;
|
|
|
|
static PyObject *
|
|
repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
repeatobject *ro;
|
|
PyObject *element;
|
|
long cnt = -1;
|
|
|
|
if (!PyArg_ParseTuple(args, "O|l:repeat", &element, &cnt))
|
|
return NULL;
|
|
|
|
if (PyTuple_Size(args) == 2 && cnt < 0)
|
|
cnt = 0;
|
|
|
|
ro = (repeatobject *)type->tp_alloc(type, 0);
|
|
if (ro == NULL)
|
|
return NULL;
|
|
Py_INCREF(element);
|
|
ro->element = element;
|
|
ro->cnt = cnt;
|
|
return (PyObject *)ro;
|
|
}
|
|
|
|
static void
|
|
repeat_dealloc(repeatobject *ro)
|
|
{
|
|
PyObject_GC_UnTrack(ro);
|
|
Py_XDECREF(ro->element);
|
|
ro->ob_type->tp_free(ro);
|
|
}
|
|
|
|
static int
|
|
repeat_traverse(repeatobject *ro, visitproc visit, void *arg)
|
|
{
|
|
if (ro->element)
|
|
return visit(ro->element, arg);
|
|
return 0;
|
|
}
|
|
|
|
static PyObject *
|
|
repeat_next(repeatobject *ro)
|
|
{
|
|
if (ro->cnt == 0)
|
|
return NULL;
|
|
if (ro->cnt > 0)
|
|
ro->cnt--;
|
|
Py_INCREF(ro->element);
|
|
return ro->element;
|
|
}
|
|
|
|
PyDoc_STRVAR(repeat_doc,
|
|
"repeat(element [,times]) -> create an iterator which returns the element\n\
|
|
for the specified number of times. If not specified, returns the element\n\
|
|
endlessly.");
|
|
|
|
PyTypeObject repeat_type = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"itertools.repeat", /* tp_name */
|
|
sizeof(repeatobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)repeat_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 */
|
|
repeat_doc, /* tp_doc */
|
|
(traverseproc)repeat_traverse, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)repeat_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 */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
repeat_new, /* tp_new */
|
|
PyObject_GC_Del, /* tp_free */
|
|
};
|
|
|
|
|
|
/* module level code ********************************************************/
|
|
|
|
PyDoc_STRVAR(module_doc,
|
|
"Functional tools for creating and using iterators.\n\
|
|
\n\
|
|
Infinite iterators:\n\
|
|
count([n]) --> n, n+1, n+2, ...\n\
|
|
cycle(p) --> p0, p1, ... plast, p0, p1, ...\n\
|
|
repeat(elem [,n]) --> elem, elem, elem, ... endlessly or up to n times\n\
|
|
\n\
|
|
Iterators terminating on the shortest input sequence:\n\
|
|
izip(p, q, ...) --> (p[0], q[0]), (p[1], q[1]), ... \n\
|
|
ifilter(pred, seq) --> elements of seq where pred(elem) is True\n\
|
|
ifilterfalse(pred, seq) --> elements of seq where pred(elem) is False\n\
|
|
islice(seq, [start,] stop [, step]) --> elements from\n\
|
|
seq[start:stop:step]\n\
|
|
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\
|
|
takewhile(pred, seq) --> seq[0], seq[1], until pred fails\n\
|
|
dropwhile(pred, seq) --> seq[n], seq[n+1], starting when pred fails\n\
|
|
");
|
|
|
|
|
|
PyMODINIT_FUNC
|
|
inititertools(void)
|
|
{
|
|
int i;
|
|
PyObject *m;
|
|
char *name;
|
|
PyTypeObject *typelist[] = {
|
|
&cycle_type,
|
|
&dropwhile_type,
|
|
&takewhile_type,
|
|
&islice_type,
|
|
&starmap_type,
|
|
&imap_type,
|
|
&chain_type,
|
|
&ifilter_type,
|
|
&ifilterfalse_type,
|
|
&count_type,
|
|
&izip_type,
|
|
&repeat_type,
|
|
NULL
|
|
};
|
|
|
|
m = Py_InitModule3("itertools", NULL, module_doc);
|
|
|
|
for (i=0 ; typelist[i] != NULL ; i++) {
|
|
if (PyType_Ready(typelist[i]) < 0)
|
|
return;
|
|
name = strchr(typelist[i]->tp_name, '.') + 1;
|
|
assert (name != NULL);
|
|
Py_INCREF(typelist[i]);
|
|
PyModule_AddObject(m, name, (PyObject *)typelist[i]);
|
|
}
|
|
}
|