pyke/mapping.c, key.c: Make the mapping code more intrusive and complete.
[pyke] / pyke.h
diff --git a/pyke.h b/pyke.h
index 64608d9..2934543 100644 (file)
--- a/pyke.h
+++ b/pyke.h
@@ -371,6 +371,55 @@ extern PyMethodDef *donemethods(void);
 
 /*----- Generic mapping support -------------------------------------------*/
 
+/* Operations table.  ME is the mapping object throughout. */
+typedef struct gmap_ops {
+  size_t isz;                          /* iterator size */
+
+  void *(*lookup)(PyObject *me, PyObject *key, unsigned *f);
+    /* Lookup the KEY.  If it is found, return an entry pointer for it; if F
+     * is not null, set *F nonzero.  Otherwise, if F is null, return a null
+     * pointer (without setting a pending exception); if F is not null, then
+     * set *F zero and return a fresh entry pointer.  Return null on a Python
+     * exception (the caller will notice the difference.)
+     */
+
+  void (*iter_init)(PyObject *me, void *i);
+    /* Initialize an iterator at I. */
+
+  void *(*iter_next)(PyObject *me, void *i);
+    /* Return an entry pointer for a different item, or null if all have been
+     * visited.
+     */
+
+  PyObject *(*entry_key)(PyObject *me, void *e);
+    /* Return the key object for a mapping entry. */
+
+  PyObject *(*entry_value)(PyObject *me, void *e);
+    /* Return the value object for a mapping entry. */
+
+  int (*set_entry)(PyObject *me, void *e, PyObject *val);
+    /* Modify the entry by storing VAL in its place.  Return 0 on success,
+     * or -1 on a Python error.
+     */
+
+  int (*del_entry)(PyObject *me, void *e);
+    /* Delete the entry.  (It may be necessary to delete a freshly allocated
+     * entry, e.g., if `set_entry' failed.)  Return 0 on success, or -1 on a
+     * Python error.
+     */
+} gmap_ops;
+
+/* The intrusion at the head of a mapping object. */
+#define GMAP_PYOBJ_HEAD                                                        \
+  PyObject_HEAD                                                                \
+  const gmap_ops *gmops;
+
+typedef struct gmap_pyobj {
+  GMAP_PYOBJ_HEAD
+} gmap_pyobj;
+#define GMAP_OPS(obj) (((gmap_pyobj *)(obj))->gmops)
+  /* Discover the operations from a mapping object. */
+
 /* Mapping methods. */
 #define GMAP_METMNAME(func) gmapmeth_##func
 #define GMAP_METH(func, doc) STD_METHOD(GMAP_METMNAME, func, 0, doc)
@@ -399,7 +448,7 @@ extern PyMethodDef *donemethods(void);
   KWMETH(setdefault,   "D.setdefault(K, [default = None]) -> VALUE")   \
   KWMETH(pop,          "D.pop(KEY, [default = <error>]) -> VALUE")     \
   NAMETH(popitem,      "D.popitem() -> (KEY, VALUE)")                  \
-  METH (update,        "D.update(MAP)")
+  KWMETH(update,       "D.update(MAP)")
 
 GMAP_DOMETHODS(GMAP_METHDECL, GMAP_KWMETHDECL, GMAP_NAMETHDECL)
 #define GMAP_ROMETHODS GMAP_DOROMETHODS(GMAP_METH, GMAP_KWMETH, GMAP_NAMETH)
@@ -407,7 +456,12 @@ GMAP_DOMETHODS(GMAP_METHDECL, GMAP_KWMETHDECL, GMAP_NAMETHDECL)
 
 /* Mapping protocol implementation. */
 extern Py_ssize_t gmap_pysize(PyObject *); /* for `mp_length' */
+extern PyObject *gmap_pyiter(PyObject *); /* for `tp_iter' */
+extern PyObject *gmap_pylookup(PyObject *, PyObject *); /* for `mp_subscript' */
+extern int gmap_pystore(PyObject *, PyObject *, PyObject *); /* for `mp_ass_subscript' */
+extern int gmap_pyhaskey(PyObject *, PyObject *); /* for `sq_contains' */
 extern const PySequenceMethods gmap_pysequence; /* for `tp_as_sequence' */
+extern const PyMethodDef gmapro_pymethods[]; /* read-only methods */
 extern const PyMethodDef gmap_pymethods[]; /* all the standard methods */
 
 /*----- That's all, folks -------------------------------------------------*/