blob: de9f2f9e5d9f0074f6e49127175beb4a09a19c8e [file] [log] [blame]
Guido van Rossum05311482001-04-20 21:06:46 +00001/* Iterator objects */
2
3#include "Python.h"
4
5typedef struct {
6 PyObject_HEAD
7 long it_index;
8 PyObject *it_seq;
Guido van Rossum213c7a62001-04-23 14:08:49 +00009} seqiterobject;
Guido van Rossum05311482001-04-20 21:06:46 +000010
11PyObject *
Guido van Rossum213c7a62001-04-23 14:08:49 +000012PySeqIter_New(PyObject *seq)
Guido van Rossum05311482001-04-20 21:06:46 +000013{
Guido van Rossum213c7a62001-04-23 14:08:49 +000014 seqiterobject *it;
Martin v. Löwis01f94bd2002-05-08 08:44:21 +000015
16 if (!PySequence_Check(seq)) {
17 PyErr_BadInternalCall();
18 return NULL;
19 }
Neil Schemenauerdbf409f2002-03-18 20:43:51 +000020 it = PyObject_GC_New(seqiterobject, &PySeqIter_Type);
Guido van Rossum05311482001-04-20 21:06:46 +000021 if (it == NULL)
22 return NULL;
23 it->it_index = 0;
24 Py_INCREF(seq);
25 it->it_seq = seq;
Neil Schemenauerdbf409f2002-03-18 20:43:51 +000026 _PyObject_GC_TRACK(it);
Guido van Rossum05311482001-04-20 21:06:46 +000027 return (PyObject *)it;
28}
29static void
Guido van Rossum213c7a62001-04-23 14:08:49 +000030iter_dealloc(seqiterobject *it)
Guido van Rossum05311482001-04-20 21:06:46 +000031{
Neil Schemenauerdbf409f2002-03-18 20:43:51 +000032 _PyObject_GC_UNTRACK(it);
Guido van Rossum05311482001-04-20 21:06:46 +000033 Py_DECREF(it->it_seq);
Neil Schemenauerdbf409f2002-03-18 20:43:51 +000034 PyObject_GC_Del(it);
Guido van Rossum05311482001-04-20 21:06:46 +000035}
36
Neil Schemenauer7eac9b72001-07-12 13:27:25 +000037static int
38iter_traverse(seqiterobject *it, visitproc visit, void *arg)
39{
40 return visit(it->it_seq, arg);
41}
42
Guido van Rossum05311482001-04-20 21:06:46 +000043static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +000044iter_next(seqiterobject *it)
Guido van Rossum05311482001-04-20 21:06:46 +000045{
46 PyObject *seq = it->it_seq;
Guido van Rossum213c7a62001-04-23 14:08:49 +000047 PyObject *result = PySequence_GetItem(seq, it->it_index++);
Guido van Rossum05311482001-04-20 21:06:46 +000048
Guido van Rossum213c7a62001-04-23 14:08:49 +000049 if (result == NULL && PyErr_ExceptionMatches(PyExc_IndexError))
50 PyErr_SetObject(PyExc_StopIteration, Py_None);
51 return result;
Guido van Rossum05311482001-04-20 21:06:46 +000052}
53
54static PyObject *
55iter_getiter(PyObject *it)
56{
57 Py_INCREF(it);
58 return it;
59}
60
Guido van Rossum213c7a62001-04-23 14:08:49 +000061static PyObject *
62iter_iternext(PyObject *iterator)
63{
64 seqiterobject *it;
65 PyObject *seq;
66
67 assert(PySeqIter_Check(iterator));
68 it = (seqiterobject *)iterator;
69 seq = it->it_seq;
70
Martin v. Löwis01f94bd2002-05-08 08:44:21 +000071 if (PyList_CheckExact(seq)) {
Guido van Rossum213c7a62001-04-23 14:08:49 +000072 PyObject *item;
73 if (it->it_index >= PyList_GET_SIZE(seq)) {
74 return NULL;
75 }
76 item = PyList_GET_ITEM(seq, it->it_index);
77 it->it_index++;
78 Py_INCREF(item);
79 return item;
80 }
Martin v. Löwis01f94bd2002-05-08 08:44:21 +000081 if (PyTuple_CheckExact(seq)) {
82 PyObject *item;
83 if (it->it_index >= PyTuple_GET_SIZE(seq)) {
84 return NULL;
85 }
86 item = PyTuple_GET_ITEM(seq, it->it_index);
87 it->it_index++;
88 Py_INCREF(item);
89 return item;
90 }
Guido van Rossum213c7a62001-04-23 14:08:49 +000091 else {
Martin v. Löwis01f94bd2002-05-08 08:44:21 +000092 PyObject *result = PySequence_ITEM(seq, it->it_index);
93 it->it_index++;
Guido van Rossum213c7a62001-04-23 14:08:49 +000094 if (result != NULL) {
95 return result;
96 }
97 if (PyErr_ExceptionMatches(PyExc_IndexError) ||
98 PyErr_ExceptionMatches(PyExc_StopIteration)) {
99 PyErr_Clear();
100 return NULL;
101 }
102 else {
103 return NULL;
104 }
105 }
106}
107
Guido van Rossum05311482001-04-20 21:06:46 +0000108static PyMethodDef iter_methods[] = {
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000109 {"next", (PyCFunction)iter_next, METH_NOARGS,
Guido van Rossum05311482001-04-20 21:06:46 +0000110 "it.next() -- get the next value, or raise StopIteration"},
111 {NULL, NULL} /* sentinel */
112};
113
Guido van Rossum213c7a62001-04-23 14:08:49 +0000114PyTypeObject PySeqIter_Type = {
Guido van Rossum05311482001-04-20 21:06:46 +0000115 PyObject_HEAD_INIT(&PyType_Type)
116 0, /* ob_size */
117 "iterator", /* tp_name */
Neil Schemenauerdbf409f2002-03-18 20:43:51 +0000118 sizeof(seqiterobject), /* tp_basicsize */
Guido van Rossum05311482001-04-20 21:06:46 +0000119 0, /* tp_itemsize */
120 /* methods */
121 (destructor)iter_dealloc, /* tp_dealloc */
122 0, /* tp_print */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000123 0, /* tp_getattr */
Guido van Rossum05311482001-04-20 21:06:46 +0000124 0, /* tp_setattr */
125 0, /* tp_compare */
126 0, /* tp_repr */
127 0, /* tp_as_number */
128 0, /* tp_as_sequence */
129 0, /* tp_as_mapping */
130 0, /* tp_hash */
131 0, /* tp_call */
132 0, /* tp_str */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000133 PyObject_GenericGetAttr, /* tp_getattro */
Guido van Rossum05311482001-04-20 21:06:46 +0000134 0, /* tp_setattro */
135 0, /* tp_as_buffer */
Neil Schemenauerdbf409f2002-03-18 20:43:51 +0000136 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
Guido van Rossum05311482001-04-20 21:06:46 +0000137 0, /* tp_doc */
Neil Schemenauer7eac9b72001-07-12 13:27:25 +0000138 (traverseproc)iter_traverse, /* tp_traverse */
Guido van Rossum05311482001-04-20 21:06:46 +0000139 0, /* tp_clear */
140 0, /* tp_richcompare */
141 0, /* tp_weaklistoffset */
142 (getiterfunc)iter_getiter, /* tp_iter */
Guido van Rossum213c7a62001-04-23 14:08:49 +0000143 (iternextfunc)iter_iternext, /* tp_iternext */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000144 iter_methods, /* tp_methods */
145 0, /* tp_members */
146 0, /* tp_getset */
147 0, /* tp_base */
148 0, /* tp_dict */
149 0, /* tp_descr_get */
150 0, /* tp_descr_set */
Guido van Rossum05311482001-04-20 21:06:46 +0000151};
152
153/* -------------------------------------- */
154
155typedef struct {
156 PyObject_HEAD
157 PyObject *it_callable;
158 PyObject *it_sentinel;
159} calliterobject;
160
161PyObject *
162PyCallIter_New(PyObject *callable, PyObject *sentinel)
163{
164 calliterobject *it;
Neil Schemenauerdbf409f2002-03-18 20:43:51 +0000165 it = PyObject_GC_New(calliterobject, &PyCallIter_Type);
Guido van Rossum05311482001-04-20 21:06:46 +0000166 if (it == NULL)
167 return NULL;
168 Py_INCREF(callable);
169 it->it_callable = callable;
170 Py_INCREF(sentinel);
171 it->it_sentinel = sentinel;
Neil Schemenauerdbf409f2002-03-18 20:43:51 +0000172 _PyObject_GC_TRACK(it);
Guido van Rossum05311482001-04-20 21:06:46 +0000173 return (PyObject *)it;
174}
175static void
176calliter_dealloc(calliterobject *it)
177{
Neil Schemenauerdbf409f2002-03-18 20:43:51 +0000178 _PyObject_GC_UNTRACK(it);
Guido van Rossum05311482001-04-20 21:06:46 +0000179 Py_DECREF(it->it_callable);
180 Py_DECREF(it->it_sentinel);
Neil Schemenauerdbf409f2002-03-18 20:43:51 +0000181 PyObject_GC_Del(it);
Guido van Rossum05311482001-04-20 21:06:46 +0000182}
Guido van Rossum213c7a62001-04-23 14:08:49 +0000183
Neil Schemenauer7eac9b72001-07-12 13:27:25 +0000184static int
185calliter_traverse(calliterobject *it, visitproc visit, void *arg)
186{
187 int err;
188 if ((err = visit(it->it_callable, arg)))
189 return err;
190 if ((err = visit(it->it_sentinel, arg)))
191 return err;
192 return 0;
193}
194
Guido van Rossum05311482001-04-20 21:06:46 +0000195static PyObject *
196calliter_next(calliterobject *it, PyObject *args)
197{
198 PyObject *result = PyObject_CallObject(it->it_callable, NULL);
199 if (result != NULL) {
200 if (PyObject_RichCompareBool(result, it->it_sentinel, Py_EQ)) {
201 PyErr_SetObject(PyExc_StopIteration, Py_None);
202 Py_DECREF(result);
203 result = NULL;
204 }
205 }
206 return result;
207}
208
209static PyMethodDef calliter_methods[] = {
210 {"next", (PyCFunction)calliter_next, METH_VARARGS,
211 "it.next() -- get the next value, or raise StopIteration"},
212 {NULL, NULL} /* sentinel */
213};
214
215static PyObject *
Guido van Rossum213c7a62001-04-23 14:08:49 +0000216calliter_iternext(calliterobject *it)
217{
218 PyObject *result = PyObject_CallObject(it->it_callable, NULL);
219 if (result != NULL) {
220 if (PyObject_RichCompareBool(result, it->it_sentinel, Py_EQ)) {
221 Py_DECREF(result);
222 result = NULL;
223 }
224 }
225 else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
226 PyErr_Clear();
227 }
228 return result;
229}
230
Guido van Rossum05311482001-04-20 21:06:46 +0000231PyTypeObject PyCallIter_Type = {
232 PyObject_HEAD_INIT(&PyType_Type)
233 0, /* ob_size */
234 "callable-iterator", /* tp_name */
Neil Schemenauerdbf409f2002-03-18 20:43:51 +0000235 sizeof(calliterobject), /* tp_basicsize */
Guido van Rossum05311482001-04-20 21:06:46 +0000236 0, /* tp_itemsize */
237 /* methods */
238 (destructor)calliter_dealloc, /* tp_dealloc */
239 0, /* tp_print */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000240 0, /* tp_getattr */
Guido van Rossum05311482001-04-20 21:06:46 +0000241 0, /* tp_setattr */
242 0, /* tp_compare */
243 0, /* tp_repr */
244 0, /* tp_as_number */
245 0, /* tp_as_sequence */
246 0, /* tp_as_mapping */
247 0, /* tp_hash */
248 0, /* tp_call */
249 0, /* tp_str */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000250 PyObject_GenericGetAttr, /* tp_getattro */
Guido van Rossum05311482001-04-20 21:06:46 +0000251 0, /* tp_setattro */
252 0, /* tp_as_buffer */
Neil Schemenauerdbf409f2002-03-18 20:43:51 +0000253 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
Guido van Rossum05311482001-04-20 21:06:46 +0000254 0, /* tp_doc */
Neil Schemenauer7eac9b72001-07-12 13:27:25 +0000255 (traverseproc)calliter_traverse, /* tp_traverse */
Guido van Rossum05311482001-04-20 21:06:46 +0000256 0, /* tp_clear */
257 0, /* tp_richcompare */
258 0, /* tp_weaklistoffset */
259 (getiterfunc)iter_getiter, /* tp_iter */
Guido van Rossum213c7a62001-04-23 14:08:49 +0000260 (iternextfunc)calliter_iternext, /* tp_iternext */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000261 calliter_methods, /* tp_methods */
262 0, /* tp_members */
263 0, /* tp_getset */
264 0, /* tp_base */
265 0, /* tp_dict */
266 0, /* tp_descr_get */
267 0, /* tp_descr_set */
Guido van Rossum05311482001-04-20 21:06:46 +0000268};