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