• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Iterator objects */
2 
3 #include "Python.h"
4 
5 typedef struct {
6     PyObject_HEAD
7     long      it_index;
8     PyObject *it_seq; /* Set to NULL when iterator is exhausted */
9 } seqiterobject;
10 
11 PyObject *
PySeqIter_New(PyObject * seq)12 PySeqIter_New(PyObject *seq)
13 {
14     seqiterobject *it;
15 
16     if (!PySequence_Check(seq)) {
17         PyErr_BadInternalCall();
18         return NULL;
19     }
20     it = PyObject_GC_New(seqiterobject, &PySeqIter_Type);
21     if (it == NULL)
22         return NULL;
23     it->it_index = 0;
24     Py_INCREF(seq);
25     it->it_seq = seq;
26     _PyObject_GC_TRACK(it);
27     return (PyObject *)it;
28 }
29 
30 static void
iter_dealloc(seqiterobject * it)31 iter_dealloc(seqiterobject *it)
32 {
33     _PyObject_GC_UNTRACK(it);
34     Py_XDECREF(it->it_seq);
35     PyObject_GC_Del(it);
36 }
37 
38 static int
iter_traverse(seqiterobject * it,visitproc visit,void * arg)39 iter_traverse(seqiterobject *it, visitproc visit, void *arg)
40 {
41     Py_VISIT(it->it_seq);
42     return 0;
43 }
44 
45 static PyObject *
iter_iternext(PyObject * iterator)46 iter_iternext(PyObject *iterator)
47 {
48     seqiterobject *it;
49     PyObject *seq;
50     PyObject *result;
51 
52     assert(PySeqIter_Check(iterator));
53     it = (seqiterobject *)iterator;
54     seq = it->it_seq;
55     if (seq == NULL)
56         return NULL;
57     if (it->it_index == LONG_MAX) {
58         PyErr_SetString(PyExc_OverflowError,
59                         "iter index too large");
60         return NULL;
61     }
62 
63     result = PySequence_GetItem(seq, it->it_index);
64     if (result != NULL) {
65         it->it_index++;
66         return result;
67     }
68     if (PyErr_ExceptionMatches(PyExc_IndexError) ||
69         PyErr_ExceptionMatches(PyExc_StopIteration))
70     {
71         PyErr_Clear();
72         it->it_seq = NULL;
73         Py_DECREF(seq);
74     }
75     return NULL;
76 }
77 
78 static PyObject *
iter_len(seqiterobject * it)79 iter_len(seqiterobject *it)
80 {
81     Py_ssize_t seqsize, len;
82 
83     if (it->it_seq) {
84         seqsize = PySequence_Size(it->it_seq);
85         if (seqsize == -1)
86             return NULL;
87         len = seqsize - it->it_index;
88         if (len >= 0)
89             return PyInt_FromSsize_t(len);
90     }
91     return PyInt_FromLong(0);
92 }
93 
94 PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
95 
96 static PyMethodDef seqiter_methods[] = {
97     {"__length_hint__", (PyCFunction)iter_len, METH_NOARGS, length_hint_doc},
98     {NULL,              NULL}           /* sentinel */
99 };
100 
101 PyTypeObject PySeqIter_Type = {
102     PyVarObject_HEAD_INIT(&PyType_Type, 0)
103     "iterator",                                 /* tp_name */
104     sizeof(seqiterobject),                      /* tp_basicsize */
105     0,                                          /* tp_itemsize */
106     /* methods */
107     (destructor)iter_dealloc,                   /* tp_dealloc */
108     0,                                          /* tp_print */
109     0,                                          /* tp_getattr */
110     0,                                          /* tp_setattr */
111     0,                                          /* tp_compare */
112     0,                                          /* tp_repr */
113     0,                                          /* tp_as_number */
114     0,                                          /* tp_as_sequence */
115     0,                                          /* tp_as_mapping */
116     0,                                          /* tp_hash */
117     0,                                          /* tp_call */
118     0,                                          /* tp_str */
119     PyObject_GenericGetAttr,                    /* tp_getattro */
120     0,                                          /* tp_setattro */
121     0,                                          /* tp_as_buffer */
122     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
123     0,                                          /* tp_doc */
124     (traverseproc)iter_traverse,                /* tp_traverse */
125     0,                                          /* tp_clear */
126     0,                                          /* tp_richcompare */
127     0,                                          /* tp_weaklistoffset */
128     PyObject_SelfIter,                          /* tp_iter */
129     iter_iternext,                              /* tp_iternext */
130     seqiter_methods,                            /* tp_methods */
131     0,                                          /* tp_members */
132 };
133 
134 /* -------------------------------------- */
135 
136 typedef struct {
137     PyObject_HEAD
138     PyObject *it_callable; /* Set to NULL when iterator is exhausted */
139     PyObject *it_sentinel; /* Set to NULL when iterator is exhausted */
140 } calliterobject;
141 
142 PyObject *
PyCallIter_New(PyObject * callable,PyObject * sentinel)143 PyCallIter_New(PyObject *callable, PyObject *sentinel)
144 {
145     calliterobject *it;
146     it = PyObject_GC_New(calliterobject, &PyCallIter_Type);
147     if (it == NULL)
148         return NULL;
149     Py_INCREF(callable);
150     it->it_callable = callable;
151     Py_INCREF(sentinel);
152     it->it_sentinel = sentinel;
153     _PyObject_GC_TRACK(it);
154     return (PyObject *)it;
155 }
156 static void
calliter_dealloc(calliterobject * it)157 calliter_dealloc(calliterobject *it)
158 {
159     _PyObject_GC_UNTRACK(it);
160     Py_XDECREF(it->it_callable);
161     Py_XDECREF(it->it_sentinel);
162     PyObject_GC_Del(it);
163 }
164 
165 static int
calliter_traverse(calliterobject * it,visitproc visit,void * arg)166 calliter_traverse(calliterobject *it, visitproc visit, void *arg)
167 {
168     Py_VISIT(it->it_callable);
169     Py_VISIT(it->it_sentinel);
170     return 0;
171 }
172 
173 static PyObject *
calliter_iternext(calliterobject * it)174 calliter_iternext(calliterobject *it)
175 {
176     if (it->it_callable != NULL) {
177         PyObject *args = PyTuple_New(0);
178         PyObject *result;
179         if (args == NULL)
180             return NULL;
181         result = PyObject_Call(it->it_callable, args, NULL);
182         Py_DECREF(args);
183         if (result != NULL) {
184             int ok;
185             ok = PyObject_RichCompareBool(result,
186                                           it->it_sentinel,
187                                           Py_EQ);
188             if (ok == 0)
189                 return result; /* Common case, fast path */
190             Py_DECREF(result);
191             if (ok > 0) {
192                 Py_CLEAR(it->it_callable);
193                 Py_CLEAR(it->it_sentinel);
194             }
195         }
196         else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
197             PyErr_Clear();
198             Py_CLEAR(it->it_callable);
199             Py_CLEAR(it->it_sentinel);
200         }
201     }
202     return NULL;
203 }
204 
205 PyTypeObject PyCallIter_Type = {
206     PyVarObject_HEAD_INIT(&PyType_Type, 0)
207     "callable-iterator",                        /* tp_name */
208     sizeof(calliterobject),                     /* tp_basicsize */
209     0,                                          /* tp_itemsize */
210     /* methods */
211     (destructor)calliter_dealloc,               /* tp_dealloc */
212     0,                                          /* tp_print */
213     0,                                          /* tp_getattr */
214     0,                                          /* tp_setattr */
215     0,                                          /* tp_compare */
216     0,                                          /* tp_repr */
217     0,                                          /* tp_as_number */
218     0,                                          /* tp_as_sequence */
219     0,                                          /* tp_as_mapping */
220     0,                                          /* tp_hash */
221     0,                                          /* tp_call */
222     0,                                          /* tp_str */
223     PyObject_GenericGetAttr,                    /* tp_getattro */
224     0,                                          /* tp_setattro */
225     0,                                          /* tp_as_buffer */
226     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
227     0,                                          /* tp_doc */
228     (traverseproc)calliter_traverse,            /* tp_traverse */
229     0,                                          /* tp_clear */
230     0,                                          /* tp_richcompare */
231     0,                                          /* tp_weaklistoffset */
232     PyObject_SelfIter,                          /* tp_iter */
233     (iternextfunc)calliter_iternext,            /* tp_iternext */
234     0,                                          /* tp_methods */
235 };
236