Compare commits
1 commit
aefdc62fb7
...
148afe7adc
Author | SHA1 | Date | |
---|---|---|---|
148afe7adc |
3 changed files with 102 additions and 11 deletions
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue