Line data Source code
1 : /* enumerate object */
2 :
3 : #include "Python.h"
4 :
5 : typedef struct {
6 : PyObject_HEAD
7 : Py_ssize_t en_index; /* current index of enumeration */
8 : PyObject* en_sit; /* secondary iterator of enumeration */
9 : PyObject* en_result; /* result tuple */
10 : PyObject* en_longindex; /* index for sequences >= PY_SSIZE_T_MAX */
11 : } enumobject;
12 :
13 : static PyObject *
14 1224 : enum_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
15 : {
16 : enumobject *en;
17 1224 : PyObject *seq = NULL;
18 1224 : PyObject *start = NULL;
19 : static char *kwlist[] = {"sequence", "start", 0};
20 :
21 1224 : if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:enumerate", kwlist,
22 : &seq, &start))
23 0 : return NULL;
24 :
25 1224 : en = (enumobject *)type->tp_alloc(type, 0);
26 1224 : if (en == NULL)
27 0 : return NULL;
28 1224 : if (start != NULL) {
29 9 : start = PyNumber_Index(start);
30 9 : if (start == NULL) {
31 0 : Py_DECREF(en);
32 0 : return NULL;
33 : }
34 : assert(PyInt_Check(start) || PyLong_Check(start));
35 9 : en->en_index = PyInt_AsSsize_t(start);
36 9 : if (en->en_index == -1 && PyErr_Occurred()) {
37 0 : PyErr_Clear();
38 0 : en->en_index = PY_SSIZE_T_MAX;
39 0 : en->en_longindex = start;
40 : } else {
41 9 : en->en_longindex = NULL;
42 9 : Py_DECREF(start);
43 : }
44 : } else {
45 1215 : en->en_index = 0;
46 1215 : en->en_longindex = NULL;
47 : }
48 1224 : en->en_sit = PyObject_GetIter(seq);
49 1224 : if (en->en_sit == NULL) {
50 0 : Py_DECREF(en);
51 0 : return NULL;
52 : }
53 1224 : en->en_result = PyTuple_Pack(2, Py_None, Py_None);
54 1224 : if (en->en_result == NULL) {
55 0 : Py_DECREF(en);
56 0 : return NULL;
57 : }
58 1224 : return (PyObject *)en;
59 : }
60 :
61 : static void
62 1224 : enum_dealloc(enumobject *en)
63 : {
64 1224 : PyObject_GC_UnTrack(en);
65 1224 : Py_XDECREF(en->en_sit);
66 1224 : Py_XDECREF(en->en_result);
67 1224 : Py_XDECREF(en->en_longindex);
68 1224 : Py_TYPE(en)->tp_free(en);
69 1224 : }
70 :
71 : static int
72 6 : enum_traverse(enumobject *en, visitproc visit, void *arg)
73 : {
74 6 : Py_VISIT(en->en_sit);
75 6 : Py_VISIT(en->en_result);
76 6 : Py_VISIT(en->en_longindex);
77 6 : return 0;
78 : }
79 :
80 : static PyObject *
81 0 : enum_next_long(enumobject *en, PyObject* next_item)
82 : {
83 : static PyObject *one = NULL;
84 0 : PyObject *result = en->en_result;
85 : PyObject *next_index;
86 : PyObject *stepped_up;
87 :
88 0 : if (en->en_longindex == NULL) {
89 0 : en->en_longindex = PyInt_FromSsize_t(PY_SSIZE_T_MAX);
90 0 : if (en->en_longindex == NULL)
91 0 : return NULL;
92 : }
93 0 : if (one == NULL) {
94 0 : one = PyInt_FromLong(1);
95 0 : if (one == NULL)
96 0 : return NULL;
97 : }
98 0 : next_index = en->en_longindex;
99 : assert(next_index != NULL);
100 0 : stepped_up = PyNumber_Add(next_index, one);
101 0 : if (stepped_up == NULL)
102 0 : return NULL;
103 0 : en->en_longindex = stepped_up;
104 :
105 0 : if (result->ob_refcnt == 1) {
106 0 : Py_INCREF(result);
107 0 : Py_DECREF(PyTuple_GET_ITEM(result, 0));
108 0 : Py_DECREF(PyTuple_GET_ITEM(result, 1));
109 : } else {
110 0 : result = PyTuple_New(2);
111 0 : if (result == NULL) {
112 0 : Py_DECREF(next_index);
113 0 : Py_DECREF(next_item);
114 0 : return NULL;
115 : }
116 : }
117 0 : PyTuple_SET_ITEM(result, 0, next_index);
118 0 : PyTuple_SET_ITEM(result, 1, next_item);
119 0 : return result;
120 : }
121 :
122 : static PyObject *
123 4482 : enum_next(enumobject *en)
124 : {
125 : PyObject *next_index;
126 : PyObject *next_item;
127 4482 : PyObject *result = en->en_result;
128 4482 : PyObject *it = en->en_sit;
129 :
130 4482 : next_item = (*Py_TYPE(it)->tp_iternext)(it);
131 4482 : if (next_item == NULL)
132 1224 : return NULL;
133 :
134 3258 : if (en->en_index == PY_SSIZE_T_MAX)
135 0 : return enum_next_long(en, next_item);
136 :
137 3258 : next_index = PyInt_FromSsize_t(en->en_index);
138 3258 : if (next_index == NULL) {
139 0 : Py_DECREF(next_item);
140 0 : return NULL;
141 : }
142 3258 : en->en_index++;
143 :
144 3258 : if (result->ob_refcnt == 1) {
145 3258 : Py_INCREF(result);
146 3258 : Py_DECREF(PyTuple_GET_ITEM(result, 0));
147 3258 : Py_DECREF(PyTuple_GET_ITEM(result, 1));
148 : } else {
149 0 : result = PyTuple_New(2);
150 0 : if (result == NULL) {
151 0 : Py_DECREF(next_index);
152 0 : Py_DECREF(next_item);
153 0 : return NULL;
154 : }
155 : }
156 3258 : PyTuple_SET_ITEM(result, 0, next_index);
157 3258 : PyTuple_SET_ITEM(result, 1, next_item);
158 3258 : return result;
159 : }
160 :
161 : PyDoc_STRVAR(enum_doc,
162 : "enumerate(iterable[, start]) -> iterator for index, value of iterable\n"
163 : "\n"
164 : "Return an enumerate object. iterable must be another object that supports\n"
165 : "iteration. The enumerate object yields pairs containing a count (from\n"
166 : "start, which defaults to zero) and a value yielded by the iterable argument.\n"
167 : "enumerate is useful for obtaining an indexed list:\n"
168 : " (0, seq[0]), (1, seq[1]), (2, seq[2]), ...");
169 :
170 : PyTypeObject PyEnum_Type = {
171 : PyVarObject_HEAD_INIT(&PyType_Type, 0)
172 : "enumerate", /* tp_name */
173 : sizeof(enumobject), /* tp_basicsize */
174 : 0, /* tp_itemsize */
175 : /* methods */
176 : (destructor)enum_dealloc, /* tp_dealloc */
177 : 0, /* tp_print */
178 : 0, /* tp_getattr */
179 : 0, /* tp_setattr */
180 : 0, /* tp_compare */
181 : 0, /* tp_repr */
182 : 0, /* tp_as_number */
183 : 0, /* tp_as_sequence */
184 : 0, /* tp_as_mapping */
185 : 0, /* tp_hash */
186 : 0, /* tp_call */
187 : 0, /* tp_str */
188 : PyObject_GenericGetAttr, /* tp_getattro */
189 : 0, /* tp_setattro */
190 : 0, /* tp_as_buffer */
191 : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
192 : Py_TPFLAGS_BASETYPE, /* tp_flags */
193 : enum_doc, /* tp_doc */
194 : (traverseproc)enum_traverse, /* tp_traverse */
195 : 0, /* tp_clear */
196 : 0, /* tp_richcompare */
197 : 0, /* tp_weaklistoffset */
198 : PyObject_SelfIter, /* tp_iter */
199 : (iternextfunc)enum_next, /* tp_iternext */
200 : 0, /* tp_methods */
201 : 0, /* tp_members */
202 : 0, /* tp_getset */
203 : 0, /* tp_base */
204 : 0, /* tp_dict */
205 : 0, /* tp_descr_get */
206 : 0, /* tp_descr_set */
207 : 0, /* tp_dictoffset */
208 : 0, /* tp_init */
209 : PyType_GenericAlloc, /* tp_alloc */
210 : enum_new, /* tp_new */
211 : PyObject_GC_Del, /* tp_free */
212 : };
213 :
214 : /* Reversed Object ***************************************************************/
215 :
216 : typedef struct {
217 : PyObject_HEAD
218 : Py_ssize_t index;
219 : PyObject* seq;
220 : } reversedobject;
221 :
222 : static PyObject *
223 3 : reversed_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
224 : {
225 : Py_ssize_t n;
226 : PyObject *seq, *reversed_meth;
227 : static PyObject *reversed_cache = NULL;
228 : reversedobject *ro;
229 :
230 3 : if (type == &PyReversed_Type && !_PyArg_NoKeywords("reversed()", kwds))
231 0 : return NULL;
232 :
233 3 : if (!PyArg_UnpackTuple(args, "reversed", 1, 1, &seq) )
234 0 : return NULL;
235 :
236 3 : if (PyInstance_Check(seq)) {
237 0 : reversed_meth = PyObject_GetAttrString(seq, "__reversed__");
238 0 : if (reversed_meth == NULL) {
239 0 : if (PyErr_ExceptionMatches(PyExc_AttributeError))
240 0 : PyErr_Clear();
241 : else
242 0 : return NULL;
243 : }
244 : }
245 : else {
246 3 : reversed_meth = _PyObject_LookupSpecial(seq, "__reversed__",
247 : &reversed_cache);
248 3 : if (reversed_meth == NULL && PyErr_Occurred())
249 0 : return NULL;
250 : }
251 3 : if (reversed_meth != NULL) {
252 3 : PyObject *res = PyObject_CallFunctionObjArgs(reversed_meth, NULL);
253 3 : Py_DECREF(reversed_meth);
254 3 : return res;
255 : }
256 :
257 0 : if (!PySequence_Check(seq)) {
258 0 : PyErr_SetString(PyExc_TypeError,
259 : "argument to reversed() must be a sequence");
260 0 : return NULL;
261 : }
262 :
263 0 : n = PySequence_Size(seq);
264 0 : if (n == -1)
265 0 : return NULL;
266 :
267 0 : ro = (reversedobject *)type->tp_alloc(type, 0);
268 0 : if (ro == NULL)
269 0 : return NULL;
270 :
271 0 : ro->index = n-1;
272 0 : Py_INCREF(seq);
273 0 : ro->seq = seq;
274 0 : return (PyObject *)ro;
275 : }
276 :
277 : static void
278 0 : reversed_dealloc(reversedobject *ro)
279 : {
280 0 : PyObject_GC_UnTrack(ro);
281 0 : Py_XDECREF(ro->seq);
282 0 : Py_TYPE(ro)->tp_free(ro);
283 0 : }
284 :
285 : static int
286 0 : reversed_traverse(reversedobject *ro, visitproc visit, void *arg)
287 : {
288 0 : Py_VISIT(ro->seq);
289 0 : return 0;
290 : }
291 :
292 : static PyObject *
293 0 : reversed_next(reversedobject *ro)
294 : {
295 : PyObject *item;
296 0 : Py_ssize_t index = ro->index;
297 :
298 0 : if (index >= 0) {
299 0 : item = PySequence_GetItem(ro->seq, index);
300 0 : if (item != NULL) {
301 0 : ro->index--;
302 0 : return item;
303 : }
304 0 : if (PyErr_ExceptionMatches(PyExc_IndexError) ||
305 0 : PyErr_ExceptionMatches(PyExc_StopIteration))
306 0 : PyErr_Clear();
307 : }
308 0 : ro->index = -1;
309 0 : Py_CLEAR(ro->seq);
310 0 : return NULL;
311 : }
312 :
313 : PyDoc_STRVAR(reversed_doc,
314 : "reversed(sequence) -> reverse iterator over values of the sequence\n"
315 : "\n"
316 : "Return a reverse iterator");
317 :
318 : static PyObject *
319 0 : reversed_len(reversedobject *ro)
320 : {
321 : Py_ssize_t position, seqsize;
322 :
323 0 : if (ro->seq == NULL)
324 0 : return PyInt_FromLong(0);
325 0 : seqsize = PySequence_Size(ro->seq);
326 0 : if (seqsize == -1)
327 0 : return NULL;
328 0 : position = ro->index + 1;
329 0 : return PyInt_FromSsize_t((seqsize < position) ? 0 : position);
330 : }
331 :
332 : PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
333 :
334 : static PyMethodDef reversediter_methods[] = {
335 : {"__length_hint__", (PyCFunction)reversed_len, METH_NOARGS, length_hint_doc},
336 : {NULL, NULL} /* sentinel */
337 : };
338 :
339 : PyTypeObject PyReversed_Type = {
340 : PyVarObject_HEAD_INIT(&PyType_Type, 0)
341 : "reversed", /* tp_name */
342 : sizeof(reversedobject), /* tp_basicsize */
343 : 0, /* tp_itemsize */
344 : /* methods */
345 : (destructor)reversed_dealloc, /* tp_dealloc */
346 : 0, /* tp_print */
347 : 0, /* tp_getattr */
348 : 0, /* tp_setattr */
349 : 0, /* tp_compare */
350 : 0, /* tp_repr */
351 : 0, /* tp_as_number */
352 : 0, /* tp_as_sequence */
353 : 0, /* tp_as_mapping */
354 : 0, /* tp_hash */
355 : 0, /* tp_call */
356 : 0, /* tp_str */
357 : PyObject_GenericGetAttr, /* tp_getattro */
358 : 0, /* tp_setattro */
359 : 0, /* tp_as_buffer */
360 : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
361 : Py_TPFLAGS_BASETYPE, /* tp_flags */
362 : reversed_doc, /* tp_doc */
363 : (traverseproc)reversed_traverse,/* tp_traverse */
364 : 0, /* tp_clear */
365 : 0, /* tp_richcompare */
366 : 0, /* tp_weaklistoffset */
367 : PyObject_SelfIter, /* tp_iter */
368 : (iternextfunc)reversed_next, /* tp_iternext */
369 : reversediter_methods, /* tp_methods */
370 : 0, /* tp_members */
371 : 0, /* tp_getset */
372 : 0, /* tp_base */
373 : 0, /* tp_dict */
374 : 0, /* tp_descr_get */
375 : 0, /* tp_descr_set */
376 : 0, /* tp_dictoffset */
377 : 0, /* tp_init */
378 : PyType_GenericAlloc, /* tp_alloc */
379 : reversed_new, /* tp_new */
380 : PyObject_GC_Del, /* tp_free */
381 : };
|