Skip to content

Commit fd30538

Browse files
committed
perf(genobject): return asend() yield values without StopIteration
1 parent 7731da1 commit fd30538

1 file changed

Lines changed: 40 additions & 22 deletions

File tree

‎Objects/genobject.c‎

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1963,8 +1963,11 @@ PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname)
19631963
return (PyObject*)ag;
19641964
}
19651965

1966-
static PyObject *
1967-
async_gen_unwrap_value(PyAsyncGenObject *gen, PyObject *result)
1966+
// Like async_gen_unwrap_value(), but an async yield is reported as
1967+
// PYGEN_RETURN with the yielded value instead of raising StopIteration.
1968+
static PySendResult
1969+
async_gen_unwrap_send(PyAsyncGenObject *gen, PyObject *result,
1970+
PyObject **presult)
19681971
{
19691972
if (result == NULL) {
19701973
if (!PyErr_Occurred()) {
@@ -1977,17 +1980,31 @@ async_gen_unwrap_value(PyAsyncGenObject *gen, PyObject *result)
19771980
FT_ATOMIC_STORE_INT8_RELAXED(gen->ag_closed, 1);
19781981
}
19791982

1980-
return NULL;
1983+
*presult = NULL;
1984+
return PYGEN_ERROR;
19811985
}
19821986

19831987
if (_PyAsyncGenWrappedValue_CheckExact(result)) {
19841988
/* async yield */
1985-
_PyGen_SetStopIterationValue(((_PyAsyncGenWrappedValue*)result)->agw_val);
1989+
*presult = Py_NewRef(((_PyAsyncGenWrappedValue*)result)->agw_val);
19861990
Py_DECREF(result);
1987-
return NULL;
1991+
return PYGEN_RETURN;
19881992
}
19891993

1990-
return result;
1994+
*presult = result;
1995+
return PYGEN_NEXT;
1996+
}
1997+
1998+
static PyObject *
1999+
async_gen_unwrap_value(PyAsyncGenObject *gen, PyObject *result)
2000+
{
2001+
PyObject *value;
2002+
if (async_gen_unwrap_send(gen, result, &value) == PYGEN_RETURN) {
2003+
_PyGen_SetStopIterationValue(value);
2004+
Py_DECREF(value);
2005+
return NULL;
2006+
}
2007+
return value;
19912008
}
19922009

19932010

@@ -2023,18 +2040,19 @@ async_gen_asend_traverse(PyObject *self, visitproc visit, void *arg)
20232040
}
20242041

20252042

2026-
static PyObject *
2027-
async_gen_asend_send(PyObject *self, PyObject *arg)
2043+
PySendResult
2044+
_PyAsyncGenASend_Send(PyObject *self, PyObject *arg, PyObject **presult)
20282045
{
20292046
PyAsyncGenASend *o = _PyAsyncGenASend_CAST(self);
20302047

2048+
*presult = NULL;
20312049
int8_t state = FT_ATOMIC_LOAD_INT8_RELAXED(o->ags_state);
20322050
do {
20332051
if (state == AWAITABLE_STATE_CLOSED) {
20342052
PyErr_SetString(
20352053
PyExc_RuntimeError,
20362054
"cannot reuse already awaited __anext__()/asend()");
2037-
return NULL;
2055+
return PYGEN_ERROR;
20382056
}
20392057
if (state == AWAITABLE_STATE_ITER) {
20402058
goto do_send;
@@ -2051,37 +2069,37 @@ async_gen_asend_send(PyObject *self, PyObject *arg)
20512069
PyErr_SetString(
20522070
PyExc_RuntimeError,
20532071
"anext(): asynchronous generator is already running");
2054-
return NULL;
2072+
return PYGEN_ERROR;
20552073
}
20562074

20572075
if (arg == NULL || arg == Py_None) {
20582076
arg = o->ags_sendval;
20592077
}
20602078

20612079
PyObject *result;
2080+
PySendResult res;
20622081
do_send:
20632082
result = gen_send((PyObject*)o->ags_gen, arg);
2064-
result = async_gen_unwrap_value(o->ags_gen, result);
2083+
res = async_gen_unwrap_send(o->ags_gen, result, presult);
20652084

2066-
if (result == NULL) {
2085+
if (res != PYGEN_NEXT) {
20672086
FT_ATOMIC_STORE_INT8_RELAXED(o->ags_state, AWAITABLE_STATE_CLOSED);
20682087
FT_ATOMIC_STORE_INT8_RELEASE(o->ags_gen->ag_running_async, 0);
20692088
}
20702089

2071-
return result;
2090+
return res;
20722091
}
20732092

2074-
PySendResult
2075-
_PyAsyncGenASend_Send(PyObject *iter, PyObject *arg, PyObject **result)
2093+
static PyObject *
2094+
async_gen_asend_send(PyObject *self, PyObject *arg)
20762095
{
2077-
*result = async_gen_asend_send(iter, arg);
2078-
if (*result != NULL) {
2079-
return PYGEN_NEXT;
2080-
}
2081-
if (_PyGen_FetchStopIterationValue(result) == 0) {
2082-
return PYGEN_RETURN;
2096+
PyObject *result;
2097+
if (_PyAsyncGenASend_Send(self, arg, &result) == PYGEN_RETURN) {
2098+
_PyGen_SetStopIterationValue(result);
2099+
Py_DECREF(result);
2100+
return NULL;
20832101
}
2084-
return PYGEN_ERROR;
2102+
return result;
20852103
}
20862104

20872105

0 commit comments

Comments
 (0)