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);
}
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);
#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 -------------------------------------------------*/