#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("get_params", rpnif_get_params, METH_NOARGS, "self, /", "Get a name tuple with parameters"), 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("__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"}, {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_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", NULL}; unsigned short pos_flag, res_flag, stack_size; PyObject *lim_obj, *const_values_obj; int ndim; char err_str[256]; expr_self = (PyRPNIterExpr_t*)self; stack_size = 16; const_values_obj = lim_obj = NULL; expr_self->rif = NULL; if(!PyArg_ParseTupleAndKeywords(args, kwds, "HHO|OH:RPNIterExpr.__init__", names, &pos_flag, &res_flag, &lim_obj, &const_values_obj, &stack_size)) { return -1; } // 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 -1; } // 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 -1; } //Check & convert lim PyObject *tmp; tmp = lim_obj; if(!PyTuple_Check(tmp)) { PyErr_SetString(PyExc_ValueError, "Invalid type for size_lim argument"); return -1; } Py_ssize_t lim_obj_sz = PyTuple_Size(tmp); ndim = lim_obj_sz; if(PyErr_Occurred()) { return -1; } if(lim_obj_sz < 1) { PyErr_SetString(PyExc_ValueError, "Size limits cannot be empty"); } if(pos_flag == RPN_IF_POSITION_XDIM) { PyObject *item = PyTuple_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"); return -1; } 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); return -1; } 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); return -1; } } size_t sz_limits[lim_obj_sz]; for(Py_ssize_t i = 0; indim = ndim; //Check & convert const values Py_ssize_t values_obj_sz = 0; tmp = NULL; if(expt_sizes[1] > 0) { tmp = const_values_obj; if(!PyTuple_Check(tmp)) { PyErr_SetString(PyExc_ValueError, "Invalid type for const_values argument"); return -1; } 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 -1; } } rpn_value_t const_values[values_obj_sz]; for(Py_ssize_t i = 0; irif = rpn_if_new(rif_params, NULL); // Creating the tuple holding RPNExpr instances of expressions expr_self->expr = PyTuple_New(expr_self->rif->params->rpn_sz); for(size_t i=0; irif->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; PyObject *res, *val; rpn_if_default_data_t *params; params = (rpn_if_default_data_t*)(expr_self->rif->params->data); short expt_sizes[2]; 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(expr_self->rif->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; isize_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; iconst_val[i]); PyTuple_SET_ITEM(values, i, val); } } return res; } PyObject *rpnif_step(PyObject *self, PyObject* opos) { PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self; 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_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; isize_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; irif->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; } } 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; ires_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 '%s' 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; 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) { 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); /**@todo check error*/ for(size_t i=0; indim; 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; } 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; ires_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; irif->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( "", 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; /**@todo TODO write the function */ 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; } /**@def _ret_append(key) * @hiderefs * local macro */ /**@def _const_res_key() * @hiderefs * local macro*/