Fast IFS using RPN notation
python
c
x86-64
nasm
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

python_if.c 24KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133
  1. #include "python_if.h"
  2. /**@file python_if.c
  3. * @brief Python RPNIterExpr type definition
  4. * @ingroup python_ext
  5. * @ingroup pymod_pyrpn_RPNExprIter
  6. */
  7. /**@brief @ref pymod_pyrpn_RPNExprIter methods definition
  8. * @ingroup pymod_pyrpn_RPNExprIter */
  9. static PyMethodDef RPNIterExpr_methods[] = {
  10. PYRPN_method("get_params", rpnif_get_params,
  11. METH_NOARGS,
  12. "self, /",
  13. "Get a name tuple with parameters"),
  14. PYRPN_method("keys", rpnif_keys,
  15. METH_NOARGS,
  16. "self, /",
  17. "Return items keys (see dict.keys)"),
  18. PYRPN_method("values", rpnif_values,
  19. METH_NOARGS,
  20. "self, /",
  21. "Return items values (see dict.values)"),
  22. PYRPN_method("items", rpnif_items,
  23. METH_NOARGS,
  24. "self, /",
  25. "Return items (key, value) list (see dict.items)"),
  26. PYRPN_method("step", rpnif_step,
  27. METH_O,
  28. "self, position, /",
  29. "Run an IF given a position and return a new position"),
  30. PYRPN_method("to_pos", rpnif_to_pos,
  31. METH_FASTCALL,
  32. "self, *args, /",
  33. "Return a position (int) from a coordinates given as"
  34. "argument."),
  35. PYRPN_method("from_pos", rpnif_from_pos,
  36. METH_O,
  37. "self, position, /",
  38. "Return a coordinates tuple from given position."),
  39. PYRPN_method("__getstate__", rpnif_getstate,
  40. METH_NOARGS,
  41. "self, /",
  42. "Pickling method (see pickle module).\n"
  43. "Return a bytes representation of the expression state."),
  44. PYRPN_method("__setstate__", rpnif_setstate,
  45. METH_O,
  46. "self, state, /",
  47. "Unpickling method (see pickle module)."),
  48. {NULL} //Sentinel
  49. };
  50. /**@brief @ref pymod_pyrpn_RPNExprIter members definition
  51. * @ingroup pymod_pyrpn_RPNExprIter */
  52. static PyMemberDef RPNIterExpr_members[] = {
  53. {"expressions", T_OBJECT, offsetof(PyRPNIterExpr_t, expr), READONLY,
  54. "The tuple of expressions"},
  55. {NULL}
  56. };
  57. /**@brief @ref pymod_pyrpn_RPNExprIter sequence methods definition
  58. * @ingroup pymod_pyrpn_RPNExprIter */
  59. static PySequenceMethods RPNIterExpr_seq_methods = {
  60. .sq_length = rpnif_len,
  61. .sq_item = rpnif_expr_item,
  62. .sq_ass_item = rpnif_expr_ass_item,
  63. };
  64. /**@brief @ref pymod_pyrpn_RPNExprIter mapping methods definition
  65. * @ingroup pymod_pyrpn_RPNExprIter */
  66. static PyMappingMethods RPNIterExpr_mapping_methods = {
  67. .mp_length = rpnif_len,
  68. .mp_subscript = rpnif_subscript,
  69. .mp_ass_subscript = rpnif_ass_subscript,
  70. };
  71. /**@brief @ref pymod_pyrpn_RPNExprIter attributes definition
  72. * @ingroup pymod_pyrpn_RPNExprIter */
  73. static PyGetSetDef RPNIterExpr_getset[] = {
  74. {NULL}
  75. };
  76. /**@brief @ref pymod_pyrpn_RPNExprIter buffer methods definition
  77. * @ingroup pymod_pyrpn_RPNExprIter */
  78. static PyBufferProcs RPNIterExpr_as_buffer = {
  79. (getbufferproc)rpnif_getbuffer,
  80. (releasebufferproc)rpnif_releasebuffer,
  81. };
  82. PyTypeObject RPNIterExprType = {
  83. PyVarObject_HEAD_INIT(NULL, 0)
  84. .tp_name = "pyrpn.RPNIterExpr",
  85. .tp_basicsize = sizeof(PyRPNIterExpr_t),
  86. .tp_itemsize = 0,
  87. .tp_del = rpnif_del,
  88. .tp_repr = rpnif_repr,
  89. .tp_as_sequence = &RPNIterExpr_seq_methods,
  90. .tp_as_mapping = &RPNIterExpr_mapping_methods,
  91. .tp_str = rpnif_str,
  92. .tp_as_buffer = &RPNIterExpr_as_buffer,
  93. .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
  94. .tp_doc = "RPN expression evaluator",
  95. .tp_methods = RPNIterExpr_methods,
  96. .tp_members = RPNIterExpr_members,
  97. .tp_getset = RPNIterExpr_getset,
  98. .tp_init = rpnif_init,
  99. .tp_new = rpnif_new,
  100. };
  101. PyObject* rpnif_new(PyTypeObject *subtype, PyObject *args, PyObject* kwds)
  102. {
  103. PyObject *ret, *err;
  104. PyRPNIterExpr_t *expr;
  105. ret = PyType_GenericNew(subtype, args, kwds);
  106. if((err = PyErr_Occurred()))
  107. {
  108. Py_DECREF(err);
  109. return ret;
  110. }
  111. expr = (PyRPNIterExpr_t*)ret;
  112. expr->rif = NULL;
  113. return ret;
  114. }
  115. int rpnif_init(PyObject *self, PyObject *args, PyObject *kwds)
  116. {
  117. PyRPNIterExpr_t *expr_self;
  118. char *names[] = {"pos_flag", "res_flag", "size_lim", "const_values", "stack_size", NULL};
  119. unsigned short pos_flag, res_flag, stack_size;
  120. PyObject *lim_obj, *const_values_obj;
  121. int ndim;
  122. char err_str[256];
  123. expr_self = (PyRPNIterExpr_t*)self;
  124. stack_size = 16;
  125. const_values_obj = lim_obj = NULL;
  126. expr_self->rif = NULL;
  127. if(!PyArg_ParseTupleAndKeywords(args, kwds, "HHO|OH:RPNIterExpr.__init__", names,
  128. &pos_flag, &res_flag, &lim_obj, &const_values_obj, &stack_size))
  129. {
  130. return -1;
  131. }
  132. // Args checking
  133. if(stack_size < 4 || stack_size > 255)
  134. {
  135. snprintf(err_str, 128,
  136. "Stack size should be in [0..255] but %u given",
  137. stack_size);
  138. PyErr_SetString(PyExc_ValueError, err_str);
  139. return -1;
  140. }
  141. // Checks flags & fetch expected sizes for size_lim & const_values
  142. short expt_sizes[2];
  143. if(rpn_if_sizes_from_flag(pos_flag, res_flag, expt_sizes) < 0)
  144. {
  145. if(expt_sizes[0] < 0)
  146. {
  147. PyErr_SetString(PyExc_ValueError,
  148. "Invalid position flag given");
  149. }
  150. else
  151. {
  152. PyErr_SetString(PyExc_ValueError,
  153. "Invalid result flag given");
  154. }
  155. return -1;
  156. }
  157. //Check & convert lim
  158. PyObject *tmp;
  159. tmp = PySequence_Fast(lim_obj, "Sequence expected for size_lim argument");
  160. if(PyErr_Occurred())
  161. {
  162. return -1;
  163. }
  164. Py_ssize_t lim_obj_sz = PySequence_Fast_GET_SIZE(tmp);
  165. ndim = lim_obj_sz;
  166. if(PyErr_Occurred())
  167. {
  168. Py_DECREF(tmp);
  169. return -1;
  170. }
  171. if(lim_obj_sz < 1)
  172. {
  173. Py_DECREF(tmp);
  174. PyErr_SetString(PyExc_ValueError,
  175. "Size limits cannot be empty");
  176. return -1;
  177. }
  178. if(pos_flag == RPN_IF_POSITION_XDIM)
  179. {
  180. PyObject *item = PySequence_Fast_GET_ITEM(tmp, 0);
  181. Py_ssize_t tmp = PyLong_AsSsize_t(item);
  182. if(PyErr_Occurred())
  183. {
  184. PyErr_SetString(PyExc_ValueError,
  185. "Unable to convert size_lim[0] to int");
  186. Py_DECREF(tmp);
  187. return -1;
  188. }
  189. if(lim_obj_sz != tmp + 1)
  190. {
  191. PyErr_Format(PyExc_ValueError,
  192. "Xdim indicate %d size_lim but len(size_lim)=%d",
  193. tmp+1, lim_obj_sz);
  194. Py_DECREF(tmp);
  195. return -1;
  196. }
  197. expt_sizes[0] = ndim = tmp;
  198. }
  199. else
  200. {
  201. if(lim_obj_sz != expt_sizes[0])
  202. {
  203. PyErr_Format(PyExc_ValueError,
  204. "Expected %d size_lim but len(size_lim)=%d",
  205. expt_sizes[0], lim_obj_sz);
  206. Py_DECREF(tmp);
  207. return -1;
  208. }
  209. }
  210. size_t sz_limits[lim_obj_sz];
  211. for(Py_ssize_t i = 0; i<lim_obj_sz; i++)
  212. {
  213. PyObject *item = PySequence_Fast_GET_ITEM(tmp, i);
  214. sz_limits[i] = PyLong_AsSize_t(item);
  215. if(PyErr_Occurred())
  216. {
  217. PyErr_Format(PyExc_ValueError,
  218. "Unable to convert size_lim[%d] to unsigned int",
  219. i);
  220. Py_DECREF(tmp);
  221. return -1;
  222. }
  223. }
  224. Py_DECREF(tmp);
  225. tmp = NULL;
  226. expr_self->ndim = ndim;
  227. //Check & convert const values
  228. Py_ssize_t values_obj_sz = 0;
  229. if(expt_sizes[1] > 0)
  230. {
  231. tmp = const_values_obj;
  232. if(!PyTuple_Check(tmp))
  233. {
  234. PyErr_SetString(PyExc_ValueError,
  235. "Invalid type for const_values argument");
  236. return -1;
  237. }
  238. values_obj_sz = PyTuple_Size(tmp);
  239. if(values_obj_sz != expt_sizes[1])
  240. {
  241. PyErr_Format(PyExc_ValueError,
  242. "Expected %d const_values but len(const_values)=%d",
  243. expt_sizes[1], values_obj_sz);
  244. return -1;
  245. }
  246. }
  247. rpn_value_t const_values[values_obj_sz];
  248. for(Py_ssize_t i = 0; i<values_obj_sz; i++)
  249. {
  250. PyObject *item = PyTuple_GET_ITEM(tmp, i);
  251. const_values[i] = PyLong_AsRpnValue_t(item);
  252. if(PyErr_Occurred())
  253. {
  254. PyErr_Format(PyExc_ValueError,
  255. "Unable to convert size_lim[%d] to unsigned int",
  256. i);
  257. return -1;
  258. }
  259. }
  260. // Creating rif params
  261. rpn_if_param_t *rif_params;
  262. if(!(rif_params = rpn_if_default_params(pos_flag, res_flag,
  263. sz_limits, const_values, stack_size)))
  264. {
  265. PyErr_SetString(PyExc_ValueError, "Unable to create parameters \
  266. with given arguments");
  267. return -1;
  268. }
  269. // Creating rif with a new memory map
  270. expr_self->rif = rpn_if_new(rif_params, NULL);
  271. if(!expr_self->rif)
  272. {
  273. PyErr_Format(PyExc_RuntimeError,
  274. "Error initalizing if : %s", strerror(errno));
  275. return -1;
  276. }
  277. // Creating the tuple holding RPNExpr instances of expressions
  278. expr_self->expr = PyTuple_New(expr_self->rif->params->rpn_sz);
  279. for(size_t i=0; i<expr_self->rif->params->rpn_sz;i++)
  280. {
  281. rpn_expr_t *expr = &expr_self->rif->rpn[i];
  282. PyObject *instance = rpnexpr_init_borrowing(expr);
  283. if(!instance)
  284. {
  285. return -1;
  286. }
  287. PyTuple_SET_ITEM(expr_self->expr, i, instance);
  288. }
  289. return 0;
  290. }
  291. /**@brief Returns the parameters in a named tuple */
  292. PyObject *rpnif_get_params(PyObject *self)
  293. {
  294. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  295. PyObject *res, *val;
  296. rpn_if_default_data_t *params;
  297. params = (rpn_if_default_data_t*)(expr_self->rif->params->data);
  298. short expt_sizes[2];
  299. if(rpn_if_sizes_from_flag(params->pos_flag, params->res_flag, expt_sizes) < 0)
  300. {
  301. PyErr_SetString(PyExc_RuntimeError, "Invalid internal state");
  302. return NULL;
  303. }
  304. res = PyStructSequence_New(&rpnif_params_SeqDesc);
  305. if(!res)
  306. {
  307. return NULL;
  308. }
  309. val = PyLong_FromLong(expr_self->rif->params->rpn_argc);
  310. PyStructSequence_SET_ITEM(res, 0, val);
  311. val = PyLong_FromLong(params->pos_flag);
  312. PyStructSequence_SET_ITEM(res, 1, val);
  313. val = PyLong_FromLong(params->res_flag);
  314. PyStructSequence_SET_ITEM(res, 2, val);
  315. if(params->pos_flag == RPN_IF_POSITION_XDIM)
  316. {
  317. expt_sizes[0] = params->size_lim[0] + 1;
  318. }
  319. PyObject *lim = PyTuple_New(expt_sizes[0]);
  320. if(!lim)
  321. {
  322. Py_DECREF(res);
  323. return NULL;
  324. }
  325. PyStructSequence_SET_ITEM(res, 3, lim);
  326. for(Py_ssize_t i=0; i<expt_sizes[0]; i++)
  327. {
  328. val = PyLong_FromSize_t(params->size_lim[i]);
  329. PyTuple_SET_ITEM(lim, i, val);
  330. }
  331. if(!params->const_val)
  332. {
  333. Py_INCREF(Py_None);
  334. PyTuple_SET_ITEM(res, 4, Py_None);
  335. }
  336. else
  337. {
  338. PyObject *values = PyTuple_New(expt_sizes[1]);
  339. if(!values)
  340. {
  341. Py_DECREF(res);
  342. return NULL;
  343. }
  344. PyStructSequence_SET_ITEM(res, 4, values);
  345. for(Py_ssize_t i=0; i<expt_sizes[1]; i++)
  346. {
  347. val = PyLong_FromRpnValue_t(params->const_val[i]);
  348. PyTuple_SET_ITEM(values, i, val);
  349. }
  350. }
  351. return res;
  352. }
  353. PyObject *rpnif_step(PyObject *self, PyObject* opos)
  354. {
  355. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  356. /** @todo allow tuple as argument !!!!! */
  357. if(!PyLong_Check(opos))
  358. {
  359. PyErr_SetString(PyExc_TypeError, "Expected position to be an int");
  360. return NULL;
  361. }
  362. size_t pos = PyLong_AsSize_t(opos);
  363. if(PyErr_Occurred())
  364. {
  365. return NULL;
  366. }
  367. pos = rpn_if_step(expr_self->rif, pos);
  368. return PyLong_FromSize_t(pos);
  369. }
  370. PyObject *rpnif_to_pos(PyObject *self, PyObject** argv, Py_ssize_t argc)
  371. {
  372. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  373. rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
  374. const short idx_off = rif_data->pos_flag == RPN_IF_POSITION_XDIM?1:0;
  375. long long value;
  376. if(argc != rif_data->ndim)
  377. {
  378. PyErr_Format(PyExc_IndexError,
  379. "Expression expect %lu dimentions coordinates,"
  380. " but %ld arguments given.",
  381. rif_data->ndim, argc);
  382. return NULL;
  383. }
  384. rpn_value_t result=0;
  385. size_t cur_dim_sz = 1;
  386. for(Py_ssize_t i=0; i<rif_data->ndim; i++)
  387. {
  388. if(!PyLong_Check(argv[i]))
  389. {
  390. PyErr_SetString(PyExc_TypeError,
  391. "coordinates must be integers");
  392. return NULL;
  393. }
  394. value = PyLong_AsLongLong(argv[i]);
  395. value = value >= 0?value:(-(rpn_value_t)-value)%rif_data->size_lim[i+idx_off];
  396. if(value >= rif_data->size_lim[i+idx_off])
  397. {
  398. PyErr_Format(PyExc_IndexError,
  399. "Coordinate %ld overflows : %R/%lu",
  400. i, argv[i],
  401. rif_data->size_lim[i+idx_off]);
  402. return NULL;
  403. }
  404. result += value * cur_dim_sz;
  405. cur_dim_sz *= rif_data->size_lim[i+idx_off];
  406. }
  407. return PyLong_FromUnsignedLongLong(result);
  408. }
  409. PyObject *rpnif_from_pos(PyObject *self, PyObject* _pos)
  410. {
  411. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  412. rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
  413. const short idx_off = rif_data->pos_flag == RPN_IF_POSITION_XDIM?1:0;
  414. if(!PyLong_Check(_pos))
  415. {
  416. PyErr_SetString(PyExc_TypeError,
  417. "Expected position to be an integer");
  418. return NULL;
  419. }
  420. size_t pos = PyLong_AsUnsignedLong(_pos);
  421. if(PyErr_Occurred())
  422. {
  423. return NULL;
  424. }
  425. PyObject *res = PyTuple_New(rif_data->ndim);
  426. if(PyErr_Occurred())
  427. {
  428. return NULL;
  429. }
  430. for(size_t i=0; i<rif_data->ndim; i++)
  431. {
  432. size_t val;
  433. size_t lim = rif_data->size_lim[i+idx_off];
  434. val = pos % lim;
  435. pos /= lim;
  436. PyObject *elt = PyLong_FromUnsignedLong(val);
  437. if(PyErr_Occurred())
  438. {
  439. goto err;
  440. }
  441. PyTuple_SET_ITEM(res, i, elt);
  442. }
  443. return res;
  444. err:
  445. Py_DECREF(res);
  446. return NULL;
  447. }
  448. PyObject *rpnif_keys(PyObject *self)
  449. {
  450. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  451. rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
  452. Py_ssize_t ret_idx = 0;
  453. char xdim_key[64];
  454. PyObject *ret = PyTuple_New(expr_self->rif->params->rpn_sz);
  455. if(PyErr_Occurred())
  456. {
  457. return NULL;
  458. }
  459. #define _ret_append(key) PyTuple_SET_ITEM(ret, ret_idx++, \
  460. PyUnicode_FromString(key))
  461. switch(rif_data->pos_flag)
  462. {
  463. case RPN_IF_POSITION_XY:
  464. _ret_append("X");
  465. _ret_append("Y");
  466. break;
  467. case RPN_IF_POSITION_LINEAR:
  468. _ret_append("X");
  469. break;
  470. case RPN_IF_POSITION_XDIM:
  471. for(size_t i=0; i<rif_data->size_lim[0];i++)
  472. {
  473. snprintf(xdim_key, 64, "D%ld", i);
  474. _ret_append(xdim_key);
  475. }
  476. break;
  477. default:
  478. PyErr_SetString(PyExc_RuntimeError,
  479. "UNKOWN POS_FLAG3");
  480. return NULL;
  481. }
  482. switch(rif_data->res_flag)
  483. {
  484. case RPN_IF_RES_BOOL:
  485. case RPN_IF_RES_XFUN:
  486. _ret_append("R");
  487. break;
  488. case RPN_IF_RES_RGB:
  489. _ret_append("R");
  490. _ret_append("G");
  491. _ret_append("B");
  492. break;
  493. case RPN_IF_RES_RGBA:
  494. _ret_append("R");
  495. _ret_append("G");
  496. _ret_append("B");
  497. _ret_append("A");
  498. break;
  499. default:
  500. break;
  501. }
  502. if(PyErr_Occurred())
  503. {
  504. return NULL;
  505. }
  506. return ret;
  507. #undef _ret_append
  508. }
  509. PyObject *rpnif_values(PyObject *self)
  510. {
  511. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  512. Py_INCREF(expr_self->expr);
  513. return expr_self->expr;
  514. }
  515. PyObject *rpnif_items(PyObject *self)
  516. {
  517. size_t i;
  518. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  519. PyObject *ret = PyTuple_New(expr_self->rif->params->rpn_sz);
  520. if(PyErr_Occurred())
  521. {
  522. return NULL;
  523. }
  524. PyObject *keys = rpnif_keys(self);
  525. for(i=0; i<expr_self->rif->params->rpn_sz; i++)
  526. {
  527. PyObject *tmp = PyTuple_New(2);
  528. if(PyErr_Occurred())
  529. {
  530. goto err_loop_newtuple;
  531. }
  532. PyObject *key = PyTuple_GET_ITEM(keys, i);
  533. PyObject *value = PyTuple_GET_ITEM(expr_self->expr, i);
  534. Py_INCREF(key);
  535. Py_INCREF(value);
  536. PyTuple_SET_ITEM(tmp, 0, key);
  537. PyTuple_SET_ITEM(tmp, 1, value);
  538. PyTuple_SET_ITEM(ret, i, tmp);
  539. if(PyErr_Occurred())
  540. {
  541. goto err_loop_setitem;
  542. }
  543. }
  544. return ret;
  545. /** @todo cleanup seems wrong... */
  546. for(i=i; i>=0; i--)
  547. {
  548. err_loop_setitem:
  549. PyObject *key = PyTuple_GET_ITEM(keys, i);
  550. PyObject *value = PyTuple_GET_ITEM(expr_self->expr, i);
  551. Py_DECREF(key);
  552. Py_DECREF(value);
  553. err_loop_newtuple:
  554. }
  555. Py_DECREF(ret);
  556. return NULL;
  557. }
  558. void rpnif_del(PyObject *self)
  559. {
  560. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  561. if(expr_self->rif)
  562. {
  563. rpn_if_free(expr_self->rif);
  564. expr_self->rif = NULL;
  565. }
  566. }
  567. Py_ssize_t rpnif_len(PyObject *self)
  568. {
  569. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  570. return expr_self->rif->params->rpn_sz;
  571. }
  572. PyObject* rpnif_expr_item(PyObject *self, Py_ssize_t idx)
  573. {
  574. Py_ssize_t _idx = idx;
  575. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  576. if(idx < 0)
  577. {
  578. idx = expr_self->rif->params->rpn_sz - 1 + idx;
  579. }
  580. if(idx < 0 || (size_t) idx >= expr_self->rif->params->rpn_sz)
  581. {
  582. PyErr_Format(PyExc_IndexError,
  583. "No expression %ld with given options",
  584. _idx);
  585. return NULL;
  586. }
  587. PyObject *ret = PyTuple_GET_ITEM(expr_self->expr, idx);
  588. Py_INCREF(ret);
  589. return ret;
  590. }
  591. int rpnif_expr_ass_item(PyObject *self, Py_ssize_t idx, PyObject* elt)
  592. {
  593. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  594. if(!PyUnicode_Check(elt))
  595. {
  596. PyErr_SetString(PyExc_TypeError, "RPNExpr expected");
  597. return -1;
  598. }
  599. PyObject *bytes_str = PyUnicode_AsASCIIString(elt);
  600. if(PyErr_Occurred())
  601. {
  602. return -1;
  603. }
  604. const char *code = PyBytes_AS_STRING(bytes_str);
  605. rpn_expr_t *expr = &(expr_self->rif->rpn[idx]);
  606. if(rpn_expr_recompile(expr, code) < 0)
  607. {
  608. PyErr_Format(PyExc_ValueError,
  609. "Error during expression '%s' compilation : %s",
  610. code, expr->err_reason);
  611. return -1;
  612. }
  613. return 0;
  614. }
  615. /** Convert key to integer index
  616. * @param self @ref PyRPNIterExpr_t instance
  617. * @param _key An expression name (str)
  618. * @return The expression index or -1 on error (raise python exception)
  619. */
  620. static Py_ssize_t _rpnif_subscript_idx(PyObject *self, PyObject *_key)
  621. {
  622. if(!PyUnicode_Check(_key))
  623. {
  624. PyErr_SetString(PyExc_TypeError, "Key should be a str");
  625. return -1;
  626. }
  627. PyObject *bytes_str = PyUnicode_AsASCIIString(_key);
  628. if(PyErr_Occurred())
  629. {
  630. return -1;
  631. }
  632. const char *key = PyBytes_AS_STRING(bytes_str);
  633. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  634. rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
  635. Py_ssize_t idx = -1;
  636. Py_ssize_t res_idx = -1;
  637. switch(rif_data->pos_flag)
  638. {
  639. case RPN_IF_POSITION_XY:
  640. res_idx = 2;
  641. if(key[1] != '\0') { break; }
  642. switch(key[0])
  643. {
  644. case 'X':
  645. idx=0;
  646. break;
  647. case 'Y':
  648. idx=1;
  649. break;
  650. }
  651. break;
  652. case RPN_IF_POSITION_LINEAR:
  653. res_idx = 1;
  654. if(!strcmp("X", key))
  655. {
  656. idx = 0;
  657. }
  658. break;
  659. case RPN_IF_POSITION_XDIM:
  660. size_t ndim = rif_data->size_lim[0];
  661. res_idx = ndim;
  662. char possible_key[64];
  663. for(size_t i=0; i<ndim; i++)
  664. {
  665. snprintf(possible_key, 64, "D%ld", i);
  666. if(!strcmp(possible_key, key))
  667. {
  668. idx = i;
  669. break;
  670. }
  671. }
  672. break;
  673. default:
  674. PyErr_SetString(PyExc_RuntimeError,
  675. "UNKOWN POS_FLAG");
  676. return -1;
  677. }
  678. if(idx < 0)
  679. {
  680. // not found yet, looking for result key
  681. switch(rif_data->res_flag)
  682. {
  683. case RPN_IF_RES_BOOL:
  684. case RPN_IF_RES_XFUN:
  685. if(!strcmp("R", key))
  686. {
  687. idx = res_idx;
  688. }
  689. break;
  690. case RPN_IF_RES_RGBA:
  691. if(!strcmp("A", key))
  692. {
  693. idx = res_idx + 3;
  694. }
  695. case RPN_IF_RES_RGB:
  696. if(key[1] != '\0')
  697. {
  698. break;
  699. }
  700. switch(key[0])
  701. {
  702. case 'R':
  703. idx=res_idx;
  704. break;
  705. case 'G':
  706. idx=res_idx+1;
  707. break;
  708. case 'B':
  709. idx=res_idx+2;
  710. break;
  711. }
  712. break;
  713. default:
  714. // not implemented, not unknown....
  715. PyErr_SetString(PyExc_RuntimeError,
  716. "UNKOWN RES_FLAG");
  717. return -1;
  718. }
  719. }
  720. return idx;
  721. }
  722. PyObject* rpnif_subscript(PyObject *self, PyObject *key)
  723. {
  724. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  725. Py_ssize_t idx = _rpnif_subscript_idx(self, key);
  726. if(idx < 0)
  727. {
  728. PyErr_Format(PyExc_IndexError,
  729. "No expression '%s' with given parameters",
  730. key);
  731. return NULL;
  732. }
  733. PyObject *expr = PyTuple_GET_ITEM(expr_self->expr, idx);
  734. Py_INCREF(expr);
  735. return expr;
  736. }
  737. int rpnif_ass_subscript(PyObject *self, PyObject *key, PyObject *elt)
  738. {
  739. Py_ssize_t idx = _rpnif_subscript_idx(self, key);
  740. if(idx < 0)
  741. {
  742. PyErr_Format(PyExc_IndexError,
  743. "Cannot set expression '%U' that do not exists with this parameters",
  744. key);
  745. return -1;
  746. }
  747. return rpnif_expr_ass_item(self, idx, elt);
  748. }
  749. int rpnif_getbuffer(PyObject *self, Py_buffer *view, int flags)
  750. {
  751. PyRPNIterExpr_t *expr_self;
  752. expr_self = (PyRPNIterExpr_t*)self;
  753. rpn_if_default_data_t *data = (rpn_if_default_data_t*)expr_self->rif->params->data;
  754. view->buf = expr_self->rif->mem;
  755. view->obj = self;
  756. view->len = expr_self->rif->params->mem_sz * expr_self->rif->params->value_sz;
  757. view->readonly = 0;
  758. //view->itemsize = expr_self->rif->params->value_sz;
  759. view->itemsize = sizeof(rpn_value_t);
  760. if(flags & PyBUF_FORMAT)
  761. {
  762. view->format = "L";
  763. }
  764. else
  765. {
  766. view->format = NULL;
  767. }
  768. view->ndim = 1;
  769. view->shape = NULL;
  770. if(flags & PyBUF_ND)
  771. {
  772. view->ndim = expr_self->ndim;
  773. // !! Error if value_sz < sizeof(rpn_value_t) !!
  774. short nval = view->itemsize / sizeof(rpn_value_t);
  775. if(nval > 1)
  776. {
  777. view->ndim++;
  778. }
  779. view->shape = malloc(sizeof(Py_ssize_t) * view->ndim); /**@todo check error*/
  780. for(size_t i=0; i<expr_self->ndim; i++)
  781. {
  782. int idx = i;
  783. if(data->pos_flag == RPN_IF_POSITION_XDIM)
  784. {
  785. idx++;
  786. }
  787. view->shape[i] = data->size_lim[idx];
  788. }
  789. if(nval>1)
  790. {
  791. view->shape[expr_self->ndim] = nval;
  792. }
  793. }
  794. view->strides = NULL;
  795. view->suboffsets = NULL;
  796. Py_INCREF(self);
  797. return 0;
  798. }
  799. void rpnif_releasebuffer(PyObject *self, Py_buffer *view)
  800. {
  801. free(view->shape);
  802. }
  803. PyObject* rpnif_str(PyObject *self)
  804. {
  805. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  806. rpn_if_default_data_t *rif_data = \
  807. (rpn_if_default_data_t*)expr_self->rif->params->data;
  808. const size_t rpn_sz = expr_self->rif->params->rpn_sz;
  809. const char pyfmt[] = "%VA%ld=%U=\"%S\";";
  810. size_t i;
  811. PyObject *buf, *tmp, *items;
  812. buf = NULL;
  813. items = rpnif_items(self);
  814. if(PyErr_Occurred()) { return NULL; }
  815. for(i=0; i<rpn_sz; i++)
  816. {
  817. PyObject *key, *value, *elt;
  818. elt = PyTuple_GET_ITEM(items, i);
  819. key = PyTuple_GET_ITEM(elt, 0);
  820. value = PyTuple_GET_ITEM(elt, 1);
  821. tmp = PyUnicode_FromFormat(pyfmt,
  822. buf, "",
  823. i, key, value);
  824. if(buf) { Py_DECREF(buf); }
  825. if(PyErr_Occurred()) { return NULL; }
  826. buf = tmp;
  827. }
  828. switch(rif_data->res_flag)
  829. {
  830. case RPN_IF_RES_CONST:
  831. tmp = PyUnicode_FromFormat("%U A%ld=C(*)=%lld",
  832. buf, i+1, rif_data->const_val[0]);
  833. Py_DECREF(buf);
  834. buf=tmp;
  835. break;
  836. case RPN_IF_RES_CONST_RGBA:
  837. tmp = PyUnicode_FromFormat("%U A%ld=R(*)=%lld A%ld=G(*)=%lld A%ld=B(*)=%lld A%ld=A(*)=%lld",
  838. buf,
  839. i+1, rif_data->const_val[0],
  840. i+2, rif_data->const_val[1],
  841. i+3, rif_data->const_val[2],
  842. i+4, rif_data->const_val[3]);
  843. Py_DECREF(buf);
  844. buf=tmp;
  845. break;
  846. }
  847. Py_INCREF(buf);
  848. return buf;
  849. }
  850. /** Return a string representation of expressions dict
  851. * @param self @ref PyRPNIterExpr_t instance
  852. * @return a str instance */
  853. static PyObject* _rpnif_expr_repr(PyObject *self)
  854. {
  855. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  856. rpn_if_default_data_t *rif_data = \
  857. (rpn_if_default_data_t*)expr_self->rif->params->data;
  858. PyObject *buf, *tmp, *items, *const_res;
  859. const char pyfmt[] = "%V\"%U\":\"%S\"%V";
  860. buf = const_res = NULL;
  861. items = rpnif_items(self);
  862. if(PyErr_Occurred()) { return NULL; }
  863. #define _const_res_key ",\"const_res\":"
  864. switch(rif_data->res_flag)
  865. {
  866. case RPN_IF_RES_CONST:
  867. const_res = PyUnicode_FromFormat(
  868. _const_res_key "{\"r\":%llu}}",
  869. rif_data->const_val[0]);
  870. break;
  871. /*
  872. case RPN_IF_RES_CONST_RGB:
  873. const_res = PyUnicode_FromFormat(
  874. "\"const_res\": {\"r\":%llu, \"g\":%llu, \"b\":%llu}}",
  875. rif_data->const_val[0],
  876. rif_data->const_val[1],
  877. rif_data->const_val[2])
  878. break;
  879. */
  880. case RPN_IF_RES_CONST_RGBA:
  881. const_res = PyUnicode_FromFormat(
  882. _const_res_key \
  883. "{\"r\":%llu,\"g\":%llu,\"b\":%llu,\"a\":%llu}}",
  884. rif_data->const_val[0],
  885. rif_data->const_val[1],
  886. rif_data->const_val[2],
  887. rif_data->const_val[3]);
  888. break;
  889. default:
  890. const_res = PyUnicode_FromFormat("}");
  891. break;
  892. }
  893. #undef _const_res_key
  894. const size_t rpn_sz = expr_self->rif->params->rpn_sz;
  895. for(size_t i=0; i<rpn_sz; i++)
  896. {
  897. PyObject *key, *value, *elt;
  898. elt = PyTuple_GET_ITEM(items, i);
  899. key = PyTuple_GET_ITEM(elt, 0);
  900. value = PyTuple_GET_ITEM(elt, 1);
  901. tmp = PyUnicode_FromFormat(pyfmt,
  902. buf, "{", key, value,
  903. i==rpn_sz-1?const_res:NULL, ",");
  904. if(buf)
  905. {
  906. Py_DECREF(buf);
  907. }
  908. if(PyErr_Occurred())
  909. {
  910. return NULL;
  911. }
  912. buf = tmp;
  913. }
  914. return buf;
  915. }
  916. PyObject* rpnif_repr(PyObject *self)
  917. {
  918. PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
  919. rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
  920. char *str_pos, *str_res;
  921. char tmp[64];
  922. PyObject *expr_repr = _rpnif_expr_repr(self);
  923. if(PyErr_Occurred()) { return NULL; }
  924. switch(rif_data->pos_flag)
  925. {
  926. case RPN_IF_POSITION_XY:
  927. str_pos = "XY";
  928. break;
  929. case RPN_IF_POSITION_LINEAR:
  930. str_pos = "LINEAR";
  931. break;
  932. case RPN_IF_POSITION_XDIM:
  933. snprintf(tmp, 64, "XDIM%ld", rif_data->size_lim[0]);
  934. str_pos = tmp;
  935. break;
  936. default:
  937. PyErr_SetString(PyExc_RuntimeError,
  938. "UNKOWN POS_FLAG2");
  939. return NULL;
  940. }
  941. PyObject *const_res = NULL;
  942. switch(rif_data->res_flag)
  943. {
  944. case RPN_IF_RES_BOOL:
  945. str_res = "BOOL";
  946. break;
  947. case RPN_IF_RES_CONST:
  948. str_res = "CONST";
  949. const_res = PyTuple_New(1);
  950. break;
  951. case RPN_IF_RES_CONST_RGBA:
  952. str_res = "CONST_RGBA";
  953. break;
  954. case RPN_IF_RES_COUNT:
  955. str_res = "COUNT";
  956. break;
  957. case RPN_IF_RES_XFUN:
  958. str_res = "XFUN";
  959. break;
  960. case RPN_IF_RES_RGB:
  961. str_res = "RGB";
  962. break;
  963. case RPN_IF_RES_RGBA:
  964. str_res = "RGBA";
  965. break;
  966. default:
  967. PyErr_SetString(PyExc_RuntimeError,
  968. "UNKOWN RES_FLAG2");
  969. return NULL;
  970. }
  971. PyObject *res;
  972. const_res = const_res?const_res:Py_None;
  973. res = PyUnicode_FromFormat(
  974. "<RPNIterExpr pos_flag:%s res_flag:%s expr:'%U' const_res:%S>",
  975. str_pos, str_res, expr_repr, const_res);
  976. if(PyErr_Occurred()) { return NULL; }
  977. return res;
  978. }
  979. PyObject* rpnif_getstate(PyObject *self, PyObject *noargs)
  980. {
  981. PyErr_SetString(PyExc_NotImplementedError,
  982. "getstate Not implemented");
  983. return NULL;
  984. /**@todo TODO write the function */
  985. Py_RETURN_NONE;
  986. }
  987. PyObject* rpnif_setstate(PyObject *self, PyObject *state_bytes)
  988. {
  989. PyErr_SetString(PyExc_NotImplementedError,
  990. "setstate Not implemented");
  991. return NULL;
  992. /**@todo TODO write the function */
  993. Py_RETURN_NONE;
  994. }
  995. /**@def _ret_append(key)
  996. * @hiderefs
  997. * local macro */
  998. /**@def _const_res_key()
  999. * @hiderefs
  1000. * local macro*/