From bc0f2ab9bbe1380a32cc63823258a337a525fb32 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 25 Nov 2003 21:12:14 +0000 Subject: Expose dict_contains() and PyDict_Contains() with is about 10% faster than PySequence_Contains() and more clearly applicable to dicts. Apply the new function in setobject.c where __contains__ checking is ubiquitous. --- Doc/api/concrete.tex | 8 ++++++++ Include/dictobject.h | 1 + Misc/NEWS | 4 ++++ Objects/dictobject.c | 7 ++++--- Objects/setobject.c | 18 +++++++++--------- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/Doc/api/concrete.tex b/Doc/api/concrete.tex index bf8d438..67852db 100644 --- a/Doc/api/concrete.tex +++ b/Doc/api/concrete.tex @@ -1808,6 +1808,14 @@ format. Empties an existing dictionary of all key-value pairs. \end{cfuncdesc} +\begin{cfuncdesc}{int}{PyDict_Contains}{PyObject *p, PyObject *key} + Determine if dictionary \var{p} contains \var{key}. If an item + in \var{p} is matches \var{key}, return \code{1}, otherwise return + \code{0}. On error, return \code{-1}. This is equivalent to the + Python expression \samp{\var{key} in \var{p}}. + \versionadded{2.4} +\end{cfuncdesc} + \begin{cfuncdesc}{PyObject*}{PyDict_Copy}{PyObject *p} Returns a new dictionary that contains the same key-value pairs as \var{p}. diff --git a/Include/dictobject.h b/Include/dictobject.h index c8ae912..554b82e 100644 --- a/Include/dictobject.h +++ b/Include/dictobject.h @@ -100,6 +100,7 @@ PyAPI_FUNC(PyObject *) PyDict_Values(PyObject *mp); PyAPI_FUNC(PyObject *) PyDict_Items(PyObject *mp); PyAPI_FUNC(int) PyDict_Size(PyObject *mp); PyAPI_FUNC(PyObject *) PyDict_Copy(PyObject *mp); +PyAPI_FUNC(int) PyDict_Contains(PyObject *mp, PyObject *key); /* PyDict_Update(mp, other) is equivalent to PyDict_Merge(mp, other, 1). */ PyAPI_FUNC(int) PyDict_Update(PyObject *mp, PyObject *other); diff --git a/Misc/NEWS b/Misc/NEWS index f7b1e96..a3f3a18 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -231,6 +231,10 @@ Build C API ----- +- Added a new function, PyDict_Contains(d, k) which is like + PySequence_Contains() but is specific to dictionaries and executes + about 10% faster. + - Added three new macros: Py_RETURN_NONE, Py_RETURN_TRUE, and Py_RETURN_FALSE. Each return the singleton they mention after Py_INCREF()ing them. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 5d22404..0cf71b5 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1814,10 +1814,11 @@ static PyMethodDef mapp_methods[] = { {NULL, NULL} /* sentinel */ }; -static int -dict_contains(dictobject *mp, PyObject *key) +int +PyDict_Contains(PyObject *op, PyObject *key) { long hash; + dictobject *mp = (dictobject *)op; if (!PyString_CheckExact(key) || (hash = ((PyStringObject *) key)->ob_shash) == -1) { @@ -1837,7 +1838,7 @@ static PySequenceMethods dict_as_sequence = { 0, /* sq_slice */ 0, /* sq_ass_item */ 0, /* sq_ass_slice */ - (objobjproc)dict_contains, /* sq_contains */ + (objobjproc)PyDict_Contains, /* sq_contains */ 0, /* sq_inplace_concat */ 0, /* sq_inplace_repeat */ }; diff --git a/Objects/setobject.c b/Objects/setobject.c index ce3f84e..c060077 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -143,13 +143,13 @@ set_contains(PySetObject *so, PyObject *key) PyObject *tmp; int result; - result = PySequence_Contains(so->data, key); + 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 -1; - result = PySequence_Contains(so->data, tmp); + result = PyDict_Contains(so->data, tmp); Py_DECREF(tmp); } return result; @@ -252,7 +252,7 @@ set_intersection(PySetObject *so, PyObject *other) } while ((item = PyIter_Next(it)) != NULL) { - if (PySequence_Contains(selfdata, item)) { + if (PyDict_Contains(selfdata, item)) { if (PyDict_SetItem(tgtdata, item, Py_True) == -1) { Py_DECREF(it); Py_DECREF(result); @@ -292,7 +292,7 @@ set_intersection_update(PySetObject *so, PyObject *other) selfdata = so->data; while ((item = PyIter_Next(it)) != NULL) { - if (PySequence_Contains(selfdata, item)) { + if (PyDict_Contains(selfdata, item)) { if (PyDict_SetItem(newdict, item, Py_True) == -1) { Py_DECREF(newdict); Py_DECREF(it); @@ -375,7 +375,7 @@ set_difference(PySetObject *so, PyObject *other) } while ((item = PyIter_Next(it)) != NULL) { - if (!PySequence_Contains(otherdata, item)) { + if (!PyDict_Contains(otherdata, item)) { if (PyDict_SetItem(tgtdata, item, Py_True) == -1) { Py_XDECREF(otherset); Py_DECREF(it); @@ -481,7 +481,7 @@ set_symmetric_difference_update(PySetObject *so, PyObject *other) return NULL; while ((item = PyIter_Next(it)) != NULL) { - if (PySequence_Contains(selfdata, item)) { + if (PyDict_Contains(selfdata, item)) { if (PyDict_DelItem(selfdata, item) == -1) { Py_XDECREF(otherset); Py_DECREF(it); @@ -541,7 +541,7 @@ set_symmetric_difference(PySetObject *so, PyObject *other) return NULL; } while ((item = PyIter_Next(it)) != NULL) { - if (!PySequence_Contains(selfdata, item)) { + if (!PyDict_Contains(selfdata, item)) { if (PyDict_SetItem(tgtdata, item, Py_True) == -1) { Py_DECREF(it); Py_DECREF(item); @@ -562,7 +562,7 @@ set_symmetric_difference(PySetObject *so, PyObject *other) return NULL; } while ((item = PyIter_Next(it)) != NULL) { - if (!PySequence_Contains(otherdata, item)) { + if (!PyDict_Contains(otherdata, item)) { if (PyDict_SetItem(tgtdata, item, Py_True) == -1) { Py_DECREF(it); Py_DECREF(item); @@ -634,7 +634,7 @@ set_issubset(PySetObject *so, PyObject *other) otherdata = ((PySetObject *)other)->data; while ((item = PyIter_Next(it)) != NULL) { - if (!PySequence_Contains(otherdata, item)) { + if (!PyDict_Contains(otherdata, item)) { Py_DECREF(it); Py_DECREF(item); Py_RETURN_FALSE; -- cgit v0.12