mirror of
https://github.com/python/cpython.git
synced 2026-01-06 15:32:22 +00:00
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.
This commit is contained in:
parent
bad3c88094
commit
6e6cc830c4
4 changed files with 158 additions and 11 deletions
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue