# HG changeset patch # Parent 154d6335a2c66b35a268c31fb24d183be661d896 add PyDict_SetItemDefault() C-API function to implement dict.setdefault() at the C-API level diff -r 154d6335a2c6 Doc/c-api/dict.rst --- a/Doc/c-api/dict.rst Thu Mar 07 14:03:27 2013 +0100 +++ b/Doc/c-api/dict.rst Thu Mar 07 15:03:03 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 *default) + + Read the value with a key of *key* from the dictionary *p*. If the key is + not in the dict, insert it with value *defaultobj* and return *defaultobj*. + 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, default)`` in Python. + + .. c:function:: PyObject* PyDict_Items(PyObject *p) Return a :c:type:`PyListObject` containing all the items from the dictionary. diff -r 154d6335a2c6 Doc/data/refcounts.dat --- a/Doc/data/refcounts.dat Thu Mar 07 14:03:27 2013 +0100 +++ b/Doc/data/refcounts.dat Thu Mar 07 15:03:03 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*:default:0:conditionally +1 if inserted into the dict + PyDict_Items:PyObject*::+1: PyDict_Items:PyObject*:p:0: diff -r 154d6335a2c6 Include/dictobject.h --- a/Include/dictobject.h Thu Mar 07 14:03:27 2013 +0100 +++ b/Include/dictobject.h Thu Mar 07 15:03:03 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 *mp, PyObject *key, PyObject *defaultobj); 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 154d6335a2c6 Objects/dictobject.c --- a/Objects/dictobject.c Thu Mar 07 14:03:27 2013 +0100 +++ b/Objects/dictobject.c Thu Mar 07 15:03:03 2013 +0100 @@ -2211,19 +2211,41 @@ return val; } +static PyObject* dict_getitemsetdefault( + PyDictObject *d, PyObject *key, PyObject *defaultobj); + +PyObject* +PyDict_GetItemSetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) +{ + if ((key == NULL | defaultobj == NULL | d == NULL) || !PyDict_Check(d)) { + PyErr_BadInternalCall(); + return NULL; + } + return dict_getitemsetdefault((PyDictObject*) d, key, defaultobj); +} + static PyObject * -dict_setdefault(register PyDictObject *mp, PyObject *args) +dict_setdefault(PyDictObject *mp, PyObject *args) { - PyObject *key; - PyObject *failobj = Py_None; + PyObject *key, *val; + PyObject *defaultobj = Py_None; + + if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &key, &defaultobj)) + return NULL; + + val = dict_getitemsetdefault(mp, key, defaultobj); + Py_XINCREF(val); + return val; +} + +static PyObject* +dict_getitemsetdefault(PyDictObject *mp, PyObject *key, PyObject *defaultobj) +{ 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); @@ -2241,17 +2263,16 @@ return NULL; ep = find_empty_slot(mp, key, hash, &value_addr); } - Py_INCREF(failobj); + Py_INCREF(defaultobj); Py_INCREF(key); - MAINTAIN_TRACKING(mp, key, failobj); + MAINTAIN_TRACKING(mp, key, defaultobj); ep->me_key = key; ep->me_hash = hash; - *value_addr = failobj; - val = failobj; + *value_addr = defaultobj; + val = defaultobj; mp->ma_keys->dk_usable--; mp->ma_used++; } - Py_INCREF(val); return val; }