summaryrefslogtreecommitdiffstats
path: root/Objects/memoryobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/memoryobject.c')
-rw-r--r--Objects/memoryobject.c138
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 */