[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 */
  };