X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb-python/blobdiff_plain/810542b01716cfd7017315c25a165ebfbe45afe5..0e5b95a8f4bf60e5cb805d25d9d202af80145734:/catacomb.c diff --git a/catacomb.c b/catacomb.c index 60dae45..23906eb 100644 --- a/catacomb.c +++ b/catacomb.c @@ -35,65 +35,72 @@ PyObject *mexp_common(PyObject *me, PyObject *arg, PyObject *(*id)(PyObject *), int (*fill)(void *, PyObject *, PyObject *, PyObject *), - PyObject *(*exp)(PyObject *, void *, int), + PyObject *(*exp)(PyObject *, void *, size_t), void (*drop)(void *)) { - int i = 0, j, n, flat; - PyObject *qq, *x, *y, *z = 0; - char *v = 0, *vv; - - if (PyTuple_GET_SIZE(arg) == 1) - arg = PyTuple_GET_ITEM(arg, 0); - Py_INCREF(arg); - if (!PySequence_Check(arg)) TYERR("not a sequence"); - n = PySequence_Size(arg); if (n < 0) goto end; - if (!n) { z = id(me); goto end; } - x = PySequence_GetItem(arg, 0); - if (PySequence_Check(x)) - flat = 0; + size_t i = 0, o, n; + int flat; + PyObject *qq = 0, *x = 0, *y = 0, *z = 0, *it = 0; + char *v = 0; + + if (PyTuple_Size(arg) == 1) arg = PyTuple_GET_ITEM(arg, 0); + it = PyObject_GetIter(arg); if (!it) goto end; + qq = PyIter_Next(it); + if (!qq) { + if (!PyErr_Occurred()) z = id(me); + else goto end; + } + flat = !PySequence_Check(qq); + if (!PySequence_Check(arg)) + n = 16; else { - if (n % 2) VALERR("must have even number of arguments"); - n /= 2; - flat = 1; + n = PySequence_Size(arg); + if (n == (size_t)-1 && PyErr_Occurred()) goto end; + if (flat) n /= 2; + if (!n) n = 16; } - Py_DECREF(x); - v = xmalloc(n * efsz); - for (i = j = 0, vv = v; i < n; i++, vv += efsz) { - if (flat) { - x = PySequence_GetItem(arg, j++); - y = PySequence_GetItem(arg, j++); - } else { - qq = PySequence_GetItem(arg, j++); - if (!qq) goto end; - if (!PySequence_Check(qq) || PySequence_Size(qq) != 2) { - Py_DECREF(qq); + v = xmalloc(n*efsz); + o = 0; + for (;;) { + if (!flat) { + if (!PySequence_Check(qq) || PySequence_Size(qq) != 2) TYERR("want a sequence of pairs"); - } x = PySequence_GetItem(qq, 0); y = PySequence_GetItem(qq, 1); - Py_DECREF(qq); + } else { + x = qq; qq = 0; + y = PyIter_Next(it); + if (!y) { + if (PyErr_Occurred()) goto end; + VALERR("must have even number of operands"); + } } if (!x || !y) goto end; - if (fill(vv, me, x, y)) { - Py_DECREF(x); - Py_DECREF(y); - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_TypeError, "type mismatch"); - goto end; + + if (i >= n) { n *= 2; v = xrealloc(v, n*efsz, i*efsz); } + if (fill(v + o, me, x, y)) { + if (PyErr_Occurred()) goto end; + TYERR("type mismatch"); + } + i++; o += efsz; + Py_DECREF(x); x = 0; + Py_DECREF(y); y = 0; + Py_XDECREF(qq); + + qq = PyIter_Next(it); + if (!qq) { + if (PyErr_Occurred()) goto end; + else break; } - Py_DECREF(x); - Py_DECREF(y); } - z = exp(me, v, n); + + z = exp(me, v, i); end: - if (v) { - for (j = 0, vv = v; j < i; j++, vv += efsz) - drop(vv); - xfree(v); - } - Py_DECREF(arg); + while (i--) { o -= efsz; drop(v + o); } + xfree(v); + Py_XDECREF(it); Py_XDECREF(qq); Py_XDECREF(x); Py_XDECREF(y); return (z); } @@ -110,6 +117,175 @@ end: return (0); } +static PyTypeObject *thingtab_pytype; + +typedef struct thingentry { + sym_base _b; + PyObject *val; +} thingentry; +#define THING_VAL(x) (((thingentry *)(x))->val) + +typedef struct thingtab_pyobj { + GMAP_PYOBJ_HEAD + sym_table t; +} thingtab_pyobj; +#define THINGTAB_T(x) (&((thingtab_pyobj *)(x))->t) + +static void *thingtab_gmlookup(PyObject *me, PyObject *key, unsigned *f) +{ + const char *p; + + p = TEXT_STR(key); if (!p) return (0); + return (sym_find(THINGTAB_T(me), p, -1, 0, f)); +} + +static void thingtab_gmiterinit(PyObject *me, void *i) + { sym_mkiter(i, THINGTAB_T(me)); } + +static void *thingtab_gmiternext(PyObject *me, void *i) + { sym_iter *it = i; void *e; SYM_NEXT(it, e); return (e); } + +static PyObject *thingtab_gmentrykey(PyObject *me, void *e) + { return (TEXT_FROMSTR(SYM_NAME(e))); } + +static PyObject *thingtab_gmentryvalue(PyObject *me, void *e) + { PyObject *rc = THING_VAL(e); RETURN_OBJ(rc); } + +static const gmap_ops thingtab_gmops = { + sizeof(sym_iter), + thingtab_gmlookup, + thingtab_gmiterinit, + thingtab_gmiternext, + thingtab_gmentrykey, + thingtab_gmentryvalue +}; + +static Py_ssize_t thing_pysize(PyObject *me) + { return gmap_pysize_from_sym(THINGTAB_T(me)); } + +static const PyMappingMethods thingtab_pymapping = { + thing_pysize, + gmap_pylookup, + 0 +}; + +static thingtab_pyobj *make_thingtab(void) +{ + thingtab_pyobj *map = PyObject_NEW(thingtab_pyobj, thingtab_pytype); + + map->gmops = &thingtab_gmops; + sym_create(&map->t); + return (map); +} + +PyObject *make_algtab(const void *tab, size_t esz, + const char *(*namefn)(const void *), + PyObject *(*valfn)(const void *)) +{ + thingtab_pyobj *map = make_thingtab(); + const char *p = tab; + const char *name; + thingentry *e; + unsigned f; + + for (;;) { + name = namefn(p); if (!name) break; + e = sym_find(&map->t, name, -1, sizeof(*e), &f); assert(!f); + e->val = valfn(p); + p += esz; + } + return ((PyObject *)map); +} + +PyObject *make_grouptab(const void *tab, size_t esz, + const char *(*namefn)(const void *), + int (*ixfn)(const void *), PyObject *(*valfn)(int)) +{ + thingtab_pyobj *map = make_thingtab(); + struct { const char *name; int ix; } *ixtab = 0; + PyObject **valtab, **vv; + size_t i = 0, n = 0; + const char *p = tab; + const char *name; + thingentry *e; + unsigned f; + + for (;;) { + name = namefn(p); if (!name) break; + if (i >= n) { + if (!n) n = 16; + else n *= 2; + ixtab = xrealloc(ixtab, n*sizeof(*ixtab), i*sizeof(*ixtab)); + } + ixtab[i].name = name; ixtab[i].ix = ixfn(p); assert(ixtab[i].ix >= 0); + p += esz; i++; + } + n = i; + + valtab = xmalloc(n*sizeof(*valtab)); + for (i = 0; i < n; i++) valtab[i] = 0; + + for (i = 0; i < n; i++) { + e = sym_find(&map->t, ixtab[i].name, -1, sizeof(*e), &f); assert(!f); + vv = &valtab[ixtab[i].ix]; + if (*vv) Py_INCREF(*vv); + else *vv = valfn(ixtab[i].ix); + e->val = *vv; + } + + xfree(ixtab); xfree(valtab); + return ((PyObject *)map); +} + +static const PyTypeObject thingtab_pytype_skel = { + PyVarObject_HEAD_INIT(0, 0) /* Header */ + "_MiscTable", /* @tp_name@ */ + sizeof(thingtab_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + 0, /* @tp_dealloc@ */ + 0, /* @tp_print@ */ + 0, /* @tp_getattr@ */ + 0, /* @tp_setattr@ */ + 0, /* @tp_compare@ */ + 0, /* @tp_repr@ */ + 0, /* @tp_as_number@ */ + PYSEQUENCE(gmap), /* @tp_as_sequence@ */ + PYMAPPING(thingtab), /* @tp_as_mapping@ */ + 0, /* @tp_hash@ */ + 0, /* @tp_call@ */ + 0, /* @tp_str@ */ + 0, /* @tp_getattro@ */ + 0, /* @tp_setattro@ */ + 0, /* @tp_as_buffer@ */ + Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ + Py_TPFLAGS_BASETYPE, + + /* @tp_doc@ */ + "Class for tables of algorithms and abstract-group data.\n" + " Not instantiable by users.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + gmap_pyiter, /* @tp_iter@ */ + 0, /* @tp_iternext@ */ + PYMETHODS(gmapro), /* @tp_methods@ */ + 0, /* @tp_members@ */ + 0, /* @tp_getset@ */ + 0, /* @tp_base@ */ + 0, /* @tp_dict@ */ + 0, /* @tp_descr_get@ */ + 0, /* @tp_descr_set@ */ + 0, /* @tp_dictoffset@ */ + 0, /* @tp_init@ */ + PyType_GenericAlloc, /* @tp_alloc@ */ + abstract_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + static PyObject *smallprimes(void) { PyObject *v = PyList_New(NPRIME); @@ -152,17 +328,42 @@ static void init_random(void) #endif } -EXPORT void init_base(void) +#ifdef PY3 +static PyModuleDef moddef = { + PyModuleDef_HEAD_INIT, + "catacomb._base", /* @m_name@ */ + "Low-level module for Catacomb bindings. Use `catacomb' instead.", + /* @m_doc@ */ + 0, /* @m_size@ */ + 0, /* @m_methods@ */ + 0, /* @m_slots@ */ + 0, /* @m_traverse@ */ + 0, /* @m_clear@ */ + 0 /* @m_free@ */ +}; +#endif + +EXPORT PyMODINIT_FUNC PY23(init_base, PyInit__base)(void) { PyObject *mod; - modname = PyString_FromString("catacomb"); + modname = TEXT_FROMSTR("catacomb"); addmethods(methods); INIT_MODULES; + INITTYPE(thingtab, root); init_random(); +#ifdef PY3 + moddef.m_methods = donemethods(); + mod = PyModule_Create(&moddef); +#else mod = Py_InitModule("catacomb._base", donemethods()); +#endif INSERT_MODULES; + INSERT("_MiscTable", thingtab_pytype); INSERT("smallprimes", smallprimes()); +#ifdef PY3 + return (mod); +#endif } /*----- That's all, folks -------------------------------------------------*/