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 15KB

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