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 2 : enum_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
15 : {
16 : enumobject *en;
17 2 : PyObject *seq = NULL;
18 2 : PyObject *start = NULL;
19 : static char *kwlist[] = {"iterable", "start", 0};
20 :
21 2 : if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:enumerate", kwlist,
22 : &seq, &start))
23 0 : return NULL;
24 :
25 2 : en = (enumobject *)type->tp_alloc(type, 0);
26 2 : if (en == NULL)
27 0 : return NULL;
28 2 : if (start != NULL) {
29 0 : start = PyNumber_Index(start);
30 0 : if (start == NULL) {
31 0 : Py_DECREF(en);
32 0 : return NULL;
33 : }
34 : assert(PyLong_Check(start));
35 0 : en->en_index = PyLong_AsSsize_t(start);
36 0 : 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 0 : en->en_longindex = NULL;
42 0 : Py_DECREF(start);
43 : }
44 : } else {
45 2 : en->en_index = 0;
46 2 : en->en_longindex = NULL;
47 : }
48 2 : en->en_sit = PyObject_GetIter(seq);
49 2 : if (en->en_sit == NULL) {
50 0 : Py_DECREF(en);
51 0 : return NULL;
52 : }
53 2 : en->en_result = PyTuple_Pack(2, Py_None, Py_None);
54 2 : if (en->en_result == NULL) {
55 0 : Py_DECREF(en);
56 0 : return NULL;
57 : }
58 2 : return (PyObject *)en;
59 : }
60 :
61 : static void
62 2 : enum_dealloc(enumobject *en)
63 : {
64 2 : PyObject_GC_UnTrack(en);
65 2 : Py_XDECREF(en->en_sit);
66 2 : Py_XDECREF(en->en_result);
67 2 : Py_XDECREF(en->en_longindex);
68 2 : Py_TYPE(en)->tp_free(en);
69 2 : }
70 :
71 : static int
72 0 : enum_traverse(enumobject *en, visitproc visit, void *arg)
73 : {
74 0 : Py_VISIT(en->en_sit);
75 0 : Py_VISIT(en->en_result);
76 0 : Py_VISIT(en->en_longindex);
77 0 : 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 = PyLong_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 = PyLong_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 11 : enum_next(enumobject *en)
124 : {
125 : PyObject *next_index;
126 : PyObject *next_item;
127 11 : PyObject *result = en->en_result;
128 11 : PyObject *it = en->en_sit;
129 :
130 11 : next_item = (*Py_TYPE(it)->tp_iternext)(it);
131 11 : if (next_item == NULL)
132 2 : return NULL;
133 :
134 9 : if (en->en_index == PY_SSIZE_T_MAX)
135 0 : return enum_next_long(en, next_item);
136 :
137 9 : next_index = PyLong_FromSsize_t(en->en_index);
138 9 : if (next_index == NULL) {
139 0 : Py_DECREF(next_item);
140 0 : return NULL;
141 : }
142 9 : en->en_index++;
143 :
144 9 : if (result->ob_refcnt == 1) {
145 9 : Py_INCREF(result);
146 9 : Py_DECREF(PyTuple_GET_ITEM(result, 0));
147 9 : 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 9 : PyTuple_SET_ITEM(result, 0, next_index);
157 9 : PyTuple_SET_ITEM(result, 1, next_item);
158 9 : return result;
159 : }
160 :
161 : static PyObject *
162 0 : enum_reduce(enumobject *en)
163 : {
164 0 : if (en->en_longindex != NULL)
165 0 : return Py_BuildValue("O(OO)", Py_TYPE(en), en->en_sit, en->en_longindex);
166 : else
167 0 : return Py_BuildValue("O(On)", Py_TYPE(en), en->en_sit, en->en_index);
168 : }
169 :
170 : PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
171 :
172 : static PyMethodDef enum_methods[] = {
173 : {"__reduce__", (PyCFunction)enum_reduce, METH_NOARGS, reduce_doc},
174 : {NULL, NULL} /* sentinel */
175 : };
176 :
177 : PyDoc_STRVAR(enum_doc,
178 : "enumerate(iterable[, start]) -> iterator for index, value of iterable\n"
179 : "\n"
180 : "Return an enumerate object. iterable must be another object that supports\n"
181 : "iteration. The enumerate object yields pairs containing a count (from\n"
182 : "start, which defaults to zero) and a value yielded by the iterable argument.\n"
183 : "enumerate is useful for obtaining an indexed list:\n"
184 : " (0, seq[0]), (1, seq[1]), (2, seq[2]), ...");
185 :
186 : PyTypeObject PyEnum_Type = {
187 : PyVarObject_HEAD_INIT(&PyType_Type, 0)
188 : "enumerate", /* tp_name */
189 : sizeof(enumobject), /* tp_basicsize */
190 : 0, /* tp_itemsize */
191 : /* methods */
192 : (destructor)enum_dealloc, /* tp_dealloc */
193 : 0, /* tp_print */
194 : 0, /* tp_getattr */
195 : 0, /* tp_setattr */
196 : 0, /* tp_reserved */
197 : 0, /* tp_repr */
198 : 0, /* tp_as_number */
199 : 0, /* tp_as_sequence */
200 : 0, /* tp_as_mapping */
201 : 0, /* tp_hash */
202 : 0, /* tp_call */
203 : 0, /* tp_str */
204 : PyObject_GenericGetAttr, /* tp_getattro */
205 : 0, /* tp_setattro */
206 : 0, /* tp_as_buffer */
207 : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
208 : Py_TPFLAGS_BASETYPE, /* tp_flags */
209 : enum_doc, /* tp_doc */
210 : (traverseproc)enum_traverse, /* tp_traverse */
211 : 0, /* tp_clear */
212 : 0, /* tp_richcompare */
213 : 0, /* tp_weaklistoffset */
214 : PyObject_SelfIter, /* tp_iter */
215 : (iternextfunc)enum_next, /* tp_iternext */
216 : enum_methods, /* tp_methods */
217 : 0, /* tp_members */
218 : 0, /* tp_getset */
219 : 0, /* tp_base */
220 : 0, /* tp_dict */
221 : 0, /* tp_descr_get */
222 : 0, /* tp_descr_set */
223 : 0, /* tp_dictoffset */
224 : 0, /* tp_init */
225 : PyType_GenericAlloc, /* tp_alloc */
226 : enum_new, /* tp_new */
227 : PyObject_GC_Del, /* tp_free */
228 : };
229 :
230 : /* Reversed Object ***************************************************************/
231 :
232 : typedef struct {
233 : PyObject_HEAD
234 : Py_ssize_t index;
235 : PyObject* seq;
236 : } reversedobject;
237 :
238 : static PyObject *
239 188 : reversed_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
240 : {
241 : Py_ssize_t n;
242 : PyObject *seq, *reversed_meth;
243 : reversedobject *ro;
244 : _Py_IDENTIFIER(__reversed__);
245 :
246 188 : if (type == &PyReversed_Type && !_PyArg_NoKeywords("reversed()", kwds))
247 0 : return NULL;
248 :
249 188 : if (!PyArg_UnpackTuple(args, "reversed", 1, 1, &seq) )
250 0 : return NULL;
251 :
252 188 : reversed_meth = _PyObject_LookupSpecial(seq, &PyId___reversed__);
253 188 : if (reversed_meth != NULL) {
254 1 : PyObject *res = PyObject_CallFunctionObjArgs(reversed_meth, NULL);
255 1 : Py_DECREF(reversed_meth);
256 1 : return res;
257 : }
258 187 : else if (PyErr_Occurred())
259 0 : return NULL;
260 :
261 187 : if (!PySequence_Check(seq)) {
262 0 : PyErr_SetString(PyExc_TypeError,
263 : "argument to reversed() must be a sequence");
264 0 : return NULL;
265 : }
266 :
267 187 : n = PySequence_Size(seq);
268 187 : if (n == -1)
269 0 : return NULL;
270 :
271 187 : ro = (reversedobject *)type->tp_alloc(type, 0);
272 187 : if (ro == NULL)
273 0 : return NULL;
274 :
275 187 : ro->index = n-1;
276 187 : Py_INCREF(seq);
277 187 : ro->seq = seq;
278 187 : return (PyObject *)ro;
279 : }
280 :
281 : static void
282 187 : reversed_dealloc(reversedobject *ro)
283 : {
284 187 : PyObject_GC_UnTrack(ro);
285 187 : Py_XDECREF(ro->seq);
286 187 : Py_TYPE(ro)->tp_free(ro);
287 187 : }
288 :
289 : static int
290 0 : reversed_traverse(reversedobject *ro, visitproc visit, void *arg)
291 : {
292 0 : Py_VISIT(ro->seq);
293 0 : return 0;
294 : }
295 :
296 : static PyObject *
297 2289 : reversed_next(reversedobject *ro)
298 : {
299 : PyObject *item;
300 2289 : Py_ssize_t index = ro->index;
301 :
302 2289 : if (index >= 0) {
303 2289 : item = PySequence_GetItem(ro->seq, index);
304 2289 : if (item != NULL) {
305 2289 : ro->index--;
306 2289 : return item;
307 : }
308 0 : if (PyErr_ExceptionMatches(PyExc_IndexError) ||
309 0 : PyErr_ExceptionMatches(PyExc_StopIteration))
310 0 : PyErr_Clear();
311 : }
312 0 : ro->index = -1;
313 0 : Py_CLEAR(ro->seq);
314 0 : return NULL;
315 : }
316 :
317 : PyDoc_STRVAR(reversed_doc,
318 : "reversed(sequence) -> reverse iterator over values of the sequence\n"
319 : "\n"
320 : "Return a reverse iterator");
321 :
322 : static PyObject *
323 0 : reversed_len(reversedobject *ro)
324 : {
325 : Py_ssize_t position, seqsize;
326 :
327 0 : if (ro->seq == NULL)
328 0 : return PyLong_FromLong(0);
329 0 : seqsize = PySequence_Size(ro->seq);
330 0 : if (seqsize == -1)
331 0 : return NULL;
332 0 : position = ro->index + 1;
333 0 : return PyLong_FromSsize_t((seqsize < position) ? 0 : position);
334 : }
335 :
336 : PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
337 :
338 : static PyObject *
339 0 : reversed_reduce(reversedobject *ro)
340 : {
341 0 : if (ro->seq)
342 0 : return Py_BuildValue("O(O)n", Py_TYPE(ro), ro->seq, ro->index);
343 : else
344 0 : return Py_BuildValue("O(())", Py_TYPE(ro));
345 : }
346 :
347 : static PyObject *
348 0 : reversed_setstate(reversedobject *ro, PyObject *state)
349 : {
350 0 : Py_ssize_t index = PyLong_AsSsize_t(state);
351 0 : if (index == -1 && PyErr_Occurred())
352 0 : return NULL;
353 0 : if (ro->seq != 0) {
354 0 : Py_ssize_t n = PySequence_Size(ro->seq);
355 0 : if (n < 0)
356 0 : return NULL;
357 0 : if (index < -1)
358 0 : index = -1;
359 0 : else if (index > n-1)
360 0 : index = n-1;
361 0 : ro->index = index;
362 : }
363 0 : Py_RETURN_NONE;
364 : }
365 :
366 : PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
367 :
368 : static PyMethodDef reversediter_methods[] = {
369 : {"__length_hint__", (PyCFunction)reversed_len, METH_NOARGS, length_hint_doc},
370 : {"__reduce__", (PyCFunction)reversed_reduce, METH_NOARGS, reduce_doc},
371 : {"__setstate__", (PyCFunction)reversed_setstate, METH_O, setstate_doc},
372 : {NULL, NULL} /* sentinel */
373 : };
374 :
375 : PyTypeObject PyReversed_Type = {
376 : PyVarObject_HEAD_INIT(&PyType_Type, 0)
377 : "reversed", /* tp_name */
378 : sizeof(reversedobject), /* tp_basicsize */
379 : 0, /* tp_itemsize */
380 : /* methods */
381 : (destructor)reversed_dealloc, /* tp_dealloc */
382 : 0, /* tp_print */
383 : 0, /* tp_getattr */
384 : 0, /* tp_setattr */
385 : 0, /* tp_reserved */
386 : 0, /* tp_repr */
387 : 0, /* tp_as_number */
388 : 0, /* tp_as_sequence */
389 : 0, /* tp_as_mapping */
390 : 0, /* tp_hash */
391 : 0, /* tp_call */
392 : 0, /* tp_str */
393 : PyObject_GenericGetAttr, /* tp_getattro */
394 : 0, /* tp_setattro */
395 : 0, /* tp_as_buffer */
396 : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
397 : Py_TPFLAGS_BASETYPE, /* tp_flags */
398 : reversed_doc, /* tp_doc */
399 : (traverseproc)reversed_traverse,/* tp_traverse */
400 : 0, /* tp_clear */
401 : 0, /* tp_richcompare */
402 : 0, /* tp_weaklistoffset */
403 : PyObject_SelfIter, /* tp_iter */
404 : (iternextfunc)reversed_next, /* tp_iternext */
405 : reversediter_methods, /* tp_methods */
406 : 0, /* tp_members */
407 : 0, /* tp_getset */
408 : 0, /* tp_base */
409 : 0, /* tp_dict */
410 : 0, /* tp_descr_get */
411 : 0, /* tp_descr_set */
412 : 0, /* tp_dictoffset */
413 : 0, /* tp_init */
414 : PyType_GenericAlloc, /* tp_alloc */
415 : reversed_new, /* tp_new */
416 : PyObject_GC_Del, /* tp_free */
417 : };
|