rpnifs/python_if.c
2023-09-11 14:36:08 +02:00

1363 lines
29 KiB
C

#include "python_if.h"
/**@file python_if.c
* @brief Python RPNIterExpr type definition
* @ingroup python_ext
* @ingroup pymod_pyrpn_RPNExprIter
*/
/**@brief @ref pymod_pyrpn_RPNExprIter methods definition
* @ingroup pymod_pyrpn_RPNExprIter */
static PyMethodDef RPNIterExpr_methods[] = {
PYRPN_method("params", rpnif_params,
METH_VARARGS | METH_KEYWORDS | METH_CLASS,
/**@todo add default values */
"cls, pos_flag, res_flag, size_lim, const_values, stack_size",
"Get a name tuple with parameters given a position \
flag, a result flag and size limits"),
PYRPN_method("get_params", rpnif_get_params,
METH_NOARGS,
"self, /",
"Get a name tuple with parameters"),
PYRPN_method("set_mmap", rpnif_set_mmap,
METH_O,
"self, mmap, /",
"Set the mmap that stores data"),
PYRPN_method("shape", rpnif_shape,
METH_NOARGS,
"self, /",
"Get the shape of the data buffer"),
PYRPN_method("keys", rpnif_keys,
METH_NOARGS,
"self, /",
"Return items keys (see dict.keys)"),
PYRPN_method("values", rpnif_values,
METH_NOARGS,
"self, /",
"Return items values (see dict.values)"),
PYRPN_method("items", rpnif_items,
METH_NOARGS,
"self, /",
"Return items (key, value) list (see dict.items)"),
PYRPN_method("step", rpnif_step,
METH_O,
"self, position, /",
"Run an IF given a position and return a new position"),
PYRPN_method("to_pos", rpnif_to_pos,
METH_FASTCALL,
"self, *args, /",
"Return a position (int) from a coordinates given as"
"argument."),
PYRPN_method("from_pos", rpnif_from_pos,
METH_O,
"self, position, /",
"Return a coordinates tuple from given position."),
PYRPN_method("__getstate__", rpnif_getstate,
METH_NOARGS,
"self, /",
"Pickling method (see pickle module).\n"
"Return a bytes representation of the expression state."),
PYRPN_method("__setstate__", rpnif_setstate,
METH_O,
"self, state, /",
"Unpickling method (see pickle module)."),
{NULL} //Sentinel
};
/**@brief @ref pymod_pyrpn_RPNExprIter members definition
* @ingroup pymod_pyrpn_RPNExprIter */
static PyMemberDef RPNIterExpr_members[] = {
{"expressions", T_OBJECT, offsetof(PyRPNIterExpr_t, expr), READONLY,
"The tuple of expressions"},
{"mmap", T_OBJECT, offsetof(PyRPNIterExpr_t, mmap), READONLY,
"The mmap storing data"},
{NULL}
};
/**@brief @ref pymod_pyrpn_RPNExprIter sequence methods definition
* @ingroup pymod_pyrpn_RPNExprIter */
static PySequenceMethods RPNIterExpr_seq_methods = {
.sq_length = rpnif_len,
.sq_item = rpnif_expr_item,
.sq_ass_item = rpnif_expr_ass_item,
};
/**@brief @ref pymod_pyrpn_RPNExprIter mapping methods definition
* @ingroup pymod_pyrpn_RPNExprIter */
static PyMappingMethods RPNIterExpr_mapping_methods = {
.mp_length = rpnif_len,
.mp_subscript = rpnif_subscript,
.mp_ass_subscript = rpnif_ass_subscript,
};
/**@brief @ref pymod_pyrpn_RPNExprIter attributes definition
* @ingroup pymod_pyrpn_RPNExprIter */
static PyGetSetDef RPNIterExpr_getset[] = {
{NULL}
};
/**@brief @ref pymod_pyrpn_RPNExprIter buffer methods definition
* @ingroup pymod_pyrpn_RPNExprIter */
static PyBufferProcs RPNIterExpr_as_buffer = {
(getbufferproc)rpnif_getbuffer,
(releasebufferproc)rpnif_releasebuffer,
};
PyTypeObject RPNIterExprType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "pyrpn.RPNIterExpr",
.tp_basicsize = sizeof(PyRPNIterExpr_t),
.tp_itemsize = 0,
.tp_del = rpnif_del,
.tp_repr = rpnif_repr,
.tp_as_sequence = &RPNIterExpr_seq_methods,
.tp_as_mapping = &RPNIterExpr_mapping_methods,
.tp_str = rpnif_str,
.tp_as_buffer = &RPNIterExpr_as_buffer,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_doc = "RPN expression evaluator",
.tp_methods = RPNIterExpr_methods,
.tp_members = RPNIterExpr_members,
.tp_getset = RPNIterExpr_getset,
.tp_init = rpnif_init,
.tp_new = rpnif_new,
};
PyObject* rpnif_params(PyObject *cls, PyObject *args, PyObject *kwds)
{
char *names[] = {"pos_flag", "res_flag", "size_lim", "const_values", "stack_size", NULL};
unsigned short pos_flag, res_flag, stack_size;
PyObject *lim_obj, *const_values_obj;
stack_size = 16;
const_values_obj = lim_obj = NULL;
if(!PyArg_ParseTupleAndKeywords(args, kwds,
"HHO|OH:RPNIterExppr.get_params", names,
&pos_flag, &res_flag, &lim_obj, &const_values_obj,
&stack_size))
{
return NULL;
}
rpn_if_param_t *rif_params = _rpnif_get_params(pos_flag, res_flag,
lim_obj, const_values_obj, stack_size);
if(!rif_params)
{
return NULL;
}
PyObject *res = _rpnif_params_to_tuple(rif_params);
if(!res)
{
goto err;
}
free(rif_params);
return res;
err:
free(rif_params);
return NULL;
}
PyObject* rpnif_new(PyTypeObject *subtype, PyObject *args, PyObject* kwds)
{
PyObject *ret, *err;
PyRPNIterExpr_t *expr;
ret = PyType_GenericNew(subtype, args, kwds);
if((err = PyErr_Occurred()))
{
Py_DECREF(err);
return ret;
}
expr = (PyRPNIterExpr_t*)ret;
expr->rif = NULL;
return ret;
}
int rpnif_init(PyObject *self, PyObject *args, PyObject *kwds)
{
PyRPNIterExpr_t *expr_self;
char *names[] = {"pos_flag", "res_flag", "size_lim", "const_values", "stack_size", "mmap", NULL};
unsigned short pos_flag, res_flag, stack_size;
PyObject *lim_obj, *const_values_obj, *mmap_obj;
expr_self = (PyRPNIterExpr_t*)self;
stack_size = 16;
const_values_obj = lim_obj = mmap_obj = NULL;
expr_self->rif = NULL;
expr_self->mmap = NULL;
if(!PyArg_ParseTupleAndKeywords(args, kwds, "HHO|OHO:RPNIterExpr.__init__", names,
&pos_flag, &res_flag, &lim_obj, &const_values_obj, &stack_size,
&mmap_obj))
{
return -1;
}
rpn_if_param_t *rif_params = _rpnif_get_params(pos_flag, res_flag,
lim_obj, const_values_obj, stack_size);
if(!rif_params)
{
return -1;
}
expr_self->ndim = ((rpn_if_default_data_t*)(rif_params->data))->ndim;
const Py_ssize_t expt_sz = rif_params->mem_sz * rif_params->value_sz;
if(!mmap_obj)
{
PyObject *fileno = PyLong_FromLong(-1);
PyObject *length = PyLong_FromSize_t(expt_sz);
mmap_obj = PyObject_CallFunctionObjArgs(mmap_cls, fileno, length, NULL);
}
else
{
if(!PyObject_TypeCheck(mmap_obj, (PyTypeObject*)mmap_cls))
{
PyErr_Format(PyExc_TypeError,
"The mmap argument MUST be an instance \
of mmap.mmap");
return -1;
}
/**@todo check if mmap is shared & writable ? */
if(PyObject_Length(mmap_obj) != (Py_ssize_t) expt_sz)
{
PyErr_Format(PyExc_ValueError,
"Expected mmap length is %ld but mmap with length %ld provided",
rif_params->mem_sz, PyObject_Length(mmap_obj));
return -1;
}
}
if(PyObject_GetBuffer(mmap_obj, &expr_self->mm_buff,
PyBUF_CONTIG) == -1)
{
return -1;
}
expr_self->mmap = mmap_obj;
// Creating rif with a new memory map
expr_self->rif = rpn_if_new(rif_params, expr_self->mm_buff.buf);
if(!expr_self->rif)
{
PyErr_Format(PyExc_RuntimeError,
"Error initalizing if : %s", strerror(errno));
return -1;
}
// Creating the tuple holding RPNExpr instances of expressions
expr_self->expr = PyTuple_New(expr_self->rif->params->rpn_sz);
for(size_t i=0; i<expr_self->rif->params->rpn_sz;i++)
{
rpn_expr_t *expr = &expr_self->rif->rpn[i];
PyObject *instance = rpnexpr_init_borrowing(expr);
if(!instance)
{
return -1;
}
PyTuple_SET_ITEM(expr_self->expr, i, instance);
}
return 0;
}
/**@brief Returns the parameters in a named tuple */
PyObject *rpnif_get_params(PyObject *self)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
return _rpnif_params_to_tuple(expr_self->rif->params);
}
PyObject *rpnif_set_mmap(PyObject *self, PyObject *mm_obj)
{
if(!PyObject_TypeCheck(mm_obj, (PyTypeObject*)mmap_cls))
{
PyErr_Format(PyExc_TypeError,
"Excpected instance of mmap.mmap");
return NULL;
}
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
Py_buffer buff;
/**@todo check mm size &writable ? */
if(PyObject_GetBuffer(mm_obj, &buff, PyBUF_CONTIG) == -1)
{
return NULL;
}
// Release old mmap
PyBuffer_Release(&expr_self->mm_buff);
Py_DECREF(expr_self->mmap);
if(expr_self->rif->self_mem)
{
const size_t mm_sz = expr_self->rif->params->mem_sz *\
expr_self->rif->params->value_sz;
munmap(expr_self->rif->mem, mm_sz);
}
// Set new mmap in python struct & rif struct
expr_self->mm_buff = buff;
expr_self->mmap = mm_obj;
expr_self->rif->mem = buff.buf;
expr_self->rif->self_mem = 0;
Py_RETURN_NONE;
}
PyObject *rpnif_shape(PyObject *self)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
rpn_if_default_data_t *params;
params = (rpn_if_default_data_t*)(expr_self->rif->params->data);
size_t res_sz;
switch(params->res_flag)
{
case RPN_IF_RES_RGB:
res_sz = 3;
break;
case RPN_IF_RES_RGBA:
res_sz = 4;
break;
default:
res_sz = 1;
break;
}
const size_t shape_sz = params->ndim + (res_sz > 1 ?1:0);
PyObject *ret = PyTuple_New(shape_sz);
if(!ret)
{
return NULL;
}
size_t i;
for(i = 0; i < params->ndim; i++)
{
size_t idx = params->pos_flag == RPN_IF_POSITION_XDIM ? i+1:i;
PyObject *d = PyLong_FromLong(params->size_lim[idx]);
if(!d)
{
goto item_err;
}
PyTuple_SET_ITEM(ret, i, d);
}
if(res_sz > 1)
{
PyObject *d = PyLong_FromLong(res_sz);
if(!d)
{
goto item_err;
}
PyTuple_SET_ITEM(ret, i, d);
}
return ret;
item_err:
Py_DECREF(ret);
return NULL;
}
PyObject *rpnif_step(PyObject *self, PyObject* opos)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
/** @todo allow tuple as argument !!!!! */
if(!PyLong_Check(opos))
{
PyErr_SetString(PyExc_TypeError, "Expected position to be an int");
return NULL;
}
size_t pos = PyLong_AsSize_t(opos);
if(PyErr_Occurred())
{
return NULL;
}
pos = rpn_if_step(expr_self->rif, pos);
return PyLong_FromSize_t(pos);
}
PyObject *rpnif_to_pos(PyObject *self, PyObject** argv, Py_ssize_t argc)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
const short idx_off = rif_data->pos_flag == RPN_IF_POSITION_XDIM?1:0;
long long value;
if((size_t)argc != rif_data->ndim)
{
PyErr_Format(PyExc_IndexError,
"Expression expect %lu dimentions coordinates,"
" but %ld arguments given.",
rif_data->ndim, argc);
return NULL;
}
rpn_value_t result=0;
size_t cur_dim_sz = 1;
for(size_t i=0; i<rif_data->ndim; i++)
{
if(!PyLong_Check(argv[i]))
{
PyErr_SetString(PyExc_TypeError,
"coordinates must be integers");
return NULL;
}
value = PyLong_AsLongLong(argv[i]);
if(value < 0)
{
value = (-(rpn_value_t)-value)%rif_data->size_lim[i+idx_off];
}
if((size_t)value >= rif_data->size_lim[i+idx_off])
{
PyErr_Format(PyExc_IndexError,
"Coordinate %ld overflows : %R/%lu",
i, argv[i],
rif_data->size_lim[i+idx_off]);
return NULL;
}
result += value * cur_dim_sz;
cur_dim_sz *= rif_data->size_lim[i+idx_off];
}
return PyLong_FromUnsignedLongLong(result);
}
PyObject *rpnif_from_pos(PyObject *self, PyObject* _pos)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
const short idx_off = rif_data->pos_flag == RPN_IF_POSITION_XDIM?1:0;
if(!PyLong_Check(_pos))
{
PyErr_SetString(PyExc_TypeError,
"Expected position to be an integer");
return NULL;
}
size_t pos = PyLong_AsUnsignedLong(_pos);
if(PyErr_Occurred())
{
return NULL;
}
PyObject *res = PyTuple_New(rif_data->ndim);
if(PyErr_Occurred())
{
return NULL;
}
for(size_t i=0; i<rif_data->ndim; i++)
{
size_t val;
size_t lim = rif_data->size_lim[i+idx_off];
val = pos % lim;
pos /= lim;
PyObject *elt = PyLong_FromUnsignedLong(val);
if(PyErr_Occurred())
{
goto err;
}
PyTuple_SET_ITEM(res, i, elt);
}
return res;
err:
Py_DECREF(res);
return NULL;
}
PyObject *rpnif_keys(PyObject *self)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
Py_ssize_t ret_idx = 0;
char xdim_key[64];
PyObject *ret = PyTuple_New(expr_self->rif->params->rpn_sz);
if(PyErr_Occurred())
{
return NULL;
}
#define _ret_append(key) PyTuple_SET_ITEM(ret, ret_idx++, \
PyUnicode_FromString(key))
switch(rif_data->pos_flag)
{
case RPN_IF_POSITION_XY:
_ret_append("X");
_ret_append("Y");
break;
case RPN_IF_POSITION_LINEAR:
_ret_append("X");
break;
case RPN_IF_POSITION_XDIM:
for(size_t i=0; i<rif_data->size_lim[0];i++)
{
snprintf(xdim_key, 64, "D%ld", i);
_ret_append(xdim_key);
}
break;
default:
PyErr_SetString(PyExc_RuntimeError,
"UNKOWN POS_FLAG3");
return NULL;
}
switch(rif_data->res_flag)
{
case RPN_IF_RES_BOOL:
case RPN_IF_RES_XFUN:
_ret_append("R");
break;
case RPN_IF_RES_RGB:
_ret_append("R");
_ret_append("G");
_ret_append("B");
break;
case RPN_IF_RES_RGBA:
_ret_append("R");
_ret_append("G");
_ret_append("B");
_ret_append("A");
break;
default:
break;
}
if(PyErr_Occurred())
{
return NULL;
}
return ret;
#undef _ret_append
}
PyObject *rpnif_values(PyObject *self)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
Py_INCREF(expr_self->expr);
return expr_self->expr;
}
PyObject *rpnif_items(PyObject *self)
{
size_t i;
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
PyObject *ret = PyTuple_New(expr_self->rif->params->rpn_sz);
if(PyErr_Occurred())
{
return NULL;
}
PyObject *keys = rpnif_keys(self);
for(i=0; i<expr_self->rif->params->rpn_sz; i++)
{
PyObject *tmp = PyTuple_New(2);
if(PyErr_Occurred())
{
goto err_loop_newtuple;
}
PyObject *key = PyTuple_GET_ITEM(keys, i);
PyObject *value = PyTuple_GET_ITEM(expr_self->expr, i);
Py_INCREF(key);
Py_INCREF(value);
PyTuple_SET_ITEM(tmp, 0, key);
PyTuple_SET_ITEM(tmp, 1, value);
PyTuple_SET_ITEM(ret, i, tmp);
if(PyErr_Occurred())
{
goto err_loop_setitem;
}
}
return ret;
/** @todo cleanup seems wrong... */
for(i=i; i>=0; i--)
{
err_loop_setitem:
PyObject *key = PyTuple_GET_ITEM(keys, i);
PyObject *value = PyTuple_GET_ITEM(expr_self->expr, i);
Py_DECREF(key);
Py_DECREF(value);
err_loop_newtuple:
}
Py_DECREF(ret);
return NULL;
}
void rpnif_del(PyObject *self)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
if(expr_self->rif)
{
rpn_if_free(expr_self->rif);
expr_self->rif = NULL;
}
if(expr_self->mm_buff.buf)
{
PyBuffer_Release(&expr_self->mm_buff);
}
Py_DECREF(expr_self->mmap);
}
Py_ssize_t rpnif_len(PyObject *self)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
return expr_self->rif->params->rpn_sz;
}
PyObject* rpnif_expr_item(PyObject *self, Py_ssize_t idx)
{
Py_ssize_t _idx = idx;
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
if(idx < 0)
{
idx = expr_self->rif->params->rpn_sz - 1 + idx;
}
if(idx < 0 || (size_t) idx >= expr_self->rif->params->rpn_sz)
{
PyErr_Format(PyExc_IndexError,
"No expression %ld with given options",
_idx);
return NULL;
}
PyObject *ret = PyTuple_GET_ITEM(expr_self->expr, idx);
Py_INCREF(ret);
return ret;
}
int rpnif_expr_ass_item(PyObject *self, Py_ssize_t idx, PyObject* elt)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
if(!PyUnicode_Check(elt))
{
PyErr_SetString(PyExc_TypeError, "RPNExpr expected");
return -1;
}
PyObject *bytes_str = PyUnicode_AsASCIIString(elt);
if(PyErr_Occurred())
{
return -1;
}
const char *code = PyBytes_AS_STRING(bytes_str);
rpn_expr_t *expr = &(expr_self->rif->rpn[idx]);
if(rpn_expr_recompile(expr, code) < 0)
{
PyErr_Format(PyExc_ValueError,
"Error during expression '%s' compilation : %s",
code, expr->err_reason);
return -1;
}
return 0;
}
/** Convert key to integer index
* @param self @ref PyRPNIterExpr_t instance
* @param _key An expression name (str)
* @return The expression index or -1 on error (raise python exception)
*/
static Py_ssize_t _rpnif_subscript_idx(PyObject *self, PyObject *_key)
{
if(!PyUnicode_Check(_key))
{
PyErr_SetString(PyExc_TypeError, "Key should be a str");
return -1;
}
PyObject *bytes_str = PyUnicode_AsASCIIString(_key);
if(PyErr_Occurred())
{
return -1;
}
const char *key = PyBytes_AS_STRING(bytes_str);
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
Py_ssize_t idx = -1;
Py_ssize_t res_idx = -1;
switch(rif_data->pos_flag)
{
case RPN_IF_POSITION_XY:
res_idx = 2;
if(key[1] != '\0') { break; }
switch(key[0])
{
case 'X':
idx=0;
break;
case 'Y':
idx=1;
break;
}
break;
case RPN_IF_POSITION_LINEAR:
res_idx = 1;
if(!strcmp("X", key))
{
idx = 0;
}
break;
case RPN_IF_POSITION_XDIM:
size_t ndim = rif_data->size_lim[0];
res_idx = ndim;
char possible_key[64];
for(size_t i=0; i<ndim; i++)
{
snprintf(possible_key, 64, "D%ld", i);
if(!strcmp(possible_key, key))
{
idx = i;
break;
}
}
break;
default:
PyErr_SetString(PyExc_RuntimeError,
"UNKOWN POS_FLAG");
return -1;
}
if(idx < 0)
{
// not found yet, looking for result key
switch(rif_data->res_flag)
{
case RPN_IF_RES_BOOL:
case RPN_IF_RES_XFUN:
if(!strcmp("R", key))
{
idx = res_idx;
}
break;
case RPN_IF_RES_RGBA:
if(!strcmp("A", key))
{
idx = res_idx + 3;
}
case RPN_IF_RES_RGB:
if(key[1] != '\0')
{
break;
}
switch(key[0])
{
case 'R':
idx=res_idx;
break;
case 'G':
idx=res_idx+1;
break;
case 'B':
idx=res_idx+2;
break;
}
break;
default:
// not implemented, not unknown....
PyErr_SetString(PyExc_RuntimeError,
"UNKOWN RES_FLAG");
return -1;
}
}
return idx;
}
PyObject* rpnif_subscript(PyObject *self, PyObject *key)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
Py_ssize_t idx = _rpnif_subscript_idx(self, key);
if(idx < 0)
{
PyErr_Format(PyExc_IndexError,
"No expression '%s' with given parameters",
key);
return NULL;
}
PyObject *expr = PyTuple_GET_ITEM(expr_self->expr, idx);
Py_INCREF(expr);
return expr;
}
int rpnif_ass_subscript(PyObject *self, PyObject *key, PyObject *elt)
{
Py_ssize_t idx = _rpnif_subscript_idx(self, key);
if(idx < 0)
{
PyErr_Format(PyExc_IndexError,
"Cannot set expression '%U' that do not exists with this parameters",
key);
return -1;
}
return rpnif_expr_ass_item(self, idx, elt);
}
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;
dprintf(2, "buffer addr %p\n", expr_self->mm_buff.buf);
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)
{
view->format = "L";
}
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;
}
void rpnif_releasebuffer(PyObject *self, Py_buffer *view)
{
free(view->shape);
}
PyObject* rpnif_str(PyObject *self)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
rpn_if_default_data_t *rif_data = \
(rpn_if_default_data_t*)expr_self->rif->params->data;
const size_t rpn_sz = expr_self->rif->params->rpn_sz;
const char pyfmt[] = "%VA%ld=%U=\"%S\";";
size_t i;
PyObject *buf, *tmp, *items;
buf = NULL;
items = rpnif_items(self);
if(PyErr_Occurred()) { return NULL; }
for(i=0; i<rpn_sz; i++)
{
PyObject *key, *value, *elt;
elt = PyTuple_GET_ITEM(items, i);
key = PyTuple_GET_ITEM(elt, 0);
value = PyTuple_GET_ITEM(elt, 1);
tmp = PyUnicode_FromFormat(pyfmt,
buf, "",
i, key, value);
if(buf) { Py_DECREF(buf); }
if(PyErr_Occurred()) { return NULL; }
buf = tmp;
}
switch(rif_data->res_flag)
{
case RPN_IF_RES_CONST:
tmp = PyUnicode_FromFormat("%U A%ld=C(*)=%lld",
buf, i+1, rif_data->const_val[0]);
Py_DECREF(buf);
buf=tmp;
break;
case RPN_IF_RES_CONST_RGBA:
tmp = PyUnicode_FromFormat("%U A%ld=R(*)=%lld A%ld=G(*)=%lld A%ld=B(*)=%lld A%ld=A(*)=%lld",
buf,
i+1, rif_data->const_val[0],
i+2, rif_data->const_val[1],
i+3, rif_data->const_val[2],
i+4, rif_data->const_val[3]);
Py_DECREF(buf);
buf=tmp;
break;
}
Py_INCREF(buf);
return buf;
}
/** Return a string representation of expressions dict
* @param self @ref PyRPNIterExpr_t instance
* @return a str instance */
static PyObject* _rpnif_expr_repr(PyObject *self)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
rpn_if_default_data_t *rif_data = \
(rpn_if_default_data_t*)expr_self->rif->params->data;
PyObject *buf, *tmp, *items, *const_res;
const char pyfmt[] = "%V\"%U\":\"%S\"%V";
buf = const_res = NULL;
items = rpnif_items(self);
if(PyErr_Occurred()) { return NULL; }
#define _const_res_key ",\"const_res\":"
switch(rif_data->res_flag)
{
case RPN_IF_RES_CONST:
const_res = PyUnicode_FromFormat(
_const_res_key "{\"r\":%llu}}",
rif_data->const_val[0]);
break;
/*
case RPN_IF_RES_CONST_RGB:
const_res = PyUnicode_FromFormat(
"\"const_res\": {\"r\":%llu, \"g\":%llu, \"b\":%llu}}",
rif_data->const_val[0],
rif_data->const_val[1],
rif_data->const_val[2])
break;
*/
case RPN_IF_RES_CONST_RGBA:
const_res = PyUnicode_FromFormat(
_const_res_key \
"{\"r\":%llu,\"g\":%llu,\"b\":%llu,\"a\":%llu}}",
rif_data->const_val[0],
rif_data->const_val[1],
rif_data->const_val[2],
rif_data->const_val[3]);
break;
default:
const_res = PyUnicode_FromFormat("}");
break;
}
#undef _const_res_key
const size_t rpn_sz = expr_self->rif->params->rpn_sz;
for(size_t i=0; i<rpn_sz; i++)
{
PyObject *key, *value, *elt;
elt = PyTuple_GET_ITEM(items, i);
key = PyTuple_GET_ITEM(elt, 0);
value = PyTuple_GET_ITEM(elt, 1);
tmp = PyUnicode_FromFormat(pyfmt,
buf, "{", key, value,
i==rpn_sz-1?const_res:NULL, ",");
if(buf)
{
Py_DECREF(buf);
}
if(PyErr_Occurred())
{
return NULL;
}
buf = tmp;
}
return buf;
}
PyObject* rpnif_repr(PyObject *self)
{
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
char *str_pos, *str_res;
char tmp[64];
PyObject *expr_repr = _rpnif_expr_repr(self);
if(PyErr_Occurred()) { return NULL; }
switch(rif_data->pos_flag)
{
case RPN_IF_POSITION_XY:
str_pos = "XY";
break;
case RPN_IF_POSITION_LINEAR:
str_pos = "LINEAR";
break;
case RPN_IF_POSITION_XDIM:
snprintf(tmp, 64, "XDIM%ld", rif_data->size_lim[0]);
str_pos = tmp;
break;
default:
PyErr_SetString(PyExc_RuntimeError,
"UNKOWN POS_FLAG2");
return NULL;
}
PyObject *const_res = NULL;
switch(rif_data->res_flag)
{
case RPN_IF_RES_BOOL:
str_res = "BOOL";
break;
case RPN_IF_RES_CONST:
str_res = "CONST";
const_res = PyTuple_New(1);
break;
case RPN_IF_RES_CONST_RGBA:
str_res = "CONST_RGBA";
break;
case RPN_IF_RES_COUNT:
str_res = "COUNT";
break;
case RPN_IF_RES_XFUN:
str_res = "XFUN";
break;
case RPN_IF_RES_RGB:
str_res = "RGB";
break;
case RPN_IF_RES_RGBA:
str_res = "RGBA";
break;
default:
PyErr_SetString(PyExc_RuntimeError,
"UNKOWN RES_FLAG2");
return NULL;
}
PyObject *res;
const_res = const_res?const_res:Py_None;
res = PyUnicode_FromFormat(
"<RPNIterExpr pos_flag:%s res_flag:%s expr:'%U' const_res:%S>",
str_pos, str_res, expr_repr, const_res);
if(PyErr_Occurred()) { return NULL; }
return res;
}
PyObject* rpnif_getstate(PyObject *self, PyObject *noargs)
{
PyErr_SetString(PyExc_NotImplementedError,
"getstate Not implemented");
return NULL;
Py_RETURN_NONE;
}
PyObject* rpnif_setstate(PyObject *self, PyObject *state_bytes)
{
PyErr_SetString(PyExc_NotImplementedError,
"setstate Not implemented");
return NULL;
/**@todo TODO write the function */
Py_RETURN_NONE;
}
rpn_if_param_t *_rpnif_get_params(unsigned short pos_flag, unsigned short res_flag,
PyObject *lim_obj, PyObject *const_values_obj,
unsigned short stack_size)
{
char err_str[256];
int ndim;
// Args checking
if(stack_size < 4 || stack_size > 255)
{
snprintf(err_str, 128,
"Stack size should be in [0..255] but %u given",
stack_size);
PyErr_SetString(PyExc_ValueError, err_str);
return NULL;
}
// Checks flags & fetch expected sizes for size_lim & const_values
short expt_sizes[2];
if(rpn_if_sizes_from_flag(pos_flag, res_flag, expt_sizes) < 0)
{
if(expt_sizes[0] < 0)
{
PyErr_SetString(PyExc_ValueError,
"Invalid position flag given");
}
else
{
PyErr_SetString(PyExc_ValueError,
"Invalid result flag given");
}
return NULL;
}
//Check & convert lim
PyObject *tmp;
tmp = PySequence_Fast(lim_obj, "Sequence expected for size_lim argument");
if(PyErr_Occurred())
{
return NULL;
}
Py_ssize_t lim_obj_sz = PySequence_Fast_GET_SIZE(tmp);
ndim = lim_obj_sz;
if(PyErr_Occurred())
{
Py_DECREF(tmp);
return NULL;
}
if(lim_obj_sz < 1)
{
Py_DECREF(tmp);
PyErr_SetString(PyExc_ValueError,
"Size limits cannot be empty");
return NULL;
}
if(pos_flag == RPN_IF_POSITION_XDIM)
{
PyObject *item = PySequence_Fast_GET_ITEM(tmp, 0);
Py_ssize_t tmp = PyLong_AsSsize_t(item);
if(PyErr_Occurred())
{
PyErr_SetString(PyExc_ValueError,
"Unable to convert size_lim[0] to int");
Py_DECREF(tmp);
return NULL;
}
if(lim_obj_sz != tmp + 1)
{
PyErr_Format(PyExc_ValueError,
"Xdim indicate %d size_lim but len(size_lim)=%d",
tmp+1, lim_obj_sz);
Py_DECREF(tmp);
return NULL;
}
expt_sizes[0] = ndim = tmp;
}
else
{
if(lim_obj_sz != expt_sizes[0])
{
PyErr_Format(PyExc_ValueError,
"Expected %d size_lim but len(size_lim)=%d",
expt_sizes[0], lim_obj_sz);
Py_DECREF(tmp);
return NULL;
}
}
size_t sz_limits[lim_obj_sz];
for(Py_ssize_t i = 0; i<lim_obj_sz; i++)
{
PyObject *item = PySequence_Fast_GET_ITEM(tmp, i);
sz_limits[i] = PyLong_AsSize_t(item);
if(PyErr_Occurred())
{
PyErr_Format(PyExc_ValueError,
"Unable to convert size_lim[%d] to unsigned int",
i);
Py_DECREF(tmp);
return NULL;
}
}
Py_DECREF(tmp);
tmp = NULL;
//Check & convert const values
Py_ssize_t values_obj_sz = 0;
if(expt_sizes[1] > 0)
{
tmp = const_values_obj;
if(!PyTuple_Check(tmp))
{
PyErr_SetString(PyExc_ValueError,
"Invalid type for const_values argument");
return NULL;
}
values_obj_sz = PyTuple_Size(tmp);
if(values_obj_sz != expt_sizes[1])
{
PyErr_Format(PyExc_ValueError,
"Expected %d const_values but len(const_values)=%d",
expt_sizes[1], values_obj_sz);
return NULL;
}
}
rpn_value_t const_values[values_obj_sz];
for(Py_ssize_t i = 0; i<values_obj_sz; i++)
{
PyObject *item = PyTuple_GET_ITEM(tmp, i);
const_values[i] = PyLong_AsRpnValue_t(item);
if(PyErr_Occurred())
{
PyErr_Format(PyExc_ValueError,
"Unable to convert size_lim[%d] to unsigned int",
i);
return NULL;
}
}
// Creating rif params
rpn_if_param_t *rif_params;
if(!(rif_params = rpn_if_default_params(pos_flag, res_flag,
sz_limits, const_values, stack_size)))
{
PyErr_SetString(PyExc_ValueError, "Unable to create parameters \
with given arguments");
return NULL;
}
return rif_params;
}
PyObject *_rpnif_params_to_tuple(const rpn_if_param_t *_params)
{
PyObject *res, *val;
short expt_sizes[2];
rpn_if_default_data_t *params;
params = (rpn_if_default_data_t*)(_params->data);
if(rpn_if_sizes_from_flag(params->pos_flag, params->res_flag, expt_sizes) < 0)
{
PyErr_SetString(PyExc_RuntimeError, "Invalid internal state");
return NULL;
}
res = PyStructSequence_New(&rpnif_params_SeqDesc);
if(!res)
{
return NULL;
}
val = PyLong_FromLong(_params->rpn_argc);
PyStructSequence_SET_ITEM(res, 0, val);
val = PyLong_FromLong(params->pos_flag);
PyStructSequence_SET_ITEM(res, 1, val);
val = PyLong_FromLong(params->res_flag);
PyStructSequence_SET_ITEM(res, 2, val);
if(params->pos_flag == RPN_IF_POSITION_XDIM)
{
expt_sizes[0] = params->size_lim[0] + 1;
}
PyObject *lim = PyTuple_New(expt_sizes[0]);
if(!lim)
{
Py_DECREF(res);
return NULL;
}
PyStructSequence_SET_ITEM(res, 3, lim);
for(Py_ssize_t i=0; i<expt_sizes[0]; i++)
{
val = PyLong_FromSize_t(params->size_lim[i]);
PyTuple_SET_ITEM(lim, i, val);
}
if(!params->const_val)
{
Py_INCREF(Py_None);
PyTuple_SET_ITEM(res, 4, Py_None);
}
else
{
PyObject *values = PyTuple_New(expt_sizes[1]);
if(!values)
{
Py_DECREF(res);
return NULL;
}
PyStructSequence_SET_ITEM(res, 4, values);
for(Py_ssize_t i=0; i<expt_sizes[1]; i++)
{
val = PyLong_FromRpnValue_t(params->const_val[i]);
PyTuple_SET_ITEM(values, i, val);
}
}
val = PyLong_FromUnsignedLong(_params->mem_sz * _params->value_sz);
PyStructSequence_SET_ITEM(res, 5, val);
return res;
}
/**@def _ret_append(key)
* @hiderefs
* local macro */
/**@def _const_res_key()
* @hiderefs
* local macro*/