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_rpnexpr.c 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. /*
  2. * Copyright (C) 2020 Weber Yann
  3. *
  4. * This file is part of pyrpn.
  5. *
  6. * pyrpn is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * any later version.
  10. *
  11. * pyrpn is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with pyrpn. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "python_rpnexpr.h"
  20. PyMethodDef RPNExpr_methods[] = {
  21. {"eval", (PyCFunction)rpnexpr_eval, METH_FASTCALL, "Evaluate an expression"},
  22. {"reset_stack", (PyCFunction)rpnexpr_reset_stack, METH_NOARGS,
  23. "Reset stack memory storage (set all items to 0)"},
  24. {"__getstate__", (PyCFunction)rpnexpr_getstate, METH_NOARGS,
  25. "Pickling method. Return a bytes repr of tokenized expression \
  26. and the stack state."},
  27. {"__setstate__", (PyCFunction)rpnexpr_setstate, METH_O,
  28. "Unpickling method"},
  29. {"uid", (PyCFunction)rpnexpr_getexprstate, METH_NOARGS,
  30. "Return a base64 uid for expression"},
  31. {NULL} //Sentinel
  32. };
  33. PyMemberDef RPNExpr_members[] = {
  34. {NULL}
  35. };
  36. PyTypeObject RPNExprType = {
  37. PyVarObject_HEAD_INIT(NULL, 0)
  38. "pyrpn.RPNExpr", /* tp_name */
  39. sizeof(PyRPNExpr_t), /* tp_basicsize */
  40. 0, /* tp_itemsize */
  41. (destructor)rpnexpr_del, /* tp_dealloc */
  42. 0, /* tp_print */
  43. 0, /* tp_getattr */
  44. 0, /* tp_setattr */
  45. 0, /* tp_reserved */
  46. rpnexpr_repr, /* tp_repr */
  47. 0, /* tp_as_number */
  48. 0, /* tp_as_sequence */
  49. 0, /* tp_as_mapping */
  50. 0, /* tp_hash */
  51. 0, /* tp_call */
  52. rpnexpr_str, /* tp_str */
  53. 0, /* tp_getattro */
  54. 0, /* tp_setattro */
  55. 0, /* tp_as_buffer */
  56. Py_TPFLAGS_DEFAULT |
  57. Py_TPFLAGS_BASETYPE, /* tp_flags */
  58. "RPN expression evaluator", /* tp_doc */
  59. 0, /* tp_traverse */
  60. 0, /* tp_clear */
  61. 0, /* tp_richcompare */
  62. 0, /* tp_weaklistoffset */
  63. 0, /* tp_iter */
  64. 0, /* tp_iternext */
  65. RPNExpr_methods, /* tp_methods */
  66. RPNExpr_members, /* tp_members */
  67. 0, /* tp_getset */
  68. 0, /* tp_base */
  69. 0, /* tp_dict */
  70. 0, /* tp_descr_get */
  71. 0, /* tp_descr_set */
  72. 0, /* tp_dictoffset */
  73. rpnexpr_init, /* tp_init */
  74. 0, /* tp_alloc */
  75. rpnexpr_new, /* tp_new */
  76. };
  77. PyObject* rpnexpr_new(PyTypeObject *subtype, PyObject *args, PyObject* kwds)
  78. {
  79. PyObject *ret, *err;
  80. PyRPNExpr_t *expr;
  81. ret = PyType_GenericNew(subtype, args, kwds);
  82. if((err = PyErr_Occurred()))
  83. {
  84. Py_DECREF(err);
  85. return ret;
  86. }
  87. expr = (PyRPNExpr_t*)ret;
  88. expr->rpn = NULL;
  89. expr->args = NULL;
  90. return ret;
  91. }
  92. int rpnexpr_init(PyObject *self, PyObject *args, PyObject *kwds)
  93. {
  94. PyRPNExpr_t *expr_self;
  95. char *names[] = {"expression", "args_count", "stack_size", NULL};
  96. char err_str[256];
  97. const char *expr;
  98. long long int args_count, stack_size;
  99. expr_self = (PyRPNExpr_t*)self;
  100. stack_size = 16;
  101. expr_self->rpn = NULL;
  102. if(!PyArg_ParseTupleAndKeywords(args, kwds, "sL|L:RPNExpr.__init__", names, &expr,
  103. &args_count, &stack_size))
  104. {
  105. return -1;
  106. }
  107. if(strlen(expr) == 0)
  108. {
  109. PyErr_SetString(PyExc_ValueError,
  110. "RpnExpr.__init__() expect expression argument to be not empty");
  111. return -1;
  112. }
  113. if(args_count < 0 || args_count > 255)
  114. {
  115. snprintf(err_str, 128,
  116. "Argument count should be in [4..255] but %lld given",
  117. args_count);
  118. PyErr_SetString(PyExc_ValueError, err_str);
  119. return -1;
  120. }
  121. if(stack_size < 4 || stack_size > 255)
  122. {
  123. snprintf(err_str, 128,
  124. "Stack size should be in [0..255] but %lld given",
  125. stack_size);
  126. PyErr_SetString(PyExc_ValueError, err_str);
  127. return -1;
  128. }
  129. expr_self->rpn = malloc(sizeof(rpn_expr_t));
  130. if(!expr_self->rpn)
  131. {
  132. snprintf(err_str, 256,
  133. "Expression memory allocation error : %s",
  134. strerror(errno));
  135. }
  136. bzero(expr_self->rpn, sizeof(rpn_expr_t));
  137. if(rpn_expr_init(expr_self->rpn, stack_size, args_count) < 0)
  138. {
  139. snprintf(err_str, 256,
  140. "Expression init error : %s",
  141. expr_self->rpn->err_reason);
  142. PyErr_SetString(PyExc_ValueError, err_str);
  143. return -1;
  144. }
  145. expr_self->args = malloc(sizeof(rpn_value_t) * args_count);
  146. if(!expr_self->args)
  147. {
  148. snprintf(err_str, 256,
  149. "Error allocating arguments memory : %s",
  150. strerror(errno));
  151. return -1;
  152. }
  153. if(rpn_expr_compile(expr_self->rpn, expr))
  154. {
  155. PyErr_SetString(PyExc_ValueError, expr_self->rpn->err_reason);
  156. return -1;
  157. }
  158. return 0;
  159. }
  160. void rpnexpr_del(PyObject *self)
  161. {
  162. PyRPNExpr_t *expr_self;
  163. expr_self = (PyRPNExpr_t*)self;
  164. if(expr_self->rpn)
  165. {
  166. rpn_expr_close(expr_self->rpn);
  167. free(expr_self->rpn);
  168. expr_self->rpn = NULL;
  169. }
  170. if(expr_self->args)
  171. {
  172. free(expr_self->args);
  173. expr_self->args = NULL;
  174. }
  175. }
  176. PyObject* rpnexpr_getexprstate(PyObject *self, PyObject *noargs)
  177. {
  178. /*
  179. PyObject *base64_mod, *base64_encode, *gzip, *compress;
  180. PyObject *bytes_repr, *comp, *res;
  181. if(!(base64_mod = PyImport_ImportModule("base64")))
  182. {
  183. return NULL;
  184. }
  185. if(!(base64_encode = PyObject_GetAttrString(base64_mod, "b64encode")))
  186. {
  187. return NULL;
  188. }
  189. if(!(gzip = PyImport_ImportModule("gzip")))
  190. {
  191. return NULL;
  192. }
  193. if(!(compress = PyObject_GetAttrString(gzip, "compress")))
  194. {
  195. return NULL;
  196. }
  197. bytes_repr = _rpnexpr_getstate(self, noargs, 0);
  198. res = PyObject_CallOneArg(base64_encode, bytes_repr);
  199. Py_DECREF(bytes_repr);
  200. return res;
  201. comp = PyObject_CallOneArg(compress, bytes_repr);
  202. Py_DECREF(bytes_repr);
  203. res = PyObject_CallOneArg(base64_encode, comp);
  204. Py_DECREF(comp);
  205. return res;
  206. */
  207. return NULL;
  208. }
  209. PyObject* rpnexpr_getstate(PyObject *self, PyObject *noargs)
  210. {
  211. PyObject *res, *part;
  212. PyRPNExpr_state_t resbuf;
  213. PyRPNExpr_t *expr_self;
  214. size_t total_sz, i;
  215. char err_str[128];
  216. expr_self = (PyRPNExpr_t*)self;
  217. if(expr_self->rpn->state != RPN_READY)
  218. {
  219. snprintf(err_str, 128,
  220. "RPNExpr.__getstate__() instance in bad state : %s",
  221. expr_self->rpn->state==RPN_ERROR?"error":"init");
  222. PyErr_SetString(PyExc_ValueError, err_str);
  223. return NULL;
  224. }
  225. total_sz = sizeof(PyRPNExpr_state_t);
  226. total_sz += expr_self->rpn->toks.tokens_sz * sizeof(rpn_token_t);
  227. total_sz += expr_self->rpn->stack_sz * sizeof(rpn_value_t);
  228. resbuf.total_sz = total_sz;
  229. resbuf.argc = expr_self->rpn->args_count;
  230. resbuf.stack_sz = expr_self->rpn->stack_sz;
  231. resbuf.token_sz = expr_self->rpn->toks.tokens_sz;
  232. if(!(res = PyBytes_FromStringAndSize((char*)&resbuf, sizeof(resbuf))))
  233. {
  234. return NULL;
  235. }
  236. if(resbuf.stack_sz)
  237. {
  238. if(!(part=PyBytes_FromStringAndSize(
  239. (char*)expr_self->rpn->stack,
  240. sizeof(rpn_value_t) * resbuf.stack_sz)))
  241. {
  242. return NULL;
  243. }
  244. PyBytes_ConcatAndDel(&res, part);
  245. if(!res)
  246. {
  247. return NULL;
  248. }
  249. }
  250. if(resbuf.token_sz)
  251. {
  252. for(i=0; i<expr_self->rpn->toks.tokens_sz;i++)
  253. {
  254. // restore op pointers
  255. expr_self->rpn->toks.tokens[i].op = NULL;
  256. }
  257. if(!(part=PyBytes_FromStringAndSize(
  258. (char*)expr_self->rpn->toks.tokens,
  259. sizeof(rpn_token_t) * resbuf.token_sz)))
  260. {
  261. return NULL;
  262. }
  263. for(i=0; i<expr_self->rpn->toks.tokens_sz;i++)
  264. {
  265. // restore op pointers
  266. expr_self->rpn->toks.tokens[i].op = &(rpn_ops[expr_self->rpn->toks.tokens[i].op_n]);
  267. }
  268. PyBytes_ConcatAndDel(&res, part);
  269. if(!res)
  270. {
  271. return NULL;
  272. }
  273. }
  274. return res;
  275. }
  276. PyObject* rpnexpr_setstate(PyObject *self, PyObject *state_bytes)
  277. {
  278. PyObject *tmp, *tmp2;
  279. PyRPNExpr_state_t *state;
  280. PyRPNExpr_t *expr_self;
  281. rpn_value_t *stack;
  282. rpn_tokenized_t toks;
  283. const char *data;
  284. size_t bsize, csize;
  285. int err;
  286. char err_str[256];
  287. size_t i;
  288. expr_self = (PyRPNExpr_t*)self;
  289. if(!PyBytes_Check(state_bytes)) /* Arg check */
  290. {
  291. tmp2 = NULL;
  292. tmp = PyObject_Type(state_bytes);
  293. if(tmp)
  294. {
  295. tmp2 = PyObject_Str(tmp);
  296. }
  297. if(tmp2)
  298. {
  299. snprintf(err_str, 128,
  300. "RPNExpr.__setstate__() expected a bytes as \
  301. argument but %s found",
  302. PyUnicode_AsUTF8(tmp2));
  303. PyErr_SetString(PyExc_ValueError, err_str);
  304. }
  305. else
  306. {
  307. PyErr_SetString(PyExc_RuntimeError,
  308. "Failing to fetch arguments type will \
  309. generating exception message !");
  310. }
  311. return NULL;
  312. }
  313. if(expr_self->rpn || expr_self->args) /* checking instance state */
  314. {
  315. PyErr_SetString(PyExc_ValueError,
  316. "RPNExpr.__getstate__() instance in bad state : \
  317. should not be initialized");
  318. return NULL;
  319. }
  320. /* Checking data size */
  321. bsize = PyBytes_GET_SIZE(state_bytes);
  322. data = PyBytes_AS_STRING(state_bytes);
  323. state = (PyRPNExpr_state_t*)data;
  324. if(bsize < sizeof(size_t))
  325. {
  326. PyErr_SetString(PyExc_ValueError, "Invalid argument");
  327. }
  328. if(bsize != state->total_sz)
  329. {
  330. snprintf(err_str, 128,
  331. "RPNExpr.__setstate__() error : expected state to \
  332. contains %ld bytes but %ld found",
  333. state->total_sz, bsize);
  334. PyErr_SetString(PyExc_ValueError, err_str);
  335. }
  336. /* Checking data "integrity" */
  337. csize = sizeof(PyRPNExpr_state_t) +
  338. state->token_sz * sizeof(rpn_token_t) +
  339. state->stack_sz * sizeof(rpn_value_t);
  340. if(state->total_sz != csize)
  341. {
  342. snprintf(err_str, 128,
  343. "RPNExpr.__setstate__() error : should have %ld as \
  344. total size but %ld found",
  345. csize, state->total_sz);
  346. PyErr_SetString(PyExc_ValueError, err_str);
  347. return NULL;
  348. }
  349. /* Alloc and init rpn expression & args buffer*/
  350. if(!(expr_self->rpn = malloc(sizeof(rpn_expr_t))))
  351. {
  352. err = errno;
  353. snprintf(err_str, 128,
  354. "RPNExpr.__setstate__() failed to allocate memory for \
  355. rpn_expr_t : %s",
  356. strerror(err));
  357. PyErr_SetString(PyExc_MemoryError, err_str);
  358. return NULL;
  359. }
  360. bzero(expr_self->rpn, sizeof(rpn_expr_t));
  361. if(!(expr_self->args = malloc(sizeof(rpn_value_t)*state->argc)))
  362. {
  363. err = errno;
  364. snprintf(err_str, 128,
  365. "RPNExpr.__setstate__() failed to allocate memory for \
  366. args buffer : %s",
  367. strerror(err));
  368. PyErr_SetString(PyExc_MemoryError, err_str);
  369. return NULL;
  370. }
  371. if(rpn_expr_init(expr_self->rpn, state->stack_sz, state->argc) < 0)
  372. {
  373. snprintf(err_str, 256,
  374. "RPNExpr.__setstate__() failed to init RPN expression \
  375. : %s",
  376. expr_self->rpn->err_reason);
  377. PyErr_SetString(PyExc_RuntimeError, err_str);
  378. goto free_err;
  379. }
  380. /* restore stack & untokenize expression */
  381. stack = (rpn_value_t*)(state+1);
  382. memcpy(expr_self->rpn->stack, stack,
  383. sizeof(rpn_value_t)*state->stack_sz);
  384. toks.argc = state->argc;
  385. toks.tokens_sz = state->token_sz;
  386. toks.tokens = malloc(sizeof(rpn_token_t)*state->token_sz);
  387. if(!toks.tokens)
  388. {
  389. snprintf(err_str, 128,
  390. "RPNExpr.__setstate__() failed to allocate tokens \
  391. : %s",
  392. strerror(errno));
  393. PyErr_SetString(PyExc_RuntimeError, err_str);
  394. goto close_err;
  395. }
  396. memcpy(toks.tokens, (rpn_token_t*)(stack+state->stack_sz),
  397. sizeof(rpn_token_t)*state->token_sz);
  398. for(i=0; i<toks.tokens_sz;i++)
  399. {
  400. // restore op pointers
  401. toks.tokens[i].op = &(rpn_ops[toks.tokens[i].op_n]);
  402. }
  403. if(rpn_expr_untokenize(expr_self->rpn, &toks, 0) < 0)
  404. {
  405. snprintf(err_str, 256,
  406. "RPNExpr.__setstate__() unable to untokenize : %s",
  407. expr_self->rpn->err_reason);
  408. PyErr_SetString(PyExc_RuntimeError, err_str);
  409. goto close_err;
  410. }
  411. expr_self->rpn->toks = toks;
  412. Py_RETURN_NONE;
  413. close_err:
  414. rpn_expr_close(expr_self->rpn);
  415. free_err:
  416. return NULL;
  417. }
  418. PyObject* rpnexpr_eval(PyObject* self, PyObject** argv, Py_ssize_t argc)
  419. {
  420. PyRPNExpr_t *expr_self;
  421. unsigned long res;
  422. char err_str[128];
  423. Py_ssize_t i;
  424. PyObject *cur, *ret;
  425. expr_self = (PyRPNExpr_t*)self;
  426. if((unsigned long)argc != expr_self->rpn->args_count)
  427. {
  428. snprintf(err_str, 128,
  429. "RPNExpr expected %ld arguments but %ld given",
  430. expr_self->rpn->args_count,
  431. argc);
  432. PyErr_SetString(PyExc_ValueError, err_str);
  433. return NULL;
  434. }
  435. for(i=0; i<argc; i++)
  436. {
  437. cur = argv[i];
  438. if(!PyLong_Check(cur))
  439. {
  440. snprintf(err_str, 128,
  441. "RpnExpr.__call__ expect int as arguments but argument %ld is not",
  442. i+1);
  443. PyErr_SetString(PyExc_ValueError, err_str);
  444. return NULL;
  445. }
  446. expr_self->args[i] = PyLong_AsUnsignedLong(argv[i]);
  447. if((ret = PyErr_Occurred()))
  448. {
  449. Py_DECREF(ret);
  450. return NULL;
  451. }
  452. }
  453. res = rpn_expr_eval(expr_self->rpn, expr_self->args);
  454. //dprintf(2, "[RES=%lu]\n", res);
  455. return PyLong_FromUnsignedLong(res);
  456. }
  457. PyObject* rpnexpr_reset_stack(PyObject *self, PyObject *noargs)
  458. {
  459. rpn_expr_reset_stack(((PyRPNExpr_t*)self)->rpn);
  460. Py_RETURN_NONE;
  461. }
  462. PyObject* rpnexpr_str(PyObject *self)
  463. {
  464. PyRPNExpr_t *expr_self;
  465. PyObject *res;
  466. expr_self = (PyRPNExpr_t*)self;
  467. res = Py_BuildValue("s", expr_self->rpn->expr);
  468. return res;
  469. }
  470. PyObject* rpnexpr_repr(PyObject *self)
  471. {
  472. PyRPNExpr_t *expr_self;
  473. PyObject *res;
  474. size_t sz;
  475. char *buff, err_str[128];
  476. expr_self = (PyRPNExpr_t*)self;
  477. sz = snprintf(NULL, 0, "<RPNExpr argc:%ld stck_sz:%d '%s'>",
  478. expr_self->rpn->args_count, expr_self->rpn->stack_sz,
  479. expr_self->rpn->expr);
  480. buff = malloc(sizeof(char) * (sz + 1));
  481. if(!buff)
  482. {
  483. snprintf(err_str, 128,
  484. "Error allocating repr : %s",
  485. strerror(errno));
  486. PyErr_SetString(PyExc_RuntimeError, err_str);
  487. return NULL;
  488. }
  489. snprintf(buff, sz+1, "<RPNExpr argc:%ld stck_sz:%d '%s'>",
  490. expr_self->rpn->args_count, expr_self->rpn->stack_sz,
  491. expr_self->rpn->expr);
  492. res = Py_BuildValue("s", buff);
  493. free(buff);
  494. return res;
  495. }