This is my nearly two year old patch

[ 400998 ] experimental support for extended slicing on lists

somewhat spruced up and better tested than it was when I wrote it.

Includes docs & tests.  The whatsnew section needs expanding, and arrays
should support extended slices -- later.
This commit is contained in:
Michael W. Hudson 2002-06-11 10:55:12 +00:00
parent f90ae20354
commit 5efaf7eac8
13 changed files with 570 additions and 22 deletions

View File

@ -2288,6 +2288,32 @@ They are found in the dictionary of type objects.
\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}

View File

@ -433,6 +433,7 @@ equal to \var{x}, else \code{1}}{}
\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,6 +447,7 @@ equal to \var{x}, else \code{1}}{}
\indexii{repetition}{operation}
\indexii{subscript}{operation}
\indexii{slice}{operation}
\indexii{extended slice}{operation}
\opindex{in}
\opindex{not in}
@ -492,6 +494,15 @@ Notes:
\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,31 +886,36 @@ The following operations are defined on mutable sequence types (where
{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}]}}{(1)}
{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}}}{(2)}
{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}}}{(3)}
{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}}{(4)}
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}}}{(5)}
{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})]}}{(3)}
{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)}
{reverses the items of \var{s} in place}{(7)}
\lineiii{\var{s}.sort(\optional{\var{cmpfunc}})}
{sort the items of \var{s} in place}{(6), (7)}
{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,32 +924,35 @@ The following operations are defined on mutable sequence types (where
\noindent
Notes:
\begin{description}
\item[(1)] The C implementation of Python has historically accepted
\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[(2)] Raises an exception when \var{x} is not a list object. The
\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[(3)] Raises \exception{ValueError} when \var{x} is not found in
\item[(4)] 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
\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[(5)] The \method{pop()} method is only supported by the list and
\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[(6)] The \method{sort()} and \method{reverse()} methods modify the
\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[(7)] The \method{sort()} method takes an optional argument
\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

View File

@ -252,6 +252,13 @@ sequence of the same type. This implies that the index set is
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}

View File

@ -336,6 +336,15 @@ strings \samp{True} and \samp{False} instead of \samp{1} and \samp{0}.
\end{seealso}
\section{Extended Slices\label{extended-slices}}
Ever since Python 1.4 the slice syntax has supported a third
``stride'' argument, but the builtin sequence types have not supported
this feature (it was initially included at the behest of the
developers of the Numerical Python package). This changes with Python
2.3.
% XXX examples, etc.
%======================================================================
%\section{Other Language Changes}

View File

@ -32,6 +32,9 @@ DL_IMPORT(PyObject *) PySlice_New(PyObject* start, PyObject* stop,
PyObject* step);
DL_IMPORT(int) PySlice_GetIndices(PySliceObject *r, int length,
int *start, int *stop, int *step);
DL_IMPORT(int) PySlice_GetIndicesEx(PySliceObject *r, int length,
int *start, int *stop,
int *step, int *slicelength);
#ifdef __cplusplus
}

View File

@ -219,7 +219,7 @@ veris(operator.isSequenceType(0), False)
veris(operator.isSequenceType([]), True)
veris(operator.contains([], 1), False)
veris(operator.contains([1], 1), True)
veris(operator.isMappingType([]), False)
veris(operator.isMappingType(1), False)
veris(operator.isMappingType({}), True)
veris(operator.lt(0, 0), False)
veris(operator.lt(0, 1), True)

View File

@ -188,6 +188,31 @@ else: raise TestFailed, 'in/not in string'
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,6 +232,19 @@ if x != (): raise TestFailed, 'tuple inplace add from () to () failed'
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,])'
@ -322,6 +360,40 @@ if a[ -pow(2,128L): 3 ] != [0,1,2]:
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])
a = range(4)
a[::-1] = a
vereq(a, [3, 2, 1, 0])
print '6.6 Mappings == Dictionaries'
d = {}
if d.keys() != []: raise TestFailed, '{}.keys()'

View File

@ -6,6 +6,10 @@ Type/class unification and new-style classes
Core and builtins
- Most builtin sequences now support "extended slices", i.e. slices
with a third "stride" parameter. For example, "range(10)[1:6:2]"
evaluates to [1, 3, 5].
- Cycles going through the __class__ link of a new-style instance are
now detected by the garbage collector.

View File

@ -1684,6 +1684,192 @@ static char list_doc[] =
staticforward PyObject * list_iter(PyObject *seq);
static PyObject*
list_subscript(PyListObject* self, PyObject* item)
{
if (PyInt_Check(item)) {
long i = PyInt_AS_LONG(item);
if (i < 0)
i += PyList_GET_SIZE(self);
return list_item(self, 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(self);
return list_item(self, i);
}
else if (PySlice_Check(item)) {
int start, stop, step, slicelength, cur, i;
PyObject* result;
PyObject* it;
if (PySlice_GetIndicesEx((PySliceObject*)item, self->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(self, 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(PyListObject* self, PyObject* item, PyObject* value)
{
if (PyInt_Check(item)) {
long i = PyInt_AS_LONG(item);
if (i < 0)
i += PyList_GET_SIZE(self);
return list_ass_item(self, 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(self);
return list_ass_item(self, i, value);
}
else if (PySlice_Check(item)) {
int start, stop, step, slicelength;
if (PySlice_GetIndicesEx((PySliceObject*)item, self->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 = (PyObject**)
PyMem_MALLOC(slicelength*sizeof(PyObject*));
/* drawing pictures might help
understand these for loops */
for (cur = start, i = 0; cur < stop; cur += step, i++) {
garbage[i] = PyList_GET_ITEM(self, cur);
for (j = 0; j < step; j++) {
PyList_SET_ITEM(self, cur + j - i,
PyList_GET_ITEM(self, cur + j + 1));
}
}
for (cur = start + slicelength*step + 1;
cur < self->ob_size; cur++) {
PyList_SET_ITEM(self, cur - slicelength,
PyList_GET_ITEM(self, cur));
}
self->ob_size -= slicelength;
item = self->ob_item;
NRESIZE(item, PyObject*, self->ob_size);
self->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 (!slicelength)
return 0;
/* protect against a[::-1] = a */
if (self == (PyListObject*)value) {
value = list_slice((PyListObject*)value, 0,
PyList_GET_SIZE(value));
}
else {
Py_INCREF(value);
}
garbage = (PyObject**)
PyMem_MALLOC(slicelength*sizeof(PyObject*));
for (cur = start, i = 0; i < slicelength;
cur += step, i++) {
garbage[i] = PyList_GET_ITEM(self, cur);
ins = PyList_GET_ITEM(value, i);
Py_INCREF(ins);
PyList_SET_ITEM(self, 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,7 +1884,7 @@ PyTypeObject PyList_Type = {
(reprfunc)list_repr, /* tp_repr */
0, /* tp_as_number */
&list_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
&list_as_mapping, /* tp_as_mapping */
list_nohash, /* tp_hash */
0, /* tp_call */
0, /* tp_str */

View File

@ -109,6 +109,59 @@ PySlice_GetIndices(PySliceObject *r, int length,
return 0;
}
int
PySlice_GetIndicesEx(PySliceObject *r, int length,
int *start, int *stop, int *step, int *slicelength)
{
/* this is harder to get right than you might think */
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)
{

View File

@ -940,6 +940,60 @@ string_hash(PyStringObject *a)
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,6 +1045,12 @@ static PySequenceMethods string_as_sequence = {
(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,7 +2989,7 @@ PyTypeObject PyString_Type = {
(reprfunc)string_repr, /* tp_repr */
0, /* tp_as_number */
&string_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
&string_as_mapping, /* tp_as_mapping */
(hashfunc)string_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)string_str, /* tp_str */
@ -3349,7 +3409,7 @@ PyString_Format(PyObject *format, PyObject *args)
arglen = -1;
argidx = -2;
}
if (args->ob_type->tp_as_mapping)
if (args->ob_type->tp_as_mapping && !PyTuple_Check(args))
dict = args;
while (--fmtcnt >= 0) {
if (*fmt != '%') {

View File

@ -541,6 +541,63 @@ static PySequenceMethods tuple_as_sequence = {
(objobjproc)tuplecontains, /* sq_contains */
};
static PyObject*
tuplesubscript(PyTupleObject* self, PyObject* item)
{
if (PyInt_Check(item)) {
long i = PyInt_AS_LONG(item);
if (i < 0)
i += PyTuple_GET_SIZE(self);
return tupleitem(self, 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(self);
return tupleitem(self, 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(self),
&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(self, 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,7 +612,7 @@ PyTypeObject PyTuple_Type = {
(reprfunc)tuplerepr, /* tp_repr */
0, /* tp_as_number */
&tuple_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
&tuple_as_mapping, /* tp_as_mapping */
(hashfunc)tuplehash, /* tp_hash */
0, /* tp_call */
0, /* tp_str */

View File

@ -5061,6 +5061,58 @@ static PySequenceMethods unicode_as_sequence = {
(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,7 +5407,7 @@ PyObject *PyUnicode_Format(PyObject *format,
arglen = -1;
argidx = -2;
}
if (args->ob_type->tp_as_mapping)
if (args->ob_type->tp_as_mapping && !PyTuple_Check(args))
dict = args;
while (--fmtcnt >= 0) {
@ -5817,7 +5869,7 @@ PyTypeObject PyUnicode_Type = {
(reprfunc) unicode_repr, /* tp_repr */
0, /* tp_as_number */
&unicode_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
&unicode_as_mapping, /* tp_as_mapping */
(hashfunc) unicode_hash, /* tp_hash*/
0, /* tp_call*/
(reprfunc) unicode_str, /* tp_str */