Coverage Report

Created: 2025-07-11 06:59

/src/Python-3.8.3/Objects/iterobject.c
Line
Count
Source (jump to first uncovered line)
1
/* Iterator objects */
2
3
#include "Python.h"
4
#include "pycore_object.h"
5
#include "pycore_pymem.h"
6
#include "pycore_pystate.h"
7
8
typedef struct {
9
    PyObject_HEAD
10
    Py_ssize_t it_index;
11
    PyObject *it_seq; /* Set to NULL when iterator is exhausted */
12
} seqiterobject;
13
14
PyObject *
15
PySeqIter_New(PyObject *seq)
16
67
{
17
67
    seqiterobject *it;
18
19
67
    if (!PySequence_Check(seq)) {
20
0
        PyErr_BadInternalCall();
21
0
        return NULL;
22
0
    }
23
67
    it = PyObject_GC_New(seqiterobject, &PySeqIter_Type);
24
67
    if (it == NULL)
25
0
        return NULL;
26
67
    it->it_index = 0;
27
67
    Py_INCREF(seq);
28
67
    it->it_seq = seq;
29
67
    _PyObject_GC_TRACK(it);
30
67
    return (PyObject *)it;
31
67
}
32
33
static void
34
iter_dealloc(seqiterobject *it)
35
67
{
36
67
    _PyObject_GC_UNTRACK(it);
37
67
    Py_XDECREF(it->it_seq);
38
67
    PyObject_GC_Del(it);
39
67
}
40
41
static int
42
iter_traverse(seqiterobject *it, visitproc visit, void *arg)
43
0
{
44
0
    Py_VISIT(it->it_seq);
45
0
    return 0;
46
0
}
47
48
static PyObject *
49
iter_iternext(PyObject *iterator)
50
147
{
51
147
    seqiterobject *it;
52
147
    PyObject *seq;
53
147
    PyObject *result;
54
55
147
    assert(PySeqIter_Check(iterator));
56
147
    it = (seqiterobject *)iterator;
57
147
    seq = it->it_seq;
58
147
    if (seq == NULL)
59
0
        return NULL;
60
147
    if (it->it_index == PY_SSIZE_T_MAX) {
61
0
        PyErr_SetString(PyExc_OverflowError,
62
0
                        "iter index too large");
63
0
        return NULL;
64
0
    }
65
66
147
    result = PySequence_GetItem(seq, it->it_index);
67
147
    if (result != NULL) {
68
80
        it->it_index++;
69
80
        return result;
70
80
    }
71
67
    if (PyErr_ExceptionMatches(PyExc_IndexError) ||
72
67
        PyErr_ExceptionMatches(PyExc_StopIteration))
73
67
    {
74
67
        PyErr_Clear();
75
67
        it->it_seq = NULL;
76
67
        Py_DECREF(seq);
77
67
    }
78
67
    return NULL;
79
147
}
80
81
static PyObject *
82
iter_len(seqiterobject *it, PyObject *Py_UNUSED(ignored))
83
2
{
84
2
    Py_ssize_t seqsize, len;
85
86
2
    if (it->it_seq) {
87
2
        if (_PyObject_HasLen(it->it_seq)) {
88
2
            seqsize = PySequence_Size(it->it_seq);
89
2
            if (seqsize == -1)
90
0
                return NULL;
91
2
        }
92
0
        else {
93
0
            Py_RETURN_NOTIMPLEMENTED;
94
0
        }
95
2
        len = seqsize - it->it_index;
96
2
        if (len >= 0)
97
2
            return PyLong_FromSsize_t(len);
98
2
    }
99
0
    return PyLong_FromLong(0);
100
2
}
101
102
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
103
104
static PyObject *
105
iter_reduce(seqiterobject *it, PyObject *Py_UNUSED(ignored))
106
0
{
107
0
    _Py_IDENTIFIER(iter);
108
0
    if (it->it_seq != NULL)
109
0
        return Py_BuildValue("N(O)n", _PyEval_GetBuiltinId(&PyId_iter),
110
0
                             it->it_seq, it->it_index);
111
0
    else
112
0
        return Py_BuildValue("N(())", _PyEval_GetBuiltinId(&PyId_iter));
113
0
}
114
115
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
116
117
static PyObject *
118
iter_setstate(seqiterobject *it, PyObject *state)
119
0
{
120
0
    Py_ssize_t index = PyLong_AsSsize_t(state);
121
0
    if (index == -1 && PyErr_Occurred())
122
0
        return NULL;
123
0
    if (it->it_seq != NULL) {
124
0
        if (index < 0)
125
0
            index = 0;
126
0
        it->it_index = index;
127
0
    }
128
0
    Py_RETURN_NONE;
129
0
}
130
131
PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
132
133
static PyMethodDef seqiter_methods[] = {
134
    {"__length_hint__", (PyCFunction)iter_len, METH_NOARGS, length_hint_doc},
135
    {"__reduce__", (PyCFunction)iter_reduce, METH_NOARGS, reduce_doc},
136
    {"__setstate__", (PyCFunction)iter_setstate, METH_O, setstate_doc},
137
    {NULL,              NULL}           /* sentinel */
138
};
139
140
PyTypeObject PySeqIter_Type = {
141
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
142
    "iterator",                                 /* tp_name */
143
    sizeof(seqiterobject),                      /* tp_basicsize */
144
    0,                                          /* tp_itemsize */
145
    /* methods */
146
    (destructor)iter_dealloc,                   /* tp_dealloc */
147
    0,                                          /* tp_vectorcall_offset */
148
    0,                                          /* tp_getattr */
149
    0,                                          /* tp_setattr */
150
    0,                                          /* tp_as_async */
151
    0,                                          /* tp_repr */
152
    0,                                          /* tp_as_number */
153
    0,                                          /* tp_as_sequence */
154
    0,                                          /* tp_as_mapping */
155
    0,                                          /* tp_hash */
156
    0,                                          /* tp_call */
157
    0,                                          /* tp_str */
158
    PyObject_GenericGetAttr,                    /* tp_getattro */
159
    0,                                          /* tp_setattro */
160
    0,                                          /* tp_as_buffer */
161
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
162
    0,                                          /* tp_doc */
163
    (traverseproc)iter_traverse,                /* tp_traverse */
164
    0,                                          /* tp_clear */
165
    0,                                          /* tp_richcompare */
166
    0,                                          /* tp_weaklistoffset */
167
    PyObject_SelfIter,                          /* tp_iter */
168
    iter_iternext,                              /* tp_iternext */
169
    seqiter_methods,                            /* tp_methods */
170
    0,                                          /* tp_members */
171
};
172
173
/* -------------------------------------- */
174
175
typedef struct {
176
    PyObject_HEAD
177
    PyObject *it_callable; /* Set to NULL when iterator is exhausted */
178
    PyObject *it_sentinel; /* Set to NULL when iterator is exhausted */
179
} calliterobject;
180
181
PyObject *
182
PyCallIter_New(PyObject *callable, PyObject *sentinel)
183
0
{
184
0
    calliterobject *it;
185
0
    it = PyObject_GC_New(calliterobject, &PyCallIter_Type);
186
0
    if (it == NULL)
187
0
        return NULL;
188
0
    Py_INCREF(callable);
189
0
    it->it_callable = callable;
190
0
    Py_INCREF(sentinel);
191
0
    it->it_sentinel = sentinel;
192
0
    _PyObject_GC_TRACK(it);
193
0
    return (PyObject *)it;
194
0
}
195
static void
196
calliter_dealloc(calliterobject *it)
197
0
{
198
0
    _PyObject_GC_UNTRACK(it);
199
0
    Py_XDECREF(it->it_callable);
200
0
    Py_XDECREF(it->it_sentinel);
201
0
    PyObject_GC_Del(it);
202
0
}
203
204
static int
205
calliter_traverse(calliterobject *it, visitproc visit, void *arg)
206
0
{
207
0
    Py_VISIT(it->it_callable);
208
0
    Py_VISIT(it->it_sentinel);
209
0
    return 0;
210
0
}
211
212
static PyObject *
213
calliter_iternext(calliterobject *it)
214
0
{
215
0
    PyObject *result;
216
217
0
    if (it->it_callable == NULL) {
218
0
        return NULL;
219
0
    }
220
221
0
    result = _PyObject_CallNoArg(it->it_callable);
222
0
    if (result != NULL) {
223
0
        int ok;
224
225
0
        ok = PyObject_RichCompareBool(it->it_sentinel, result, Py_EQ);
226
0
        if (ok == 0) {
227
0
            return result; /* Common case, fast path */
228
0
        }
229
230
0
        Py_DECREF(result);
231
0
        if (ok > 0) {
232
0
            Py_CLEAR(it->it_callable);
233
0
            Py_CLEAR(it->it_sentinel);
234
0
        }
235
0
    }
236
0
    else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
237
0
        PyErr_Clear();
238
0
        Py_CLEAR(it->it_callable);
239
0
        Py_CLEAR(it->it_sentinel);
240
0
    }
241
0
    return NULL;
242
0
}
243
244
static PyObject *
245
calliter_reduce(calliterobject *it, PyObject *Py_UNUSED(ignored))
246
0
{
247
0
    _Py_IDENTIFIER(iter);
248
0
    if (it->it_callable != NULL && it->it_sentinel != NULL)
249
0
        return Py_BuildValue("N(OO)", _PyEval_GetBuiltinId(&PyId_iter),
250
0
                             it->it_callable, it->it_sentinel);
251
0
    else
252
0
        return Py_BuildValue("N(())", _PyEval_GetBuiltinId(&PyId_iter));
253
0
}
254
255
static PyMethodDef calliter_methods[] = {
256
    {"__reduce__", (PyCFunction)calliter_reduce, METH_NOARGS, reduce_doc},
257
    {NULL,              NULL}           /* sentinel */
258
};
259
260
PyTypeObject PyCallIter_Type = {
261
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
262
    "callable_iterator",                        /* tp_name */
263
    sizeof(calliterobject),                     /* tp_basicsize */
264
    0,                                          /* tp_itemsize */
265
    /* methods */
266
    (destructor)calliter_dealloc,               /* tp_dealloc */
267
    0,                                          /* tp_vectorcall_offset */
268
    0,                                          /* tp_getattr */
269
    0,                                          /* tp_setattr */
270
    0,                                          /* tp_as_async */
271
    0,                                          /* tp_repr */
272
    0,                                          /* tp_as_number */
273
    0,                                          /* tp_as_sequence */
274
    0,                                          /* tp_as_mapping */
275
    0,                                          /* tp_hash */
276
    0,                                          /* tp_call */
277
    0,                                          /* tp_str */
278
    PyObject_GenericGetAttr,                    /* tp_getattro */
279
    0,                                          /* tp_setattro */
280
    0,                                          /* tp_as_buffer */
281
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
282
    0,                                          /* tp_doc */
283
    (traverseproc)calliter_traverse,            /* tp_traverse */
284
    0,                                          /* tp_clear */
285
    0,                                          /* tp_richcompare */
286
    0,                                          /* tp_weaklistoffset */
287
    PyObject_SelfIter,                          /* tp_iter */
288
    (iternextfunc)calliter_iternext,            /* tp_iternext */
289
    calliter_methods,                           /* tp_methods */
290
};
291
292