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