diff options
author | Thomas Wouters <thomas@python.org> | 2007-08-28 15:28:19 (GMT) |
---|---|---|
committer | Thomas Wouters <thomas@python.org> | 2007-08-28 15:28:19 (GMT) |
commit | 3ccec68a05abae43cf74dc7821c61ba88ab6cb46 (patch) | |
tree | 07e97200d168eec13110e16a11b974310b8b550a /Objects/bufferobject.c | |
parent | 0f4a14b56fcbd939e60f424517db61ca6f2f3885 (diff) | |
download | cpython-3ccec68a05abae43cf74dc7821c61ba88ab6cb46.zip cpython-3ccec68a05abae43cf74dc7821c61ba88ab6cb46.tar.gz cpython-3ccec68a05abae43cf74dc7821c61ba88ab6cb46.tar.bz2 |
Improve extended slicing support in builtin types and classes. Specifically:
- Specialcase extended slices that amount to a shallow copy the same way as
is done for simple slices, in the tuple, string and unicode case.
- Specialcase step-1 extended slices to optimize the common case for all
involved types.
- For lists, allow extended slice assignment of differing lengths as long
as the step is 1. (Previously, 'l[:2:1] = []' failed even though
'l[:2] = []' and 'l[:2:None] = []' do not.)
- Implement extended slicing for buffer, array, structseq, mmap and
UserString.UserString.
- Implement slice-object support (but not non-step-1 slice assignment) for
UserString.MutableString.
- Add tests for all new functionality.
Diffstat (limited to 'Objects/bufferobject.c')
-rw-r--r-- | Objects/bufferobject.c | 155 |
1 files changed, 154 insertions, 1 deletions
diff --git a/Objects/bufferobject.c b/Objects/bufferobject.c index 98be771..13442c9 100644 --- a/Objects/bufferobject.c +++ b/Objects/bufferobject.c @@ -472,6 +472,61 @@ buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right) right - left); } +static PyObject * +buffer_subscript(PyBufferObject *self, PyObject *item) +{ + void *p; + Py_ssize_t size; + + if (!get_buf(self, &p, &size, ANY_BUFFER)) + return NULL; + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += size; + return buffer_item(self, i); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength, cur, i; + + if (PySlice_GetIndicesEx((PySliceObject*)item, size, + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + if (slicelength <= 0) + return PyString_FromStringAndSize("", 0); + else if (step == 1) + return PyString_FromStringAndSize((char *)p + start, + stop - start); + else { + PyObject *result; + char *source_buf = (char *)p; + char *result_buf = (char *)PyMem_Malloc(slicelength); + + if (result_buf == NULL) + return PyErr_NoMemory(); + + 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, + "sequence index must be integer"); + return NULL; + } +} + static int buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other) { @@ -581,6 +636,98 @@ buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObje return 0; } +static int +buffer_ass_subscript(PyBufferObject *self, PyObject *item, PyObject *value) +{ + PyBufferProcs *pb; + void *ptr1, *ptr2; + Py_ssize_t selfsize; + Py_ssize_t othersize; + + if ( self->b_readonly ) { + PyErr_SetString(PyExc_TypeError, + "buffer is read-only"); + return -1; + } + + pb = value ? value->ob_type->tp_as_buffer : NULL; + if ( pb == NULL || + pb->bf_getreadbuffer == NULL || + pb->bf_getsegcount == NULL ) + { + PyErr_BadArgument(); + return -1; + } + if ( (*pb->bf_getsegcount)(value, NULL) != 1 ) + { + /* ### use a different exception type/message? */ + PyErr_SetString(PyExc_TypeError, + "single-segment buffer object expected"); + return -1; + } + if (!get_buf(self, &ptr1, &selfsize, ANY_BUFFER)) + return -1; + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += selfsize; + return buffer_ass_item(self, i, value); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((PySliceObject *)item, selfsize, + &start, &stop, &step, &slicelength) < 0) + return -1; + + pb = value ? value->ob_type->tp_as_buffer : NULL; + if (pb == NULL || + pb->bf_getreadbuffer == NULL || + pb->bf_getsegcount == NULL) { + PyErr_BadArgument(); + return -1; + } + if ((*pb->bf_getsegcount)(value, NULL) != 1) { + /* ### use a different exception type/message? */ + PyErr_SetString(PyExc_TypeError, + "single-segment buffer object expected"); + return -1; + } + if ((othersize = (*pb->bf_getreadbuffer)(value, 0, &ptr2)) < 0) + return -1; + + if (othersize != slicelength) { + PyErr_SetString( + PyExc_TypeError, + "right operand length must match slice length"); + return -1; + } + + if (slicelength == 0) + return 0; + else if (step == 1) { + memcpy((char *)ptr1 + start, ptr2, slicelength); + return 0; + } + else { + Py_ssize_t cur, i; + + for (cur = start, i = 0; i < slicelength; + cur += step, i++) { + ((char *)ptr1)[cur] = ((char *)ptr2)[i]; + } + + return 0; + } + } else { + PyErr_SetString(PyExc_TypeError, + "buffer indices must be integers"); + return -1; + } +} + /* Buffer methods */ static Py_ssize_t @@ -656,6 +803,12 @@ static PySequenceMethods buffer_as_sequence = { (ssizessizeobjargproc)buffer_ass_slice, /*sq_ass_slice*/ }; +static PyMappingMethods buffer_as_mapping = { + (lenfunc)buffer_length, + (binaryfunc)buffer_subscript, + (objobjargproc)buffer_ass_subscript, +}; + static PyBufferProcs buffer_as_buffer = { (readbufferproc)buffer_getreadbuf, (writebufferproc)buffer_getwritebuf, @@ -676,7 +829,7 @@ PyTypeObject PyBuffer_Type = { (reprfunc)buffer_repr, /* tp_repr */ 0, /* tp_as_number */ &buffer_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ + &buffer_as_mapping, /* tp_as_mapping */ (hashfunc)buffer_hash, /* tp_hash */ 0, /* tp_call */ (reprfunc)buffer_str, /* tp_str */ |