]> granicus.if.org Git - python/commitdiff
* Added a new method flag, METH_COEXIST.
authorRaymond Hettinger <python@rcn.com>
Sat, 13 Dec 2003 11:26:12 +0000 (11:26 +0000)
committerRaymond Hettinger <python@rcn.com>
Sat, 13 Dec 2003 11:26:12 +0000 (11:26 +0000)
* Used the flag to optimize set.__contains__(), dict.__contains__(),
  dict.__getitem__(), and list.__getitem__().

Doc/api/newtypes.tex
Include/methodobject.h
Misc/NEWS
Objects/dictobject.c
Objects/listobject.c
Objects/methodobject.c
Objects/setobject.c
Objects/typeobject.c

index 1fadc465f7ddf62ded65f1187dc576bc2f0fb17b..038cce9280bfda894aea12ffffd4a633d033112e 100644 (file)
@@ -306,6 +306,21 @@ may be set for any given method.
   \versionadded{2.3}
 \end{datadesc}
 
+One other constant controls whether a method is loaded in place of
+another definition with the same method name.
+
+\begin{datadesc}{METH_COEXIST}
+  The method will be loaded in place of existing definitions.  Without
+  \var{METH_COEXIST}, the default is to skip repeated definitions.  Since
+  slot wrappers are loaded before the method table, the existence of a
+  \var{sq_contains} slot, for example, would generate a wrapped method
+  named \method{__contains__()} and preclude the loading of a
+  corresponding PyCFunction with the same name.  With the flag defined,
+  the PyCFunction will be loaded in place of the wrapper object and will
+  co-exist with the slot.  This is helpful because calls to PyCFunctions
+  are optimized more than wrapper object calls.
+  \versionadded{2.4}
+\end{datadesc}
 
 \begin{cfuncdesc}{PyObject*}{Py_FindMethod}{PyMethodDef table[],
                                             PyObject *ob, char *name}
index 887385d5e89825c60c72d41c4e386d3d41930502..0f605499ee9a3091de2a68b94d6d23cff239be20 100644 (file)
@@ -58,6 +58,13 @@ PyAPI_FUNC(PyObject *) PyCFunction_NewEx(PyMethodDef *, PyObject *,
 #define METH_CLASS    0x0010
 #define METH_STATIC   0x0020
 
+/* METH_COEXIST allows a method to be entered eventhough a slot has
+   already filled the entry.  When defined, the flag allows a separate
+   method, "__contains__" for example, to coexist with a defined 
+   slot like sq_contains. */
+
+#define METH_COEXIST   0x0040
+
 typedef struct PyMethodChain {
     PyMethodDef *methods;              /* Methods of this type */
     struct PyMethodChain *link;        /* NULL or base type */
index a28d0424c4e9cc6f46a906ed0be41c5b6ac49a8c..53dbe06b7dd217b873e229bf72c7640e895cb2a0 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -281,6 +281,12 @@ Build
 C API
 -----
 
+- Created a new method flag, METH_COEXIST, which causes a method to be loaded
+  even if already defined by a slot wrapper.  This allows a __contains__
+  method, for example, to co-exist with a defined sq_contains slot.  This
+  is helpful because the PyCFunction can take advantage of optimized calls
+  whenever METH_O or METH_NOARGS flags are defined.
+
 - Added a new function, PyDict_Contains(d, k) which is like
   PySequence_Contains() but is specific to dictionaries and executes
   about 10% faster.
index 0cf71b53f6590b179b492681ff83c7611e6c6dc6..013f5f2cb810d76fb7cf5973bf4efbd86048f1c6 100644 (file)
@@ -498,6 +498,31 @@ PyDict_GetItem(PyObject *op, PyObject *key)
        return (mp->ma_lookup)(mp, key, hash)->me_value;
 }
 
+static PyObject *
+dict_getitem(PyObject *op, PyObject *key)
+{
+       long hash;
+       dictobject *mp = (dictobject *)op;
+       PyObject *v;
+
+       if (!PyDict_Check(op)) {
+               return NULL;
+       }
+       if (!PyString_CheckExact(key) ||
+           (hash = ((PyStringObject *) key)->ob_shash) == -1)
+       {
+               hash = PyObject_Hash(key);
+               if (hash == -1)
+                       return NULL;
+       }
+       v = (mp->ma_lookup)(mp, key, hash) -> me_value;
+       if (v == NULL)
+               PyErr_SetObject(PyExc_KeyError, key);
+       else
+               Py_INCREF(v);
+       return v;
+}
+
 /* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
  * dictionary if it is merely replacing the value for an existing key.
  * This is means that it's safe to loop over a dictionary with
@@ -1735,6 +1760,11 @@ dict_iteritems(dictobject *dict)
 PyDoc_STRVAR(has_key__doc__,
 "D.has_key(k) -> True if D has a key k, else False");
 
+PyDoc_STRVAR(contains__doc__,
+"D.__contains__(k) -> True if D has a key k, else False");
+
+PyDoc_STRVAR(getitem__doc__, "x.__getitem__(y) <==> x[y]");
+
 PyDoc_STRVAR(get__doc__,
 "D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.");
 
@@ -1781,6 +1811,10 @@ PyDoc_STRVAR(iteritems__doc__,
 "D.iteritems() -> an iterator over the (key, value) items of D");
 
 static PyMethodDef mapp_methods[] = {
+       {"__contains__",(PyCFunction)dict_has_key,      METH_O | METH_COEXIST,
+        contains__doc__},
+       {"__getitem__", (PyCFunction)dict_getitem,      METH_O | METH_COEXIST,
+        getitem__doc__},
        {"has_key",     (PyCFunction)dict_has_key,      METH_O,
         has_key__doc__},
        {"get",         (PyCFunction)dict_get,          METH_VARARGS,
index 7d5c8b4ec1678208e7981669d913c8ac615f6940..3915cc928b4f65ea329619195fc147628c233aea 100644 (file)
@@ -2371,6 +2371,8 @@ list_nohash(PyObject *self)
 static PyObject *list_iter(PyObject *seq);
 static PyObject *list_reversed(PyListObject* seq, PyObject* unused);
 
+PyDoc_STRVAR(getitem_doc,
+"x.__getitem__(y) <==> x[y]");
 PyDoc_STRVAR(reversed_doc,
 "L.__reversed__() -- return a reverse iterator over the list");
 PyDoc_STRVAR(append_doc,
@@ -2396,7 +2398,10 @@ PyDoc_STRVAR(sorted_doc,
 "list.sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list;\n\
 cmp(x, y) -> -1, 0, 1");
 
+static PyObject *list_subscript(PyListObject*, PyObject*);
+
 static PyMethodDef list_methods[] = {
+       {"__getitem__", (PyCFunction)list_subscript, METH_O|METH_COEXIST, getitem_doc},
        {"__reversed__",(PyCFunction)list_reversed, METH_NOARGS, reversed_doc},
        {"append",      (PyCFunction)listappend,  METH_O, append_doc},
        {"insert",      (PyCFunction)listinsert,  METH_VARARGS, insert_doc},
index 3a92fa45ce33b3c67d0818e2bb519a196c11dbe5..5818616dfbfbf378246c836f5160c1f646511f0c 100644 (file)
@@ -67,7 +67,7 @@ PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw)
        PyObject *self = PyCFunction_GET_SELF(func);
        int size;
 
-       switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC)) {
+       switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)) {
        case METH_VARARGS:
                if (kw == NULL || PyDict_Size(kw) == 0)
                        return (*meth)(self, arg);
index c060077350e020d98fae6438fa1c4a66b6261a1d..8e70546a2ada9e5248e2f816c3085c3145ae1f20 100644 (file)
@@ -155,6 +155,28 @@ set_contains(PySetObject *so, PyObject *key)
        return result;
 }
 
+static PyObject *
+set_direct_contains(PySetObject *so, PyObject *key)
+{
+       PyObject *tmp;
+       long result;
+
+       result = PyDict_Contains(so->data, key);
+       if (result == -1 && PyAnySet_Check(key)) {
+               PyErr_Clear();
+               tmp = frozenset_dict_wrapper(((PySetObject *)(key))->data);
+               if (tmp == NULL)
+                       return NULL;
+               result = PyDict_Contains(so->data, tmp);
+               Py_DECREF(tmp);
+       }
+       if (result == -1)
+               return NULL;
+       return PyBool_FromLong(result);
+}
+
+PyDoc_STRVAR(contains_doc, "x.__contains__(y) <==> y in x.");
+
 static PyObject *
 set_copy(PySetObject *so)
 {
@@ -968,6 +990,8 @@ static PyMethodDef set_methods[] = {
         add_doc},
        {"clear",       (PyCFunction)set_clear,         METH_NOARGS,
         clear_doc},
+       {"__contains__",        (PyCFunction)set_direct_contains,       METH_O | METH_COEXIST,
+        contains_doc},
        {"copy",        (PyCFunction)set_copy,          METH_NOARGS,
         copy_doc},
        {"__copy__",    (PyCFunction)set_copy,          METH_NOARGS,
@@ -1094,6 +1118,8 @@ PyTypeObject PySet_Type = {
 
 
 static PyMethodDef frozenset_methods[] = {
+       {"__contains__",        (PyCFunction)set_direct_contains,       METH_O | METH_COEXIST,
+        contains_doc},
        {"copy",        (PyCFunction)frozenset_copy,    METH_NOARGS,
         copy_doc},
        {"__copy__",    (PyCFunction)frozenset_copy,    METH_NOARGS,
index e4eadb89a7652f77376d4ce25548175078ea461d..545dba6533721faaf3528b173aa47b9d122553a2 100644 (file)
@@ -2792,8 +2792,9 @@ add_methods(PyTypeObject *type, PyMethodDef *meth)
 
        for (; meth->ml_name != NULL; meth++) {
                PyObject *descr;
-               if (PyDict_GetItemString(dict, meth->ml_name))
-                       continue;
+               if (PyDict_GetItemString(dict, meth->ml_name) &&
+                       !(meth->ml_flags & METH_COEXIST))
+                               continue;
                if (meth->ml_flags & METH_CLASS) {
                        if (meth->ml_flags & METH_STATIC) {
                                PyErr_SetString(PyExc_ValueError,