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