diff options
Diffstat (limited to 'Objects/memoryobject.c')
-rw-r--r-- | Objects/memoryobject.c | 138 |
1 files changed, 83 insertions, 55 deletions
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 9b77ea7..2e32b2a 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); if (self->view.obj != NULL) res = PyObject_GetBuffer(self->view.obj, view, flags); if (view) @@ -57,11 +75,15 @@ PyMemoryView_FromBuffer(Py_buffer *info) { PyMemoryViewObject *mview; + if (info->buf == NULL) { + PyErr_SetString(PyExc_ValueError, + "cannot make memory view from a buffer with a NULL data pointer"); + return NULL; + } mview = (PyMemoryViewObject *) PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type); if (mview == NULL) return NULL; - mview->base = NULL; dup_buffer(&mview->view, info); /* NOTE: mview->view.obj should already have been incref'ed as part of PyBuffer_FillInfo(). */ @@ -91,8 +113,6 @@ PyMemoryView_FromObject(PyObject *base) return NULL; } - mview->base = base; - Py_INCREF(base); return (PyObject *)mview; } @@ -270,8 +290,6 @@ PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort) if (PyBuffer_IsContiguous(view, fort)) { /* no copy needed */ - Py_INCREF(obj); - mem->base = obj; _PyObject_GC_TRACK(mem); return (PyObject *)mem; } @@ -303,21 +321,7 @@ PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort) Py_DECREF(mem); return NULL; } - } - if (buffertype == PyBUF_SHADOW) { - /* return a shadowed memory-view object */ - view->buf = dest; - mem->base = PyTuple_Pack(2, obj, bytes); - Py_DECREF(bytes); - if (mem->base == NULL) { - Py_DECREF(mem); - return NULL; - } - } - else { PyBuffer_Release(view); /* XXX ? */ - /* steal the reference */ - mem->base = bytes; } _PyObject_GC_TRACK(mem); return (PyObject *)mem; @@ -327,12 +331,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); } @@ -348,8 +354,9 @@ _IntTupleFromSsizet(int len, Py_ssize_t *vals) return Py_None; } intTuple = PyTuple_New(len); - if (!intTuple) return NULL; - for(i=0; i<len; i++) { + if (!intTuple) + return NULL; + for (i=0; i<len; i++) { o = PyLong_FromSsize_t(vals[i]); if (!o) { Py_DECREF(intTuple); @@ -363,30 +370,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); } @@ -405,6 +417,7 @@ static PyGetSetDef memory_getsetlist[] ={ static PyObject * memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs) { + CHECK_RELEASED(mem); return PyObject_CallFunctionObjArgs( (PyObject *) &PyBytes_Type, mem, NULL); } @@ -420,6 +433,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"); @@ -446,9 +460,37 @@ memory_tolist(PyMemoryViewObject *mem, PyObject *noargs) return res; } +static void +do_release(PyMemoryViewObject *self) +{ + if (self->view.obj != NULL) { + PyBuffer_Release(&(self->view)); + } + 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 */ }; @@ -457,43 +499,24 @@ static void memory_dealloc(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 - with buffer interface and the second element is a - contiguous "shadow" that must be copied back into - the data areay of the first tuple element before - releasing the buffer on the first element. - */ - - 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); - } + 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); } @@ -505,6 +528,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"); @@ -554,6 +578,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)) { @@ -576,7 +601,7 @@ memory_subscript(PyMemoryViewObject *self, PyObject *key) else if (PySlice_Check(key)) { Py_ssize_t start, stop, step, slicelength; - if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view), + if (PySlice_GetIndicesEx(key, get_shape0(view), &start, &stop, &step, &slicelength) < 0) { return NULL; } @@ -623,6 +648,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"); @@ -654,7 +680,7 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value) else if (PySlice_Check(key)) { Py_ssize_t stop, step; - if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view), + if (PySlice_GetIndicesEx(key, get_shape0(view), &start, &stop, &step, &len) < 0) { return -1; } @@ -715,6 +741,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; @@ -750,8 +781,6 @@ _notimpl: static int memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg) { - if (self->base != NULL) - Py_VISIT(self->base); if (self->view.obj != NULL) Py_VISIT(self->view.obj); return 0; @@ -760,7 +789,6 @@ memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg) static int memory_clear(PyMemoryViewObject *self) { - Py_CLEAR(self->base); PyBuffer_Release(&self->view); return 0; } @@ -774,10 +802,10 @@ static PyMappingMethods memory_as_mapping = { }; static PySequenceMethods memory_as_sequence = { - 0, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - (ssizeargfunc)memory_item, /* sq_item */ + 0, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + (ssizeargfunc)memory_item, /* sq_item */ }; /* Buffer methods */ |