* Added a new method flag, METH_COEXIST.
* Used the flag to optimize set.__contains__(), dict.__contains__(), dict.__getitem__(), and list.__getitem__().
This commit is contained in:
parent
feb78c94fa
commit
8f5cdaa784
|
@ -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}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue