Index: Doc/api/concrete.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/api/concrete.tex,v retrieving revision 1.15 diff -c -r1.15 concrete.tex *** Doc/api/concrete.tex 29 Apr 2002 17:28:43 -0000 1.15 --- Doc/api/concrete.tex 8 Jun 2002 16:00:44 -0000 *************** *** 2288,2293 **** --- 2288,2319 ---- \begin{cfuncdesc}{int}{PySlice_GetIndices}{PySliceObject *slice, int length, int *start, int *stop, int *step} + Retrieve the start, stop and step indices from the slice object + \var{slice}, assuming a sequence of length \var{length}. Treats + indices greater than \var{length} as errors. + + Returns 0 on success and -1 on error with no exception set (unless one + of the indices was not \constant{None} and failed to be converted to + an integer, in which case -1 is returned with an exception set). + + You probably do not want to use this function. If you want to use + slice objects in versions of Python prior to 2.3, you would probably + do well to incorporate the source of \cfunction{PySlice_GetIndicesEx}, + suitably renamed, in the source of your extension. + \end{cfuncdesc} + + \begin{cfuncdesc}{int}{PySlice_GetIndicesEx}{PySliceObject *slice, int length, + int *start, int *stop, int *step, + int *slicelength} + Usable replacement for \cfunction{PySlice_GetIndices}. Retrieve the + start, stop, and step indices from the slice object \var{slice} + assuming a sequence of length \var{length}, and store the length of + the slice in \var{slicelength}. Out of bounds indices are clipped in + a manner consistent with the handling of normal slices. + + Returns 0 on success and -1 on error with exception set. + + \versionadded{2.3} \end{cfuncdesc} Index: Doc/lib/libstdtypes.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libstdtypes.tex,v retrieving revision 1.95 diff -c -r1.95 libstdtypes.tex *** Doc/lib/libstdtypes.tex 22 May 2002 20:39:43 -0000 1.95 --- Doc/lib/libstdtypes.tex 8 Jun 2002 16:00:44 -0000 *************** *** 433,438 **** --- 433,439 ---- \hline \lineiii{\var{s}[\var{i}]}{\var{i}'th item of \var{s}, origin 0}{(2)} \lineiii{\var{s}[\var{i}:\var{j}]}{slice of \var{s} from \var{i} to \var{j}}{(2), (3)} + \lineiii{\var{s}[\var{i}:\var{j}:\var{k}]}{slice of \var{s} from \var{i} to \var{j} with step \var{k}}{(2), (4)} \hline \lineiii{len(\var{s})}{length of \var{s}}{} \lineiii{min(\var{s})}{smallest item of \var{s}}{} *************** *** 446,451 **** --- 447,453 ---- \indexii{repetition}{operation} \indexii{subscript}{operation} \indexii{slice}{operation} + \indexii{extended slice}{operation} \opindex{in} \opindex{not in} *************** *** 492,497 **** --- 494,508 ---- \code{len(\var{s})}, use \code{len(\var{s})}. If \var{i} is omitted, use \code{0}. If \var{j} is omitted, use \code{len(\var{s})}. If \var{i} is greater than or equal to \var{j}, the slice is empty. + + \item[(4)] The slice of \var{s} from \var{i} to \var{j} with step \var{k} + is defined as the sequence of items with index \code{\var{x} = + \var{i} + \var{n}*\var{k}} such that \var{n} \code{>=} \code{0} and + \code{\var{i} <= \var{x} < \var{j}}. If \var{i} or \var{j} is + greater than \code{len(\var{s})}, use \code{len(\var{s})}. If + \var{i} or \var{j} are ommitted then they become ``end'' values + (which end depends on the sign of \var{k}). + \end{description} *************** *** 875,905 **** {slice of \var{s} from \var{i} to \var{j} is replaced by \var{t}}{} \lineiii{del \var{s}[\var{i}:\var{j}]} {same as \code{\var{s}[\var{i}:\var{j}] = []}}{} \lineiii{\var{s}.append(\var{x})} ! {same as \code{\var{s}[len(\var{s}):len(\var{s})] = [\var{x}]}}{(1)} \lineiii{\var{s}.extend(\var{x})} ! {same as \code{\var{s}[len(\var{s}):len(\var{s})] = \var{x}}}{(2)} \lineiii{\var{s}.count(\var{x})} {return number of \var{i}'s for which \code{\var{s}[\var{i}] == \var{x}}}{} \lineiii{\var{s}.index(\var{x})} ! {return smallest \var{i} such that \code{\var{s}[\var{i}] == \var{x}}}{(3)} \lineiii{\var{s}.insert(\var{i}, \var{x})} {same as \code{\var{s}[\var{i}:\var{i}] = [\var{x}]} ! if \code{\var{i} >= 0}}{(4)} \lineiii{\var{s}.pop(\optional{\var{i}})} ! {same as \code{\var{x} = \var{s}[\var{i}]; del \var{s}[\var{i}]; return \var{x}}}{(5)} \lineiii{\var{s}.remove(\var{x})} ! {same as \code{del \var{s}[\var{s}.index(\var{x})]}}{(3)} \lineiii{\var{s}.reverse()} ! {reverses the items of \var{s} in place}{(6)} \lineiii{\var{s}.sort(\optional{\var{cmpfunc}})} ! {sort the items of \var{s} in place}{(6), (7)} \end{tableiii} \indexiv{operations on}{mutable}{sequence}{types} \indexiii{operations on}{sequence}{types} \indexiii{operations on}{list}{type} \indexii{subscript}{assignment} \indexii{slice}{assignment} \stindex{del} \withsubitem{(list method)}{ \ttindex{append()}\ttindex{extend()}\ttindex{count()}\ttindex{index()} --- 886,921 ---- {slice of \var{s} from \var{i} to \var{j} is replaced by \var{t}}{} \lineiii{del \var{s}[\var{i}:\var{j}]} {same as \code{\var{s}[\var{i}:\var{j}] = []}}{} + \lineiii{\var{s}[\var{i}:\var{j}:\var{k}] = \var{t}} + {the elements of \code{\var{s}[\var{i}:\var{j}:\var{k}]} are replaced by those of \var{t}}{(1)} + \lineiii{del \var{s}[\var{i}:\var{j}:\var{k}]} + {removes the elements of \code{\var{s}[\var{i}:\var{j}:\var{k}]} from the list}{} \lineiii{\var{s}.append(\var{x})} ! {same as \code{\var{s}[len(\var{s}):len(\var{s})] = [\var{x}]}}{(2)} \lineiii{\var{s}.extend(\var{x})} ! {same as \code{\var{s}[len(\var{s}):len(\var{s})] = \var{x}}}{(3)} \lineiii{\var{s}.count(\var{x})} {return number of \var{i}'s for which \code{\var{s}[\var{i}] == \var{x}}}{} \lineiii{\var{s}.index(\var{x})} ! {return smallest \var{i} such that \code{\var{s}[\var{i}] == \var{x}}}{(4)} \lineiii{\var{s}.insert(\var{i}, \var{x})} {same as \code{\var{s}[\var{i}:\var{i}] = [\var{x}]} ! if \code{\var{i} >= 0}}{(5)} \lineiii{\var{s}.pop(\optional{\var{i}})} ! {same as \code{\var{x} = \var{s}[\var{i}]; del \var{s}[\var{i}]; return \var{x}}}{(6)} \lineiii{\var{s}.remove(\var{x})} ! {same as \code{del \var{s}[\var{s}.index(\var{x})]}}{(4)} \lineiii{\var{s}.reverse()} ! {reverses the items of \var{s} in place}{(7)} \lineiii{\var{s}.sort(\optional{\var{cmpfunc}})} ! {sort the items of \var{s} in place}{(7), (8)} \end{tableiii} \indexiv{operations on}{mutable}{sequence}{types} \indexiii{operations on}{sequence}{types} \indexiii{operations on}{list}{type} \indexii{subscript}{assignment} \indexii{slice}{assignment} + \indexii{extended slice}{assignment} \stindex{del} \withsubitem{(list method)}{ \ttindex{append()}\ttindex{extend()}\ttindex{count()}\ttindex{index()} *************** *** 908,939 **** \noindent Notes: \begin{description} ! \item[(1)] The C implementation of Python has historically accepted multiple parameters and implicitly joined them into a tuple; this no longer works in Python 2.0. Use of this misfeature has been deprecated since Python 1.4. ! \item[(2)] Raises an exception when \var{x} is not a list object. The \method{extend()} method is experimental and not supported by mutable sequence types other than lists. ! \item[(3)] Raises \exception{ValueError} when \var{x} is not found in \var{s}. ! \item[(4)] When a negative index is passed as the first parameter to the \method{insert()} method, the new element is prepended to the sequence. ! \item[(5)] The \method{pop()} method is only supported by the list and array types. The optional argument \var{i} defaults to \code{-1}, so that by default the last item is removed and returned. ! \item[(6)] The \method{sort()} and \method{reverse()} methods modify the list in place for economy of space when sorting or reversing a large list. To remind you that they operate by side effect, they don't return the sorted or reversed list. ! \item[(7)] The \method{sort()} method takes an optional argument specifying a comparison function of two arguments (list items) which should return a negative, zero or positive number depending on whether the first argument is considered smaller than, equal to, or larger --- 924,958 ---- \noindent Notes: \begin{description} ! \item[(1)] \var{t} must have the same length as the slice it is ! replacing. ! ! \item[(2)] The C implementation of Python has historically accepted multiple parameters and implicitly joined them into a tuple; this no longer works in Python 2.0. Use of this misfeature has been deprecated since Python 1.4. ! \item[(3)] Raises an exception when \var{x} is not a list object. The \method{extend()} method is experimental and not supported by mutable sequence types other than lists. ! \item[(4)] Raises \exception{ValueError} when \var{x} is not found in \var{s}. ! \item[(5)] When a negative index is passed as the first parameter to the \method{insert()} method, the new element is prepended to the sequence. ! \item[(6)] The \method{pop()} method is only supported by the list and array types. The optional argument \var{i} defaults to \code{-1}, so that by default the last item is removed and returned. ! \item[(7)] The \method{sort()} and \method{reverse()} methods modify the list in place for economy of space when sorting or reversing a large list. To remind you that they operate by side effect, they don't return the sorted or reversed list. ! \item[(8)] The \method{sort()} method takes an optional argument specifying a comparison function of two arguments (list items) which should return a negative, zero or positive number depending on whether the first argument is considered smaller than, equal to, or larger Index: Doc/ref/ref3.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ref/ref3.tex,v retrieving revision 1.90 diff -c -r1.90 ref3.tex *** Doc/ref/ref3.tex 4 Jun 2002 16:25:57 -0000 1.90 --- Doc/ref/ref3.tex 8 Jun 2002 16:00:44 -0000 *************** *** 252,257 **** --- 252,264 ---- renumbered so that it starts at 0. \index{slicing} + Some sequences also support ``extended slicing'' with a third ``step'' + parameter: \code{\var{a}[\var{i}:\var{j}:\var{k}]} selects all items + of \var{a} with index \var{x} where \code{\var{x} = \var{i} + + \var{n}*\var{k}}, \var{n} \code{>=} \code{0} and \var{i} \code{<=} + \var{x} \code{<} \var{j}. + \index{extended slicing} + Sequences are distinguished according to their mutability: \begin{description} Index: Lib/test/test_bool.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_bool.py,v retrieving revision 1.5 diff -c -r1.5 test_bool.py *** Lib/test/test_bool.py 20 May 2002 14:22:28 -0000 1.5 --- Lib/test/test_bool.py 8 Jun 2002 16:00:44 -0000 *************** *** 219,225 **** veris(operator.isSequenceType([]), True) veris(operator.contains([], 1), False) veris(operator.contains([1], 1), True) ! veris(operator.isMappingType([]), False) veris(operator.isMappingType({}), True) veris(operator.lt(0, 0), False) veris(operator.lt(0, 1), True) --- 219,225 ---- veris(operator.isSequenceType([]), True) veris(operator.contains([], 1), False) veris(operator.contains([1], 1), True) ! #veris(operator.isMappingType([]), False) veris(operator.isMappingType({}), True) veris(operator.lt(0, 0), False) veris(operator.lt(0, 1), True) Index: Lib/test/test_types.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_types.py,v retrieving revision 1.29 diff -c -r1.29 test_types.py *** Lib/test/test_types.py 2 May 2002 04:27:20 -0000 1.29 --- Lib/test/test_types.py 8 Jun 2002 16:00:44 -0000 *************** *** 188,193 **** --- 188,218 ---- x = 'x'*103 if '%s!'%x != x+'!': raise TestFailed, 'nasty string formatting bug' + #extended slices for strings + a = '0123456789' + vereq(a[::], a) + vereq(a[::2], '02468') + vereq(a[1::2], '13579') + vereq(a[::-1],'9876543210') + vereq(a[::-2], '97531') + vereq(a[3::-2], '31') + vereq(a[-100:100:], a) + vereq(a[100:-100:-1], a[::-1]) + vereq(a[-100L:100L:2L], '02468') + + if have_unicode: + a = unicode('0123456789', 'ascii') + vereq(a[::], a) + vereq(a[::2], unicode('02468', 'ascii')) + vereq(a[1::2], unicode('13579', 'ascii')) + vereq(a[::-1], unicode('9876543210', 'ascii')) + vereq(a[::-2], unicode('97531', 'ascii')) + vereq(a[3::-2], unicode('31', 'ascii')) + vereq(a[-100:100:], a) + vereq(a[100:-100:-1], a[::-1]) + vereq(a[-100L:100L:2L], unicode('02468', 'ascii')) + + print '6.5.2 Tuples' if len(()) != 0: raise TestFailed, 'len(())' if len((1,)) != 1: raise TestFailed, 'len((1,))' *************** *** 207,212 **** --- 232,250 ---- x += (1,) if x != (1,): raise TestFailed, 'tuple resize from () failed' + # extended slicing - subscript only for tuples + a = (0,1,2,3,4) + vereq(a[::], a) + vereq(a[::2], (0,2,4)) + vereq(a[1::2], (1,3)) + vereq(a[::-1], (4,3,2,1,0)) + vereq(a[::-2], (4,2,0)) + vereq(a[3::-2], (3,1)) + vereq(a[-100:100:], a) + vereq(a[100:-100:-1], a[::-1]) + vereq(a[-100L:100L:2L], (0,2,4)) + + print '6.5.3 Lists' if len([]) != 0: raise TestFailed, 'len([])' if len([1,]) != 1: raise TestFailed, 'len([1,])' *************** *** 321,326 **** --- 359,396 ---- raise TestFailed, "list slicing with too-small long integer" if a[ 3: pow(2,145L) ] != [3,4]: raise TestFailed, "list slicing with too-large long integer" + + + # extended slicing + + # subscript + a = [0,1,2,3,4] + vereq(a[::], a) + vereq(a[::2], [0,2,4]) + vereq(a[1::2], [1,3]) + vereq(a[::-1], [4,3,2,1,0]) + vereq(a[::-2], [4,2,0]) + vereq(a[3::-2], [3,1]) + vereq(a[-100:100:], a) + vereq(a[100:-100:-1], a[::-1]) + vereq(a[-100L:100L:2L], [0,2,4]) + # deletion + del a[::2] + vereq(a, [1,3]) + a = range(5) + del a[1::2] + vereq(a, [0,2,4]) + a = range(5) + del a[1::-2] + vereq(a, [0,2,3,4]) + # assignment + a = range(10) + a[::2] = [-1]*5 + vereq(a, [-1, 1, -1, 3, -1, 5, -1, 7, -1, 9]) + a = range(10) + a[::-4] = [10]*3 + vereq(a, [0, 10, 2, 3, 4, 10, 6, 7, 8 ,10]) + print '6.6 Mappings == Dictionaries' d = {} Index: Objects/listobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/listobject.c,v retrieving revision 2.108 diff -c -r2.108 listobject.c *** Objects/listobject.c 1 Jun 2002 05:22:55 -0000 2.108 --- Objects/listobject.c 8 Jun 2002 16:00:44 -0000 *************** *** 1684,1689 **** --- 1684,1881 ---- staticforward PyObject * list_iter(PyObject *seq); + static PyObject* + list_subscript(PyObject* self, PyObject* item) + { + PyListObject* list; + + if (!PyList_Check(self)) { + PyErr_BadInternalCall(); + return NULL; + } + else { + list = (PyListObject*)self; + } + + if (PyInt_Check(item)) { + long i = PyInt_AS_LONG(item); + if (i < 0) + i += PyList_GET_SIZE(list); + return list_item(list,i); + } + else if (PyLong_Check(item)) { + long i = PyLong_AsLong(item); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += PyList_GET_SIZE(list); + return list_item(list,i); + } + else if (PySlice_Check(item)) { + int start, stop, step, slicelength, cur, i; + PyObject* result; + PyObject* it; + + if (PySlice_GetIndicesEx((PySliceObject*)item, list->ob_size, + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + if (slicelength <= 0) { + return PyList_New(0); + } + else { + result = PyList_New(slicelength); + if (!result) return NULL; + + for (cur = start, i = 0; i < slicelength; cur += step, i++) { + it = PyList_GET_ITEM(list, cur); + Py_INCREF(it); + PyList_SET_ITEM(result, i, it); + } + + return result; + } + } + else { + PyErr_SetString(PyExc_TypeError, "list indices must be integers"); + return NULL; + } + } + + static int list_ass_subscript(PyObject* self, PyObject* item, PyObject* value) + { + PyListObject* list; + + if (!PyList_Check(self)) { + PyErr_BadInternalCall(); + return -1; + } + else { + list = (PyListObject*)self; + } + + if (PyInt_Check(item)) { + long i = PyInt_AS_LONG(item); + if (i < 0) + i += PyList_GET_SIZE(list); + return list_ass_item(list,i,value); + } + else if (PyLong_Check(item)) { + long i = PyLong_AsLong(item); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += PyList_GET_SIZE(list); + return list_ass_item(list,i,value); + } + else if (PySlice_Check(item)) { + int start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((PySliceObject*)item, list->ob_size, + &start, &stop, &step, &slicelength) < 0) { + return -1; + } + + if (value == NULL) { + /* delete slice */ + PyObject **garbage,**item; + int cur, i, j; + + if (slicelength <= 0) + return 0; + + if (step < 0) { + stop = start + 1; + start = stop + step*(slicelength - 1) - 1; + step = -step; + } + garbage = PyMem_New(PyObject*, slicelength); + + /* drawing pictures might help understand these for loops */ + for (cur = start, i = 0; cur < stop; cur += step, i++) { + garbage[i] = PyList_GET_ITEM(list, cur); + + for (j = 0; j < step; j++) { + PyList_SET_ITEM(list, cur + j - i, PyList_GET_ITEM(list, cur + j + 1)); + } + } + for (cur = start + slicelength*step + 1; cur < list->ob_size; cur++) { + PyList_SET_ITEM(list, cur - slicelength, PyList_GET_ITEM(list, cur)); + } + list->ob_size -= slicelength; + item = list->ob_item; + NRESIZE(item, PyObject*, list->ob_size); + list->ob_item = item; + + for (i = 0; i < slicelength; i++) { + Py_DECREF(garbage[i]); + } + PyMem_FREE(garbage); + + return 0; + } + else { + /* assign slice */ + PyObject **garbage,*ins; + int cur, i; + + if (!PyList_Check(value)) { + PyErr_Format(PyExc_TypeError, + "must assign list (not \"%.200s\") to slice", + value->ob_type->tp_name); + return -1; + } + + if (PyList_GET_SIZE(value) != slicelength) { + PyErr_Format(PyExc_ValueError, + "attempt to assign list of size %d to extended slice of size %d", + PyList_Size(value), slicelength); + return -1; + } + + if (self == value) { /* protect against a[::-1] = a */ + value = list_slice((PyListObject*)value, 0, PyList_GET_SIZE(value)); + } + else { + Py_INCREF(value); + } + + if (!slicelength) + return 0; + + garbage = PyMem_New(PyObject*, slicelength); + + for (cur = start, i = 0; (cur-stop)*step < 0; cur += step, i++) { + garbage[i] = PyList_GET_ITEM(list,cur); + + ins = PyList_GET_ITEM(value, i); + Py_INCREF(ins); + PyList_SET_ITEM(list, cur, ins); + } + + for (i = 0; i < slicelength; i++) { + Py_DECREF(garbage[i]); + } + + PyMem_FREE(garbage); + Py_DECREF(value); + + return 0; + } + } + else { + PyErr_SetString(PyExc_TypeError, "list indices must be integers"); + return -1; + } + } + + static PyMappingMethods list_as_mapping = { + (inquiry)list_length, + (binaryfunc)list_subscript, + (objobjargproc)list_ass_subscript + }; + PyTypeObject PyList_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, *************** *** 1698,1704 **** (reprfunc)list_repr, /* tp_repr */ 0, /* tp_as_number */ &list_as_sequence, /* tp_as_sequence */ ! 0, /* tp_as_mapping */ list_nohash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ --- 1890,1896 ---- (reprfunc)list_repr, /* tp_repr */ 0, /* tp_as_number */ &list_as_sequence, /* tp_as_sequence */ ! &list_as_mapping, /* tp_as_mapping */ list_nohash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ Index: Objects/sliceobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/sliceobject.c,v retrieving revision 2.12 diff -c -r2.12 sliceobject.c *** Objects/sliceobject.c 12 Apr 2002 03:04:15 -0000 2.12 --- Objects/sliceobject.c 8 Jun 2002 16:00:44 -0000 *************** *** 109,114 **** --- 109,165 ---- return 0; } + int + PySlice_GetIndicesEx(PySliceObject *r, int length, + int *start, int *stop, int *step, int *slicelength) + { + int defstart, defstop; + + if (r->step == Py_None) { + *step = 1; + } else { + *step = PyInt_AsLong(r->step); + if (*step == -1 && PyErr_Occurred()) { + return -1; + } + else if (*step == 0) { + PyErr_SetString(PyExc_ValueError, + "slice step cannot be zero"); + return -1; + } + } + + defstart = *step < 0 ? length-1 : 0; + defstop = *step < 0 ? -1 : length; + + if (r->start == Py_None) { + *start = defstart; + } else { + if (!_PyEval_SliceIndex(r->start, start)) return -1; + if (*start < 0) *start += length; + if (*start < 0) *start = (*step < 0) ? -1 : 0; + if (*start >= length) *start = (*step < 0) ? length - 1 : length; + } + + if (r->stop == Py_None) { + *stop = defstop; + } else { + if (!_PyEval_SliceIndex(r->stop, stop)) return -1; + if (*stop < 0) *stop += length; + if (*stop < 0) *stop = -1; + if (*stop > length) *stop = length; + } + + if (*step < 0) { + *slicelength = (*stop-*start+1)/(*step)+1; + } else { + *slicelength = (*stop-*start-1)/(*step)+1; + } + if (*slicelength < 0) *slicelength = 0; + + return 0; + } + static void slice_dealloc(PySliceObject *r) { *************** *** 163,168 **** --- 214,240 ---- return result; } + static PyObject* + slice_indices(PySliceObject* self, PyObject* lengtho) + { + int length, start, stop, step, slicelength; + + if ((length = PyInt_AsLong(lengtho)) == -1 && PyErr_Occurred()) { + return NULL; + } + + if (PySlice_GetIndicesEx(self, length, &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + return Py_BuildValue("(iiii)", start, stop, step, slicelength); + } + + static PyMethodDef slice_methods[] = { + {"indices", (PyCFunction)slice_indices, METH_O, NULL}, + {NULL, NULL} + }; + PyTypeObject PySlice_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, /* Number of items for varobject */ *************** *** 192,198 **** 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ ! 0, /* tp_methods */ slice_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ --- 264,270 ---- 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ ! slice_methods, /* tp_methods */ slice_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ Index: Objects/stringobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/stringobject.c,v retrieving revision 2.165 diff -c -r2.165 stringobject.c *** Objects/stringobject.c 31 May 2002 19:58:01 -0000 2.165 --- Objects/stringobject.c 8 Jun 2002 16:00:45 -0000 *************** *** 940,945 **** --- 940,995 ---- return x; } + static PyObject* + string_subscript(PyStringObject* self, PyObject* item) + { + if (PyInt_Check(item)) { + long i = PyInt_AS_LONG(item); + if (i < 0) + i += PyString_GET_SIZE(self); + return string_item(self,i); + } + else if (PyLong_Check(item)) { + long i = PyLong_AsLong(item); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += PyString_GET_SIZE(self); + return string_item(self,i); + } + else if (PySlice_Check(item)) { + int start, stop, step, slicelength, cur, i; + char* source_buf; + char* result_buf; + PyObject* result; + + if (PySlice_GetIndicesEx((PySliceObject*)item, PyString_GET_SIZE(self), + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + if (slicelength <= 0) { + return PyString_FromStringAndSize("", 0); + } + else { + source_buf = PyString_AsString((PyObject*)self); + result_buf = PyMem_Malloc(slicelength); + + for (cur = start, i = 0; i < slicelength; cur += step, i++) { + result_buf[i] = source_buf[cur]; + } + + result = PyString_FromStringAndSize(result_buf, slicelength); + PyMem_Free(result_buf); + return result; + } + } + else { + PyErr_SetString(PyExc_TypeError, "string indices must be integers"); + return NULL; + } + } + static int string_buffer_getreadbuf(PyStringObject *self, int index, const void **ptr) { *************** *** 991,996 **** --- 1041,1052 ---- (objobjproc)string_contains /*sq_contains*/ }; + static PyMappingMethods string_as_mapping = { + (inquiry)string_length, + (binaryfunc)string_subscript, + 0, + }; + static PyBufferProcs string_as_buffer = { (getreadbufferproc)string_buffer_getreadbuf, (getwritebufferproc)string_buffer_getwritebuf, *************** *** 2929,2935 **** (reprfunc)string_repr, /* tp_repr */ 0, /* tp_as_number */ &string_as_sequence, /* tp_as_sequence */ ! 0, /* tp_as_mapping */ (hashfunc)string_hash, /* tp_hash */ 0, /* tp_call */ (reprfunc)string_str, /* tp_str */ --- 2985,2991 ---- (reprfunc)string_repr, /* tp_repr */ 0, /* tp_as_number */ &string_as_sequence, /* tp_as_sequence */ ! &string_as_mapping, /* tp_as_mapping */ (hashfunc)string_hash, /* tp_hash */ 0, /* tp_call */ (reprfunc)string_str, /* tp_str */ *************** *** 3349,3355 **** arglen = -1; argidx = -2; } ! if (args->ob_type->tp_as_mapping) dict = args; while (--fmtcnt >= 0) { if (*fmt != '%') { --- 3405,3411 ---- arglen = -1; argidx = -2; } ! if (args->ob_type->tp_as_mapping && !PyTuple_Check(args)) dict = args; while (--fmtcnt >= 0) { if (*fmt != '%') { Index: Objects/tupleobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/tupleobject.c,v retrieving revision 2.64 diff -c -r2.64 tupleobject.c *** Objects/tupleobject.c 12 Apr 2002 03:05:52 -0000 2.64 --- Objects/tupleobject.c 8 Jun 2002 16:00:45 -0000 *************** *** 541,546 **** --- 541,610 ---- (objobjproc)tuplecontains, /* sq_contains */ }; + static PyObject* + tuplesubscript(PyObject* self, PyObject* item) + { + PyTupleObject* tuple; + + if (!PyTuple_Check(self)) { + PyErr_BadInternalCall(); + return NULL; + } + else { + tuple = (PyTupleObject*)self; + } + + if (PyInt_Check(item)) { + long i = PyInt_AS_LONG(item); + if (i < 0) + i += PyTuple_GET_SIZE(tuple); + return tupleitem(tuple,i); + } + else if (PyLong_Check(item)) { + long i = PyLong_AsLong(item); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += PyTuple_GET_SIZE(tuple); + return tupleitem(tuple,i); + } + else if (PySlice_Check(item)) { + int start, stop, step, slicelength, cur, i; + PyObject* result; + PyObject* it; + + if (PySlice_GetIndicesEx((PySliceObject*)item, PyTuple_GET_SIZE(tuple), + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + if (slicelength <= 0) { + return PyTuple_New(0); + } + else { + result = PyTuple_New(slicelength); + + for (cur = start, i = 0; i < slicelength; cur += step, i++) { + it = PyTuple_GET_ITEM(tuple, cur); + Py_INCREF(it); + PyTuple_SET_ITEM(result, i, it); + } + + return result; + } + } + else { + PyErr_SetString(PyExc_TypeError, "tuple indices must be integers"); + return NULL; + } + } + + static PyMappingMethods tuple_as_mapping = { + (inquiry)tuplelength, + (binaryfunc)tuplesubscript, + 0 + }; + PyTypeObject PyTuple_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, *************** *** 555,561 **** (reprfunc)tuplerepr, /* tp_repr */ 0, /* tp_as_number */ &tuple_as_sequence, /* tp_as_sequence */ ! 0, /* tp_as_mapping */ (hashfunc)tuplehash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ --- 619,625 ---- (reprfunc)tuplerepr, /* tp_repr */ 0, /* tp_as_number */ &tuple_as_sequence, /* tp_as_sequence */ ! &tuple_as_mapping, /* tp_as_mapping */ (hashfunc)tuplehash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ Index: Objects/unicodeobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/unicodeobject.c,v retrieving revision 2.151 diff -c -r2.151 unicodeobject.c *** Objects/unicodeobject.c 29 May 2002 13:46:29 -0000 2.151 --- Objects/unicodeobject.c 8 Jun 2002 16:00:45 -0000 *************** *** 5061,5066 **** --- 5061,5118 ---- (objobjproc)PyUnicode_Contains, /*sq_contains*/ }; + static PyObject* + unicode_subscript(PyUnicodeObject* self, PyObject* item) + { + if (PyInt_Check(item)) { + long i = PyInt_AS_LONG(item); + if (i < 0) + i += PyString_GET_SIZE(self); + return unicode_getitem(self,i); + } else if (PyLong_Check(item)) { + long i = PyLong_AsLong(item); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += PyString_GET_SIZE(self); + return unicode_getitem(self,i); + } else if (PySlice_Check(item)) { + int start, stop, step, slicelength, cur, i; + Py_UNICODE* source_buf; + Py_UNICODE* result_buf; + PyObject* result; + + if (PySlice_GetIndicesEx((PySliceObject*)item, PyString_GET_SIZE(self), + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + if (slicelength <= 0) { + return PyUnicode_FromUnicode(NULL, 0); + } else { + source_buf = PyUnicode_AS_UNICODE((PyObject*)self); + result_buf = PyMem_Malloc(slicelength*sizeof(Py_UNICODE)); + + for (cur = start, i = 0; i < slicelength; cur += step, i++) { + result_buf[i] = source_buf[cur]; + } + + result = PyUnicode_FromUnicode(result_buf, slicelength); + PyMem_Free(result_buf); + return result; + } + } else { + PyErr_SetString(PyExc_TypeError, "string indices must be integers"); + return NULL; + } + } + + static PyMappingMethods unicode_as_mapping = { + (inquiry)unicode_length, /* mp_length */ + (binaryfunc)unicode_subscript, /* mp_subscript */ + (objobjargproc)0, /* mp_ass_subscript */ + }; + static int unicode_buffer_getreadbuf(PyUnicodeObject *self, int index, *************** *** 5355,5361 **** arglen = -1; argidx = -2; } ! if (args->ob_type->tp_as_mapping) dict = args; while (--fmtcnt >= 0) { --- 5407,5413 ---- arglen = -1; argidx = -2; } ! if (args->ob_type->tp_as_mapping && !PyTuple_Check(args)) dict = args; while (--fmtcnt >= 0) { *************** *** 5817,5823 **** (reprfunc) unicode_repr, /* tp_repr */ 0, /* tp_as_number */ &unicode_as_sequence, /* tp_as_sequence */ ! 0, /* tp_as_mapping */ (hashfunc) unicode_hash, /* tp_hash*/ 0, /* tp_call*/ (reprfunc) unicode_str, /* tp_str */ --- 5869,5875 ---- (reprfunc) unicode_repr, /* tp_repr */ 0, /* tp_as_number */ &unicode_as_sequence, /* tp_as_sequence */ ! &unicode_as_mapping, /* tp_as_mapping */ (hashfunc) unicode_hash, /* tp_hash*/ 0, /* tp_call*/ (reprfunc) unicode_str, /* tp_str */