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