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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  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. {NULL} //Sentinel
  25. };
  26. PyMemberDef RPNExpr_members[] = {
  27. {NULL}
  28. };
  29. PyTypeObject RPNExprType = {
  30. PyVarObject_HEAD_INIT(NULL, 0)
  31. "rpn.RPNExpr", /* tp_name */
  32. sizeof(PyRPNExpr_t), /* tp_basicsize */
  33. 0, /* tp_itemsize */
  34. (destructor)rpnexpr_del, /* tp_dealloc */
  35. 0, /* tp_print */
  36. 0, /* tp_getattr */
  37. 0, /* tp_setattr */
  38. 0, /* tp_reserved */
  39. rpnexpr_repr, /* tp_repr */
  40. 0, /* tp_as_number */
  41. 0, /* tp_as_sequence */
  42. 0, /* tp_as_mapping */
  43. 0, /* tp_hash */
  44. 0, /* tp_call */
  45. rpnexpr_str, /* tp_str */
  46. 0, /* tp_getattro */
  47. 0, /* tp_setattro */
  48. 0, /* tp_as_buffer */
  49. Py_TPFLAGS_DEFAULT |
  50. Py_TPFLAGS_BASETYPE, /* tp_flags */
  51. "RPN expression evaluator", /* tp_doc */
  52. 0, /* tp_traverse */
  53. 0, /* tp_clear */
  54. 0, /* tp_richcompare */
  55. 0, /* tp_weaklistoffset */
  56. 0, /* tp_iter */
  57. 0, /* tp_iternext */
  58. RPNExpr_methods, /* tp_methods */
  59. RPNExpr_members, /* tp_members */
  60. 0, /* tp_getset */
  61. 0, /* tp_base */
  62. 0, /* tp_dict */
  63. 0, /* tp_descr_get */
  64. 0, /* tp_descr_set */
  65. 0, /* tp_dictoffset */
  66. rpnexpr_init, /* tp_init */
  67. 0, /* tp_alloc */
  68. rpnexpr_new, /* tp_new */
  69. };
  70. PyObject* rpnexpr_new(PyTypeObject *subtype, PyObject *args, PyObject* kwds)
  71. {
  72. PyObject *ret, *err;
  73. PyRPNExpr_t *expr;
  74. ret = PyType_GenericNew(subtype, args, kwds);
  75. if((err = PyErr_Occurred()))
  76. {
  77. Py_DECREF(err);
  78. return ret;
  79. }
  80. expr = (PyRPNExpr_t*)ret;
  81. expr->rpn = NULL;
  82. expr->args = NULL;
  83. return ret;
  84. }
  85. int rpnexpr_init(PyObject *self, PyObject *args, PyObject *kwds)
  86. {
  87. PyRPNExpr_t *expr_self;
  88. char *names[] = {"expression", "args_count", "stack_size", NULL};
  89. char err_str[256];
  90. const char *expr;
  91. long long int args_count, stack_size;
  92. expr_self = (PyRPNExpr_t*)self;
  93. stack_size = 16;
  94. expr_self->rpn = NULL;
  95. if(!PyArg_ParseTupleAndKeywords(args, kwds, "sL|L:RPNExpr.__init__", names, &expr,
  96. &args_count, &stack_size))
  97. {
  98. return -1;
  99. }
  100. if(strlen(expr) == 0)
  101. {
  102. PyErr_SetString(PyExc_ValueError,
  103. "RpnExpr.__init__() expect expression argument to be not empty");
  104. return -1;
  105. }
  106. if(args_count < 0 || args_count > 255)
  107. {
  108. snprintf(err_str, 128,
  109. "Argument count should be in [4..255] but %lld given",
  110. args_count);
  111. PyErr_SetString(PyExc_ValueError, err_str);
  112. return -1;
  113. }
  114. if(stack_size < 4 || stack_size > 255)
  115. {
  116. snprintf(err_str, 128,
  117. "Stack size should be in [0..255] but %lld given",
  118. stack_size);
  119. PyErr_SetString(PyExc_ValueError, err_str);
  120. return -1;
  121. }
  122. expr_self->rpn = malloc(sizeof(rpn_expr_t));
  123. if(!expr_self->rpn)
  124. {
  125. snprintf(err_str, 256,
  126. "Expression memory allocation error : %s",
  127. strerror(errno));
  128. }
  129. bzero(expr_self->rpn, sizeof(rpn_expr_t));
  130. if(rpn_expr_init(expr_self->rpn, stack_size, args_count) < 0)
  131. {
  132. snprintf(err_str, 256,
  133. "Expression init error : %s",
  134. expr_self->rpn->err_reason);
  135. PyErr_SetString(PyExc_ValueError, err_str);
  136. return -1;
  137. }
  138. if(!stack_size)
  139. {
  140. expr_self->args = NULL;
  141. return 0;
  142. }
  143. expr_self->args = malloc(sizeof(unsigned long) * 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_eval(PyObject* self, PyObject** argv, Py_ssize_t argc)
  175. {
  176. PyRPNExpr_t *expr_self;
  177. unsigned long res;
  178. char err_str[128];
  179. Py_ssize_t i;
  180. PyObject *cur, *ret;
  181. expr_self = (PyRPNExpr_t*)self;
  182. if((unsigned long)argc != expr_self->rpn->args_count)
  183. {
  184. snprintf(err_str, 128,
  185. "RPNExpr expected %ld arguments but %ld given",
  186. expr_self->rpn->args_count,
  187. argc);
  188. PyErr_SetString(PyExc_ValueError, err_str);
  189. return NULL;
  190. }
  191. for(i=0; i<argc; i++)
  192. {
  193. cur = argv[i];
  194. if(!PyLong_Check(cur))
  195. {
  196. snprintf(err_str, 128,
  197. "RpnExpr.__call__ expect int as arguments but argument %ld is not",
  198. i+1);
  199. PyErr_SetString(PyExc_ValueError, err_str);
  200. return NULL;
  201. }
  202. expr_self->args[i] = PyLong_AsUnsignedLong(argv[i]);
  203. if((ret = PyErr_Occurred()))
  204. {
  205. Py_DECREF(ret);
  206. return NULL;
  207. }
  208. }
  209. res = rpn_expr_eval(expr_self->rpn, expr_self->args);
  210. //dprintf(2, "[RES=%lu]\n", res);
  211. return PyLong_FromUnsignedLong(res);
  212. }
  213. PyObject* rpnexpr_reset_stack(PyObject *self, PyObject *noargs)
  214. {
  215. rpn_expr_reset_stack(((PyRPNExpr_t*)self)->rpn);
  216. Py_RETURN_NONE;
  217. }
  218. PyObject* rpnexpr_str(PyObject *self)
  219. {
  220. PyRPNExpr_t *expr_self;
  221. PyObject *res;
  222. expr_self = (PyRPNExpr_t*)self;
  223. res = Py_BuildValue("s", expr_self->rpn->expr);
  224. return res;
  225. }
  226. PyObject* rpnexpr_repr(PyObject *self)
  227. {
  228. PyRPNExpr_t *expr_self;
  229. PyObject *res;
  230. size_t sz;
  231. char *buff, err_str[128];
  232. expr_self = (PyRPNExpr_t*)self;
  233. sz = snprintf(NULL, 0, "<RPNExpr argc:%ld stck_sz:%d '%s'>",
  234. expr_self->rpn->args_count, expr_self->rpn->stack_sz,
  235. expr_self->rpn->expr);
  236. buff = malloc(sizeof(char) * (sz + 1));
  237. if(!buff)
  238. {
  239. snprintf(err_str, 128,
  240. "Error allocating repr : %s",
  241. strerror(errno));
  242. PyErr_SetString(PyExc_RuntimeError, err_str);
  243. return NULL;
  244. }
  245. snprintf(buff, sz+1, "<RPNExpr argc:%ld stck_sz:%d '%s'>",
  246. expr_self->rpn->args_count, expr_self->rpn->stack_sz,
  247. expr_self->rpn->expr);
  248. res = Py_BuildValue("s", buff);
  249. free(buff);
  250. return res;
  251. }