[Python-checkins] CVS: python/dist/src/Objects abstract.c,2.59,2.60 classobject.c,2.126,2.127 dictobject.c,2.79,2.80 fileobject.c,2.111,2.112 iterobject.c,1.2,1.3
Guido van Rossum
gvanrossum@users.sourceforge.net
Mon, 23 Apr 2001 07:08:51 -0700
Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv26282/Objects
Modified Files:
abstract.c classobject.c dictobject.c fileobject.c
iterobject.c
Log Message:
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.
Index: abstract.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v
retrieving revision 2.59
retrieving revision 2.60
diff -C2 -r2.59 -r2.60
*** abstract.c 2001/04/20 19:13:02 2.59
--- abstract.c 2001/04/23 14:08:49 2.60
***************
*** 1749,1757 ****
if (f == NULL) {
if (PySequence_Check(o))
! return PyIter_New(o);
PyErr_SetString(PyExc_TypeError, "iter() of non-sequence");
return NULL;
}
! else
! return (*f)(o);
}
--- 1749,1779 ----
if (f == NULL) {
if (PySequence_Check(o))
! return PySeqIter_New(o);
PyErr_SetString(PyExc_TypeError, "iter() of non-sequence");
return NULL;
}
! else {
! PyObject *res = (*f)(o);
! if (res != NULL && !PyIter_Check(res)) {
! PyErr_Format(PyExc_TypeError,
! "iter() returned non-iterator "
! "of type '%.100s'",
! res->ob_type->tp_name);
! Py_DECREF(res);
! res = NULL;
! }
! return res;
! }
! }
!
! PyObject *
! PyIter_Next(PyObject *iter)
! {
! if (!PyIter_Check(iter)) {
! PyErr_Format(PyExc_TypeError,
! "'%.100s' object is not an iterator",
! iter->ob_type->tp_name);
! return NULL;
! }
! return (*iter->ob_type->tp_iternext)(iter);
}
Index: classobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/classobject.c,v
retrieving revision 2.126
retrieving revision 2.127
diff -C2 -r2.126 -r2.127
*** classobject.c 2001/04/20 19:13:02 2.126
--- classobject.c 2001/04/23 14:08:49 2.127
***************
*** 849,853 ****
}
! static PyObject *getitemstr, *setitemstr, *delitemstr, *lenstr, *iterstr;
static int
--- 849,854 ----
}
! static PyObject *getitemstr, *setitemstr, *delitemstr, *lenstr;
! static PyObject *iterstr, *nextstr;
static int
***************
*** 1727,1730 ****
--- 1728,1739 ----
PyObject *res = PyEval_CallObject(func, (PyObject *)NULL);
Py_DECREF(func);
+ if (res != NULL && !PyIter_Check(res)) {
+ PyErr_Format(PyExc_TypeError,
+ "__iter__ returned non-iterator "
+ "of type '%.100s'",
+ res->ob_type->tp_name);
+ Py_DECREF(res);
+ res = NULL;
+ }
return res;
}
***************
*** 1735,1739 ****
}
Py_DECREF(func);
! return PyIter_New((PyObject *)self);
}
--- 1744,1774 ----
}
Py_DECREF(func);
! return PySeqIter_New((PyObject *)self);
! }
!
!
! /* Call the iterator's next */
! static PyObject *
! instance_iternext(PyInstanceObject *self)
! {
! PyObject *func;
!
! if (nextstr == NULL)
! nextstr = PyString_InternFromString("next");
!
! if ((func = instance_getattr(self, nextstr)) != NULL) {
! PyObject *res = PyEval_CallObject(func, (PyObject *)NULL);
! Py_DECREF(func);
! if (res != NULL) {
! return res;
! }
! if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
! PyErr_Clear();
! return NULL;
! }
! return NULL;
! }
! PyErr_SetString(PyExc_TypeError, "instance has no next() method");
! return NULL;
}
***************
*** 1804,1807 ****
--- 1839,1843 ----
offsetof(PyInstanceObject, in_weakreflist), /* tp_weaklistoffset */
(getiterfunc)instance_getiter, /* tp_iter */
+ (iternextfunc)instance_iternext, /* tp_iternext */
};
Index: dictobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/dictobject.c,v
retrieving revision 2.79
retrieving revision 2.80
diff -C2 -r2.79 -r2.80
*** dictobject.c 2001/04/20 19:13:02 2.79
--- dictobject.c 2001/04/23 14:08:49 2.80
***************
*** 1355,1358 ****
--- 1355,1359 ----
0, /* tp_weaklistoffset */
(getiterfunc)dictiter_new, /* tp_iter */
+ 0, /* tp_iternext */
};
***************
*** 1434,1437 ****
--- 1435,1439 ----
{
PyObject *key;
+
if (di->di_size != di->di_dict->ma_size) {
PyErr_SetString(PyExc_RuntimeError,
***************
*** 1461,1467 ****
static PyObject *
! dictiter_getattr(dictiterobject *it, char *name)
{
! return Py_FindMethod(dictiter_methods, (PyObject *)it, name);
}
--- 1463,1485 ----
static PyObject *
! dictiter_getattr(dictiterobject *di, char *name)
! {
! return Py_FindMethod(dictiter_methods, (PyObject *)di, name);
! }
!
! static PyObject *dictiter_iternext(dictiterobject *di)
{
! PyObject *key;
!
! if (di->di_size != di->di_dict->ma_size) {
! PyErr_SetString(PyExc_RuntimeError,
! "dictionary changed size during iteration");
! return NULL;
! }
! if (PyDict_Next((PyObject *)(di->di_dict), &di->di_pos, &key, NULL)) {
! Py_INCREF(key);
! return key;
! }
! return NULL;
}
***************
*** 1495,1497 ****
--- 1513,1516 ----
0, /* tp_weaklistoffset */
(getiterfunc)dictiter_getiter, /* tp_iter */
+ (iternextfunc)dictiter_iternext, /* tp_iternext */
};
Index: fileobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/fileobject.c,v
retrieving revision 2.111
retrieving revision 2.112
diff -C2 -r2.111 -r2.112
*** fileobject.c 2001/04/21 13:20:18 2.111
--- fileobject.c 2001/04/23 14:08:49 2.112
***************
*** 1341,1344 ****
--- 1341,1345 ----
0, /* tp_weaklistoffset */
(getiterfunc)file_getiter, /* tp_iter */
+ 0, /* tp_iternext */
};
Index: iterobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/iterobject.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -r1.2 -r1.3
*** iterobject.c 2001/04/20 21:06:46 1.2
--- iterobject.c 2001/04/23 14:08:49 1.3
***************
*** 7,17 ****
long it_index;
PyObject *it_seq;
! } iterobject;
PyObject *
! PyIter_New(PyObject *seq)
{
! iterobject *it;
! it = PyObject_NEW(iterobject, &PyIter_Type);
if (it == NULL)
return NULL;
--- 7,17 ----
long it_index;
PyObject *it_seq;
! } seqiterobject;
PyObject *
! PySeqIter_New(PyObject *seq)
{
! seqiterobject *it;
! it = PyObject_NEW(seqiterobject, &PySeqIter_Type);
if (it == NULL)
return NULL;
***************
*** 22,26 ****
}
static void
! iter_dealloc(iterobject *it)
{
Py_DECREF(it->it_seq);
--- 22,26 ----
}
static void
! iter_dealloc(seqiterobject *it)
{
Py_DECREF(it->it_seq);
***************
*** 29,40 ****
static PyObject *
! iter_next(iterobject *it, PyObject *args)
{
PyObject *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;
}
--- 29,63 ----
static PyObject *
! 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)) {
return NULL;
}
***************
*** 46,63 ****
else {
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;
- }
-
static PyMethodDef iter_methods[] = {
{"next", (PyCFunction)iter_next, METH_VARARGS,
--- 69,86 ----
else {
PyObject *result = PySequence_GetItem(seq, it->it_index++);
! if (result != NULL) {
! return result;
! }
! if (PyErr_ExceptionMatches(PyExc_IndexError) ||
! PyErr_ExceptionMatches(PyExc_StopIteration)) {
! PyErr_Clear();
! return NULL;
! }
! else {
! return NULL;
! }
}
}
static PyMethodDef iter_methods[] = {
{"next", (PyCFunction)iter_next, METH_VARARGS,
***************
*** 67,80 ****
static PyObject *
! iter_getattr(iterobject *it, char *name)
{
return Py_FindMethod(iter_methods, (PyObject *)it, name);
}
! PyTypeObject PyIter_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */
"iterator", /* tp_name */
! sizeof(iterobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
--- 90,103 ----
static PyObject *
! iter_getattr(seqiterobject *it, char *name)
{
return Py_FindMethod(iter_methods, (PyObject *)it, name);
}
! PyTypeObject PySeqIter_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */
"iterator", /* tp_name */
! sizeof(seqiterobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
***************
*** 101,104 ****
--- 124,128 ----
0, /* tp_weaklistoffset */
(getiterfunc)iter_getiter, /* tp_iter */
+ (iternextfunc)iter_iternext, /* tp_iternext */
};
***************
*** 131,134 ****
--- 155,159 ----
PyObject_DEL(it);
}
+
static PyObject *
calliter_next(calliterobject *it, PyObject *args)
***************
*** 157,160 ****
--- 182,201 ----
}
+ 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)
***************
*** 186,188 ****
--- 227,230 ----
0, /* tp_weaklistoffset */
(getiterfunc)iter_getiter, /* tp_iter */
+ (iternextfunc)calliter_iternext, /* tp_iternext */
};