/*----- Iteration ---------------------------------------------------------*/
-static PyTypeObject *itemiter_pytype, *valiter_pytype;
+static PyTypeObject *keyiter_pytype, *itemiter_pytype, *valiter_pytype;
+
+union iterstate {
+ void *external;
+ void *internal[4];
+};
typedef struct iter_pyobj {
PyObject_HEAD
PyObject *map;
- PyObject *i;
+ union iterstate iter;
} iter_pyobj;
#define ITER_MAP(o) (((iter_pyobj *)(o))->map)
-#define ITER_I(o) (((iter_pyobj *)(o))->i)
+#define ITER_ITER(o) (&((iter_pyobj *)(o))->iter)
+#define ITER_EXTERNALP(o) \
+ (GMAP_OPS(ITER_MAP(o))->isz > sizeof(union iterstate))
+#define ITER_I(o) (ITER_EXTERNALP(o) ? ITER_ITER(o)->external \
+ : &ITER_ITER(o)->internal)
+
+static void *iter_init(PyObject *me, union iterstate *iter)
+{
+ const gmap_ops *gmops = GMAP_OPS(me);
+ void *i;
+
+ if (gmops->isz <= sizeof(*iter)) i = &iter->internal;
+ else { i = iter->external = PyObject_Malloc(gmops->isz); assert(i); }
+ gmops->iter_init(me, i);
+ return (i);
+}
+
+static void iter_free(PyObject *me, union iterstate *iter)
+ { if (GMAP_OPS(me)->isz > sizeof(*iter)) PyObject_Free(iter->external); }
static void iter_pydealloc(PyObject *me)
- { Py_DECREF(ITER_MAP(me)); Py_DECREF(ITER_I(me)); FREEOBJ(me); }
+{
+ PyObject *map = ITER_MAP(me);
+ iter_free(map, ITER_ITER(me));
+ Py_DECREF(map); FREEOBJ(me);
+}
-static PyObject *itemiter_pynext(PyObject *me)
+static PyObject *gmap_mkiter(PyObject *me, PyTypeObject *ty)
{
- PyObject *k = 0, *v = 0, *rc = 0;
+ iter_pyobj *iter = PyObject_NEW(iter_pyobj, ty);
- if ((k = PyIter_Next(ITER_I(me))) != 0 &&
- (v = PyObject_GetItem(ITER_MAP(me), k)) != 0)
- rc = Py_BuildValue("(OO)", k, v);
- Py_XDECREF(k); Py_XDECREF(v);
- return (rc);
+ iter->map = me; Py_INCREF(me);
+ iter_init(me, &iter->iter);
+ return ((PyObject *)iter);
}
-static const PyTypeObject itemiter_pytype_skel = {
- PyObject_HEAD_INIT(0) 0, /* Header */
- "ItemIter", /* @tp_name@ */
+static PyObject *keyiter_pynext(PyObject *me)
+{
+ PyObject *map = ITER_MAP(me);
+ const struct gmap_ops *gmops = GMAP_OPS(map);
+ void *e = gmops->iter_next(map, ITER_I(me));
+
+ if (!e) return (0);
+ else return (gmops->entry_key(map, e));
+}
+
+static const PyTypeObject keyiter_pytype_skel = {
+ PyVarObject_HEAD_INIT(0, 0) /* Header */
+ "_KeyIter", /* @tp_name@ */
sizeof(iter_pyobj), /* @tp_basicsize@ */
0, /* @tp_itemsize@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "Iterates over the items of a mapping.",
+ "Iterates over the keys of a mapping.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
0, /* @tp_richcompare@ */
0, /* @tp_weaklistoffset@ */
PyObject_SelfIter, /* @tp_iter@ */
- itemiter_pynext, /* @tp_iternext@ */
+ keyiter_pynext, /* @tp_iternext@ */
0, /* @tp_methods@ */
0, /* @tp_members@ */
0, /* @tp_getset@ */
static PyObject *valiter_pynext(PyObject *me)
{
- PyObject *k = 0, *rc = 0;
+ PyObject *map = ITER_MAP(me);
+ const struct gmap_ops *gmops = GMAP_OPS(map);
+ void *e = gmops->iter_next(map, ITER_I(me));
- if ((k = PyIter_Next(ITER_I(me))) != 0)
- rc = PyObject_GetItem(ITER_MAP(me), k);
- Py_XDECREF(k);
- return (rc);
+ if (!e) return (0);
+ else return (gmops->entry_value(map, e));
}
static const PyTypeObject valiter_pytype_skel = {
- PyObject_HEAD_INIT(0) 0, /* Header */
- "ValueIter", /* @tp_name@ */
+ PyVarObject_HEAD_INIT(0, 0) /* Header */
+ "_ValueIter", /* @tp_name@ */
sizeof(iter_pyobj), /* @tp_basicsize@ */
0, /* @tp_itemsize@ */
0 /* @tp_is_gc@ */
};
-const PySequenceMethods gmap_pysequence = {
- 0, /* @sq_length@ */
+static PyObject *itemiter_pynext(PyObject *me)
+{
+ PyObject *map = ITER_MAP(me);
+ const struct gmap_ops *gmops = GMAP_OPS(map);
+ void *e = gmops->iter_next(map, ITER_I(me));
+ PyObject *rc = 0;
+
+ if (e)
+ rc = Py_BuildValue("(NN)",
+ gmops->entry_key(map, e),
+ gmops->entry_value(map, e));
+ return (rc);
+}
+
+static const PyTypeObject itemiter_pytype_skel = {
+ PyVarObject_HEAD_INIT(0, 0) /* Header */
+ "_ItemIter", /* @tp_name@ */
+ sizeof(iter_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ iter_pydealloc, /* @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@ */
+ 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@ */
+ "Iterates over the items of a mapping.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ PyObject_SelfIter, /* @tp_iter@ */
+ itemiter_pynext, /* @tp_iternext@ */
+ 0, /* @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@ */
+};
+
+/*----- Mapping views -----------------------------------------------------*/
+
+#ifdef PY3
+
+static PyTypeObject *keyview_pytype, *itemview_pytype, *valview_pytype;
+
+typedef struct view_pyobj {
+ PyObject_HEAD
+ PyObject *map;
+} view_pyobj;
+#define VIEW_MAP(o) (((view_pyobj *)(o))->map)
+
+static PyObject *gmap_mkview(PyObject *me, PyTypeObject *ty)
+{
+ view_pyobj *v = PyObject_NEW(view_pyobj, ty);
+ v->map = me; Py_INCREF(me);
+ return ((PyObject *)v);
+}
+
+static void view_pydealloc(PyObject *me)
+ { Py_DECREF(VIEW_MAP(me)); FREEOBJ(me); }
+
+#define BINOP(op, update) \
+ static PyObject *view_py##op(PyObject *me, PyObject *you) \
+ { \
+ PyObject *set = 0; \
+ PyObject *rc = 0; \
+ \
+ set = PySet_New(me); if (!set) goto end; \
+ if (!PyObject_CallMethod(set, #update, "(O)", you)) goto end; \
+ rc = set; set = 0; \
+ end: \
+ Py_XDECREF(set); \
+ return (rc); \
+ }
+BINOP(and, intersection_update)
+BINOP(or, update)
+BINOP(xor, symmetric_difference_update)
+#undef BINOP
+
+static int all_contained_p(PyObject *x, PyObject *y)
+{
+ PyObject *i = 0, *e;
+ int b, rc = -1;
+
+ i = PyObject_GetIter(x); if (!i) goto end;
+ for (;;) {
+ e = PyIter_Next(i); if (!e) break;
+ b = PySequence_Contains(y, e); Py_DECREF(e); if (b < 0) goto end;
+ if (!b) { rc = 0; goto end; }
+ }
+ if (PyErr_Occurred()) goto end;
+ rc = 1;
+end:
+ Py_XDECREF(i);
+ return (rc);
+}
+
+static Py_ssize_t view_pysize(PyObject *me)
+ { return (PyMapping_Size(VIEW_MAP(me))); }
+
+static PyObject *view_pyrichcompare(PyObject *me, PyObject *you, int op)
+{
+ PyObject *map = ITER_MAP(me);
+ Py_ssize_t mysz, yoursz;
+ int b;
+
+ mysz = PyMapping_Size(map); if (mysz < 0) return (0);
+ yoursz = PyObject_Size(you);
+ if (yoursz < 0) { PyErr_Clear(); RETURN_NOTIMPL; }
+
+ switch (op) {
+ case Py_EQ:
+ if (mysz != yoursz) RETURN_FALSE;
+ b = all_contained_p(you, me);
+ break;
+ case Py_NE:
+ if (mysz != yoursz) RETURN_TRUE;
+ b = all_contained_p(you, me);
+ break;
+ case Py_LT:
+ if (mysz >= yoursz) RETURN_FALSE;
+ b = all_contained_p(me, you);
+ break;
+ case Py_LE:
+ if (mysz > yoursz) RETURN_FALSE;
+ b = all_contained_p(me, you);
+ break;
+ case Py_GE:
+ if (mysz < yoursz) RETURN_FALSE;
+ b = all_contained_p(you, me);
+ break;
+ case Py_GT:
+ if (mysz <= yoursz) RETURN_FALSE;
+ b = all_contained_p(you, me);
+ break;
+ default:
+ abort();
+ }
+ if (b < 0) return (0);
+ return (getbool(b));
+}
+
+static PyObject *keyview_pyiter(PyObject *me)
+ { return (gmap_mkiter(VIEW_MAP(me), keyiter_pytype)); }
+
+static int keyview_pyhaskey(PyObject *me, PyObject *k)
+{
+ PyObject *map = VIEW_MAP(me);
+ const struct gmap_ops *gmops = GMAP_OPS(map);
+ return (gmops->lookup(map, k, 0) ? 1 : PyErr_Occurred() ? -1 : 0);
+}
+
+static int itemview_pyhaskey(PyObject *me, PyObject *it)
+{
+ PyObject *map = VIEW_MAP(me);
+ const struct gmap_ops *gmops = GMAP_OPS(map);
+ void *e;
+ int b;
+ PyObject *v;
+
+ if (!PyTuple_Check(it) || PyTuple_GET_SIZE(it) != 2) return (0);
+ e = gmops->lookup(map, PyTuple_GET_ITEM(it, 0), 0);
+ if (!e) return (PyErr_Occurred() ? -1 : 0);
+ v = gmops->entry_value(map, e); if (!v) return (-1);
+ b = PyObject_RichCompareBool(v, PyTuple_GET_ITEM(it, 1), Py_EQ);
+ Py_DECREF(v); return (b);
+}
+
+static PyObject *valview_pyiter(PyObject *me)
+ { return (gmap_mkiter(VIEW_MAP(me), valiter_pytype)); }
+
+static PyObject *itemview_pyiter(PyObject *me)
+ { return (gmap_mkiter(VIEW_MAP(me), itemiter_pytype)); }
+
+static const PyNumberMethods view_pynumber = {
+ 0, /* @nb_add@ */
+ 0, /* @nb_subtract@ */
+ 0, /* @nb_multiply@ */
+#ifdef PY2
+ 0, /* @nb_divide@ */
+#endif
+ 0, /* @nb_remainder@ */
+ 0, /* @nb_divmod@ */
+ 0, /* @nb_power@ */
+ 0, /* @nb_negative@ */
+ 0, /* @nb_positive@ */
+ 0, /* @nb_absolute@ */
+ 0, /* @nb_nonzero@ */
+ 0, /* @nb_invert@ */
+ 0, /* @nb_lshift@ */
+ 0, /* @nb_rshift@ */
+ view_pyand, /* @nb_and@ */
+ view_pyxor, /* @nb_xor@ */
+ view_pyor, /* @nb_or@ */
+ 0, /* @nb_coerce@ */
+ 0, /* @nb_int@ */
+ 0, /* @nb_long@ */
+ 0, /* @nb_float@ */
+ 0, /* @nb_oct@ */
+ 0, /* @nb_hex@ */
+};
+
+static const PySequenceMethods keyview_pysequence = {
+ view_pysize, /* @sq_length@ */
0, /* @sq_concat@ */
0, /* @sq_repeat@ */
0, /* @sq_item@ */
0, /* @sq_slice@ */
0, /* @sq_ass_item@ */
0, /* @sq_ass_slice@ */
- PyMapping_HasKey, /* @sq_contains@ */
+ keyview_pyhaskey, /* @sq_contains@ */
0, /* @sq_inplace_concat@ */
- 0 /* @sq_inplace_repeat@ */
+ 0, /* @sq_inplace_repeat@ */
};
+static const PyTypeObject keyview_pytype_skel = {
+ PyVarObject_HEAD_INIT(0, 0) /* Header */
+ "_KeyView", /* @tp_name@ */
+ sizeof(view_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ view_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ PYNUMBER(view), /* @tp_as_number@ */
+ PYSEQUENCE(keyview), /* @tp_as_sequence@ */
+ 0, /* @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@ */
+ "View of a mapping's keys.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ view_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ keyview_pyiter, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ 0, /* @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 const PySequenceMethods valview_pysequence = {
+ view_pysize, /* @sq_length@ */
+ 0, /* @sq_concat@ */
+ 0, /* @sq_repeat@ */
+ 0, /* @sq_item@ */
+ 0, /* @sq_slice@ */
+ 0, /* @sq_ass_item@ */
+ 0, /* @sq_ass_slice@ */
+ 0, /* @sq_contains@ */
+ 0, /* @sq_inplace_concat@ */
+ 0, /* @sq_inplace_repeat@ */
+};
+
+static const PyTypeObject valview_pytype_skel = {
+ PyVarObject_HEAD_INIT(0, 0) /* Header */
+ "_ValueView", /* @tp_name@ */
+ sizeof(view_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ view_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ PYNUMBER(view), /* @tp_as_number@ */
+ PYSEQUENCE(valview), /* @tp_as_sequence@ */
+ 0, /* @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@ */
+ "View of a mapping's values.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ valview_pyiter, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ 0, /* @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 const PySequenceMethods itemview_pysequence = {
+ view_pysize, /* @sq_length@ */
+ 0, /* @sq_concat@ */
+ 0, /* @sq_repeat@ */
+ 0, /* @sq_item@ */
+ 0, /* @sq_slice@ */
+ 0, /* @sq_ass_item@ */
+ 0, /* @sq_ass_slice@ */
+ itemview_pyhaskey, /* @sq_contains@ */
+ 0, /* @sq_inplace_concat@ */
+ 0, /* @sq_inplace_repeat@ */
+};
+
+static const PyTypeObject itemview_pytype_skel = {
+ PyVarObject_HEAD_INIT(0, 0) /* Header */
+ "_ItemView", /* @tp_name@ */
+ sizeof(view_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ view_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ PYNUMBER(view), /* @tp_as_number@ */
+ PYSEQUENCE(itemview), /* @tp_as_sequence@ */
+ 0, /* @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@ */
+ "View of a mapping's key/value items.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ view_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ itemview_pyiter, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ 0, /* @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@ */
+};
+
+#endif
+
/*----- Other mapping protocol support ------------------------------------*/
Py_ssize_t gmap_pysize(PyObject *me)
{
- PyObject *i = 0, *x = 0;
- Py_ssize_t rc = -1, n = 0;
+ const gmap_ops *gmops = GMAP_OPS(me);
+ union iterstate iter;
+ void *i;
+ Py_ssize_t n = 0;
+
+ i = iter_init(me, &iter);
+ while (gmops->iter_next(me, i)) n++;
+ iter_free(me, &iter);
+ return (n);
+}
- if ((i = PyObject_GetIter(me)) == 0) goto done;
- while ((x = PyIter_Next(i)) != 0) { n++; Py_DECREF(x); x = 0; }
- if (PyErr_Occurred()) goto done;
- rc = n;
-done:
- Py_XDECREF(i); Py_XDECREF(x);
+PyObject *gmap_pylookup(PyObject *me, PyObject *key)
+{
+ const gmap_ops *gmops = GMAP_OPS(me);
+ void *e = gmops->lookup(me, key, 0);
+ PyObject *rc = 0;
+
+ if (!e) { if (!PyErr_Occurred()) MAPERR(key); else goto end; }
+ rc = gmops->entry_value(me, e);
+end:
+ return (rc);
+}
+
+int gmap_pystore(PyObject *me, PyObject *key, PyObject *value)
+{
+ const gmap_ops *gmops = GMAP_OPS(me);
+ unsigned f;
+ void *e = gmops->lookup(me, key, &f);
+ int rc = -1;
+
+ if (!e) goto end;
+ if (!value)
+ rc = gmops->del_entry(me, e);
+ else {
+ rc = gmops->set_entry(me, e, value);
+ if (rc && !f) gmops->del_entry(me, e);
+ }
+ rc = 0;
+end:
return (rc);
}
+int gmap_pyhaskey(PyObject *me, PyObject *key)
+ { return (GMAP_OPS(me)->lookup(me, key, 0) ? 1 : PyErr_Occurred() ? -1 : 0); }
+
+const PySequenceMethods gmap_pysequence = {
+ 0, /* @sq_length@ */
+ 0, /* @sq_concat@ */
+ 0, /* @sq_repeat@ */
+ 0, /* @sq_item@ */
+ 0, /* @sq_slice@ */
+ 0, /* @sq_ass_item@ */
+ 0, /* @sq_ass_slice@ */
+ gmap_pyhaskey, /* @sq_contains@ */
+ 0, /* @sq_inplace_concat@ */
+ 0 /* @sq_inplace_repeat@ */
+};
+
+#ifdef PY3
+
+PyObject *gmapmeth_keys(PyObject *me)
+ { return (gmap_mkview(me, keyview_pytype)); }
+
+PyObject *gmapmeth_values(PyObject *me)
+ { return (gmap_mkview(me, valview_pytype)); }
+
+PyObject *gmapmeth_items(PyObject *me)
+ { return (gmap_mkview(me, itemview_pytype)); }
+
+#else
+
PyObject *gmapmeth_has_key(PyObject *me, PyObject *arg)
{
PyObject *k;
+ void *e;
if (!PyArg_ParseTuple(arg, "O:has_key", &k)) return (0);
- return (getbool(PyMapping_HasKey(me, k)));
+ e = GMAP_OPS(me)->lookup(me, k, 0);
+ if (e) RETURN_TRUE;
+ else if (!PyErr_Occurred()) RETURN_FALSE;
+ else return (0);
}
PyObject *gmapmeth_keys(PyObject *me)
{
- PyObject *l = 0, *i = 0, *k, *rc = 0;
+ const gmap_ops *gmops = GMAP_OPS(me);
+ union iterstate iter; void *i = 0, *e;
+ PyObject *l = 0, *k, *rc = 0;
int err;
- if ((l = PyList_New(0)) == 0 ||
- (i = PyObject_GetIter(me)) == 0)
- goto done;
- while ((k = PyIter_Next(i)) != 0)
- { err = PyList_Append(l, k); Py_DECREF(k); if (err) goto done; }
- if (PyErr_Occurred()) goto done;
+ if ((l = PyList_New(0)) == 0) goto done;
+ i = iter_init(me, &iter);
+ while ((e = gmops->iter_next(me, i)) != 0) {
+ k = gmops->entry_key(me, e);
+ err = PyList_Append(l, k);
+ Py_DECREF(k);
+ if (err) goto done;
+ }
rc = l; l = 0;
done:
- Py_XDECREF(l); Py_XDECREF(i);
+ Py_XDECREF(l);
+ if (i) iter_free(me, &iter);
return (rc);
}
PyObject *gmapmeth_values(PyObject *me)
{
- PyObject *l = 0, *i = 0, *k, *v, *rc = 0;
- int err = 0;
-
- if ((l = PyList_New(0)) == 0 ||
- (i = PyObject_GetIter(me)) == 0)
- goto done;
- while ((k = PyIter_Next(i)) != 0) {
- if ((v = PyObject_GetItem(me, k)) == 0 ||
- PyList_Append(l, v))
- err = -1;
- Py_DECREF(k); Py_XDECREF(v);
+ const gmap_ops *gmops = GMAP_OPS(me);
+ union iterstate iter; void *i = 0, *e;
+ PyObject *l = 0, *v, *rc = 0;
+ int err;
+
+ if ((l = PyList_New(0)) == 0) goto done;
+ i = iter_init(me, &iter);
+ while ((e = gmops->iter_next(me, i)) != 0) {
+ v = gmops->entry_value(me, e);
+ err = PyList_Append(l, v);
+ Py_DECREF(v);
if (err) goto done;
}
- if (PyErr_Occurred()) goto done;
rc = l; l = 0;
done:
- Py_XDECREF(l); Py_XDECREF(i);
+ Py_XDECREF(l);
+ if (i) iter_free(me, &iter);
return (rc);
}
PyObject *gmapmeth_items(PyObject *me)
{
- PyObject *l = 0, *i = 0, *k, *v, *z, *rc = 0;
- int err = 0;
-
- if ((l = PyList_New(0)) == 0 ||
- (i = PyObject_GetIter(me)) == 0)
- goto done;
- while ((k = PyIter_Next(i)) != 0) {
- z = 0;
- if ((v = PyObject_GetItem(me, k)) == 0 ||
- (z = Py_BuildValue("(OO)", k, v)) == 0 ||
- PyList_Append(l, z))
- err = -1;
- Py_DECREF(k); Py_XDECREF(v); Py_XDECREF(z);
+ const gmap_ops *gmops = GMAP_OPS(me);
+ union iterstate iter; void *i = 0, *e;
+ PyObject *l = 0, *z, *rc = 0;
+ int err;
+
+ if ((l = PyList_New(0)) == 0) goto done;
+ i = iter_init(me, &iter);
+ while ((e = gmops->iter_next(me, i)) != 0) {
+ if ((z = Py_BuildValue("(NN)",
+ gmops->entry_key(me, e),
+ gmops->entry_value(me, e))) == 0)
+ goto done;
+ err = PyList_Append(l, z);
+ Py_XDECREF(z);
if (err) goto done;
}
- if (PyErr_Occurred()) goto done;
rc = l; l = 0;
done:
- Py_XDECREF(l); Py_XDECREF(i);
+ Py_XDECREF(l);
+ if (i) iter_free(me, &iter);
return (rc);
}
PyObject *gmapmeth_iterkeys(PyObject *me)
- { return (PyObject_GetIter(me)); }
+ { return (gmap_mkiter(me, keyiter_pytype)); }
PyObject *gmapmeth_itervalues(PyObject *me)
-{
- PyObject *i;
- iter_pyobj *ii;
-
- if ((i = PyObject_GetIter(me)) == 0)
- return (0);
- ii = PyObject_NEW(iter_pyobj, valiter_pytype);
- ii->map = me; Py_INCREF(me);
- ii->i = i;
- return ((PyObject *)ii);
-}
+ { return (gmap_mkiter(me, valiter_pytype)); }
PyObject *gmapmeth_iteritems(PyObject *me)
-{
- PyObject *i;
- iter_pyobj *ii;
+ { return (gmap_mkiter(me, itemiter_pytype)); }
- if ((i = PyObject_GetIter(me)) == 0)
- return (0);
- ii = PyObject_NEW(iter_pyobj, itemiter_pytype);
- ii->map = me; Py_INCREF(me);
- ii->i = i;
- return ((PyObject *)ii);
-}
+#endif
+
+PyObject *gmap_pyiter(PyObject *me)
+ { return gmap_mkiter(me, keyiter_pytype); }
PyObject *gmapmeth_clear(PyObject *me)
{
- PyObject *i = 0, *k = 0, *rc = 0;
-
- if ((i = PyObject_GetIter(me)) == 0)
- goto end;
- while ((k = PyIter_Next(i)) != 0) {
- PyObject_DelItem(me, k);
- Py_DECREF(k);
+ const gmap_ops *gmops = GMAP_OPS(me);
+ union iterstate iter;
+ void *i, *e;
+ PyObject *rc = 0;
+
+ i = iter_init(me, &iter);
+ for (;;) {
+ e = gmops->iter_next(me, i); if (!e) break;
+ if (gmops->del_entry(me, e)) goto end;
}
- if (PyErr_Occurred()) goto end;
+ iter_free(me, &iter);
rc = me; Py_INCREF(me);
end:
- Py_XDECREF(i);
return (rc);
}
PyObject *gmapmeth_get(PyObject *me, PyObject *arg, PyObject *kw)
{
- PyObject *k, *def = Py_None, *v;
+ const gmap_ops *gmops = GMAP_OPS(me);
+ PyObject *k, *def = Py_None;
+ void *e;
if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:get", DEF_KWLIST, &k, &def))
return (0);
- if ((v = PyObject_GetItem(me, k)) != 0) return (v);
- PyErr_Clear();
- RETURN_OBJ(def);
+ e = gmops->lookup(me, k, 0);
+ if (e) return (gmops->entry_value(me, e));
+ else if (!PyErr_Occurred()) RETURN_OBJ(def);
+ else return (0);
}
PyObject *gmapmeth_setdefault(PyObject *me, PyObject *arg, PyObject *kw)
{
- PyObject *k, *def = Py_None, *v;
+ const gmap_ops *gmops = GMAP_OPS(me);
+ PyObject *k, *def = Py_None;
+ void *e;
+ unsigned f;
if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:setdefault", DEF_KWLIST,
&k, &def))
return (0);
- if ((v = PyObject_GetItem(me, k)) != 0) return (v);
- PyErr_Clear();
- if (PyObject_SetItem(me, k, def)) return (0);
- RETURN_OBJ(def);
+ e = gmops->lookup(me, k, &f);
+ if (!e) return (0);
+ else if (f) return (gmops->entry_value(me, e));
+ else if (gmops->set_entry(me, e, def)) return (0);
+ else RETURN_OBJ(def);
}
PyObject *gmapmeth_pop(PyObject *me, PyObject *arg, PyObject *kw)
{
- PyObject *k, *def = 0, *v;
+ const gmap_ops *gmops = GMAP_OPS(me);
+ PyObject *k, *def = 0;
+ PyObject *rc = 0;
+ void *e;
if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:pop", DEF_KWLIST, &k, &def))
- return (0);
- if ((v = PyObject_GetItem(me, k)) != 0) {
- PyObject_DelItem(me, k);
- return (v);
- } else if (def) {
- PyErr_Clear();
- RETURN_OBJ(def);
- } else
- return (0);
+ goto end;
+ e = gmops->lookup(me, k, 0);
+ if (!e) {
+ if (PyErr_Occurred()) goto end;
+ else if (def) { rc = def; Py_INCREF(rc); }
+ else MAPERR(k);
+ } else {
+ rc = gmops->entry_value(me, e);
+ if (gmops->del_entry(me, e)) { Py_DECREF(rc); rc = 0; }
+ }
+end:
+ return (rc);
}
-PyObject *gmapmeth_update(PyObject *me, PyObject *arg)
+static int update_core(PyObject *me, PyObject *map)
{
- PyObject *map, *i = 0, *k, *v, *rc = 0;
- int err = 0;
-
- if (!PyArg_ParseTuple(arg, "O:update", &map) ||
- (i = PyObject_GetIter(map)) == 0)
- goto end;
- while ((k = PyIter_Next(i)) != 0) {
- if ((v = PyObject_GetItem(map, k)) == 0 ||
- PyObject_SetItem(me, k, v))
- err = -1;
- Py_DECREF(k); Py_XDECREF(v);
- if (err) goto end;
+ const gmap_ops *gmops = GMAP_OPS(me);
+ PyObject *i = 0, *item = 0, *k = 0, *v = 0;
+ void *e;
+ unsigned foundp;
+ int rc = -1;
+
+ v = PyObject_CallMethod(map, PY23("iteritems", "items"), 0);
+#ifdef PY3
+ if (v) { i = PyObject_GetIter(v); Py_DECREF(v); v = 0; }
+#else
+ i = v; v = 0;
+#endif
+
+ if (i) {
+ for (;;) {
+ item = PyIter_Next(i); if (!item) break;
+ if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 2)
+ TYERR("wanted a pair");
+ k = PyTuple_GET_ITEM(item, 0); Py_INCREF(k);
+ v = PyTuple_GET_ITEM(item, 1); Py_INCREF(v);
+ e = gmops->lookup(me, k, &foundp); if (!e) goto end;
+ if (gmops->set_entry(me, e, v)) goto end;
+ Py_DECREF(item); Py_DECREF(k); Py_DECREF(v); item = k = v = 0;
+ }
+ if (PyErr_Occurred()) goto end;
+ } else {
+ PyErr_Clear();
+ i = PyObject_GetIter(map); if (!i) goto end;
+ for (;;) {
+ k = PyIter_Next(i); if (!k) goto end;
+ v = PyObject_GetItem(map, k); if (!v) goto end;
+ e = gmops->lookup(me, k, &foundp); if (!e) goto end;
+ if (gmops->set_entry(me, e, v)) goto end;
+ Py_DECREF(k); Py_DECREF(v); k = v = 0;
+ }
+ if (PyErr_Occurred()) goto end;
}
- if (PyErr_Occurred()) goto end;
- rc = me; Py_INCREF(me);
+ rc = 0;
end:
- Py_XDECREF(i);
+ Py_XDECREF(i); Py_XDECREF(item);
+ Py_XDECREF(k); Py_XDECREF(v);
return (rc);
}
-PyObject *gmapmeth_popitem(PyObject *me)
+PyObject *gmapmeth_update(PyObject *me, PyObject *arg, PyObject *kw)
{
- PyObject *i = 0, *k = 0, *v = 0, *rc = 0;
+ PyObject *map = 0;
- if ((i = PyObject_GetIter(me)) == 0)
- goto end;
- if ((k = PyIter_Next(i)) == 0) {
- if (!PyErr_Occurred()) VALERR("popitem(): mapping is empty");
- goto end;
+ if (!PyArg_ParseTuple(arg, "|O:update", &map)) return (0);
+ if (map && update_core(me, map)) return (0);
+ if (kw && update_core(me, kw)) return (0);
+ RETURN_ME;
+}
+
+PyObject *gmapmeth_popitem(PyObject *me)
+{
+ const gmap_ops *gmops = GMAP_OPS(me);
+ union iterstate iter;
+ void *i;
+ PyObject *rc = 0;
+ void *e;
+
+ i = iter_init(me, &iter);
+ e = gmops->iter_next(me, i);
+ iter_free(me, &iter);
+ if (!e)
+ MAPERR(Py_None);
+ else {
+ rc = Py_BuildValue("(NN)",
+ gmops->entry_key(me, e), gmops->entry_value(me, e));
+ if (gmops->del_entry(me, e)) { Py_DECREF(rc); rc = 0; }
}
- if ((v = PyObject_GetItem(me, k)) == 0 ||
- PyObject_DelItem(me, k))
- goto end;
- rc = Py_BuildValue("(OO)", k, v);
end:
- Py_XDECREF(i); Py_XDECREF(k); Py_XDECREF(v);
return (rc);
}
+const PyMethodDef gmapro_pymethods[] = {
+ GMAP_ROMETHODS
+ { 0 }
+};
+
const PyMethodDef gmap_pymethods[] = {
GMAP_METHODS
{ 0 }
void pyke_gmap_pyinit(void)
{
+ INITTYPE(keyiter, root);
INITTYPE(itemiter, root);
INITTYPE(valiter, root);
+#ifdef PY3
+ INITTYPE(keyview, root);
+ INITTYPE(valview, root);
+ INITTYPE(itemview, root);
+#endif
}
void pyke_gmap_pyinsert(PyObject *mod)
{
- INSERT("ItemIter", itemiter_pytype);
- INSERT("ValueIter", valiter_pytype);
+ INSERT("_KeyIter", keyiter_pytype);
+ INSERT("_ValueIter", valiter_pytype);
+ INSERT("_ItemIter", itemiter_pytype);
+#ifdef PY3
+ INSERT("_KeyView", keyview_pytype);
+ INSERT("_ValueView", valview_pytype);
+ INSERT("_ItemView", itemview_pytype);
+#endif
}
/*----- That's all, folks -------------------------------------------------*/