mirror of https://github.com/python/cpython
Make PyIter_Next() a little smarter (wrt its knowledge of iterator
internals) so clients can be a lot dumber (wrt their knowledge).
This commit is contained in:
parent
648b4de3d3
commit
f4848dac41
|
@ -484,9 +484,8 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
|
||||||
DL_IMPORT(PyObject *) PyIter_Next(PyObject *);
|
DL_IMPORT(PyObject *) PyIter_Next(PyObject *);
|
||||||
/* Takes an iterator object and calls its tp_iternext slot,
|
/* Takes an iterator object and calls its tp_iternext slot,
|
||||||
returning the next value. If the iterator is exhausted,
|
returning the next value. If the iterator is exhausted,
|
||||||
this can return NULL without setting an exception, *or*
|
this returns NULL without setting an exception.
|
||||||
NULL with a StopIteration exception.
|
NULL with an exception means an error occurred. */
|
||||||
NULL with any other exception means an error occurred. */
|
|
||||||
|
|
||||||
/* Number Protocol:*/
|
/* Number Protocol:*/
|
||||||
|
|
||||||
|
|
|
@ -1276,17 +1276,9 @@ PySequence_List(PyObject *v)
|
||||||
for (i = 0; ; i++) {
|
for (i = 0; ; i++) {
|
||||||
PyObject *item = PyIter_Next(it);
|
PyObject *item = PyIter_Next(it);
|
||||||
if (item == NULL) {
|
if (item == NULL) {
|
||||||
/* We're out of here in any case, but if this is a
|
|
||||||
* StopIteration exception it's expected, but if
|
|
||||||
* any other kind of exception it's an error.
|
|
||||||
*/
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
if (PyErr_ExceptionMatches(PyExc_StopIteration))
|
Py_DECREF(result);
|
||||||
PyErr_Clear();
|
result = NULL;
|
||||||
else {
|
|
||||||
Py_DECREF(result);
|
|
||||||
result = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1796,14 +1788,27 @@ PyObject_GetIter(PyObject *o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return next item.
|
||||||
|
* If an error occurs, return NULL. PyErr_Occurred() will be true.
|
||||||
|
* If the iteration terminates normally, return NULL and clear the
|
||||||
|
* PyExc_StopIteration exception (if it was set). PyErr_Occurred()
|
||||||
|
* will be false.
|
||||||
|
* Else return the next object. PyErr_Occurred() will be false.
|
||||||
|
*/
|
||||||
PyObject *
|
PyObject *
|
||||||
PyIter_Next(PyObject *iter)
|
PyIter_Next(PyObject *iter)
|
||||||
{
|
{
|
||||||
|
PyObject *result;
|
||||||
if (!PyIter_Check(iter)) {
|
if (!PyIter_Check(iter)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"'%.100s' object is not an iterator",
|
"'%.100s' object is not an iterator",
|
||||||
iter->ob_type->tp_name);
|
iter->ob_type->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return (*iter->ob_type->tp_iternext)(iter);
|
result = (*iter->ob_type->tp_iternext)(iter);
|
||||||
|
if (result == NULL &&
|
||||||
|
PyErr_Occurred() &&
|
||||||
|
PyErr_ExceptionMatches(PyExc_StopIteration))
|
||||||
|
PyErr_Clear();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,7 +164,7 @@ builtin_filter(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *func, *seq, *result, *it;
|
PyObject *func, *seq, *result, *it;
|
||||||
int len; /* guess for result list size */
|
int len; /* guess for result list size */
|
||||||
register int i, j;
|
register int j;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "OO:filter", &func, &seq))
|
if (!PyArg_ParseTuple(args, "OO:filter", &func, &seq))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -204,22 +204,15 @@ builtin_filter(PyObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build the result list. */
|
/* Build the result list. */
|
||||||
for (i = j = 0; ; ++i) {
|
j = 0;
|
||||||
|
for (;;) {
|
||||||
PyObject *item, *good;
|
PyObject *item, *good;
|
||||||
int ok;
|
int ok;
|
||||||
|
|
||||||
item = PyIter_Next(it);
|
item = PyIter_Next(it);
|
||||||
if (item == NULL) {
|
if (item == NULL) {
|
||||||
/* We're out of here in any case, but if this is a
|
if (PyErr_Occurred())
|
||||||
* StopIteration exception it's expected, but if
|
goto Fail_result_it;
|
||||||
* any other kind of exception it's an error.
|
|
||||||
*/
|
|
||||||
if (PyErr_Occurred()) {
|
|
||||||
if (PyErr_ExceptionMatches(PyExc_StopIteration))
|
|
||||||
PyErr_Clear();
|
|
||||||
else
|
|
||||||
goto Fail_result_it;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1030,24 +1023,14 @@ builtin_map(PyObject *self, PyObject *args)
|
||||||
if (item)
|
if (item)
|
||||||
++numactive;
|
++numactive;
|
||||||
else {
|
else {
|
||||||
/* StopIteration is *implied* by a
|
|
||||||
* NULL return from PyIter_Next() if
|
|
||||||
* PyErr_Occurred() is false.
|
|
||||||
*/
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
if (PyErr_ExceptionMatches(
|
Py_XDECREF(alist);
|
||||||
PyExc_StopIteration))
|
goto Fail_1;
|
||||||
PyErr_Clear();
|
|
||||||
else {
|
|
||||||
Py_XDECREF(alist);
|
|
||||||
goto Fail_1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
item = Py_None;
|
item = Py_None;
|
||||||
sqp->saw_StopIteration = 1;
|
sqp->saw_StopIteration = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (alist)
|
if (alist)
|
||||||
PyTuple_SET_ITEM(alist, j, item);
|
PyTuple_SET_ITEM(alist, j, item);
|
||||||
|
@ -1445,7 +1428,6 @@ Return the dictionary containing the current scope's local variables.";
|
||||||
static PyObject *
|
static PyObject *
|
||||||
min_max(PyObject *args, int op)
|
min_max(PyObject *args, int op)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
PyObject *v, *w, *x, *it;
|
PyObject *v, *w, *x, *it;
|
||||||
|
|
||||||
if (PyTuple_Size(args) > 1)
|
if (PyTuple_Size(args) > 1)
|
||||||
|
@ -1458,21 +1440,13 @@ min_max(PyObject *args, int op)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
w = NULL; /* the result */
|
w = NULL; /* the result */
|
||||||
for (i = 0; ; i++) {
|
for (;;) {
|
||||||
x = PyIter_Next(it);
|
x = PyIter_Next(it);
|
||||||
if (x == NULL) {
|
if (x == NULL) {
|
||||||
/* We're out of here in any case, but if this is a
|
|
||||||
* StopIteration exception it's expected, but if
|
|
||||||
* any other kind of exception it's an error.
|
|
||||||
*/
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
if (PyErr_ExceptionMatches(PyExc_StopIteration))
|
Py_XDECREF(w);
|
||||||
PyErr_Clear();
|
Py_DECREF(it);
|
||||||
else {
|
return NULL;
|
||||||
Py_XDECREF(w);
|
|
||||||
Py_DECREF(it);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1880,16 +1854,9 @@ builtin_reduce(PyObject *self, PyObject *args)
|
||||||
|
|
||||||
op2 = PyIter_Next(it);
|
op2 = PyIter_Next(it);
|
||||||
if (op2 == NULL) {
|
if (op2 == NULL) {
|
||||||
/* StopIteration is *implied* by a NULL return from
|
if (PyErr_Occurred())
|
||||||
* PyIter_Next() if PyErr_Occurred() is false.
|
goto Fail;
|
||||||
*/
|
break;
|
||||||
if (PyErr_Occurred()) {
|
|
||||||
if (PyErr_ExceptionMatches(PyExc_StopIteration))
|
|
||||||
PyErr_Clear();
|
|
||||||
else
|
|
||||||
goto Fail;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
|
|
|
@ -1894,11 +1894,9 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
||||||
PUSH(x);
|
PUSH(x);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!PyErr_Occurred() ||
|
if (!PyErr_Occurred()) {
|
||||||
PyErr_ExceptionMatches(
|
/* iterator ended normally */
|
||||||
PyExc_StopIteration))
|
x = v = POP();
|
||||||
{
|
|
||||||
x = v = POP();
|
|
||||||
Py_DECREF(v);
|
Py_DECREF(v);
|
||||||
JUMPBY(oparg);
|
JUMPBY(oparg);
|
||||||
continue;
|
continue;
|
||||||
|
|
Loading…
Reference in New Issue