diff -cr src/Doc/lib/libstdtypes.tex src-3/Doc/lib/libstdtypes.tex *** src/Doc/lib/libstdtypes.tex Wed Aug 16 00:04:20 2000 --- src-3/Doc/lib/libstdtypes.tex Wed Aug 16 20:15:25 2000 *************** *** 359,364 **** --- 359,365 ---- \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}}{} *************** *** 372,377 **** --- 373,379 ---- \indexii{repetition}{operation} \indexii{subscript}{operation} \indexii{slice}{operation} + \indexii{extended slice}{operation} \opindex{in} \opindex{not in} *************** *** 394,399 **** --- 396,410 ---- \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} *************** *** 674,704 **** {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}}{} \lineiii{\var{s}.pop(\optional{\var{i}})} ! {same as \code{\var{x} = \var{s}[\var{i}]; del \var{s}[\var{i}]; return \var{x}}}{(4)} \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}{(5)} \lineiii{\var{s}.sort(\optional{\var{cmpfunc}})} ! {sort the items of \var{s} in place}{(5), (6)} \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()} --- 685,720 ---- {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}}{} \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})]}}{(4)} \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} + \indexii{extended slice}{assignment} \stindex{del} \withsubitem{(list method)}{ \ttindex{append()}\ttindex{extend()}\ttindex{count()}\ttindex{index()} *************** *** 707,734 **** \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)] 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[(5)] The \method{sort()} and \method{reverse()} methods modify the list in place for economy of space when sorting or reversing a large list. They don't return the sorted or reversed list to remind you of this side effect. ! \item[(6)] The \method{sort()} method takes an optional argument specifying a comparison function of two arguments (list items) which should return \code{-1}, \code{0} or \code{1} depending on whether the first argument is considered smaller than, equal to, or larger --- 723,753 ---- \noindent Notes: \begin{description} ! \item[(1)] \var{t} must have the same length as the slice is 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)] 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. They don't return the sorted or reversed list to remind you of this side effect. ! \item[(7)] The \method{sort()} method takes an optional argument specifying a comparison function of two arguments (list items) which should return \code{-1}, \code{0} or \code{1} depending on whether the first argument is considered smaller than, equal to, or larger diff -cr src/Doc/ref/ref3.tex src-3/Doc/ref/ref3.tex *** src/Doc/ref/ref3.tex Wed Aug 16 19:38:08 2000 --- src-3/Doc/ref/ref3.tex Wed Aug 16 20:15:12 2000 *************** *** 232,237 **** --- 232,244 ---- 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} diff -cr src/Lib/test/test_types.py src-3/Lib/test/test_types.py *** src/Lib/test/test_types.py Wed Aug 16 01:24:37 2000 --- src-3/Lib/test/test_types.py Wed Aug 16 01:28:46 2000 *************** *** 124,129 **** --- 124,141 ---- if 0 in (0,1,2) and 1 in (0,1,2) and 2 in (0,1,2) and 3 not in (0,1,2): pass else: raise TestFailed, 'in/not in tuple' + # extended slicing - subscript only for tuples + a = (0,1,2,3,4) + if a[::] != a: raise TestFailed + if a[::2] != (0,2,4): raise TestFailed + if a[1::2] != (1,3): raise TestFailed + if a[::-1] != (4,3,2,1,0): raise TestFailed + if a[::-2] != (4,2,0): raise TestFailed + if a[3::-2] != (3,1): raise TestFailed + if a[-100:100:] != a: raise TestFailed + if a[-100L:100L:2L] != (0,2,4): raise TestFailed + + print '6.5.3 Lists' if len([]) <> 0: raise TestFailed, 'len([])' if len([1,]) <> 1: raise TestFailed, 'len([1,])' *************** *** 216,221 **** --- 228,256 ---- 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] + if a[::] != a: raise TestFailed + if a[::2] != [0,2,4]: raise TestFailed + if a[1::2] != [1,3]: raise TestFailed + if a[::-1] != [4,3,2,1,0]: raise TestFailed + if a[::-2] != [4,2,0]: raise TestFailed + if a[3::-2] != [3,1]: raise TestFailed + if a[-100:100:] != a: raise TestFailed + if a[-100L:100L:2L] != [0,2,4]: raise TestFailed + # deletion + del a[::2] + if a != [1,3]: raise TestFailed + a = range(5) + del a[1::2] + if a != [0,2,4]: raise TestFailed + a = range(5) + del a[1::-2] + if a != [0,2,3,4]: raise TestFailed + print '6.6 Mappings == Dictionaries' d = {} diff -cr src/Objects/listobject.c src-3/Objects/listobject.c *** src/Objects/listobject.c Sun Aug 13 23:47:45 2000 --- src-3/Objects/listobject.c Wed Aug 16 20:15:47 2000 *************** *** 1405,1410 **** --- 1405,1597 ---- (objobjproc)list_contains, /*sq_contains*/ }; + 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, cur, i; + PyObject* result; + PyObject* it; + + if (PySlice_GetIndices((PySliceObject*)item,list->ob_size,&start,&stop,&step) < 0) { + return NULL; + } + + if ((stop - start)*step <= 0) { + return PyList_New(0); + } else { + if (step < 0) { + result = PyList_New((stop-start+1)/step+1); + } else { + result = PyList_New((stop-start-1)/step+1); + } + + for (cur = start, i = 0; (stop-cur)*step > 0; 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; + + if (PySlice_GetIndices((PySliceObject*)item,list->ob_size,&start,&stop,&step) < 0) { + return -1; + } + + if (value == NULL) { + /* delete slice */ + PyObject **garbage,**item; + int cur, i, j; + int slice_size; + + if ((stop - start)*step <= 0) + return 0; + + if (step < 0) { + slice_size = (stop-start+1)/step+1; + stop = start + 1; + start = stop + step*(slice_size - 1) - 1; + step = -step; + } else { + slice_size = (stop-start-1)/step+1; + } + garbage = PyMem_New(PyObject*, slice_size); + + /* 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+slice_size*step+1; cur < list->ob_size; cur++) { + PyList_SET_ITEM(list, cur - slice_size, PyList_GET_ITEM(list, cur)); + } + list->ob_size -= slice_size; + item = list->ob_item; + NRESIZE(item, PyObject*, list->ob_size); + list->ob_item = item; + + for (i = 0; i < slice_size; i++) { + Py_DECREF(garbage[i]); + } + PyMem_FREE(garbage); + + return 0; + } else { + /* assign slice */ + PyObject **garbage,*ins; + int cur, i; + int slice_size; + + if (!PyList_Check(value)) { + PyErr_Format(PyExc_TypeError, + "must assign list (not \"%.200s\") to slice", + value->ob_type->tp_name); + return -1; + } + + if ((stop - start)*step <= 0) { + slice_size = 0; + } else if (step < 0) { + slice_size = (stop-start+1)/step+1; + } else { + slice_size = (stop-start-1)/step+1; + } + + if (PyList_GET_SIZE(value) != slice_size) { + PyErr_Format(PyExc_ValueError, + "attempt to assign list of size %d to extended slice of size %d", + PyList_Size(value),slice_size); + return -1; + } + + if (!slice_size) + return 0; + + garbage = PyMem_New(PyObject*, slice_size); + + 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 < slice_size; i++) { + Py_DECREF(garbage[i]); + } + PyMem_FREE(garbage); + + 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, *************** *** 1419,1425 **** (reprfunc)list_repr, /*tp_repr*/ 0, /*tp_as_number*/ &list_as_sequence, /*tp_as_sequence*/ ! 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ --- 1606,1612 ---- (reprfunc)list_repr, /*tp_repr*/ 0, /*tp_as_number*/ &list_as_sequence, /*tp_as_sequence*/ ! &list_as_mapping, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ diff -cr src/Objects/sliceobject.c src-3/Objects/sliceobject.c *** src/Objects/sliceobject.c Sun Jul 9 07:21:27 2000 --- src-3/Objects/sliceobject.c Wed Aug 16 01:29:54 2000 *************** *** 73,101 **** PySlice_GetIndices(PySliceObject *r, int length, int *start, int *stop, int *step) { if (r->step == Py_None) { *step = 1; } else { ! if (!PyInt_Check(r->step)) return -1; ! *step = PyInt_AsLong(r->step); } if (r->start == Py_None) { ! *start = *step < 0 ? length-1 : 0; } else { ! if (!PyInt_Check(r->start)) return -1; ! *start = PyInt_AsLong(r->start); if (*start < 0) *start += length; } if (r->stop == Py_None) { ! *stop = *step < 0 ? -1 : length; } else { ! if (!PyInt_Check(r->stop)) return -1; ! *stop = PyInt_AsLong(r->stop); if (*stop < 0) *stop += length; } - if (*stop > length) return -1; - if (*start >= length) return -1; - if (*step == 0) return -1; return 0; } --- 73,125 ---- PySlice_GetIndices(PySliceObject *r, int length, int *start, int *stop, int *step) { + int defstart,defstop; + if (r->step == Py_None) { *step = 1; } else { ! if (PyInt_Check(r->step)) { ! *step = PyInt_AsLong(r->step); ! } else { ! if (PyLong_Check(r->step)) { ! *step = PyLong_AsLong(r->step); ! if (*step == -1 && PyErr_Occurred()) { ! return -1; ! } ! } else { ! PyErr_SetString(PyExc_TypeError, ! "slice step must be integer or None"); ! 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 = 0; + if (*start >= length) *start = length - 1; } 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 (*stop > length) *stop = defstop; + if (*start >= length) *start = defstart; + if (*step == 0) { + PyErr_SetString(PyExc_ValueError, + "slice step cannot be zero"); + return -1; } return 0; } diff -cr src/Objects/stringobject.c src-3/Objects/stringobject.c *** src/Objects/stringobject.c Mon Jul 31 16:28:04 2000 --- src-3/Objects/stringobject.c Wed Aug 16 01:29:14 2000 *************** *** 2481,2487 **** arglen = -1; argidx = -2; } ! if (args->ob_type->tp_as_mapping) dict = args; while (--fmtcnt >= 0) { if (*fmt != '%') { --- 2481,2487 ---- arglen = -1; argidx = -2; } ! if (args->ob_type->tp_as_mapping && !PyTuple_Check(args)) dict = args; while (--fmtcnt >= 0) { if (*fmt != '%') { diff -cr src/Objects/tupleobject.c src-3/Objects/tupleobject.c *** src/Objects/tupleobject.c Sun Jul 9 08:04:36 2000 --- src-3/Objects/tupleobject.c Wed Aug 16 01:29:10 2000 *************** *** 404,409 **** --- 404,472 ---- (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, cur, i; + PyObject* result; + PyObject* it; + + if (PySlice_GetIndices((PySliceObject*)item,PyTuple_GET_SIZE(tuple), + &start,&stop,&step) < 0) { + return NULL; + } + + if ((stop - start)*step <= 0) { + return PyTuple_New(0); + } else { + if (step < 0) { + result = PyTuple_New((stop-start+1)/step+1); + } else { + result = PyTuple_New((stop-start-1)/step+1); + } + + for (cur = start, i = 0; (stop-cur)*step > 0; 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, *************** *** 418,424 **** (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*/ --- 481,487 ---- (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*/ diff -cr src/Objects/unicodeobject.c src-3/Objects/unicodeobject.c *** src/Objects/unicodeobject.c Mon Aug 14 12:29:19 2000 --- src-3/Objects/unicodeobject.c Wed Aug 16 01:29:22 2000 *************** *** 4754,4760 **** arglen = -1; argidx = -2; } ! if (args->ob_type->tp_as_mapping) dict = args; while (--fmtcnt >= 0) { --- 4754,4760 ---- arglen = -1; argidx = -2; } ! if (args->ob_type->tp_as_mapping && !PyTuple_Check(args)) dict = args; while (--fmtcnt >= 0) {