/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 | | |