[Python-checkins] cpython: Add PyDict_SetDefault. (closes #17327)

benjamin.peterson python-checkins at python.org
Fri Mar 8 04:17:27 CET 2013


http://hg.python.org/cpython/rev/a0b750ea3397
changeset:   82542:a0b750ea3397
user:        Benjamin Peterson <benjamin at python.org>
date:        Thu Mar 07 22:16:29 2013 -0500
summary:
  Add PyDict_SetDefault. (closes #17327)

Patch by Stefan Behnel and I.

files:
  Doc/c-api/dict.rst     |   9 +++++++
  Doc/data/refcounts.dat |   5 ++++
  Include/dictobject.h   |   2 +
  Misc/NEWS              |   2 +
  Objects/dictobject.c   |  34 ++++++++++++++++++++---------
  5 files changed, 41 insertions(+), 11 deletions(-)


diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst
--- a/Doc/c-api/dict.rst
+++ b/Doc/c-api/dict.rst
@@ -110,6 +110,15 @@
    :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.
diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat
--- a/Doc/data/refcounts.dat
+++ b/Doc/data/refcounts.dat
@@ -220,6 +220,11 @@
 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:
 
diff --git a/Include/dictobject.h b/Include/dictobject.h
--- a/Include/dictobject.h
+++ b/Include/dictobject.h
@@ -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_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);
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,8 @@
 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.
 
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -2211,19 +2211,19 @@
     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 @@
                 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)

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list