Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
370 lines (310 sloc) 10.7 KB
#include "_pymodule.h"
static int get_writable_buffer(PyObject* obj, Py_buffer *buf, int force)
{
Py_buffer read_buf;
int flags = PyBUF_ND|PyBUF_STRIDES|PyBUF_FORMAT;
int ret;
/* Attempt to get a writable buffer */
if (!PyObject_GetBuffer(obj, buf, flags|PyBUF_WRITABLE))
return 0;
if (!force)
return -1;
/* Make a writable buffer from a read-only buffer */
PyErr_Clear();
if(-1 == PyObject_GetBuffer(obj, &read_buf, flags))
return -1;
ret = PyBuffer_FillInfo(buf, NULL, read_buf.buf, read_buf.len, 0,
flags|PyBUF_WRITABLE);
PyBuffer_Release(&read_buf);
return ret;
}
static int get_readonly_buffer(PyObject* obj, Py_buffer *buf)
{
int flags = PyBUF_ND|PyBUF_STRIDES|PyBUF_FORMAT;
return PyObject_GetBuffer(obj, buf, flags);
}
static void free_buffer(Py_buffer * buf)
{
PyBuffer_Release(buf);
}
/**
* Return a pointer to the data of a writable buffer from obj. If only a
* read-only buffer is available and force is True, a read-write buffer based on
* the read-only buffer is obtained. Note that this may have some surprising
* effects on buffers which expect the data from their read-only buffer not to
* be modified.
*/
static PyObject*
memoryview_get_buffer(PyObject *self, PyObject *args){
PyObject *obj = NULL;
int force = 0;
int readonly = 0;
PyObject *ret = NULL;
Py_buffer buf;
if (!PyArg_ParseTuple(args, "O|ii", &obj, &force, &readonly))
return NULL;
if (readonly) {
if (get_readonly_buffer(obj, &buf))
return NULL;
} else {
if (get_writable_buffer(obj, &buf, force))
return NULL;
}
ret = PyLong_FromVoidPtr(buf.buf);
free_buffer(&buf);
return ret;
}
/**
* Gets a half-open range [start, end) which contains the array data
* Modified from numpy/core/src/multiarray/array_assign.c
*/
static PyObject*
get_extents(Py_ssize_t *shape, Py_ssize_t *strides, int ndim,
Py_ssize_t itemsize, Py_ssize_t ptr)
{
Py_ssize_t start, end;
int idim;
Py_ssize_t *dimensions = shape;
PyObject *ret = NULL;
if (ndim < 0 ){
PyErr_SetString(PyExc_ValueError, "buffer ndim < 0");
return NULL;
}
if (!dimensions) {
if (ndim == 0) {
start = end = ptr;
end += itemsize;
return Py_BuildValue("nn", start, end);
}
PyErr_SetString(PyExc_ValueError, "buffer shape is not defined");
return NULL;
}
if (!strides) {
PyErr_SetString(PyExc_ValueError, "buffer strides is not defined");
return NULL;
}
/* Calculate with a closed range [start, end] */
start = end = ptr;
for (idim = 0; idim < ndim; ++idim) {
Py_ssize_t stride = strides[idim], dim = dimensions[idim];
/* If the array size is zero, return an empty range */
if (dim == 0) {
start = end = ptr;
ret = Py_BuildValue("nn", start, end);
break;
}
/* Expand either upwards or downwards depending on stride */
else {
if (stride > 0) {
end += stride * (dim - 1);
}
else if (stride < 0) {
start += stride * (dim - 1);
}
}
}
if (!ret) {
/* Return a half-open range */
Py_ssize_t out_start = start;
Py_ssize_t out_end = end + itemsize;
ret = Py_BuildValue("nn", out_start, out_end);
}
return ret;
}
static PyObject*
memoryview_get_extents(PyObject *self, PyObject *args)
{
PyObject *obj = NULL;
PyObject *ret = NULL;
Py_buffer b;
if (!PyArg_ParseTuple(args, "O", &obj))
return NULL;
if (get_readonly_buffer(obj, &b))
return NULL;
ret = get_extents(b.shape, b.strides, b.ndim, b.itemsize,
(Py_ssize_t)b.buf);
free_buffer(&b);
return ret;
}
static PyObject*
memoryview_get_extents_info(PyObject *self, PyObject *args)
{
int i;
Py_ssize_t *shape_ary = NULL;
Py_ssize_t *strides_ary = NULL;
PyObject *shape_tuple = NULL;
PyObject *strides_tuple = NULL;
PyObject *shape = NULL, *strides = NULL;
Py_ssize_t itemsize = 0;
int ndim = 0;
PyObject* res = NULL;
if (!PyArg_ParseTuple(args, "OOin", &shape, &strides, &ndim, &itemsize))
goto cleanup;
if (ndim < 0) {
PyErr_SetString(PyExc_ValueError, "ndim is negative");
goto cleanup;
}
if (itemsize <= 0) {
PyErr_SetString(PyExc_ValueError, "ndim <= 0");
goto cleanup;
}
shape_ary = malloc(sizeof(Py_ssize_t) * ndim + 1);
strides_ary = malloc(sizeof(Py_ssize_t) * ndim + 1);
shape_tuple = PySequence_Fast(shape, "shape is not a sequence");
if (!shape_tuple) goto cleanup;
for (i = 0; i < ndim; ++i) {
shape_ary[i] = PyNumber_AsSsize_t(
PySequence_Fast_GET_ITEM(shape_tuple, i),
PyExc_OverflowError);
}
strides_tuple = PySequence_Fast(strides, "strides is not a sequence");
if (!strides_tuple) goto cleanup;
for (i = 0; i < ndim; ++i) {
strides_ary[i] = PyNumber_AsSsize_t(
PySequence_Fast_GET_ITEM(strides_tuple, i),
PyExc_OverflowError);
}
res = get_extents(shape_ary, strides_ary, ndim, itemsize, 0);
cleanup:
free(shape_ary);
free(strides_ary);
Py_XDECREF(shape_tuple);
Py_XDECREF(strides_tuple);
return res;
}
/* new type to expose buffer interface */
typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
} MemAllocObject;
static int
get_bufinfo(PyObject *self, Py_ssize_t *psize, void **pptr)
{
PyObject *buflen = NULL;
PyObject *bufptr = NULL;
Py_ssize_t size = 0;
void* ptr = NULL;
int ret = -1;
buflen = PyObject_GetAttrString(self, "_buflen_");
if (!buflen) goto cleanup;
bufptr = PyObject_GetAttrString(self, "_bufptr_");
if (!bufptr) goto cleanup;
size = PyNumber_AsSsize_t(buflen, PyExc_OverflowError);
if (size == -1 && PyErr_Occurred()) goto cleanup;
else if (size < 0) {
PyErr_SetString(PyExc_ValueError, "negative buffer size");
goto cleanup;
}
ptr = PyLong_AsVoidPtr(PyNumber_Long(bufptr));
if (PyErr_Occurred())
goto cleanup;
else if (!ptr) {
PyErr_SetString(PyExc_ValueError, "null buffer pointer");
goto cleanup;
}
*psize = size;
*pptr = ptr;
ret = 0;
cleanup:
Py_XDECREF(buflen);
Py_XDECREF(bufptr);
return ret;
}
static int
MemAllocObject_getbuffer(PyObject *self, Py_buffer *view, int flags)
{
Py_ssize_t size = 0;
void *ptr = 0;
int readonly;
if(-1 == get_bufinfo(self, &size, &ptr))
return -1;
readonly = (PyBUF_WRITABLE & flags) != PyBUF_WRITABLE;
/* fill buffer */
if (-1 == PyBuffer_FillInfo(view, self, (void*)ptr, size, readonly, flags))
return -1;
return 0;
}
static void
MemAllocObject_releasebuffer(PyObject *self, Py_buffer *view)
{
/* Do nothing */
}
static PyBufferProcs MemAlloc_as_buffer = {
MemAllocObject_getbuffer,
MemAllocObject_releasebuffer,
};
static PyTypeObject MemAllocType = {
PyVarObject_HEAD_INIT(NULL, 0)
"mviewbuf.MemAlloc", /* tp_name */
sizeof(MemAllocObject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
#if PY_MAJOR_VERSION >= 3
0, /* tp_reserved */
#else
0, /* tp_compare */
#endif
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
&MemAlloc_as_buffer, /*tp_as_buffer*/
(Py_TPFLAGS_DEFAULT| Py_TPFLAGS_BASETYPE), /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
0, /* tp_free */
0, /* tp_is_gc */
0, /* tp_bases */
0, /* tp_mro */
0, /* tp_cache */
0, /* tp_subclasses */
0, /* tp_weaklist */
0, /* tp_del */
0, /* tp_version_tag */
};
static PyMethodDef core_methods[] = {
#define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL }
declmethod(memoryview_get_buffer),
declmethod(memoryview_get_extents),
declmethod(memoryview_get_extents_info),
{ NULL },
#undef declmethod
};
MOD_INIT(mviewbuf) {
PyObject *module;
MOD_DEF(module, "mviewbuf", "No docs", core_methods)
if (module == NULL)
return MOD_ERROR_VAL;
MemAllocType.tp_new = PyType_GenericNew;
if (PyType_Ready(&MemAllocType) < 0){
return MOD_ERROR_VAL;
}
Py_INCREF(&MemAllocType);
PyModule_AddObject(module, "MemAlloc", (PyObject*)&MemAllocType);
return MOD_SUCCESS_VAL(module);
}
You can’t perform that action at this time.