diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2010-09-09 12:59:39 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2010-09-09 12:59:39 (GMT) |
commit | 6e6cc830c4968f040ded1e474db86a9aeb37c33e (patch) | |
tree | 4d374c13135309484270452752e97135055d78e0 /Objects | |
parent | bad3c88094f43f3bc7dcce22f47b8c2a8dddabcf (diff) | |
download | cpython-6e6cc830c4968f040ded1e474db86a9aeb37c33e.zip cpython-6e6cc830c4968f040ded1e474db86a9aeb37c33e.tar.gz cpython-6e6cc830c4968f040ded1e474db86a9aeb37c33e.tar.bz2 |
Issue #9757: memoryview objects get a release() method to release the
underlying buffer (previously this was only done when deallocating the
memoryview), and gain support for the context management protocol.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/memoryobject.c | 85 |
1 files changed, 75 insertions, 10 deletions
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 802a922..36626b2 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -3,6 +3,23 @@ #include "Python.h" +#define IS_RELEASED(memobj) \ + (((PyMemoryViewObject *) memobj)->view.buf == NULL) + +#define CHECK_RELEASED(memobj) \ + if (IS_RELEASED(memobj)) { \ + PyErr_SetString(PyExc_ValueError, \ + "operation forbidden on released memoryview object"); \ + return NULL; \ + } + +#define CHECK_RELEASED_INT(memobj) \ + if (IS_RELEASED(memobj)) { \ + PyErr_SetString(PyExc_ValueError, \ + "operation forbidden on released memoryview object"); \ + return -1; \ + } + static Py_ssize_t get_shape0(Py_buffer *buf) { @@ -34,6 +51,7 @@ static int memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags) { int res = 0; + CHECK_RELEASED_INT(self); /* XXX for whatever reason fixing the flags seems necessary */ if (self->view.readonly) flags &= ~PyBUF_WRITABLE; @@ -330,12 +348,14 @@ PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort) static PyObject * memory_format_get(PyMemoryViewObject *self) { + CHECK_RELEASED(self); return PyUnicode_FromString(self->view.format); } static PyObject * memory_itemsize_get(PyMemoryViewObject *self) { + CHECK_RELEASED(self); return PyLong_FromSsize_t(self->view.itemsize); } @@ -366,30 +386,35 @@ _IntTupleFromSsizet(int len, Py_ssize_t *vals) static PyObject * memory_shape_get(PyMemoryViewObject *self) { + CHECK_RELEASED(self); return _IntTupleFromSsizet(self->view.ndim, self->view.shape); } static PyObject * memory_strides_get(PyMemoryViewObject *self) { + CHECK_RELEASED(self); return _IntTupleFromSsizet(self->view.ndim, self->view.strides); } static PyObject * memory_suboffsets_get(PyMemoryViewObject *self) { + CHECK_RELEASED(self); return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets); } static PyObject * memory_readonly_get(PyMemoryViewObject *self) { + CHECK_RELEASED(self); return PyBool_FromLong(self->view.readonly); } static PyObject * memory_ndim_get(PyMemoryViewObject *self) { + CHECK_RELEASED(self); return PyLong_FromLong(self->view.ndim); } @@ -408,6 +433,7 @@ static PyGetSetDef memory_getsetlist[] ={ static PyObject * memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs) { + CHECK_RELEASED(mem); return PyObject_CallFunctionObjArgs( (PyObject *) &PyBytes_Type, mem, NULL); } @@ -423,6 +449,7 @@ memory_tolist(PyMemoryViewObject *mem, PyObject *noargs) PyObject *res, *item; char *buf; + CHECK_RELEASED(mem); if (strcmp(view->format, "B") || view->itemsize != 1) { PyErr_SetString(PyExc_NotImplementedError, "tolist() only supports byte views"); @@ -449,17 +476,9 @@ 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}, - {NULL, NULL} /* sentinel */ -}; - - static void -memory_dealloc(PyMemoryViewObject *self) +do_release(PyMemoryViewObject *self) { - _PyObject_GC_UNTRACK(self); if (self->view.obj != NULL) { if (self->base && PyTuple_Check(self->base)) { /* Special case when first element is generic object @@ -484,19 +503,57 @@ memory_dealloc(PyMemoryViewObject *self) } Py_CLEAR(self->base); } + self->view.obj = NULL; + self->view.buf = NULL; +} + +static PyObject * +memory_enter(PyObject *self, PyObject *args) +{ + CHECK_RELEASED(self); + Py_INCREF(self); + return self; +} + +static PyObject * +memory_exit(PyObject *self, PyObject *args) +{ + do_release((PyMemoryViewObject *) self); + Py_RETURN_NONE; +} + +static PyMethodDef memory_methods[] = { + {"release", memory_exit, METH_NOARGS}, + {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL}, + {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL}, + {"__enter__", memory_enter, METH_NOARGS}, + {"__exit__", memory_exit, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + + +static void +memory_dealloc(PyMemoryViewObject *self) +{ + _PyObject_GC_UNTRACK(self); + do_release(self); PyObject_GC_Del(self); } static PyObject * memory_repr(PyMemoryViewObject *self) { - return PyUnicode_FromFormat("<memory at %p>", self); + if (IS_RELEASED(self)) + return PyUnicode_FromFormat("<released memory at %p>", self); + else + return PyUnicode_FromFormat("<memory at %p>", self); } /* Sequence methods */ static Py_ssize_t memory_length(PyMemoryViewObject *self) { + CHECK_RELEASED_INT(self); return get_shape0(&self->view); } @@ -508,6 +565,7 @@ memory_item(PyMemoryViewObject *self, Py_ssize_t result) { Py_buffer *view = &(self->view); + CHECK_RELEASED(self); if (view->ndim == 0) { PyErr_SetString(PyExc_IndexError, "invalid indexing of 0-dim memory"); @@ -557,6 +615,7 @@ memory_subscript(PyMemoryViewObject *self, PyObject *key) Py_buffer *view; view = &(self->view); + CHECK_RELEASED(self); if (view->ndim == 0) { if (key == Py_Ellipsis || (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) { @@ -626,6 +685,7 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value) Py_buffer *view = &(self->view); char *srcbuf, *destbuf; + CHECK_RELEASED_INT(self); if (view->readonly) { PyErr_SetString(PyExc_TypeError, "cannot modify read-only memory"); @@ -718,6 +778,11 @@ memory_richcompare(PyObject *v, PyObject *w, int op) ww.obj = NULL; if (op != Py_EQ && op != Py_NE) goto _notimpl; + if ((PyMemoryView_Check(v) && IS_RELEASED(v)) || + (PyMemoryView_Check(w) && IS_RELEASED(w))) { + equal = (v == w); + goto _end; + } if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) { PyErr_Clear(); goto _notimpl; |