Index: Objects/abstract.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v retrieving revision 2.135 diff -c -w -r2.135 abstract.c *** Objects/abstract.c 18 Dec 2004 19:00:59 -0000 2.135 --- Objects/abstract.c 24 Jan 2005 11:05:42 -0000 *************** *** 106,111 **** --- 106,126 ---- return type_error("sequence index must be integer"); } + if (PyIter_Check(o)) { + return PyIter_GetItem(o, key); + } + + if (o->ob_type->tp_iter) { + PyObject *result = NULL; + PyObject *iterator = PyObject_GetIter(o); + if (iterator == NULL) { + return NULL; + } + result = PyIter_GetItem(o, key); + Py_DECREF(iterator); + return result; + } + return type_error("unsubscriptable object"); } *************** *** 2219,2221 **** --- 2234,2298 ---- PyErr_Clear(); return result; } + + /* Iterator slicing + * If an error occurs, return NULL. PyErr_Occurred() will be true. + * For a simple index, consumes the iterator up to that point and + * returns the item at the supplied index. PyErr_Occurred() will be false. + * For a slice index, constructs an itertools.islice object based on the + * iterator and returns it. PyErr_Occurred() will be false. + */ + PyObject * + PyIter_GetItem(PyObject *iter, PyObject *key) + { + assert(PyIter_Check(iter)); + if (key == NULL) { + return null_error(); + } + + if (PySlice_Check(key)) { + PyObject * itertools = NULL; + PySliceObject *slice = (PySliceObject *) key; + PyObject * iterslice = NULL; + + itertools = PyImport_ImportModule("itertools"); + if (itertools) { + iterslice = PyObject_CallMethod(itertools, "islice", "OOOO", + iter, slice->start, slice->stop, slice->step); + Py_DECREF(itertools); + } + return iterslice; + } else { + long current = 0; + long key_value = 0; + PyObject * item = NULL; + if (PyInt_Check(key)) { + key_value = PyInt_AsLong(key); + } else if (PyLong_Check(key)) { + key_value = PyLong_AsLong(key); + if (key_value == -1 && PyErr_Occurred()) { + return NULL; + } + } else { + return type_error("iterator index must be integer or slice"); + } + if (key_value < 0) { + PyErr_SetString(PyExc_IndexError, "iterator requires non-negative index"); + return NULL; + } + /* Retrieve items until we reach the desired index */ + while ((item = PyIter_Next(iter)) && (current < key_value)) { + ++current; + /* Note this decref does NOT fire for the item at the key index! */ + Py_DECREF(item); + } + if (PyErr_Occurred()) { + return NULL; + } + if (current < key_value) { + PyErr_SetString(PyExc_IndexError, "iterator exhausted before reaching index"); + return NULL; + } + return item; + } + } Index: Include/abstract.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/abstract.h,v retrieving revision 2.51 diff -c -w -r2.51 abstract.h *** Include/abstract.h 12 Mar 2004 16:38:17 -0000 2.51 --- Include/abstract.h 24 Jan 2005 11:05:42 -0000 *************** *** 528,533 **** --- 528,541 ---- this returns NULL without setting an exception. NULL with an exception means an error occurred. */ + PyAPI_FUNC(PyObject *) PyIter_GetItem(PyObject *o, PyObject *key); + /* + Return the ith element of o, or NULL on failure. This is the + equivalent of the Python expression: o[i]. + Negative indices are not allowed. + Extended slicing is supported (positive steps only) + */ + /* Number Protocol:*/ PyAPI_FUNC(int) PyNumber_Check(PyObject *o);