summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2009-01-03 16:59:18 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2009-01-03 16:59:18 (GMT)
commitc3b39245a7695cf39ba5524f59deeff52b00e5f9 (patch)
tree9736aa9a6d7c03b55eeb7d362a53f91d6000dda3 /Objects
parent8bcddcabd770dd424b97d7c667ef8e5337436215 (diff)
downloadcpython-c3b39245a7695cf39ba5524f59deeff52b00e5f9.zip
cpython-c3b39245a7695cf39ba5524f59deeff52b00e5f9.tar.gz
cpython-c3b39245a7695cf39ba5524f59deeff52b00e5f9.tar.bz2
Issue #4580: slicing of memoryviews when itemsize != 1 is wrong.
Also fix len() to return number of items rather than length in bytes. I'm sorry it was not possible for me to work on this without reindenting a bit some stuff around. The indentation in memoryobject.c is a mess, I'll open a separate bug for it.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/memoryobject.c131
-rw-r--r--Objects/unicodeobject.c2
2 files changed, 64 insertions, 69 deletions
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c
index f96fcbe..df89313 100644
--- a/Objects/memoryobject.c
+++ b/Objects/memoryobject.c
@@ -3,26 +3,31 @@
#include "Python.h"
-static void
-dup_buffer(Py_buffer *dest, Py_buffer *src)
-{
- *dest = *src;
- if (src->shape == &(src->len))
- dest->shape = &(dest->len);
- if (src->strides == &(src->itemsize))
- dest->strides = &(dest->itemsize);
-}
-
-/* XXX The buffer API should mandate that the shape array be non-NULL, but
- it would complicate some code since the (de)allocation semantics of shape
- are not specified. */
static Py_ssize_t
get_shape0(Py_buffer *buf)
{
if (buf->shape != NULL)
return buf->shape[0];
- assert(buf->ndim == 1 && buf->itemsize > 0);
- return buf->len / buf->itemsize;
+ if (buf->ndim == 0)
+ return 1;
+ PyErr_SetString(PyExc_TypeError,
+ "exported buffer does not have any shape information associated "
+ "to it");
+ return -1;
+}
+
+static void
+dup_buffer(Py_buffer *dest, Py_buffer *src)
+{
+ *dest = *src;
+ if (src->ndim == 1 && src->shape != NULL) {
+ dest->shape = &(dest->smalltable[0]);
+ dest->shape[0] = get_shape0(src);
+ }
+ if (src->ndim == 1 && src->strides != NULL) {
+ dest->strides = &(dest->smalltable[1]);
+ dest->strides[0] = src->strides[0];
+ }
}
static int
@@ -449,8 +454,6 @@ memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
return res;
}
-
-
static PyMethodDef memory_methods[] = {
{"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
{"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
@@ -474,19 +477,19 @@ memory_dealloc(PyMemoryViewObject *self)
PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
PyTuple_GET_ITEM(self->base,1));
- /* The view member should have readonly == -1 in
- this instance indicating that the memory can
- be "locked" and was locked and will be unlocked
- again after this call.
- */
- PyBuffer_Release(&(self->view));
- }
- else {
- PyBuffer_Release(&(self->view));
- }
- Py_CLEAR(self->base);
+ /* The view member should have readonly == -1 in
+ this instance indicating that the memory can
+ be "locked" and was locked and will be unlocked
+ again after this call.
+ */
+ PyBuffer_Release(&(self->view));
}
- PyObject_GC_Del(self);
+ else {
+ PyBuffer_Release(&(self->view));
+ }
+ Py_CLEAR(self->base);
+ }
+ PyObject_GC_Del(self);
}
static PyObject *
@@ -512,16 +515,10 @@ memory_str(PyMemoryViewObject *self)
}
/* Sequence methods */
-
static Py_ssize_t
memory_length(PyMemoryViewObject *self)
{
- Py_buffer view;
-
- if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
- return -1;
- PyBuffer_Release(&view);
- return view.len;
+ return get_shape0(&self->view);
}
/*
@@ -589,40 +586,38 @@ memory_subscript(PyMemoryViewObject *self, PyObject *key)
}
}
else if (PySlice_Check(key)) {
- Py_ssize_t start, stop, step, slicelength;
-
+ Py_ssize_t start, stop, step, slicelength;
+
if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
- &start, &stop, &step, &slicelength) < 0) {
- return NULL;
- }
+ &start, &stop, &step, &slicelength) < 0) {
+ return NULL;
+ }
- if (step == 1 && view->ndim == 1) {
- Py_buffer newview;
- void *newbuf = (char *) view->buf
- + start * view->itemsize;
- int newflags = view->readonly
- ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
+ if (step == 1 && view->ndim == 1) {
+ Py_buffer newview;
+ void *newbuf = (char *) view->buf
+ + start * view->itemsize;
+ int newflags = view->readonly
+ ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
- /* XXX There should be an API to create a subbuffer */
- if (view->obj != NULL) {
- if (PyObject_GetBuffer(view->obj,
- &newview, newflags) == -1)
- return NULL;
- }
- else {
- newview = *view;
- }
- newview.buf = newbuf;
- newview.len = slicelength;
- newview.format = view->format;
- if (view->shape == &(view->len))
- newview.shape = &(newview.len);
- if (view->strides == &(view->itemsize))
- newview.strides = &(newview.itemsize);
- return PyMemoryView_FromBuffer(&newview);
- }
- PyErr_SetNone(PyExc_NotImplementedError);
- return NULL;
+ /* XXX There should be an API to create a subbuffer */
+ if (view->obj != NULL) {
+ if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
+ return NULL;
+ }
+ else {
+ newview = *view;
+ }
+ newview.buf = newbuf;
+ newview.len = slicelength * newview.itemsize;
+ newview.format = view->format;
+ newview.shape = &(newview.smalltable[0]);
+ newview.shape[0] = slicelength;
+ newview.strides = &(newview.itemsize);
+ return PyMemoryView_FromBuffer(&newview);
+ }
+ PyErr_SetNone(PyExc_NotImplementedError);
+ return NULL;
}
PyErr_Format(PyExc_TypeError,
"cannot index memory using \"%.200s\"",
@@ -747,7 +742,7 @@ memory_richcompare(PyObject *v, PyObject *w, int op)
if (vv.itemsize != ww.itemsize || vv.len != ww.len)
goto _end;
- equal = !memcmp(vv.buf, ww.buf, vv.len * vv.itemsize);
+ equal = !memcmp(vv.buf, ww.buf, vv.len);
_end:
PyBuffer_Release(&vv);
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 3a33429..8316e91 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -1205,7 +1205,7 @@ PyObject *PyUnicode_Decode(const char *s,
/* Decode via the codec registry */
buffer = NULL;
- if (PyBuffer_FillInfo(&info, NULL, (void *)s, size, 1, PyBUF_SIMPLE) < 0)
+ if (PyBuffer_FillInfo(&info, NULL, (void *)s, size, 1, PyBUF_FULL_RO) < 0)
goto onError;
buffer = PyMemoryView_FromBuffer(&info);
if (buffer == NULL)