123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510 |
- /* Iterator objects */
- #include "Python.h"
- #include "pycore_call.h" // _PyObject_CallNoArgs()
- #include "pycore_object.h" // _PyObject_GC_TRACK()
- typedef struct {
- PyObject_HEAD
- Py_ssize_t it_index;
- PyObject *it_seq; /* Set to NULL when iterator is exhausted */
- } seqiterobject;
- PyObject *
- PySeqIter_New(PyObject *seq)
- {
- seqiterobject *it;
- if (!PySequence_Check(seq)) {
- PyErr_BadInternalCall();
- return NULL;
- }
- it = PyObject_GC_New(seqiterobject, &PySeqIter_Type);
- if (it == NULL)
- return NULL;
- it->it_index = 0;
- it->it_seq = Py_NewRef(seq);
- _PyObject_GC_TRACK(it);
- return (PyObject *)it;
- }
- static void
- iter_dealloc(seqiterobject *it)
- {
- _PyObject_GC_UNTRACK(it);
- Py_XDECREF(it->it_seq);
- PyObject_GC_Del(it);
- }
- static int
- iter_traverse(seqiterobject *it, visitproc visit, void *arg)
- {
- Py_VISIT(it->it_seq);
- return 0;
- }
- static PyObject *
- iter_iternext(PyObject *iterator)
- {
- seqiterobject *it;
- PyObject *seq;
- PyObject *result;
- assert(PySeqIter_Check(iterator));
- it = (seqiterobject *)iterator;
- seq = it->it_seq;
- if (seq == NULL)
- return NULL;
- if (it->it_index == PY_SSIZE_T_MAX) {
- PyErr_SetString(PyExc_OverflowError,
- "iter index too large");
- return NULL;
- }
- result = PySequence_GetItem(seq, it->it_index);
- if (result != NULL) {
- it->it_index++;
- return result;
- }
- if (PyErr_ExceptionMatches(PyExc_IndexError) ||
- PyErr_ExceptionMatches(PyExc_StopIteration))
- {
- PyErr_Clear();
- it->it_seq = NULL;
- Py_DECREF(seq);
- }
- return NULL;
- }
- static PyObject *
- iter_len(seqiterobject *it, PyObject *Py_UNUSED(ignored))
- {
- Py_ssize_t seqsize, len;
- if (it->it_seq) {
- if (_PyObject_HasLen(it->it_seq)) {
- seqsize = PySequence_Size(it->it_seq);
- if (seqsize == -1)
- return NULL;
- }
- else {
- Py_RETURN_NOTIMPLEMENTED;
- }
- len = seqsize - it->it_index;
- if (len >= 0)
- return PyLong_FromSsize_t(len);
- }
- return PyLong_FromLong(0);
- }
- PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
- static PyObject *
- iter_reduce(seqiterobject *it, PyObject *Py_UNUSED(ignored))
- {
- PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter));
- /* _PyEval_GetBuiltin can invoke arbitrary code,
- * call must be before access of iterator pointers.
- * see issue #101765 */
- if (it->it_seq != NULL)
- return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index);
- else
- return Py_BuildValue("N(())", iter);
- }
- PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
- static PyObject *
- iter_setstate(seqiterobject *it, PyObject *state)
- {
- Py_ssize_t index = PyLong_AsSsize_t(state);
- if (index == -1 && PyErr_Occurred())
- return NULL;
- if (it->it_seq != NULL) {
- if (index < 0)
- index = 0;
- it->it_index = index;
- }
- Py_RETURN_NONE;
- }
- PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
- static PyMethodDef seqiter_methods[] = {
- {"__length_hint__", (PyCFunction)iter_len, METH_NOARGS, length_hint_doc},
- {"__reduce__", (PyCFunction)iter_reduce, METH_NOARGS, reduce_doc},
- {"__setstate__", (PyCFunction)iter_setstate, METH_O, setstate_doc},
- {NULL, NULL} /* sentinel */
- };
- PyTypeObject PySeqIter_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "iterator", /* tp_name */
- sizeof(seqiterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)iter_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- 0, /* tp_doc */
- (traverseproc)iter_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- iter_iternext, /* tp_iternext */
- seqiter_methods, /* tp_methods */
- 0, /* tp_members */
- };
- /* -------------------------------------- */
- typedef struct {
- PyObject_HEAD
- PyObject *it_callable; /* Set to NULL when iterator is exhausted */
- PyObject *it_sentinel; /* Set to NULL when iterator is exhausted */
- } calliterobject;
- PyObject *
- PyCallIter_New(PyObject *callable, PyObject *sentinel)
- {
- calliterobject *it;
- it = PyObject_GC_New(calliterobject, &PyCallIter_Type);
- if (it == NULL)
- return NULL;
- it->it_callable = Py_NewRef(callable);
- it->it_sentinel = Py_NewRef(sentinel);
- _PyObject_GC_TRACK(it);
- return (PyObject *)it;
- }
- static void
- calliter_dealloc(calliterobject *it)
- {
- _PyObject_GC_UNTRACK(it);
- Py_XDECREF(it->it_callable);
- Py_XDECREF(it->it_sentinel);
- PyObject_GC_Del(it);
- }
- static int
- calliter_traverse(calliterobject *it, visitproc visit, void *arg)
- {
- Py_VISIT(it->it_callable);
- Py_VISIT(it->it_sentinel);
- return 0;
- }
- static PyObject *
- calliter_iternext(calliterobject *it)
- {
- PyObject *result;
- if (it->it_callable == NULL) {
- return NULL;
- }
- result = _PyObject_CallNoArgs(it->it_callable);
- if (result != NULL && it->it_sentinel != NULL){
- int ok;
- ok = PyObject_RichCompareBool(it->it_sentinel, result, Py_EQ);
- if (ok == 0) {
- return result; /* Common case, fast path */
- }
- if (ok > 0) {
- Py_CLEAR(it->it_callable);
- Py_CLEAR(it->it_sentinel);
- }
- }
- else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
- PyErr_Clear();
- Py_CLEAR(it->it_callable);
- Py_CLEAR(it->it_sentinel);
- }
- Py_XDECREF(result);
- return NULL;
- }
- static PyObject *
- calliter_reduce(calliterobject *it, PyObject *Py_UNUSED(ignored))
- {
- PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter));
- /* _PyEval_GetBuiltin can invoke arbitrary code,
- * call must be before access of iterator pointers.
- * see issue #101765 */
- if (it->it_callable != NULL && it->it_sentinel != NULL)
- return Py_BuildValue("N(OO)", iter, it->it_callable, it->it_sentinel);
- else
- return Py_BuildValue("N(())", iter);
- }
- static PyMethodDef calliter_methods[] = {
- {"__reduce__", (PyCFunction)calliter_reduce, METH_NOARGS, reduce_doc},
- {NULL, NULL} /* sentinel */
- };
- PyTypeObject PyCallIter_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "callable_iterator", /* tp_name */
- sizeof(calliterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)calliter_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- 0, /* tp_doc */
- (traverseproc)calliter_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- (iternextfunc)calliter_iternext, /* tp_iternext */
- calliter_methods, /* tp_methods */
- };
- /* -------------------------------------- */
- typedef struct {
- PyObject_HEAD
- PyObject *wrapped;
- PyObject *default_value;
- } anextawaitableobject;
- static void
- anextawaitable_dealloc(anextawaitableobject *obj)
- {
- _PyObject_GC_UNTRACK(obj);
- Py_XDECREF(obj->wrapped);
- Py_XDECREF(obj->default_value);
- PyObject_GC_Del(obj);
- }
- static int
- anextawaitable_traverse(anextawaitableobject *obj, visitproc visit, void *arg)
- {
- Py_VISIT(obj->wrapped);
- Py_VISIT(obj->default_value);
- return 0;
- }
- static PyObject *
- anextawaitable_getiter(anextawaitableobject *obj)
- {
- assert(obj->wrapped != NULL);
- PyObject *awaitable = _PyCoro_GetAwaitableIter(obj->wrapped);
- if (awaitable == NULL) {
- return NULL;
- }
- if (Py_TYPE(awaitable)->tp_iternext == NULL) {
- /* _PyCoro_GetAwaitableIter returns a Coroutine, a Generator,
- * or an iterator. Of these, only coroutines lack tp_iternext.
- */
- assert(PyCoro_CheckExact(awaitable));
- unaryfunc getter = Py_TYPE(awaitable)->tp_as_async->am_await;
- PyObject *new_awaitable = getter(awaitable);
- if (new_awaitable == NULL) {
- Py_DECREF(awaitable);
- return NULL;
- }
- Py_SETREF(awaitable, new_awaitable);
- if (!PyIter_Check(awaitable)) {
- PyErr_SetString(PyExc_TypeError,
- "__await__ returned a non-iterable");
- Py_DECREF(awaitable);
- return NULL;
- }
- }
- return awaitable;
- }
- static PyObject *
- anextawaitable_iternext(anextawaitableobject *obj)
- {
- /* Consider the following class:
- *
- * class A:
- * async def __anext__(self):
- * ...
- * a = A()
- *
- * Then `await anext(a)` should call
- * a.__anext__().__await__().__next__()
- *
- * On the other hand, given
- *
- * async def agen():
- * yield 1
- * yield 2
- * gen = agen()
- *
- * Then `await anext(gen)` can just call
- * gen.__anext__().__next__()
- */
- PyObject *awaitable = anextawaitable_getiter(obj);
- if (awaitable == NULL) {
- return NULL;
- }
- PyObject *result = (*Py_TYPE(awaitable)->tp_iternext)(awaitable);
- Py_DECREF(awaitable);
- if (result != NULL) {
- return result;
- }
- if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) {
- _PyGen_SetStopIterationValue(obj->default_value);
- }
- return NULL;
- }
- static PyObject *
- anextawaitable_proxy(anextawaitableobject *obj, char *meth, PyObject *arg) {
- PyObject *awaitable = anextawaitable_getiter(obj);
- if (awaitable == NULL) {
- return NULL;
- }
- PyObject *ret = PyObject_CallMethod(awaitable, meth, "O", arg);
- Py_DECREF(awaitable);
- if (ret != NULL) {
- return ret;
- }
- if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) {
- /* `anextawaitableobject` is only used by `anext()` when
- * a default value is provided. So when we have a StopAsyncIteration
- * exception we replace it with a `StopIteration(default)`, as if
- * it was the return value of `__anext__()` coroutine.
- */
- _PyGen_SetStopIterationValue(obj->default_value);
- }
- return NULL;
- }
- static PyObject *
- anextawaitable_send(anextawaitableobject *obj, PyObject *arg) {
- return anextawaitable_proxy(obj, "send", arg);
- }
- static PyObject *
- anextawaitable_throw(anextawaitableobject *obj, PyObject *arg) {
- return anextawaitable_proxy(obj, "throw", arg);
- }
- static PyObject *
- anextawaitable_close(anextawaitableobject *obj, PyObject *arg) {
- return anextawaitable_proxy(obj, "close", arg);
- }
- PyDoc_STRVAR(send_doc,
- "send(arg) -> send 'arg' into the wrapped iterator,\n\
- return next yielded value or raise StopIteration.");
- PyDoc_STRVAR(throw_doc,
- "throw(value)\n\
- throw(typ[,val[,tb]])\n\
- \n\
- raise exception in the wrapped iterator, return next yielded value\n\
- or raise StopIteration.\n\
- the (type, val, tb) signature is deprecated, \n\
- and may be removed in a future version of Python.");
- PyDoc_STRVAR(close_doc,
- "close() -> raise GeneratorExit inside generator.");
- static PyMethodDef anextawaitable_methods[] = {
- {"send",(PyCFunction)anextawaitable_send, METH_O, send_doc},
- {"throw",(PyCFunction)anextawaitable_throw, METH_VARARGS, throw_doc},
- {"close",(PyCFunction)anextawaitable_close, METH_VARARGS, close_doc},
- {NULL, NULL} /* Sentinel */
- };
- static PyAsyncMethods anextawaitable_as_async = {
- PyObject_SelfIter, /* am_await */
- 0, /* am_aiter */
- 0, /* am_anext */
- 0, /* am_send */
- };
- PyTypeObject _PyAnextAwaitable_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "anext_awaitable", /* tp_name */
- sizeof(anextawaitableobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)anextawaitable_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- &anextawaitable_as_async, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- 0, /* tp_doc */
- (traverseproc)anextawaitable_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- (unaryfunc)anextawaitable_iternext, /* tp_iternext */
- anextawaitable_methods, /* tp_methods */
- };
- PyObject *
- PyAnextAwaitable_New(PyObject *awaitable, PyObject *default_value)
- {
- anextawaitableobject *anext = PyObject_GC_New(
- anextawaitableobject, &_PyAnextAwaitable_Type);
- if (anext == NULL) {
- return NULL;
- }
- anext->wrapped = Py_NewRef(awaitable);
- anext->default_value = Py_NewRef(default_value);
- _PyObject_GC_TRACK(anext);
- return (PyObject *)anext;
- }
|