Coverage Report

Created: 2026-02-26 06:53

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