Implement buffer protocol for RPNIFS class
This commit is contained in:
parent
7c335fcff0
commit
d25529c5c6
4 changed files with 145 additions and 62 deletions
139
python_if.c
139
python_if.c
|
|
@ -889,71 +889,22 @@ int rpnif_getbuffer(PyObject *self, Py_buffer *view, int flags)
|
|||
PyRPNIterExpr_t *expr_self;
|
||||
expr_self = (PyRPNIterExpr_t*)self;
|
||||
|
||||
return PyObject_GetBuffer(expr_self->mmap, view, flags);
|
||||
|
||||
rpn_if_default_data_t *data = (rpn_if_default_data_t*)expr_self->rif->params->data;
|
||||
|
||||
view->buf = expr_self->rif->mem;
|
||||
view->obj = self;
|
||||
view->len = expr_self->rif->params->mem_sz * expr_self->rif->params->value_sz;
|
||||
view->readonly = 0;
|
||||
//view->itemsize = expr_self->rif->params->value_sz;
|
||||
view->itemsize = sizeof(rpn_value_t);
|
||||
if(flags & PyBUF_FORMAT)
|
||||
if(expr_self->mmap)
|
||||
{
|
||||
view->format = "L";
|
||||
return PyObject_GetBuffer(expr_self->mmap, view, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
view->format = NULL;
|
||||
}
|
||||
view->ndim = 1;
|
||||
view->shape = NULL;
|
||||
if(flags & PyBUF_ND)
|
||||
{
|
||||
view->ndim = expr_self->ndim;
|
||||
|
||||
// !! Error if value_sz < sizeof(rpn_value_t) !!
|
||||
short nval = view->itemsize / sizeof(rpn_value_t);
|
||||
if(nval > 1)
|
||||
{
|
||||
view->ndim++;
|
||||
}
|
||||
view->shape = malloc(sizeof(Py_ssize_t) * view->ndim);
|
||||
if(!view->shape)
|
||||
{
|
||||
goto buff_error;
|
||||
}
|
||||
for(size_t i=0; i<expr_self->ndim; i++)
|
||||
{
|
||||
int idx = i;
|
||||
if(data->pos_flag == RPN_IF_POSITION_XDIM)
|
||||
{
|
||||
idx++;
|
||||
}
|
||||
view->shape[i] = data->size_lim[idx];
|
||||
}
|
||||
if(nval>1)
|
||||
{
|
||||
view->shape[expr_self->ndim] = nval;
|
||||
}
|
||||
}
|
||||
view->strides = NULL;
|
||||
view->suboffsets = NULL;
|
||||
|
||||
Py_INCREF(self);
|
||||
return 0;
|
||||
|
||||
buff_error:
|
||||
PyErr_Format(PyExc_BufferError,
|
||||
"Unable to provide buffer : %s", strerror(errno));
|
||||
view->obj = NULL;
|
||||
return -1;
|
||||
return _rpnif_getbuffer_nopymap(self, expr_self->rif->params,
|
||||
expr_self->_mmap, view, flags);
|
||||
}
|
||||
|
||||
void rpnif_releasebuffer(PyObject *self, Py_buffer *view)
|
||||
{
|
||||
free(view->shape);
|
||||
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
|
||||
if(expr_self->mmap)
|
||||
{
|
||||
return PyBuffer_Release(view);
|
||||
}
|
||||
return _rpnif_releasebuffer_nopymap(self, view);
|
||||
}
|
||||
|
||||
PyObject* rpnif_str(PyObject *self)
|
||||
|
|
@ -1676,6 +1627,76 @@ err:
|
|||
}
|
||||
|
||||
|
||||
int _rpnif_getbuffer_nopymap(PyObject *self, const rpn_if_param_t *params,
|
||||
void *buf, Py_buffer *view, int flags)
|
||||
{
|
||||
rpn_if_default_data_t *data = (rpn_if_default_data_t*)params->data;
|
||||
|
||||
view->buf = buf;
|
||||
view->obj = self;
|
||||
view->len = params->mem_sz * params->value_sz;
|
||||
view->readonly = 0;
|
||||
view->itemsize = sizeof(rpn_value_t);
|
||||
view->format = (flags & PyBUF_FORMAT)?"L":NULL;
|
||||
view->ndim = 1;
|
||||
view->shape = NULL;
|
||||
if(flags & PyBUF_ND)
|
||||
{
|
||||
short nval;
|
||||
switch(data->res_flag)
|
||||
{
|
||||
case RPN_IF_RES_BOOL:
|
||||
case RPN_IF_RES_CONST:
|
||||
case RPN_IF_RES_COUNT:
|
||||
nval = 1;
|
||||
break;
|
||||
case RPN_IF_RES_RGBA:
|
||||
case RPN_IF_RES_CONST_RGBA:
|
||||
nval = 4;
|
||||
break;
|
||||
case RPN_IF_RES_RGB:
|
||||
nval = 3;
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_BufferError,
|
||||
"Unsupported result flag");
|
||||
return -1;
|
||||
}
|
||||
view->ndim += (nval>1)?1:0;
|
||||
if(!(view->shape = malloc(sizeof(Py_ssize_t) * view->ndim)))
|
||||
{
|
||||
PyErr_Format(PyExc_BufferError,
|
||||
"Buffer's shape allocation error : %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
for(size_t i=0; i<data->ndim; i++)
|
||||
{
|
||||
const int idx = i + \
|
||||
(data->pos_flag == RPN_IF_POSITION_XDIM)?1:0;
|
||||
view->shape[i] = data->size_lim[idx];
|
||||
}
|
||||
if(nval>1)
|
||||
{
|
||||
view->shape[data->ndim] = nval;
|
||||
}
|
||||
|
||||
}
|
||||
view->strides = NULL;
|
||||
view->suboffsets = NULL;
|
||||
Py_INCREF(self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void _rpnif_releasebuffer_nopymap(PyObject *self, Py_buffer *view)
|
||||
{
|
||||
if(view->shape) { free(view->shape); }
|
||||
view->buf = NULL;
|
||||
Py_DECREF(self);
|
||||
}
|
||||
|
||||
|
||||
int _rpnif_init_expr_tuple(PyRPNIterExpr_t *expr_self)
|
||||
{
|
||||
expr_self->expr = PyTuple_New(expr_self->rif->params->rpn_sz);
|
||||
|
|
|
|||
18
python_if.h
18
python_if.h
|
|
@ -153,6 +153,7 @@ void rpnif_del(PyObject *self);
|
|||
* @param view A memoryview to fill depending on flags
|
||||
* @param flags Indicates the request type
|
||||
* @return -1 on error
|
||||
* @note Used by RPNIterExpr and RPNIFS (proper way to implement it is base class)
|
||||
* See python documentation at
|
||||
* https://docs.python.org/3/c-api/buffer.html#buffer-request-types
|
||||
* @ingroup pymod_pyrpn_RPNExprIter
|
||||
|
|
@ -332,6 +333,23 @@ PyObject *_rpnif_to_pos(rpn_if_default_data_t *rif_data, PyObject** argv, Py_ssi
|
|||
/**@brief Implementation of bot RPNIterExpr.to_pos and RPNIFS.from_pos */
|
||||
PyObject *_rpnif_from_pos(rpn_if_default_data_t *rif_data, PyObject* _pos);
|
||||
|
||||
|
||||
/**@brief Buffer protocol request handler method when no python mmap exist
|
||||
* (deserialized instance)
|
||||
* @param self RPNIterExpr instance
|
||||
* @param view A memoryview to fill depending on flags
|
||||
* @param flags Indicates the request type
|
||||
* @return -1 on error
|
||||
* @note Used by RPNIterExpr and RPNIFS (proper way to implement it is base class)
|
||||
* See python documentation at
|
||||
* https://docs.python.org/3/c-api/buffer.html#buffer-request-types
|
||||
* @ingroup pymod_pyrpn_RPNExprIter
|
||||
*/
|
||||
int _rpnif_getbuffer_nopymap(PyObject *self, const rpn_if_param_t *params,
|
||||
void *buf, Py_buffer *view, int flags);
|
||||
void _rpnif_releasebuffer_nopymap(PyObject *self, Py_buffer *view);
|
||||
|
||||
/**@todo doc */
|
||||
int _rpnif_init_expr_tuple(PyRPNIterExpr_t *expr_self);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
17
python_ifs.c
17
python_ifs.c
|
|
@ -456,13 +456,24 @@ int rpnifs_expr_ass_item(PyObject *self, Py_ssize_t idx, PyObject *value)
|
|||
|
||||
int rpnifs_getbuffer(PyObject *self, Py_buffer *view, int flags)
|
||||
{
|
||||
PyErr_SetString(PyExc_NotImplementedError, "TODO");
|
||||
return -1;
|
||||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
|
||||
if(ifs_self->mmap)
|
||||
{
|
||||
return PyObject_GetBuffer(ifs_self->mmap, view, flags);
|
||||
}
|
||||
return _rpnif_getbuffer_nopymap(self, &ifs_self->ifs->params,
|
||||
ifs_self->_mmap, view, flags);
|
||||
}
|
||||
|
||||
void rpnifs_releasebuffer(PyObject *self, Py_buffer *view)
|
||||
{
|
||||
PyErr_SetString(PyExc_NotImplementedError, "TODO");
|
||||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
if(ifs_self->mmap)
|
||||
{
|
||||
return PyBuffer_Release(view);
|
||||
}
|
||||
return _rpnif_releasebuffer_nopymap(self, view);
|
||||
}
|
||||
|
||||
int _rpnifs_update_if_tuple(PyRPNIFS_t *ifs_self)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,16 @@ import sys
|
|||
|
||||
import unittest
|
||||
|
||||
try:
|
||||
import numpy as np
|
||||
except (ImportError, NameError) as e:
|
||||
np = None
|
||||
warnings.warn("Numpy not found, some tests skipped", warnings.ImportWarning)
|
||||
|
||||
def skipIfNoNumpy():
|
||||
if np is not None:
|
||||
return lambda func: func
|
||||
return unittest.skip("Numpy not found")
|
||||
|
||||
try:
|
||||
import pyrpn
|
||||
|
|
@ -124,6 +134,29 @@ class TestRPNIFS(unittest.TestCase):
|
|||
percent = steps / (dist * 100)
|
||||
self.assertLess(percent, 1)
|
||||
|
||||
@skipIfNoNumpy()
|
||||
def test_buffer_protocol(self):
|
||||
""" Testing buffer protocol on ifs's mmaps """
|
||||
sz = [512,512]
|
||||
ifs = pyrpn.RPNIFS(pyrpn.const.POS_XY,
|
||||
pyrpn.const.RESULT_COUNT,
|
||||
sz)
|
||||
ifs.weights([1,2])
|
||||
for rif in ifs:
|
||||
for expr in rif:
|
||||
expr.mutate(n_mutations=20)
|
||||
|
||||
buf = np.frombuffer(ifs, dtype=np.uint64)
|
||||
buf2 = np.frombuffer(ifs[0], dtype=np.uint64)
|
||||
|
||||
for _ in range(512):
|
||||
pos = random.randint(0, len(buf))
|
||||
buf[pos] = random.randint(0, 0xFFFFFFFF)
|
||||
pos = random.randint(0, len(buf))
|
||||
buf2[pos] = random.randint(0, 0xFFFFFFFF)
|
||||
|
||||
self.assertTrue((buf == buf2).all())
|
||||
|
||||
class TestRPNIFSCoordinates(unittest.TestCase):
|
||||
""" Testing methods for coordinates <-> position convertions """
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue