SOURCES: statesaver.c (NEW), statesaver-setup.py (NEW) - new
arekm
arekm at pld-linux.org
Tue Dec 20 00:39:25 CET 2005
Author: arekm Date: Mon Dec 19 23:39:25 2005 GMT
Module: SOURCES Tag: HEAD
---- Log message:
- new
---- Files affected:
SOURCES:
statesaver.c (NONE -> 1.1) (NEW), statesaver-setup.py (NONE -> 1.1) (NEW)
---- Diffs:
================================================================
Index: SOURCES/statesaver.c
diff -u /dev/null SOURCES/statesaver.c:1.1
--- /dev/null Tue Dec 20 00:39:25 2005
+++ SOURCES/statesaver.c Tue Dec 20 00:39:20 2005
@@ -0,0 +1,425 @@
+#include <Python.h>
+#include <compile.h>
+#include <frameobject.h>
+#include <eval.h>
+
+
+static PyObject* copyrec(PyObject* o); /* forward */
+
+
+static PyObject* genbuild(PyObject* g)
+{
+ PyObject* x;
+ PyFrameObject* f;
+ PyCodeObject* co;
+ PyObject** dummy;
+ int i, res;
+
+ x = PyObject_GetAttrString(g, "gi_running");
+ if (x == NULL)
+ return NULL;
+ res = PyObject_IsTrue(x);
+ if (res < 0)
+ return NULL;
+ if (res) {
+ PyErr_SetString(PyExc_ValueError, "generator is running");
+ return NULL;
+ }
+
+ x = PyObject_GetAttrString(g, "gi_frame");
+ if (x == NULL)
+ return NULL;
+ if (!PyFrame_Check(x)) {
+ PyErr_SetString(PyExc_TypeError, "g.gi_frame must be a frame object");
+ return NULL;
+ }
+ f = (PyFrameObject*) x;
+ co = f->f_code;
+
+ if (!(co->co_flags & CO_GENERATOR)) {
+ PyErr_SetString(PyExc_ValueError, "the frame is not from a generator");
+ return NULL;
+ }
+ if (f->f_stacktop == NULL) {
+ Py_INCREF(g); /* exhausted -- can return 'g' itself */
+ return g;
+ }
+ if (f->f_nfreevars || f->f_ncells) {
+ PyErr_SetString(PyExc_ValueError, "generator has cell or free vars");
+ return NULL;
+ }
+
+ dummy = (PyObject**) malloc(co->co_argcount * sizeof(PyObject*));
+ if (dummy == NULL)
+ return PyErr_NoMemory();
+ for (i=0; i<co->co_argcount; i++)
+ dummy[i] = Py_None;
+ x = PyEval_EvalCodeEx(co, f->f_globals, f->f_locals,
+ dummy, co->co_argcount, NULL, 0,
+ NULL, 0, NULL);
+ free(dummy);
+ return x;
+}
+
+static int gencopy(PyObject* g2, PyObject* g)
+{
+ PyObject* x;
+ PyFrameObject* f;
+ PyFrameObject* f2;
+ PyCodeObject* co;
+ int i, res;
+
+ if (g != g2)
+ {
+ if (g2->ob_type != g->ob_type)
+ {
+ PyErr_SetString(PyExc_TypeError, "type mismatch");
+ return -1;
+ }
+
+ x = PyObject_GetAttrString(g, "gi_frame");
+ if (x == NULL)
+ return -1;
+ if (!PyFrame_Check(x)) {
+ PyErr_SetString(PyExc_TypeError, "g.gi_frame must be a frame object");
+ return -1;
+ }
+ f = (PyFrameObject*) x;
+ co = f->f_code;
+
+ x = PyObject_GetAttrString(g2, "gi_frame");
+ if (x == NULL)
+ return -1;
+ if (!PyFrame_Check(x)) {
+ PyErr_SetString(PyExc_TypeError, "returned gi_frame");
+ return -1;
+ }
+ f2 = (PyFrameObject*) x;
+ if (f2->f_stacksize != f->f_stacksize) {
+ PyErr_SetString(PyExc_TypeError, "stack size mismatch");
+ return -1;
+ }
+
+ if (f2->f_stacktop != NULL)
+ while (f2->f_stacktop != f2->f_localsplus)
+ {
+ f2->f_stacktop--;
+ Py_XDECREF(*f2->f_stacktop);
+ }
+
+ res = f->f_stacktop - f->f_localsplus;
+ f2->f_lasti = f->f_lasti;
+ f2->f_iblock = f->f_iblock;
+ memcpy(f2->f_blockstack, f->f_blockstack, sizeof(PyTryBlock)*f->f_iblock);
+ f2->f_stacktop = f2->f_localsplus;
+ for (i=0; i<res; i++)
+ {
+ x = f->f_localsplus[i];
+ if (x != NULL)
+ x = copyrec(x);
+ *f2->f_stacktop++ = x;
+ }
+ }
+ return 0;
+}
+
+
+typedef struct {
+ PyObject_HEAD
+ long it_index;
+ PyObject *it_seq; /* Set to NULL when iterator is exhausted */
+} seqiterobject;
+
+static PyObject* seqiterbuild(PyObject* o)
+{
+ seqiterobject* iter = (seqiterobject*) o;
+ if (iter->it_seq == NULL)
+ {
+ Py_INCREF(iter); /* exhausted */
+ return (PyObject*) iter;
+ }
+ else
+ return PySeqIter_New(iter->it_seq);
+}
+
+static int seqitercopy(PyObject* o2, PyObject* o)
+{
+ PyObject* x;
+ seqiterobject* iter = (seqiterobject*) o;
+ seqiterobject* iter2 = (seqiterobject*) o2;
+
+ iter2->it_index = iter->it_index;
+ if (iter->it_seq != NULL)
+ {
+ x = copyrec(iter->it_seq);
+ Py_XDECREF(iter2->it_seq);
+ iter2->it_seq = x;
+ }
+ return 0;
+}
+
+
+/* HACKS HACKS HACKS */
+
+typedef struct {
+ PyObject_HEAD
+ PyObject* o;
+} KeyObject;
+
+#define KEYS_BY_BLOCK 1024
+
+struct key_block {
+ KeyObject keys[KEYS_BY_BLOCK];
+ struct key_block* next;
+};
+
+static long key_hash(KeyObject* k)
+{
+ return (long)(k->o);
+}
+
+static PyObject* key_richcmp(KeyObject* k1, KeyObject* k2, int op)
+{
+ PyObject* r;
+ assert(op == 2 /*PyCmp_EQ*/ );
+ r = k1->o == k2->o ? Py_True : Py_False;
+ Py_INCREF(r);
+ return r;
+}
+
+static PyTypeObject keytype = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "key",
+ sizeof(KeyObject),
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc)key_hash, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ (richcmpfunc)key_richcmp, /* tp_richcompare */
+};
+
+
+/* global state */
+static PyObject* ss_memo;
+static struct key_block* ss_block;
+static int ss_next_in_block;
+
+static PyObject* str_inst_build;
+static PyTypeObject* GeneratorType;
+
+static PyObject* copyrec(PyObject* o)
+{
+ PyTypeObject* t;
+ PyObject* n;
+ PyObject* key;
+ KeyObject* fkey;
+
+ if (o == Py_None || o->ob_type == &PyInt_Type || o->ob_type == &PyString_Type)
+ {
+ Py_INCREF(o);
+ return o;
+ }
+ if (ss_next_in_block < 0)
+ {
+ struct key_block* b = (struct key_block*) malloc(sizeof(struct key_block));
+ if (!b) { PyErr_NoMemory(); goto fail1; }
+ b->next = ss_block;
+ ss_block = b;
+ ss_next_in_block = KEYS_BY_BLOCK - 1;
+ }
+ fkey = ss_block->keys + ss_next_in_block;
+ fkey->ob_refcnt = 1;
+ fkey->ob_type = &keytype;
+ fkey->o = o;
+ key = (PyObject*) fkey;
+ n = PyDict_GetItem(ss_memo, key);
+ if (n)
+ {
+ Py_INCREF(n);
+ return n;
+ }
+ ss_next_in_block--;
+ Py_INCREF(o); /* reference stored in 'fkey->o' */
+ t = o->ob_type;
+ if (t == &PyTuple_Type)
+ {
+ int i, count = PyTuple_GET_SIZE(o);
+ n = PyTuple_New(count);
+ if (!n || PyDict_SetItem(ss_memo, key, n)) goto fail;
+ for (i=0; i<count; i++)
+ PyTuple_SET_ITEM(n, i, copyrec(PyTuple_GET_ITEM(o, i)));
+ return n;
+ }
+ if (t == &PyList_Type)
+ {
+ int i, count = PyList_GET_SIZE(o);
+ n = PyList_New(count);
+ if (!n || PyDict_SetItem(ss_memo, key, n)) goto fail;
+ for (i=0; i<count; i++)
+ PyList_SET_ITEM(n, i, copyrec(PyList_GET_ITEM(o, i)));
+ return n;
+ }
+ if (t == &PyDict_Type)
+ {
+ int i = 0;
+ PyObject* dictkey;
+ PyObject* dictvalue;
+ n = PyDict_New();
+ if (!n || PyDict_SetItem(ss_memo, key, n)) goto fail;
+ while (PyDict_Next(o, &i, &dictkey, &dictvalue))
+ if (PyDict_SetItem(n, copyrec(dictkey), copyrec(dictvalue)))
+ goto fail;
+ return n;
+ }
+ if (t == &PyInstance_Type)
+ {
+ int i = 0;
+ PyObject* dictkey;
+ PyObject* dictvalue;
+ PyObject* dsrc;
+ PyObject* ddest;
+ PyObject* inst_build = PyObject_GetAttr(o, str_inst_build);
+ if (inst_build == NULL)
+ {
+ PyErr_Clear();
+ goto unmodified;
+ }
+ n = PyObject_CallObject(inst_build, NULL);
+ if (!n || PyDict_SetItem(ss_memo, key, n)) goto fail;
+ dsrc = ((PyInstanceObject*) o)->in_dict;
+ ddest = ((PyInstanceObject*) n)->in_dict;
+ while (PyDict_Next(dsrc, &i, &dictkey, &dictvalue))
+ if (PyDict_SetItem(ddest, copyrec(dictkey), copyrec(dictvalue)))
+ goto fail;
+ return n;
+ }
+ if (t == &PyFunction_Type)
+ {
+ int i, count;
+ PyObject* tsrc = PyFunction_GET_DEFAULTS(o);
+ PyObject* tdest;
+ if (!tsrc) goto unmodified;
+ count = PyTuple_GET_SIZE(tsrc);
+ if (count == 0) goto unmodified;
+ n = PyFunction_New(PyFunction_GET_CODE(o), PyFunction_GET_GLOBALS(o));
+ if (!n || PyDict_SetItem(ss_memo, key, n)) goto fail;
+ tdest = PyTuple_New(count);
+ if (!tdest) goto fail;
+ for (i=0; i<count; i++)
+ PyTuple_SET_ITEM(tdest, i, copyrec(PyTuple_GET_ITEM(tsrc, i)));
+ i = PyFunction_SetDefaults(n, tdest);
+ Py_DECREF(tdest);
+ if (i) goto fail;
+ return n;
+ }
+ if (t == &PyMethod_Type)
+ {
+ PyObject* x;
+ n = PyMethod_New(PyMethod_GET_FUNCTION(o),
+ PyMethod_GET_SELF(o),
+ PyMethod_GET_CLASS(o));
+ if (!n || PyDict_SetItem(ss_memo, key, n)) goto fail;
+ x = copyrec(PyMethod_GET_FUNCTION(n));
+ Py_DECREF(PyMethod_GET_FUNCTION(n));
+ PyMethod_GET_FUNCTION(n) = x;
+ x = copyrec(PyMethod_GET_SELF(n));
+ Py_DECREF(PyMethod_GET_SELF(n));
+ PyMethod_GET_SELF(n) = x;
+ return n;
+ }
+ if (t == GeneratorType)
+ {
+ n = genbuild(o);
+ if (!n || PyDict_SetItem(ss_memo, key, n)) goto fail;
+ if (gencopy(n, o)) goto fail;
+ return n;
+ }
+ if (t == &PySeqIter_Type)
+ {
+ n = seqiterbuild(o);
+ if (!n || PyDict_SetItem(ss_memo, key, n)) goto fail;
+ if (seqitercopy(n, o)) goto fail;
+ return n;
+ }
+ ss_next_in_block++;
+ return o; /* reference no longer stored in 'fkey->o' */
+
+ unmodified:
+ PyDict_SetItem(ss_memo, key, o);
+ Py_INCREF(o);
+ return o;
+
+ fail1:
+ n = NULL;
+ fail:
+ Py_INCREF(o);
+ Py_XDECREF(n);
+ return o;
+}
+
+static PyObject* sscopy(PyObject* self, PyObject* o)
+{
+ PyObject* n;
+ ss_memo = PyDict_New();
+ if (!ss_memo)
+ return NULL;
+
+ ss_block = NULL;
+ ss_next_in_block = -1;
+ n = copyrec(o);
+ Py_DECREF(ss_memo);
+ while (ss_block)
+ {
+ int i;
+ struct key_block* b = ss_block;
+ ss_block = b->next;
+ for (i=ss_next_in_block+1; i<KEYS_BY_BLOCK; i++)
+ Py_DECREF(b->keys[i].o);
+ free(b);
+ ss_next_in_block = -1;
+ }
+ if (PyErr_Occurred())
+ {
+ Py_DECREF(n);
+ n = NULL;
+ }
+ return n;
+}
+
+
+static PyMethodDef StateSaverMethods[] = {
+ {"copy", sscopy, METH_O},
+ {NULL, NULL} /* Sentinel */
+};
+
+void initstatesaver(void)
+{
+ PyObject* m;
+ m = Py_InitModule("statesaver", StateSaverMethods);
+ if (m == NULL)
+ return;
+ keytype.ob_type = &PyType_Type;
+ str_inst_build = PyString_InternFromString("inst_build");
+
+ m = PyImport_ImportModule("types");
+ if (!m) return;
+ GeneratorType = (PyTypeObject*) PyObject_GetAttrString(m, "GeneratorType");
+ if (!GeneratorType) return;
+}
================================================================
Index: SOURCES/statesaver-setup.py
diff -u /dev/null SOURCES/statesaver-setup.py:1.1
--- /dev/null Tue Dec 20 00:39:25 2005
+++ SOURCES/statesaver-setup.py Tue Dec 20 00:39:20 2005
@@ -0,0 +1,22 @@
+#! /usr/bin/env python
+
+from distutils.core import setup
+from distutils.extension import Extension
+
+##setup ( name="gencopy",
+## version="0.1",
+## description="generator and iterator state",
+## author="Armin",
+## author_email="arigo at tunes.org",
+## ext_modules=[Extension(name = 'gencopy',
+## sources = ['gencopy.c'])]
+## )
+
+setup ( name="statesaver",
+ version="0.1",
+ description="object duplicator working on generators and iterators",
+ author="Armin",
+ author_email="arigo at tunes.org",
+ ext_modules=[Extension(name = 'statesaver',
+ sources = ['statesaver.c'])]
+ )
================================================================
More information about the pld-cvs-commit
mailing list