diff options
author | Guido van Rossum <guido@python.org> | 2001-04-23 14:08:49 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2001-04-23 14:08:49 (GMT) |
commit | 213c7a6aa5889f42495352199715a1c1a0833a00 (patch) | |
tree | 7559cd072f732c861cb28adb7192561a877fd6fb /Objects/iterobject.c | |
parent | 8b3d6ca3df1097752a1091b2c8f6d7de1b36a81d (diff) | |
download | cpython-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.c | 84 |
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 */ }; |