• 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 
58     result = PySequence_GetItem(seq, it->it_index);
59     if (result != NULL) {
60         it->it_index++;
61         return result;
62     }
63     if (PyErr_ExceptionMatches(PyExc_IndexError) ||
64         PyErr_ExceptionMatches(PyExc_StopIteration))
65     {
66         PyErr_Clear();
67         Py_DECREF(seq);
68         it->it_seq = NULL;
69     }
70     return NULL;
71 }
72 
73 static PyObject *
iter_len(seqiterobject * it)74 iter_len(seqiterobject *it)
75 {
76     Py_ssize_t seqsize, len;
77 
78     if (it->it_seq) {
79         seqsize = PySequence_Size(it->it_seq);
80         if (seqsize == -1)
81             return NULL;
82         len = seqsize - it->it_index;
83         if (len >= 0)
84             return PyInt_FromSsize_t(len);
85     }
86     return PyInt_FromLong(0);
87 }
88 
89 PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
90 
91 static PyMethodDef seqiter_methods[] = {
92     {"__length_hint__", (PyCFunction)iter_len, METH_NOARGS, length_hint_doc},
93     {NULL,              NULL}           /* sentinel */
94 };
95 
96 PyTypeObject PySeqIter_Type = {
97     PyVarObject_HEAD_INIT(&PyType_Type, 0)
98     "iterator",                                 /* tp_name */
99     sizeof(seqiterobject),                      /* tp_basicsize */
100     0,                                          /* tp_itemsize */
101     /* methods */
102     (destructor)iter_dealloc,                   /* tp_dealloc */
103     0,                                          /* tp_print */
104     0,                                          /* tp_getattr */
105     0,                                          /* tp_setattr */
106     0,                                          /* tp_compare */
107     0,                                          /* tp_repr */
108     0,                                          /* tp_as_number */
109     0,                                          /* tp_as_sequence */
110     0,                                          /* tp_as_mapping */
111     0,                                          /* tp_hash */
112     0,                                          /* tp_call */
113     0,                                          /* tp_str */
114     PyObject_GenericGetAttr,                    /* tp_getattro */
115     0,                                          /* tp_setattro */
116     0,                                          /* tp_as_buffer */
117     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
118     0,                                          /* tp_doc */
119     (traverseproc)iter_traverse,                /* tp_traverse */
120     0,                                          /* tp_clear */
121     0,                                          /* tp_richcompare */
122     0,                                          /* tp_weaklistoffset */
123     PyObject_SelfIter,                          /* tp_iter */
124     iter_iternext,                              /* tp_iternext */
125     seqiter_methods,                            /* tp_methods */
126     0,                                          /* tp_members */
127 };
128 
129 /* -------------------------------------- */
130 
131 typedef struct {
132     PyObject_HEAD
133     PyObject *it_callable; /* Set to NULL when iterator is exhausted */
134     PyObject *it_sentinel; /* Set to NULL when iterator is exhausted */
135 } calliterobject;
136 
137 PyObject *
PyCallIter_New(PyObject * callable,PyObject * sentinel)138 PyCallIter_New(PyObject *callable, PyObject *sentinel)
139 {
140     calliterobject *it;
141     it = PyObject_GC_New(calliterobject, &PyCallIter_Type);
142     if (it == NULL)
143         return NULL;
144     Py_INCREF(callable);
145     it->it_callable = callable;
146     Py_INCREF(sentinel);
147     it->it_sentinel = sentinel;
148     _PyObject_GC_TRACK(it);
149     return (PyObject *)it;
150 }
151 static void
calliter_dealloc(calliterobject * it)152 calliter_dealloc(calliterobject *it)
153 {
154     _PyObject_GC_UNTRACK(it);
155     Py_XDECREF(it->it_callable);
156     Py_XDECREF(it->it_sentinel);
157     PyObject_GC_Del(it);
158 }
159 
160 static int
calliter_traverse(calliterobject * it,visitproc visit,void * arg)161 calliter_traverse(calliterobject *it, visitproc visit, void *arg)
162 {
163     Py_VISIT(it->it_callable);
164     Py_VISIT(it->it_sentinel);
165     return 0;
166 }
167 
168 static PyObject *
calliter_iternext(calliterobject * it)169 calliter_iternext(calliterobject *it)
170 {
171     if (it->it_callable != NULL) {
172         PyObject *args = PyTuple_New(0);
173         PyObject *result;
174         if (args == NULL)
175             return NULL;
176         result = PyObject_Call(it->it_callable, args, NULL);
177         Py_DECREF(args);
178         if (result != NULL) {
179             int ok;
180             ok = PyObject_RichCompareBool(result,
181                                           it->it_sentinel,
182                                           Py_EQ);
183             if (ok == 0)
184                 return result; /* Common case, fast path */
185             Py_DECREF(result);
186             if (ok > 0) {
187                 Py_CLEAR(it->it_callable);
188                 Py_CLEAR(it->it_sentinel);
189             }
190         }
191         else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
192             PyErr_Clear();
193             Py_CLEAR(it->it_callable);
194             Py_CLEAR(it->it_sentinel);
195         }
196     }
197     return NULL;
198 }
199 
200 PyTypeObject PyCallIter_Type = {
201     PyVarObject_HEAD_INIT(&PyType_Type, 0)
202     "callable-iterator",                        /* tp_name */
203     sizeof(calliterobject),                     /* tp_basicsize */
204     0,                                          /* tp_itemsize */
205     /* methods */
206     (destructor)calliter_dealloc,               /* tp_dealloc */
207     0,                                          /* tp_print */
208     0,                                          /* tp_getattr */
209     0,                                          /* tp_setattr */
210     0,                                          /* tp_compare */
211     0,                                          /* tp_repr */
212     0,                                          /* tp_as_number */
213     0,                                          /* tp_as_sequence */
214     0,                                          /* tp_as_mapping */
215     0,                                          /* tp_hash */
216     0,                                          /* tp_call */
217     0,                                          /* tp_str */
218     PyObject_GenericGetAttr,                    /* tp_getattro */
219     0,                                          /* tp_setattro */
220     0,                                          /* tp_as_buffer */
221     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
222     0,                                          /* tp_doc */
223     (traverseproc)calliter_traverse,            /* tp_traverse */
224     0,                                          /* tp_clear */
225     0,                                          /* tp_richcompare */
226     0,                                          /* tp_weaklistoffset */
227     PyObject_SelfIter,                          /* tp_iter */
228     (iternextfunc)calliter_iternext,            /* tp_iternext */
229     0,                                          /* tp_methods */
230 };
231