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

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