Compare commits

...

1 commit

3 changed files with 102 additions and 11 deletions

View file

@ -27,6 +27,8 @@ PyMethodDef RPNExpr_methods[] = {
and the stack state."},
{"__setstate__", (PyCFunction)rpnexpr_setstate, METH_O,
"Unpickling method"},
{"uid", (PyCFunction)rpnexpr_getexprstate, METH_NOARGS,
"Return a base64 uid for expression"},
{NULL} //Sentinel
};
@ -191,12 +193,50 @@ void rpnexpr_del(PyObject *self)
}
PyObject* rpnexpr_getexprstate(PyObject *self, PyObject *noargs)
{
/*
PyObject *base64_mod, *base64_encode, *gzip, *compress;
PyObject *bytes_repr, *comp, *res;
if(!(base64_mod = PyImport_ImportModule("base64")))
{
return NULL;
}
if(!(base64_encode = PyObject_GetAttrString(base64_mod, "b64encode")))
{
return NULL;
}
if(!(gzip = PyImport_ImportModule("gzip")))
{
return NULL;
}
if(!(compress = PyObject_GetAttrString(gzip, "compress")))
{
return NULL;
}
bytes_repr = _rpnexpr_getstate(self, noargs, 0);
res = PyObject_CallOneArg(base64_encode, bytes_repr);
Py_DECREF(bytes_repr);
return res;
comp = PyObject_CallOneArg(compress, bytes_repr);
Py_DECREF(bytes_repr);
res = PyObject_CallOneArg(base64_encode, comp);
Py_DECREF(comp);
return res;
*/
return NULL;
}
PyObject* rpnexpr_getstate(PyObject *self, PyObject *noargs)
{
PyObject *res, *part;
PyRPNExpr_state_t resbuf;
PyRPNExpr_t *expr_self;
size_t total_sz;
size_t total_sz, i;
char err_str[128];
expr_self = (PyRPNExpr_t*)self;
@ -239,12 +279,24 @@ PyObject* rpnexpr_getstate(PyObject *self, PyObject *noargs)
}
if(resbuf.token_sz)
{
for(i=0; i<expr_self->rpn->toks.tokens_sz;i++)
{
// restore op pointers
expr_self->rpn->toks.tokens[i].op = NULL;
}
if(!(part=PyBytes_FromStringAndSize(
(char*)expr_self->rpn->toks.tokens,
sizeof(rpn_token_t) * resbuf.token_sz)))
{
return NULL;
}
for(i=0; i<expr_self->rpn->toks.tokens_sz;i++)
{
// restore op pointers
expr_self->rpn->toks.tokens[i].op = &(rpn_ops[expr_self->rpn->toks.tokens[i].op_n]);
}
PyBytes_ConcatAndDel(&res, part);
if(!res)
{
@ -393,8 +445,6 @@ args buffer : %s",
toks.tokens[i].op = &(rpn_ops[toks.tokens[i].op_n]);
}
expr_self->rpn->toks = toks;
if(rpn_expr_untokenize(expr_self->rpn, &toks, 0) < 0)
{
snprintf(err_str, 256,
@ -403,6 +453,8 @@ args buffer : %s",
PyErr_SetString(PyExc_RuntimeError, err_str);
goto close_err;
}
expr_self->rpn->toks = toks;
Py_RETURN_NONE;
close_err:

View file

@ -99,13 +99,21 @@ int rpnexpr_init(PyObject *self, PyObject *args, PyObject *kwds);
*/
void rpnexpr_del(PyObject *self);
/**@brief Returns a byte representation of expression (like getstate but
* without the stack informations
* @param self RPNExpr instance
* @param noargs Not an argument...
* @return A bytes Python instance
*/
PyObject* rpnexpr_getexprstate(PyObject *self, PyObject *noargs);
/**@brief RPNExpr __getstate__ method for pickling
* @param cls RPNExpr type object
* @param self RPNExpr type object
* @param noargs Not an argument...
* @return A bytes Python instance suitable as argument for
* @ref rpnexpr_setstate
*/
PyObject* rpnexpr_getstate(PyObject *cls, PyObject *noargs);
PyObject* rpnexpr_getstate(PyObject *self, PyObject *noargs);
/**@brief RPNExpr __setstate__ method for pickling
* @param cls RPNExpr type object

View file

@ -34,6 +34,29 @@ except (ImportError, NameError) as e:
file=sys.stderr)
raise e
## TODO : move this function somewhere or implement it in C
def decode_state(state):
""" Return a dict containing rpn state dump fields
"""
res = dict()
res['real_sz'] = len(state)
res['total_sz'] = int.from_bytes(state[0:8], byteorder="little")
res['argc'] = int.from_bytes(state[8:16], byteorder="little")
res['stack_sz_bytes'] = state[16:24]
res['stack_sz'] = state[16]
res['token_sz'] = int.from_bytes(state[24:32], byteorder="little", signed=True)
res['stack'] = [int.from_bytes(state[i:i+8], byteorder="little")
for i in range(32, 32 + (8*res['stack_sz']),8)]
res['tokens_off'] = 32 + (8*res['stack_sz'])
res['tokens_real_sz'] = res['real_sz'] - res['tokens_off']
res['tokens'] = [state[i:i+24]
for i in range(res['tokens_off'],
res['tokens_off'] + (24*res['token_sz']),
24)]
return res
pass
class Test0RpnModule(unittest.TestCase):
def test_init(self):
@ -121,16 +144,24 @@ class Test0RpnModule(unittest.TestCase):
def test_pickle_state(self):
""" Testing pickling/unpickling """
e = pyrpn.RPNExpr(pyrpn.random_expr(2), 2)
e = pyrpn.RPNExpr('0x42 + A0', 2)
e2 = pickle.loads(pickle.dumps(e))
ds_e = decode_state(e.__getstate__())
ds_e2 = decode_state(e2.__getstate__())
self.assertEqual(e.__getstate__(), e2.__getstate__(),
msg="EXPR: %r != %r (%r != %r)" % (e, e2, ds_e, ds_e2))
for i in range(100):
e = pyrpn.RPNExpr(pyrpn.random_expr(0), 2)
self.assertEqual(e.__getstate__(), e2.__getstate__())
e2 = pickle.loads(pickle.dumps(e))
e3 = pickle.loads(pickle.dumps(e2))
self.assertEqual(e.__getstate__(), e2.__getstate__(),
msg="EXPR#%d : %r != %r" % (i,e, e2))
self.assertEqual(e.__getstate__(), e3.__getstate__())
self.assertEqual(e2.__getstate__(), e3.__getstate__())
e3 = pickle.loads(pickle.dumps(e2))
self.assertEqual(e.__getstate__(), e3.__getstate__(), msg=e)
self.assertEqual(e2.__getstate__(), e3.__getstate__(), msg=e)
if __name__ == '__main__':
unittest.main()