xref: /third_party/python/Objects/iterobject.c (revision 7db96d56)
1/* Iterator objects */
2
3#include "Python.h"
4#include "pycore_call.h"          // _PyObject_CallNoArgs()
5#include "pycore_object.h"        // _PyObject_GC_TRACK()
6
7typedef struct {
8    PyObject_HEAD
9    Py_ssize_t it_index;
10    PyObject *it_seq; /* Set to NULL when iterator is exhausted */
11} seqiterobject;
12
13PyObject *
14PySeqIter_New(PyObject *seq)
15{
16    seqiterobject *it;
17
18    if (!PySequence_Check(seq)) {
19        PyErr_BadInternalCall();
20        return NULL;
21    }
22    it = PyObject_GC_New(seqiterobject, &PySeqIter_Type);
23    if (it == NULL)
24        return NULL;
25    it->it_index = 0;
26    Py_INCREF(seq);
27    it->it_seq = seq;
28    _PyObject_GC_TRACK(it);
29    return (PyObject *)it;
30}
31
32static void
33iter_dealloc(seqiterobject *it)
34{
35    _PyObject_GC_UNTRACK(it);
36    Py_XDECREF(it->it_seq);
37    PyObject_GC_Del(it);
38}
39
40static int
41iter_traverse(seqiterobject *it, visitproc visit, void *arg)
42{
43    Py_VISIT(it->it_seq);
44    return 0;
45}
46
47static PyObject *
48iter_iternext(PyObject *iterator)
49{
50    seqiterobject *it;
51    PyObject *seq;
52    PyObject *result;
53
54    assert(PySeqIter_Check(iterator));
55    it = (seqiterobject *)iterator;
56    seq = it->it_seq;
57    if (seq == NULL)
58        return NULL;
59    if (it->it_index == PY_SSIZE_T_MAX) {
60        PyErr_SetString(PyExc_OverflowError,
61                        "iter index too large");
62        return NULL;
63    }
64
65    result = PySequence_GetItem(seq, it->it_index);
66    if (result != NULL) {
67        it->it_index++;
68        return result;
69    }
70    if (PyErr_ExceptionMatches(PyExc_IndexError) ||
71        PyErr_ExceptionMatches(PyExc_StopIteration))
72    {
73        PyErr_Clear();
74        it->it_seq = NULL;
75        Py_DECREF(seq);
76    }
77    return NULL;
78}
79
80static PyObject *
81iter_len(seqiterobject *it, PyObject *Py_UNUSED(ignored))
82{
83    Py_ssize_t seqsize, len;
84
85    if (it->it_seq) {
86        if (_PyObject_HasLen(it->it_seq)) {
87            seqsize = PySequence_Size(it->it_seq);
88            if (seqsize == -1)
89                return NULL;
90        }
91        else {
92            Py_RETURN_NOTIMPLEMENTED;
93        }
94        len = seqsize - it->it_index;
95        if (len >= 0)
96            return PyLong_FromSsize_t(len);
97    }
98    return PyLong_FromLong(0);
99}
100
101PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
102
103static PyObject *
104iter_reduce(seqiterobject *it, PyObject *Py_UNUSED(ignored))
105{
106    PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter));
107
108    /* _PyEval_GetBuiltin can invoke arbitrary code,
109     * call must be before access of iterator pointers.
110     * see issue #101765 */
111
112    if (it->it_seq != NULL)
113        return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index);
114    else
115        return Py_BuildValue("N(())", iter);
116}
117
118PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
119
120static PyObject *
121iter_setstate(seqiterobject *it, PyObject *state)
122{
123    Py_ssize_t index = PyLong_AsSsize_t(state);
124    if (index == -1 && PyErr_Occurred())
125        return NULL;
126    if (it->it_seq != NULL) {
127        if (index < 0)
128            index = 0;
129        it->it_index = index;
130    }
131    Py_RETURN_NONE;
132}
133
134PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
135
136static PyMethodDef seqiter_methods[] = {
137    {"__length_hint__", (PyCFunction)iter_len, METH_NOARGS, length_hint_doc},
138    {"__reduce__", (PyCFunction)iter_reduce, METH_NOARGS, reduce_doc},
139    {"__setstate__", (PyCFunction)iter_setstate, METH_O, setstate_doc},
140    {NULL,              NULL}           /* sentinel */
141};
142
143PyTypeObject PySeqIter_Type = {
144    PyVarObject_HEAD_INIT(&PyType_Type, 0)
145    "iterator",                                 /* tp_name */
146    sizeof(seqiterobject),                      /* tp_basicsize */
147    0,                                          /* tp_itemsize */
148    /* methods */
149    (destructor)iter_dealloc,                   /* tp_dealloc */
150    0,                                          /* tp_vectorcall_offset */
151    0,                                          /* tp_getattr */
152    0,                                          /* tp_setattr */
153    0,                                          /* tp_as_async */
154    0,                                          /* tp_repr */
155    0,                                          /* tp_as_number */
156    0,                                          /* tp_as_sequence */
157    0,                                          /* tp_as_mapping */
158    0,                                          /* tp_hash */
159    0,                                          /* tp_call */
160    0,                                          /* tp_str */
161    PyObject_GenericGetAttr,                    /* tp_getattro */
162    0,                                          /* tp_setattro */
163    0,                                          /* tp_as_buffer */
164    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
165    0,                                          /* tp_doc */
166    (traverseproc)iter_traverse,                /* tp_traverse */
167    0,                                          /* tp_clear */
168    0,                                          /* tp_richcompare */
169    0,                                          /* tp_weaklistoffset */
170    PyObject_SelfIter,                          /* tp_iter */
171    iter_iternext,                              /* tp_iternext */
172    seqiter_methods,                            /* tp_methods */
173    0,                                          /* tp_members */
174};
175
176/* -------------------------------------- */
177
178typedef struct {
179    PyObject_HEAD
180    PyObject *it_callable; /* Set to NULL when iterator is exhausted */
181    PyObject *it_sentinel; /* Set to NULL when iterator is exhausted */
182} calliterobject;
183
184PyObject *
185PyCallIter_New(PyObject *callable, PyObject *sentinel)
186{
187    calliterobject *it;
188    it = PyObject_GC_New(calliterobject, &PyCallIter_Type);
189    if (it == NULL)
190        return NULL;
191    Py_INCREF(callable);
192    it->it_callable = callable;
193    Py_INCREF(sentinel);
194    it->it_sentinel = sentinel;
195    _PyObject_GC_TRACK(it);
196    return (PyObject *)it;
197}
198static void
199calliter_dealloc(calliterobject *it)
200{
201    _PyObject_GC_UNTRACK(it);
202    Py_XDECREF(it->it_callable);
203    Py_XDECREF(it->it_sentinel);
204    PyObject_GC_Del(it);
205}
206
207static int
208calliter_traverse(calliterobject *it, visitproc visit, void *arg)
209{
210    Py_VISIT(it->it_callable);
211    Py_VISIT(it->it_sentinel);
212    return 0;
213}
214
215static PyObject *
216calliter_iternext(calliterobject *it)
217{
218    PyObject *result;
219
220    if (it->it_callable == NULL) {
221        return NULL;
222    }
223
224    result = _PyObject_CallNoArgs(it->it_callable);
225    if (result != NULL && it->it_sentinel != NULL){
226        int ok;
227
228        ok = PyObject_RichCompareBool(it->it_sentinel, result, Py_EQ);
229        if (ok == 0) {
230            return result; /* Common case, fast path */
231        }
232
233        if (ok > 0) {
234            Py_CLEAR(it->it_callable);
235            Py_CLEAR(it->it_sentinel);
236        }
237    }
238    else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
239        PyErr_Clear();
240        Py_CLEAR(it->it_callable);
241        Py_CLEAR(it->it_sentinel);
242    }
243    Py_XDECREF(result);
244    return NULL;
245}
246
247static PyObject *
248calliter_reduce(calliterobject *it, PyObject *Py_UNUSED(ignored))
249{
250    PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter));
251
252    /* _PyEval_GetBuiltin can invoke arbitrary code,
253     * call must be before access of iterator pointers.
254     * see issue #101765 */
255
256    if (it->it_callable != NULL && it->it_sentinel != NULL)
257        return Py_BuildValue("N(OO)", iter, it->it_callable, it->it_sentinel);
258    else
259        return Py_BuildValue("N(())", iter);
260}
261
262static PyMethodDef calliter_methods[] = {
263    {"__reduce__", (PyCFunction)calliter_reduce, METH_NOARGS, reduce_doc},
264    {NULL,              NULL}           /* sentinel */
265};
266
267PyTypeObject PyCallIter_Type = {
268    PyVarObject_HEAD_INIT(&PyType_Type, 0)
269    "callable_iterator",                        /* tp_name */
270    sizeof(calliterobject),                     /* tp_basicsize */
271    0,                                          /* tp_itemsize */
272    /* methods */
273    (destructor)calliter_dealloc,               /* tp_dealloc */
274    0,                                          /* tp_vectorcall_offset */
275    0,                                          /* tp_getattr */
276    0,                                          /* tp_setattr */
277    0,                                          /* tp_as_async */
278    0,                                          /* tp_repr */
279    0,                                          /* tp_as_number */
280    0,                                          /* tp_as_sequence */
281    0,                                          /* tp_as_mapping */
282    0,                                          /* tp_hash */
283    0,                                          /* tp_call */
284    0,                                          /* tp_str */
285    PyObject_GenericGetAttr,                    /* tp_getattro */
286    0,                                          /* tp_setattro */
287    0,                                          /* tp_as_buffer */
288    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
289    0,                                          /* tp_doc */
290    (traverseproc)calliter_traverse,            /* tp_traverse */
291    0,                                          /* tp_clear */
292    0,                                          /* tp_richcompare */
293    0,                                          /* tp_weaklistoffset */
294    PyObject_SelfIter,                          /* tp_iter */
295    (iternextfunc)calliter_iternext,            /* tp_iternext */
296    calliter_methods,                           /* tp_methods */
297};
298
299
300/* -------------------------------------- */
301
302typedef struct {
303    PyObject_HEAD
304    PyObject *wrapped;
305    PyObject *default_value;
306} anextawaitableobject;
307
308static void
309anextawaitable_dealloc(anextawaitableobject *obj)
310{
311    _PyObject_GC_UNTRACK(obj);
312    Py_XDECREF(obj->wrapped);
313    Py_XDECREF(obj->default_value);
314    PyObject_GC_Del(obj);
315}
316
317static int
318anextawaitable_traverse(anextawaitableobject *obj, visitproc visit, void *arg)
319{
320    Py_VISIT(obj->wrapped);
321    Py_VISIT(obj->default_value);
322    return 0;
323}
324
325static PyObject *
326anextawaitable_getiter(anextawaitableobject *obj)
327{
328    assert(obj->wrapped != NULL);
329    PyObject *awaitable = _PyCoro_GetAwaitableIter(obj->wrapped);
330    if (awaitable == NULL) {
331        return NULL;
332    }
333    if (Py_TYPE(awaitable)->tp_iternext == NULL) {
334        /* _PyCoro_GetAwaitableIter returns a Coroutine, a Generator,
335         * or an iterator. Of these, only coroutines lack tp_iternext.
336         */
337        assert(PyCoro_CheckExact(awaitable));
338        unaryfunc getter = Py_TYPE(awaitable)->tp_as_async->am_await;
339        PyObject *new_awaitable = getter(awaitable);
340        if (new_awaitable == NULL) {
341            Py_DECREF(awaitable);
342            return NULL;
343        }
344        Py_SETREF(awaitable, new_awaitable);
345        if (!PyIter_Check(awaitable)) {
346            PyErr_SetString(PyExc_TypeError,
347                            "__await__ returned a non-iterable");
348            Py_DECREF(awaitable);
349            return NULL;
350        }
351    }
352    return awaitable;
353}
354
355static PyObject *
356anextawaitable_iternext(anextawaitableobject *obj)
357{
358    /* Consider the following class:
359     *
360     *     class A:
361     *         async def __anext__(self):
362     *             ...
363     *     a = A()
364     *
365     * Then `await anext(a)` should call
366     * a.__anext__().__await__().__next__()
367     *
368     * On the other hand, given
369     *
370     *     async def agen():
371     *         yield 1
372     *         yield 2
373     *     gen = agen()
374     *
375     * Then `await anext(gen)` can just call
376     * gen.__anext__().__next__()
377     */
378    PyObject *awaitable = anextawaitable_getiter(obj);
379    if (awaitable == NULL) {
380        return NULL;
381    }
382    PyObject *result = (*Py_TYPE(awaitable)->tp_iternext)(awaitable);
383    Py_DECREF(awaitable);
384    if (result != NULL) {
385        return result;
386    }
387    if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) {
388        _PyGen_SetStopIterationValue(obj->default_value);
389    }
390    return NULL;
391}
392
393
394static PyObject *
395anextawaitable_proxy(anextawaitableobject *obj, char *meth, PyObject *arg) {
396    PyObject *awaitable = anextawaitable_getiter(obj);
397    if (awaitable == NULL) {
398        return NULL;
399    }
400    PyObject *ret = PyObject_CallMethod(awaitable, meth, "O", arg);
401    Py_DECREF(awaitable);
402    if (ret != NULL) {
403        return ret;
404    }
405    if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) {
406        /* `anextawaitableobject` is only used by `anext()` when
407         * a default value is provided. So when we have a StopAsyncIteration
408         * exception we replace it with a `StopIteration(default)`, as if
409         * it was the return value of `__anext__()` coroutine.
410         */
411        _PyGen_SetStopIterationValue(obj->default_value);
412    }
413    return NULL;
414}
415
416
417static PyObject *
418anextawaitable_send(anextawaitableobject *obj, PyObject *arg) {
419    return anextawaitable_proxy(obj, "send", arg);
420}
421
422
423static PyObject *
424anextawaitable_throw(anextawaitableobject *obj, PyObject *arg) {
425    return anextawaitable_proxy(obj, "throw", arg);
426}
427
428
429static PyObject *
430anextawaitable_close(anextawaitableobject *obj, PyObject *arg) {
431    return anextawaitable_proxy(obj, "close", arg);
432}
433
434
435PyDoc_STRVAR(send_doc,
436"send(arg) -> send 'arg' into the wrapped iterator,\n\
437return next yielded value or raise StopIteration.");
438
439
440PyDoc_STRVAR(throw_doc,
441"throw(typ[,val[,tb]]) -> raise exception in the wrapped iterator,\n\
442return next yielded value or raise StopIteration.");
443
444
445PyDoc_STRVAR(close_doc,
446"close() -> raise GeneratorExit inside generator.");
447
448
449static PyMethodDef anextawaitable_methods[] = {
450    {"send",(PyCFunction)anextawaitable_send, METH_O, send_doc},
451    {"throw",(PyCFunction)anextawaitable_throw, METH_VARARGS, throw_doc},
452    {"close",(PyCFunction)anextawaitable_close, METH_VARARGS, close_doc},
453    {NULL, NULL}        /* Sentinel */
454};
455
456
457static PyAsyncMethods anextawaitable_as_async = {
458    PyObject_SelfIter,                          /* am_await */
459    0,                                          /* am_aiter */
460    0,                                          /* am_anext */
461    0,                                          /* am_send  */
462};
463
464PyTypeObject _PyAnextAwaitable_Type = {
465    PyVarObject_HEAD_INIT(&PyType_Type, 0)
466    "anext_awaitable",                          /* tp_name */
467    sizeof(anextawaitableobject),               /* tp_basicsize */
468    0,                                          /* tp_itemsize */
469    /* methods */
470    (destructor)anextawaitable_dealloc,         /* tp_dealloc */
471    0,                                          /* tp_vectorcall_offset */
472    0,                                          /* tp_getattr */
473    0,                                          /* tp_setattr */
474    &anextawaitable_as_async,                   /* tp_as_async */
475    0,                                          /* tp_repr */
476    0,                                          /* tp_as_number */
477    0,                                          /* tp_as_sequence */
478    0,                                          /* tp_as_mapping */
479    0,                                          /* tp_hash */
480    0,                                          /* tp_call */
481    0,                                          /* tp_str */
482    PyObject_GenericGetAttr,                    /* tp_getattro */
483    0,                                          /* tp_setattro */
484    0,                                          /* tp_as_buffer */
485    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
486    0,                                          /* tp_doc */
487    (traverseproc)anextawaitable_traverse,      /* tp_traverse */
488    0,                                          /* tp_clear */
489    0,                                          /* tp_richcompare */
490    0,                                          /* tp_weaklistoffset */
491    PyObject_SelfIter,                          /* tp_iter */
492    (unaryfunc)anextawaitable_iternext,         /* tp_iternext */
493    anextawaitable_methods,                     /* tp_methods */
494};
495
496PyObject *
497PyAnextAwaitable_New(PyObject *awaitable, PyObject *default_value)
498{
499    anextawaitableobject *anext = PyObject_GC_New(
500            anextawaitableobject, &_PyAnextAwaitable_Type);
501    if (anext == NULL) {
502        return NULL;
503    }
504    Py_INCREF(awaitable);
505    anext->wrapped = awaitable;
506    Py_INCREF(default_value);
507    anext->default_value = default_value;
508    _PyObject_GC_TRACK(anext);
509    return (PyObject *)anext;
510}
511