summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2010-09-09 12:59:39 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2010-09-09 12:59:39 (GMT)
commit6e6cc830c4968f040ded1e474db86a9aeb37c33e (patch)
tree4d374c13135309484270452752e97135055d78e0 /Objects
parentbad3c88094f43f3bc7dcce22f47b8c2a8dddabcf (diff)
downloadcpython-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.c85
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;