# HG changeset patch # Parent 5c4b005811981afa49c079c09c7aaa872733891a add PyDict_SetItemDefault() C-API function to implement dict.setdefault() at the C-API level diff -r 5c4b00581198 Doc/c-api/dict.rst --- a/Doc/c-api/dict.rst Fri Feb 08 11:24:55 2013 +0200 +++ b/Doc/c-api/dict.rst Fri Mar 01 14:39:01 2013 +0100 @@ -110,6 +110,16 @@ :c:type:`char\*`, rather than a :c:type:`PyObject\*`. +.. c:function:: PyObject* PyDict_GetItemSetDefault(PyObject *p, PyObject *key, PyObject *failobj) + + Read the value with a key of *key* from the dictionary *p*. If the key + is not in the dict, insert it with value *failobj* and return *failobj*. + This function evaluates the hash function of *key* only once, instead of + evaluating it independently for the lookup and the insertion. *key* must + be :term:`hashable`; if it isn't, :exc:`TypeError` will be raised. This + is the same as ``p.setdefault(key, failobj)`` in Python. + + .. c:function:: PyObject* PyDict_Items(PyObject *p) Return a :c:type:`PyListObject` containing all the items from the dictionary. diff -r 5c4b00581198 Doc/data/refcounts.dat --- a/Doc/data/refcounts.dat Fri Feb 08 11:24:55 2013 +0200 +++ b/Doc/data/refcounts.dat Fri Mar 01 14:39:01 2013 +0100 @@ -220,6 +220,11 @@ PyDict_GetItemString:PyObject*:p:0: PyDict_GetItemString:char*:key:: +PyDict_GetItemSetDefault:PyObject*::0: +PyDict_GetItemSetDefault:PyObject*:p:0: +PyDict_GetItemSetDefault:PyObject*:key:0:conditionally +1 if inserted into the dict +PyDict_GetItemSetDefault:PyObject*:failobj:0:conditionally +1 if inserted into the dict + PyDict_Items:PyObject*::+1: PyDict_Items:PyObject*:p:0: diff -r 5c4b00581198 Include/dictobject.h --- a/Include/dictobject.h Fri Feb 08 11:24:55 2013 +0200 +++ b/Include/dictobject.h Fri Mar 01 14:39:01 2013 +0100 @@ -53,6 +53,8 @@ PyAPI_FUNC(PyObject *) PyDict_GetItemWithError(PyObject *mp, PyObject *key); PyAPI_FUNC(PyObject *) _PyDict_GetItemIdWithError(PyObject *dp, struct _Py_Identifier *key); +PyAPI_FUNC(PyObject*) PyDict_GetItemSetDefault( + PyObject* d, PyObject* key, PyObject* failobj); PyAPI_FUNC(int) PyDict_SetItem(PyObject *mp, PyObject *key, PyObject *item); PyAPI_FUNC(int) PyDict_DelItem(PyObject *mp, PyObject *key); PyAPI_FUNC(void) PyDict_Clear(PyObject *mp); diff -r 5c4b00581198 Objects/dictobject.c --- a/Objects/dictobject.c Fri Feb 08 11:24:55 2013 +0200 +++ b/Objects/dictobject.c Fri Mar 01 14:39:01 2013 +0100 @@ -2211,19 +2211,41 @@ return val; } +static PyObject* dict_getitemsetdefault( + PyDictObject* d, PyObject* key, PyObject* failobj); + +PyObject* +PyDict_GetItemSetDefault(PyObject* d, PyObject* key, PyObject* failobj) +{ + if ((key == NULL | failobj == NULL | d == NULL) || !PyDict_Check(d)) { + PyErr_BadInternalCall(); + return NULL; + } + return dict_getitemsetdefault((PyDictObject*) d, key, failobj); +} + static PyObject * -dict_setdefault(register PyDictObject *mp, PyObject *args) +dict_setdefault(PyDictObject *mp, PyObject *args) { - PyObject *key; + PyObject *key, *val; PyObject *failobj = Py_None; + + if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &key, &failobj)) + return NULL; + + val = dict_getitemsetdefault(mp, key, failobj); + Py_XINCREF(val); + return val; +} + +static PyObject* +dict_getitemsetdefault(register PyDictObject* mp, PyObject* key, PyObject* failobj) +{ PyObject *val = NULL; Py_hash_t hash; PyDictKeyEntry *ep; PyObject **value_addr; - if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &key, &failobj)) - return NULL; - if (!PyUnicode_CheckExact(key) || (hash = ((PyASCIIObject *) key)->hash) == -1) { hash = PyObject_Hash(key); @@ -2251,7 +2273,6 @@ mp->ma_keys->dk_usable--; mp->ma_used++; } - Py_INCREF(val); return val; }