summaryrefslogtreecommitdiffstats
path: root/Objects/iterobject.c
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2001-04-23 14:08:49 (GMT)
committerGuido van Rossum <guido@python.org>2001-04-23 14:08:49 (GMT)
commit213c7a6aa5889f42495352199715a1c1a0833a00 (patch)
tree7559cd072f732c861cb28adb7192561a877fd6fb /Objects/iterobject.c
parent8b3d6ca3df1097752a1091b2c8f6d7de1b36a81d (diff)
downloadcpython-213c7a6aa5889f42495352199715a1c1a0833a00.zip
cpython-213c7a6aa5889f42495352199715a1c1a0833a00.tar.gz
cpython-213c7a6aa5889f42495352199715a1c1a0833a00.tar.bz2
Mondo changes to the iterator stuff, without changing how Python code
sees it (test_iter.py is unchanged). - Added a tp_iternext slot, which calls the iterator's next() method; this is much faster for built-in iterators over built-in types such as lists and dicts, speeding up pybench's ForLoop with about 25% compared to Python 2.1. (Now there's a good argument for iterators. ;-) - Renamed the built-in sequence iterator SeqIter, affecting the C API functions for it. (This frees up the PyIter prefix for generic iterator operations.) - Added PyIter_Check(obj), which checks that obj's type has a tp_iternext slot and that the proper feature flag is set. - Added PyIter_Next(obj) which calls the tp_iternext slot. It has a somewhat complex return condition due to the need for speed: when it returns NULL, it may not have set an exception condition, meaning the iterator is exhausted; when the exception StopIteration is set (or a derived exception class), it means the same thing; any other exception means some other error occurred.
Diffstat (limited to 'Objects/iterobject.c')
-rw-r--r--Objects/iterobject.c84
1 files changed, 63 insertions, 21 deletions
diff --git a/Objects/iterobject.c b/Objects/iterobject.c
index 616417a..8601980 100644
--- a/Objects/iterobject.c
+++ b/Objects/iterobject.c
@@ -6,13 +6,13 @@ typedef struct {
PyObject_HEAD
long it_index;
PyObject *it_seq;
-} iterobject;
+} seqiterobject;
PyObject *
-PyIter_New(PyObject *seq)
+PySeqIter_New(PyObject *seq)
{
- iterobject *it;
- it = PyObject_NEW(iterobject, &PyIter_Type);
+ seqiterobject *it;
+ it = PyObject_NEW(seqiterobject, &PySeqIter_Type);
if (it == NULL)
return NULL;
it->it_index = 0;
@@ -21,21 +21,44 @@ PyIter_New(PyObject *seq)
return (PyObject *)it;
}
static void
-iter_dealloc(iterobject *it)
+iter_dealloc(seqiterobject *it)
{
Py_DECREF(it->it_seq);
PyObject_DEL(it);
}
static PyObject *
-iter_next(iterobject *it, PyObject *args)
+iter_next(seqiterobject *it, PyObject *args)
{
PyObject *seq = it->it_seq;
+ PyObject *result = PySequence_GetItem(seq, it->it_index++);
+
+ if (result == NULL && PyErr_ExceptionMatches(PyExc_IndexError))
+ PyErr_SetObject(PyExc_StopIteration, Py_None);
+ return result;
+}
+
+static PyObject *
+iter_getiter(PyObject *it)
+{
+ Py_INCREF(it);
+ return it;
+}
+
+/* Return (value, 0) if OK; (NULL, 0) at end; (NULL, -1) if exception */
+static PyObject *
+iter_iternext(PyObject *iterator)
+{
+ seqiterobject *it;
+ PyObject *seq;
+
+ assert(PySeqIter_Check(iterator));
+ it = (seqiterobject *)iterator;
+ seq = it->it_seq;
if (PyList_Check(seq)) {
PyObject *item;
if (it->it_index >= PyList_GET_SIZE(seq)) {
- PyErr_SetObject(PyExc_StopIteration, Py_None);
return NULL;
}
item = PyList_GET_ITEM(seq, it->it_index);
@@ -45,20 +68,20 @@ iter_next(iterobject *it, PyObject *args)
}
else {
PyObject *result = PySequence_GetItem(seq, it->it_index++);
- if (result == NULL &&
- PyErr_ExceptionMatches(PyExc_IndexError))
- PyErr_SetObject(PyExc_StopIteration, Py_None);
- return result;
+ if (result != NULL) {
+ return result;
+ }
+ if (PyErr_ExceptionMatches(PyExc_IndexError) ||
+ PyErr_ExceptionMatches(PyExc_StopIteration)) {
+ PyErr_Clear();
+ return NULL;
+ }
+ else {
+ return NULL;
+ }
}
}
-static PyObject *
-iter_getiter(PyObject *it)
-{
- Py_INCREF(it);
- return it;
-}
-
static PyMethodDef iter_methods[] = {
{"next", (PyCFunction)iter_next, METH_VARARGS,
"it.next() -- get the next value, or raise StopIteration"},
@@ -66,16 +89,16 @@ static PyMethodDef iter_methods[] = {
};
static PyObject *
-iter_getattr(iterobject *it, char *name)
+iter_getattr(seqiterobject *it, char *name)
{
return Py_FindMethod(iter_methods, (PyObject *)it, name);
}
-PyTypeObject PyIter_Type = {
+PyTypeObject PySeqIter_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */
"iterator", /* tp_name */
- sizeof(iterobject), /* tp_basicsize */
+ sizeof(seqiterobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)iter_dealloc, /* tp_dealloc */
@@ -100,6 +123,7 @@ PyTypeObject PyIter_Type = {
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)iter_getiter, /* tp_iter */
+ (iternextfunc)iter_iternext, /* tp_iternext */
};
/* -------------------------------------- */
@@ -130,6 +154,7 @@ calliter_dealloc(calliterobject *it)
Py_DECREF(it->it_sentinel);
PyObject_DEL(it);
}
+
static PyObject *
calliter_next(calliterobject *it, PyObject *args)
{
@@ -156,6 +181,22 @@ calliter_getattr(calliterobject *it, char *name)
return Py_FindMethod(calliter_methods, (PyObject *)it, name);
}
+static PyObject *
+calliter_iternext(calliterobject *it)
+{
+ PyObject *result = PyObject_CallObject(it->it_callable, NULL);
+ if (result != NULL) {
+ if (PyObject_RichCompareBool(result, it->it_sentinel, Py_EQ)) {
+ Py_DECREF(result);
+ result = NULL;
+ }
+ }
+ else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
+ PyErr_Clear();
+ }
+ return result;
+}
+
PyTypeObject PyCallIter_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */
@@ -185,4 +226,5 @@ PyTypeObject PyCallIter_Type = {
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)iter_getiter, /* tp_iter */
+ (iternextfunc)calliter_iternext, /* tp_iternext */
};