|
|
/* 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 voidenum_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 intenum_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 voidreversed_dealloc(reversedobject *ro){ PyObject_GC_UnTrack(ro); Py_XDECREF(ro->seq); Py_TYPE(ro)->tp_free(ro);}
static intreversed_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 */};
|