]> granicus.if.org Git - python/commitdiff
Add PyDict_SetDefault. (closes #17327)
authorBenjamin Peterson <benjamin@python.org>
Fri, 8 Mar 2013 03:16:29 +0000 (22:16 -0500)
committerBenjamin Peterson <benjamin@python.org>
Fri, 8 Mar 2013 03:16:29 +0000 (22:16 -0500)
Patch by Stefan Behnel and I.

Doc/c-api/dict.rst
Doc/data/refcounts.dat
Include/dictobject.h
Misc/NEWS
Objects/dictobject.c

index 6bacc326824104c7cb18c13a2fc78f333befb91f..dc8ef53c2641649a0e37b718c1bbac6fd12b5e1a 100644 (file)
@@ -110,6 +110,15 @@ Dictionary Objects
    :c:type:`char\*`, rather than a :c:type:`PyObject\*`.
 
 
+.. c:function:: PyObject* PyDict_SetDefault(PyObject *p, PyObject *key, PyObject *default)
+
+   This is the same the Python-level :meth:`dict.setdefault`.  If present, it
+   returns the value corresponding to *key* from the dictionary *p*.  If the key
+   is not in the dict, it is inserted with value *defaultobj* and *defaultobj*
+   is inserted.  This function evaluates the hash function of *key* only once,
+   instead of evaluating it independently for the lookup and the insertion.
+
+
 .. c:function:: PyObject* PyDict_Items(PyObject *p)
 
    Return a :c:type:`PyListObject` containing all the items from the dictionary.
index fac89afbd67fb1061ab3ed9099340fbed51b5cdb..e2990503820e05a270e0e3d5a8695e33673c5ef0 100644 (file)
@@ -220,6 +220,11 @@ PyDict_GetItemString:PyObject*::0:
 PyDict_GetItemString:PyObject*:p:0:
 PyDict_GetItemString:char*:key::
 
+PyDict_SetDefault:PyObject*::0:
+PyDict_SetDefault:PyObject*:p:0:
+PyDict_SetDefault:PyObject*:key:0:conditionally +1 if inserted into the dict
+PyDict_SetDefault:PyObject*:default:0:conditionally +1 if inserted into the dict
+
 PyDict_Items:PyObject*::+1:
 PyDict_Items:PyObject*:p:0:
 
index d89aac8932159cf6a0dfa3866540a801210de2fb..16bd1d6cb1f21ccea44b77f13b669b48311cf498 100644 (file)
@@ -53,6 +53,8 @@ PyAPI_FUNC(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key);
 PyAPI_FUNC(PyObject *) PyDict_GetItemWithError(PyObject *mp, PyObject *key);
 PyAPI_FUNC(PyObject *) _PyDict_GetItemIdWithError(PyObject *dp,
                                                   struct _Py_Identifier *key);
+PyAPI_FUNC(PyObject *) PyDict_SetDefault(
+    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);
index f15165147ebf7dbcd478297bfdb6c998a4c6a359..17282af6b781fd3830a7181c793478b3b7ab04f8 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,8 @@ What's New in Python 3.4.0 Alpha 1?
 Core and Builtins
 -----------------
 
+- Issue #17327: Add PyDict_SetDefault.
+
 - Issue #17032: The "global" in the "NameError: global name 'x' is not defined"
   error message has been removed.  Patch by Ram Rachum.
 
index 9080ddfd2888961baf46ad53bb1ad358ed23a284..2e8679fba4eb2768ea0be419c8c7e04121ea927b 100644 (file)
@@ -2211,19 +2211,19 @@ dict_get(register PyDictObject *mp, PyObject *args)
     return val;
 }
 
-static PyObject *
-dict_setdefault(register PyDictObject *mp, PyObject *args)
+PyObject *
+PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
 {
-    PyObject *key;
-    PyObject *failobj = Py_None;
+    PyDictObject *mp = (PyDictObject *)d;
     PyObject *val = NULL;
     Py_hash_t hash;
     PyDictKeyEntry *ep;
     PyObject **value_addr;
 
-    if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &key, &failobj))
+    if (!PyDict_Check(d)) {
+        PyErr_BadInternalCall();
         return NULL;
-
+    }
     if (!PyUnicode_CheckExact(key) ||
         (hash = ((PyASCIIObject *) key)->hash) == -1) {
         hash = PyObject_Hash(key);
@@ -2241,20 +2241,32 @@ dict_setdefault(register PyDictObject *mp, PyObject *args)
                 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;
 }
 
+static PyObject *
+dict_setdefault(PyDictObject *mp, PyObject *args)
+{
+    PyObject *key, *val;
+    PyObject *defaultobj = Py_None;
+
+    if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &key, &defaultobj))
+        return NULL;
+
+    val = PyDict_SetDefault(mp, key, defaultobj);
+    Py_XINCREF(val);
+    return val;
+}
 
 static PyObject *
 dict_clear(register PyDictObject *mp)