| /* enumerate object */ | |
| #include "Python.h" | |
| typedef struct { | |
| PyObject_HEAD | |
| Py_ssize_t en_index; /* current index of enumeration */ | |
| PyObject* en_sit; /* secondary iterator of enumeration */ | |
| PyObject* en_result; /* result tuple */ | |
| PyObject* en_longindex; /* index for sequences >= PY_SSIZE_T_MAX */ | |
| } enumobject; | |
| static PyObject * | |
| enum_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | |
| { | |
| enumobject *en; | |
| PyObject *seq = NULL; | |
| PyObject *start = NULL; | |
| static char *kwlist[] = {"sequence", "start", 0}; | |
| if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:enumerate", kwlist, | |
| &seq, &start)) | |
| return NULL; | |
| en = (enumobject *)type->tp_alloc(type, 0); | |
| if (en == NULL) | |
| return NULL; | |
| if (start != NULL) { | |
| start = PyNumber_Index(start); | |
| if (start == NULL) { | |
| Py_DECREF(en); | |
| return NULL; | |
| } | |
| assert(PyInt_Check(start) || PyLong_Check(start)); | |
| en->en_index = PyInt_AsSsize_t(start); | |
| if (en->en_index == -1 && PyErr_Occurred()) { | |
| PyErr_Clear(); | |
| en->en_index = PY_SSIZE_T_MAX; | |
| en->en_longindex = start; | |
| } else { | |
| en->en_longindex = NULL; | |
| Py_DECREF(start); | |
| } | |
| } else { | |
| en->en_index = 0; | |
| en->en_longindex = NULL; | |
| } | |
| en->en_sit = PyObject_GetIter(seq); | |
| if (en->en_sit == NULL) { | |
| Py_DECREF(en); | |
| return NULL; | |
| } | |
| en->en_result = PyTuple_Pack(2, Py_None, Py_None); | |
| if (en->en_result == NULL) { | |
| Py_DECREF(en); | |
| return NULL; | |
| } | |
| return (PyObject *)en; | |
| } | |
| static void | |
| enum_dealloc(enumobject *en) | |
| { | |
| PyObject_GC_UnTrack(en); | |
| Py_XDECREF(en->en_sit); | |
| Py_XDECREF(en->en_result); | |
| Py_XDECREF(en->en_longindex); | |
| Py_TYPE(en)->tp_free(en); | |
| } | |
| static int | |
| enum_traverse(enumobject *en, visitproc visit, void *arg) | |
| { | |
| Py_VISIT(en->en_sit); | |
| Py_VISIT(en->en_result); | |
| Py_VISIT(en->en_longindex); | |
| return 0; | |
| } | |
| static PyObject * | |
| enum_next_long(enumobject *en, PyObject* next_item) | |
| { | |
| static PyObject *one = NULL; | |
| PyObject *result = en->en_result; | |
| PyObject *next_index; | |
| PyObject *stepped_up; | |
| if (en->en_longindex == NULL) { | |
| en->en_longindex = PyInt_FromSsize_t(PY_SSIZE_T_MAX); | |
| if (en->en_longindex == NULL) | |
| return NULL; | |
| } | |
| if (one == NULL) { | |
| one = PyInt_FromLong(1); | |
| if (one == NULL) | |
| return NULL; | |
| } | |
| next_index = en->en_longindex; | |
| assert(next_index != NULL); | |
| stepped_up = PyNumber_Add(next_index, one); | |
| if (stepped_up == NULL) | |
| return NULL; | |
| en->en_longindex = stepped_up; | |
| if (result->ob_refcnt == 1) { | |
| Py_INCREF(result); | |
| Py_DECREF(PyTuple_GET_ITEM(result, 0)); | |
| Py_DECREF(PyTuple_GET_ITEM(result, 1)); | |
| } else { | |
| result = PyTuple_New(2); | |
| if (result == NULL) { | |
| Py_DECREF(next_index); | |
| Py_DECREF(next_item); | |
| return NULL; | |
| } | |
| } | |
| PyTuple_SET_ITEM(result, 0, next_index); | |
| PyTuple_SET_ITEM(result, 1, next_item); | |
| return result; | |
| } | |
| static PyObject * | |
| enum_next(enumobject *en) | |
| { | |
| PyObject *next_index; | |
| PyObject *next_item; | |
| PyObject *result = en->en_result; | |
| PyObject *it = en->en_sit; | |
| next_item = (*Py_TYPE(it)->tp_iternext)(it); | |
| if (next_item == NULL) | |
| return NULL; | |
| if (en->en_index == PY_SSIZE_T_MAX) | |
| return enum_next_long(en, next_item); | |
| next_index = PyInt_FromSsize_t(en->en_index); | |
| if (next_index == NULL) { | |
| Py_DECREF(next_item); | |
| return NULL; | |
| } | |
| en->en_index++; | |
| if (result->ob_refcnt == 1) { | |
| Py_INCREF(result); | |
| Py_DECREF(PyTuple_GET_ITEM(result, 0)); | |
| Py_DECREF(PyTuple_GET_ITEM(result, 1)); | |
| } else { | |
| result = PyTuple_New(2); | |
| if (result == NULL) { | |
| Py_DECREF(next_index); | |
| Py_DECREF(next_item); | |
| return NULL; | |
| } | |
| } | |
| PyTuple_SET_ITEM(result, 0, next_index); | |
| PyTuple_SET_ITEM(result, 1, next_item); | |
| return result; | |
| } | |
| PyDoc_STRVAR(enum_doc, | |
| "enumerate(iterable[, start]) -> iterator for index, value of iterable\n" | |
| "\n" | |
| "Return an enumerate object. iterable must be another object that supports\n" | |
| "iteration. The enumerate object yields pairs containing a count (from\n" | |
| "start, which defaults to zero) and a value yielded by the iterable argument.\n" | |
| "enumerate is useful for obtaining an indexed list:\n" | |
| " (0, seq[0]), (1, seq[1]), (2, seq[2]), ..."); | |
| PyTypeObject PyEnum_Type = { | |
| PyVarObject_HEAD_INIT(&PyType_Type, 0) | |
| "enumerate", /* tp_name */ | |
| sizeof(enumobject), /* tp_basicsize */ | |
| 0, /* tp_itemsize */ | |
| /* methods */ | |
| (destructor)enum_dealloc, /* tp_dealloc */ | |
| 0, /* tp_print */ | |
| 0, /* tp_getattr */ | |
| 0, /* tp_setattr */ | |
| 0, /* tp_compare */ | |
| 0, /* tp_repr */ | |
| 0, /* tp_as_number */ | |
| 0, /* tp_as_sequence */ | |
| 0, /* tp_as_mapping */ | |
| 0, /* tp_hash */ | |
| 0, /* tp_call */ | |
| 0, /* tp_str */ | |
| PyObject_GenericGetAttr, /* tp_getattro */ | |
| 0, /* tp_setattro */ | |
| 0, /* tp_as_buffer */ | |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | | |
| Py_TPFLAGS_BASETYPE, /* tp_flags */ | |
| enum_doc, /* tp_doc */ | |
| (traverseproc)enum_traverse, /* tp_traverse */ | |
| 0, /* tp_clear */ | |
| 0, /* tp_richcompare */ | |
| 0, /* tp_weaklistoffset */ | |
| PyObject_SelfIter, /* tp_iter */ | |
| (iternextfunc)enum_next, /* tp_iternext */ | |
| 0, /* tp_methods */ | |
| 0, /* tp_members */ | |
| 0, /* tp_getset */ | |
| 0, /* tp_base */ | |
| 0, /* tp_dict */ | |
| 0, /* tp_descr_get */ | |
| 0, /* tp_descr_set */ | |
| 0, /* tp_dictoffset */ | |
| 0, /* tp_init */ | |
| PyType_GenericAlloc, /* tp_alloc */ | |
| enum_new, /* tp_new */ | |
| PyObject_GC_Del, /* tp_free */ | |
| }; | |
| /* Reversed Object ***************************************************************/ | |
| typedef struct { | |
| PyObject_HEAD | |
| Py_ssize_t index; | |
| PyObject* seq; | |
| } reversedobject; | |
| static PyObject * | |
| reversed_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | |
| { | |
| Py_ssize_t n; | |
| PyObject *seq, *reversed_meth; | |
| static PyObject *reversed_cache = NULL; | |
| reversedobject *ro; | |
| if (type == &PyReversed_Type && !_PyArg_NoKeywords("reversed()", kwds)) | |
| return NULL; | |
| if (!PyArg_UnpackTuple(args, "reversed", 1, 1, &seq) ) | |
| return NULL; | |
| if (PyInstance_Check(seq)) { | |
| reversed_meth = PyObject_GetAttrString(seq, "__reversed__"); | |
| if (reversed_meth == NULL) { | |
| if (PyErr_ExceptionMatches(PyExc_AttributeError)) | |
| PyErr_Clear(); | |
| else | |
| return NULL; | |
| } | |
| } | |
| else { | |
| reversed_meth = _PyObject_LookupSpecial(seq, "__reversed__", | |
| &reversed_cache); | |
| if (reversed_meth == NULL && PyErr_Occurred()) | |
| return NULL; | |
| } | |
| if (reversed_meth != NULL) { | |
| PyObject *res = PyObject_CallFunctionObjArgs(reversed_meth, NULL); | |
| Py_DECREF(reversed_meth); | |
| return res; | |
| } | |
| if (!PySequence_Check(seq)) { | |
| PyErr_SetString(PyExc_TypeError, | |
| "argument to reversed() must be a sequence"); | |
| return NULL; | |
| } | |
| n = PySequence_Size(seq); | |
| if (n == -1) | |
| return NULL; | |
| ro = (reversedobject *)type->tp_alloc(type, 0); | |
| if (ro == NULL) | |
| return NULL; | |
| ro->index = n-1; | |
| Py_INCREF(seq); | |
| ro->seq = seq; | |
| return (PyObject *)ro; | |
| } | |
| static void | |
| reversed_dealloc(reversedobject *ro) | |
| { | |
| PyObject_GC_UnTrack(ro); | |
| Py_XDECREF(ro->seq); | |
| Py_TYPE(ro)->tp_free(ro); | |
| } | |
| static int | |
| reversed_traverse(reversedobject *ro, visitproc visit, void *arg) | |
| { | |
| Py_VISIT(ro->seq); | |
| return 0; | |
| } | |
| static PyObject * | |
| reversed_next(reversedobject *ro) | |
| { | |
| PyObject *item; | |
| Py_ssize_t index = ro->index; | |
| if (index >= 0) { | |
| item = PySequence_GetItem(ro->seq, index); | |
| if (item != NULL) { | |
| ro->index--; | |
| return item; | |
| } | |
| if (PyErr_ExceptionMatches(PyExc_IndexError) || | |
| PyErr_ExceptionMatches(PyExc_StopIteration)) | |
| PyErr_Clear(); | |
| } | |
| ro->index = -1; | |
| Py_CLEAR(ro->seq); | |
| return NULL; | |
| } | |
| PyDoc_STRVAR(reversed_doc, | |
| "reversed(sequence) -> reverse iterator over values of the sequence\n" | |
| "\n" | |
| "Return a reverse iterator"); | |
| static PyObject * | |
| reversed_len(reversedobject *ro) | |
| { | |
| Py_ssize_t position, seqsize; | |
| if (ro->seq == NULL) | |
| return PyInt_FromLong(0); | |
| seqsize = PySequence_Size(ro->seq); | |
| if (seqsize == -1) | |
| return NULL; | |
| position = ro->index + 1; | |
| return PyInt_FromSsize_t((seqsize < position) ? 0 : position); | |
| } | |
| PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); | |
| static PyMethodDef reversediter_methods[] = { | |
| {"__length_hint__", (PyCFunction)reversed_len, METH_NOARGS, length_hint_doc}, | |
| {NULL, NULL} /* sentinel */ | |
| }; | |
| PyTypeObject PyReversed_Type = { | |
| PyVarObject_HEAD_INIT(&PyType_Type, 0) | |
| "reversed", /* tp_name */ | |
| sizeof(reversedobject), /* tp_basicsize */ | |
| 0, /* tp_itemsize */ | |
| /* methods */ | |
| (destructor)reversed_dealloc, /* tp_dealloc */ | |
| 0, /* tp_print */ | |
| 0, /* tp_getattr */ | |
| 0, /* tp_setattr */ | |
| 0, /* tp_compare */ | |
| 0, /* tp_repr */ | |
| 0, /* tp_as_number */ | |
| 0, /* tp_as_sequence */ | |
| 0, /* tp_as_mapping */ | |
| 0, /* tp_hash */ | |
| 0, /* tp_call */ | |
| 0, /* tp_str */ | |
| PyObject_GenericGetAttr, /* tp_getattro */ | |
| 0, /* tp_setattro */ | |
| 0, /* tp_as_buffer */ | |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | | |
| Py_TPFLAGS_BASETYPE, /* tp_flags */ | |
| reversed_doc, /* tp_doc */ | |
| (traverseproc)reversed_traverse,/* tp_traverse */ | |
| 0, /* tp_clear */ | |
| 0, /* tp_richcompare */ | |
| 0, /* tp_weaklistoffset */ | |
| PyObject_SelfIter, /* tp_iter */ | |
| (iternextfunc)reversed_next, /* tp_iternext */ | |
| reversediter_methods, /* tp_methods */ | |
| 0, /* tp_members */ | |
| 0, /* tp_getset */ | |
| 0, /* tp_base */ | |
| 0, /* tp_dict */ | |
| 0, /* tp_descr_get */ | |
| 0, /* tp_descr_set */ | |
| 0, /* tp_dictoffset */ | |
| 0, /* tp_init */ | |
| PyType_GenericAlloc, /* tp_alloc */ | |
| reversed_new, /* tp_new */ | |
| PyObject_GC_Del, /* tp_free */ | |
| }; |