Coverage Report

Created: 2025-07-04 06:49

/src/cpython/Objects/iterobject.c
Line
Count
Source (jump to first uncovered line)
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
591
{
20
591
    seqiterobject *it;
21
22
591
    if (!PySequence_Check(seq)) {
23
0
        PyErr_BadInternalCall();
24
0
        return NULL;
25
0
    }
26
591
    it = PyObject_GC_New(seqiterobject, &PySeqIter_Type);
27
591
    if (it == NULL)
28
0
        return NULL;
29
591
    it->it_index = 0;
30
591
    it->it_seq = Py_NewRef(seq);
31
591
    _PyObject_GC_TRACK(it);
32
591
    return (PyObject *)it;
33
591
}
34
35
static void
36
iter_dealloc(PyObject *op)
37
591
{
38
591
    seqiterobject *it = (seqiterobject*)op;
39
591
    _PyObject_GC_UNTRACK(it);
40
591
    Py_XDECREF(it->it_seq);
41
591
    PyObject_GC_Del(it);
42
591
}
43
44
static int
45
iter_traverse(PyObject *op, visitproc visit, void *arg)
46
0
{
47
0
    seqiterobject *it = (seqiterobject*)op;
48
0
    Py_VISIT(it->it_seq);
49
0
    return 0;
50
0
}
51
52
static PyObject *
53
iter_iternext(PyObject *iterator)
54
1.37k
{
55
1.37k
    seqiterobject *it;
56
1.37k
    PyObject *seq;
57
1.37k
    PyObject *result;
58
59
1.37k
    assert(PySeqIter_Check(iterator));
60
1.37k
    it = (seqiterobject *)iterator;
61
1.37k
    seq = it->it_seq;
62
1.37k
    if (seq == NULL)
63
0
        return NULL;
64
1.37k
    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
1.37k
    result = PySequence_GetItem(seq, it->it_index);
71
1.37k
    if (result != NULL) {
72
783
        it->it_index++;
73
783
        return result;
74
783
    }
75
591
    if (PyErr_ExceptionMatches(PyExc_IndexError) ||
76
591
        PyErr_ExceptionMatches(PyExc_StopIteration))
77
591
    {
78
591
        PyErr_Clear();
79
591
        it->it_seq = NULL;
80
591
        Py_DECREF(seq);
81
591
    }
82
591
    return NULL;
83
1.37k
}
84
85
static PyObject *
86
iter_len(PyObject *op, PyObject *Py_UNUSED(ignored))
87
10
{
88
10
    seqiterobject *it = (seqiterobject*)op;
89
10
    Py_ssize_t seqsize, len;
90
91
10
    if (it->it_seq) {
92
10
        if (_PyObject_HasLen(it->it_seq)) {
93
10
            seqsize = PySequence_Size(it->it_seq);
94
10
            if (seqsize == -1)
95
0
                return NULL;
96
10
        }
97
0
        else {
98
0
            Py_RETURN_NOTIMPLEMENTED;
99
0
        }
100
10
        len = seqsize - it->it_index;
101
10
        if (len >= 0)
102
10
            return PyLong_FromSsize_t(len);
103
10
    }
104
0
    return PyLong_FromLong(0);
105
10
}
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
338k
{
195
338k
    calliterobject *it;
196
338k
    it = PyObject_GC_New(calliterobject, &PyCallIter_Type);
197
338k
    if (it == NULL)
198
0
        return NULL;
199
338k
    it->it_callable = Py_NewRef(callable);
200
338k
    it->it_sentinel = Py_NewRef(sentinel);
201
338k
    _PyObject_GC_TRACK(it);
202
338k
    return (PyObject *)it;
203
338k
}
204
static void
205
calliter_dealloc(PyObject *op)
206
338k
{
207
338k
    calliterobject *it = (calliterobject*)op;
208
338k
    _PyObject_GC_UNTRACK(it);
209
338k
    Py_XDECREF(it->it_callable);
210
338k
    Py_XDECREF(it->it_sentinel);
211
338k
    PyObject_GC_Del(it);
212
338k
}
213
214
static int
215
calliter_traverse(PyObject *op, visitproc visit, void *arg)
216
373
{
217
373
    calliterobject *it = (calliterobject*)op;
218
373
    Py_VISIT(it->it_callable);
219
373
    Py_VISIT(it->it_sentinel);
220
373
    return 0;
221
373
}
222
223
static PyObject *
224
calliter_iternext(PyObject *op)
225
2.73M
{
226
2.73M
    calliterobject *it = (calliterobject*)op;
227
2.73M
    PyObject *result;
228
229
2.73M
    if (it->it_callable == NULL) {
230
0
        return NULL;
231
0
    }
232
233
2.73M
    result = _PyObject_CallNoArgs(it->it_callable);
234
2.73M
    if (result != NULL && it->it_sentinel != NULL){
235
2.73M
        int ok;
236
237
2.73M
        ok = PyObject_RichCompareBool(it->it_sentinel, result, Py_EQ);
238
2.73M
        if (ok == 0) {
239
2.39M
            return result; /* Common case, fast path */
240
2.39M
        }
241
242
338k
        if (ok > 0) {
243
338k
            Py_CLEAR(it->it_callable);
244
338k
            Py_CLEAR(it->it_sentinel);
245
338k
        }
246
338k
    }
247
0
    else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
248
0
        PyErr_Clear();
249
0
        Py_CLEAR(it->it_callable);
250
0
        Py_CLEAR(it->it_sentinel);
251
0
    }
252
338k
    Py_XDECREF(result);
253
338k
    return NULL;
254
2.73M
}
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_SetString(PyExc_TypeError,
361
0
                            "__await__ returned a non-iterable");
362
0
            Py_DECREF(awaitable);
363
0
            return NULL;
364
0
        }
365
0
    }
366
0
    return awaitable;
367
0
}
368
369
static PyObject *
370
anextawaitable_iternext(PyObject *op)
371
0
{
372
    /* Consider the following class:
373
     *
374
     *     class A:
375
     *         async def __anext__(self):
376
     *             ...
377
     *     a = A()
378
     *
379
     * Then `await anext(a)` should call
380
     * a.__anext__().__await__().__next__()
381
     *
382
     * On the other hand, given
383
     *
384
     *     async def agen():
385
     *         yield 1
386
     *         yield 2
387
     *     gen = agen()
388
     *
389
     * Then `await anext(gen)` can just call
390
     * gen.__anext__().__next__()
391
     */
392
0
    anextawaitableobject *obj = anextawaitableobject_CAST(op);
393
0
    PyObject *awaitable = anextawaitable_getiter(obj);
394
0
    if (awaitable == NULL) {
395
0
        return NULL;
396
0
    }
397
0
    PyObject *result = (*Py_TYPE(awaitable)->tp_iternext)(awaitable);
398
0
    Py_DECREF(awaitable);
399
0
    if (result != NULL) {
400
0
        return result;
401
0
    }
402
0
    if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) {
403
0
        PyErr_Clear();
404
0
        _PyGen_SetStopIterationValue(obj->default_value);
405
0
    }
406
0
    return NULL;
407
0
}
408
409
410
static PyObject *
411
anextawaitable_proxy(anextawaitableobject *obj, char *meth, PyObject *arg)
412
0
{
413
0
    PyObject *awaitable = anextawaitable_getiter(obj);
414
0
    if (awaitable == NULL) {
415
0
        return NULL;
416
0
    }
417
    // When specified, 'arg' may be a tuple (if coming from a METH_VARARGS
418
    // method) or a single object (if coming from a METH_O method).
419
0
    PyObject *ret = arg == NULL
420
0
        ? PyObject_CallMethod(awaitable, meth, NULL)
421
0
        : PyObject_CallMethod(awaitable, meth, "O", arg);
422
0
    Py_DECREF(awaitable);
423
0
    if (ret != NULL) {
424
0
        return ret;
425
0
    }
426
0
    if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) {
427
        /* `anextawaitableobject` is only used by `anext()` when
428
         * a default value is provided. So when we have a StopAsyncIteration
429
         * exception we replace it with a `StopIteration(default)`, as if
430
         * it was the return value of `__anext__()` coroutine.
431
         */
432
0
        PyErr_Clear();
433
0
        _PyGen_SetStopIterationValue(obj->default_value);
434
0
    }
435
0
    return NULL;
436
0
}
437
438
439
static PyObject *
440
anextawaitable_send(PyObject *op, PyObject *arg)
441
0
{
442
0
    anextawaitableobject *obj = anextawaitableobject_CAST(op);
443
0
    return anextawaitable_proxy(obj, "send", arg);
444
0
}
445
446
447
static PyObject *
448
anextawaitable_throw(PyObject *op, PyObject *args)
449
0
{
450
0
    anextawaitableobject *obj = anextawaitableobject_CAST(op);
451
0
    return anextawaitable_proxy(obj, "throw", args);
452
0
}
453
454
455
static PyObject *
456
anextawaitable_close(PyObject *op, PyObject *Py_UNUSED(dummy))
457
0
{
458
0
    anextawaitableobject *obj = anextawaitableobject_CAST(op);
459
0
    return anextawaitable_proxy(obj, "close", NULL);
460
0
}
461
462
463
PyDoc_STRVAR(send_doc,
464
"send(arg) -> send 'arg' into the wrapped iterator,\n\
465
return next yielded value or raise StopIteration.");
466
467
468
PyDoc_STRVAR(throw_doc,
469
"throw(value)\n\
470
throw(typ[,val[,tb]])\n\
471
\n\
472
raise exception in the wrapped iterator, return next yielded value\n\
473
or raise StopIteration.\n\
474
the (type, val, tb) signature is deprecated, \n\
475
and may be removed in a future version of Python.");
476
477
478
PyDoc_STRVAR(close_doc,
479
"close() -> raise GeneratorExit inside generator.");
480
481
482
static PyMethodDef anextawaitable_methods[] = {
483
    {"send", anextawaitable_send, METH_O, send_doc},
484
    {"throw", anextawaitable_throw, METH_VARARGS, throw_doc},
485
    {"close", anextawaitable_close, METH_NOARGS, close_doc},
486
    {NULL, NULL}        /* Sentinel */
487
};
488
489
490
static PyAsyncMethods anextawaitable_as_async = {
491
    PyObject_SelfIter,                          /* am_await */
492
    0,                                          /* am_aiter */
493
    0,                                          /* am_anext */
494
    0,                                          /* am_send  */
495
};
496
497
PyTypeObject _PyAnextAwaitable_Type = {
498
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
499
    "anext_awaitable",                          /* tp_name */
500
    sizeof(anextawaitableobject),               /* tp_basicsize */
501
    0,                                          /* tp_itemsize */
502
    /* methods */
503
    anextawaitable_dealloc,                     /* tp_dealloc */
504
    0,                                          /* tp_vectorcall_offset */
505
    0,                                          /* tp_getattr */
506
    0,                                          /* tp_setattr */
507
    &anextawaitable_as_async,                   /* tp_as_async */
508
    0,                                          /* tp_repr */
509
    0,                                          /* tp_as_number */
510
    0,                                          /* tp_as_sequence */
511
    0,                                          /* tp_as_mapping */
512
    0,                                          /* tp_hash */
513
    0,                                          /* tp_call */
514
    0,                                          /* tp_str */
515
    PyObject_GenericGetAttr,                    /* tp_getattro */
516
    0,                                          /* tp_setattro */
517
    0,                                          /* tp_as_buffer */
518
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
519
    0,                                          /* tp_doc */
520
    anextawaitable_traverse,                    /* tp_traverse */
521
    0,                                          /* tp_clear */
522
    0,                                          /* tp_richcompare */
523
    0,                                          /* tp_weaklistoffset */
524
    PyObject_SelfIter,                          /* tp_iter */
525
    anextawaitable_iternext,                    /* tp_iternext */
526
    anextawaitable_methods,                     /* tp_methods */
527
};
528
529
PyObject *
530
PyAnextAwaitable_New(PyObject *awaitable, PyObject *default_value)
531
0
{
532
0
    anextawaitableobject *anext = PyObject_GC_New(
533
0
            anextawaitableobject, &_PyAnextAwaitable_Type);
534
0
    if (anext == NULL) {
535
0
        return NULL;
536
0
    }
537
0
    anext->wrapped = Py_NewRef(awaitable);
538
0
    anext->default_value = Py_NewRef(default_value);
539
0
    _PyObject_GC_TRACK(anext);
540
0
    return (PyObject *)anext;
541
0
}