summaryrefslogtreecommitdiffstats
path: root/Objects/dictobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/dictobject.c')
-rw-r--r--Objects/dictobject.c68
1 files changed, 47 insertions, 21 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 6dcd5a1..475d92d 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1055,6 +1055,7 @@ insert_into_dictkeys(PyDictKeysObject *keys, PyObject *name)
Internal routine to insert a new item into the table.
Used both by the internal resize routine and by the public insert routine.
Returns -1 if an error occurred, or 0 on success.
+Consumes key and value references.
*/
static int
insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
@@ -1062,8 +1063,6 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
PyObject *old_value;
PyDictKeyEntry *ep;
- Py_INCREF(key);
- Py_INCREF(value);
if (mp->ma_values != NULL && !PyUnicode_CheckExact(key)) {
if (insertion_resize(mp) < 0)
goto Fail;
@@ -1138,6 +1137,7 @@ Fail:
}
// Same to insertdict but specialized for ma_keys = Py_EMPTY_KEYS.
+// Consumes key and value references.
static int
insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash,
PyObject *value)
@@ -1146,6 +1146,8 @@ insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash,
PyDictKeysObject *newkeys = new_keys_object(PyDict_LOG_MINSIZE);
if (newkeys == NULL) {
+ Py_DECREF(key);
+ Py_DECREF(value);
return -1;
}
if (!PyUnicode_CheckExact(key)) {
@@ -1155,8 +1157,6 @@ insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash,
mp->ma_keys = newkeys;
mp->ma_values = NULL;
- Py_INCREF(key);
- Py_INCREF(value);
MAINTAIN_TRACKING(mp, key, value);
size_t hashpos = (size_t)hash & (PyDict_MINSIZE-1);
@@ -1529,32 +1529,24 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
return value;
}
-/* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
- * dictionary if it's merely replacing the value for an existing key.
- * This means that it's safe to loop over a dictionary with PyDict_Next()
- * and occasionally replace a value -- but you can't insert new keys or
- * remove them.
- */
+/* Consumes references to key and value */
int
-PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value)
+_PyDict_SetItem_Take2(PyDictObject *mp, PyObject *key, PyObject *value)
{
- PyDictObject *mp;
- Py_hash_t hash;
- if (!PyDict_Check(op)) {
- PyErr_BadInternalCall();
- return -1;
- }
assert(key);
assert(value);
- mp = (PyDictObject *)op;
+ assert(PyDict_Check(mp));
+ Py_hash_t hash;
if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1)
{
hash = PyObject_Hash(key);
- if (hash == -1)
+ if (hash == -1) {
+ Py_DECREF(key);
+ Py_DECREF(value);
return -1;
+ }
}
-
if (mp->ma_keys == Py_EMPTY_KEYS) {
return insert_to_emptydict(mp, key, hash, value);
}
@@ -1562,6 +1554,26 @@ PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value)
return insertdict(mp, key, hash, value);
}
+/* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
+ * dictionary if it's merely replacing the value for an existing key.
+ * This means that it's safe to loop over a dictionary with PyDict_Next()
+ * and occasionally replace a value -- but you can't insert new keys or
+ * remove them.
+ */
+int
+PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value)
+{
+ if (!PyDict_Check(op)) {
+ PyErr_BadInternalCall();
+ return -1;
+ }
+ assert(key);
+ assert(value);
+ Py_INCREF(key);
+ Py_INCREF(value);
+ return _PyDict_SetItem_Take2((PyDictObject *)op, key, value);
+}
+
int
_PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
Py_hash_t hash)
@@ -1577,6 +1589,8 @@ _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
assert(hash != -1);
mp = (PyDictObject *)op;
+ Py_INCREF(key);
+ Py_INCREF(value);
if (mp->ma_keys == Py_EMPTY_KEYS) {
return insert_to_emptydict(mp, key, hash, value);
}
@@ -1917,6 +1931,8 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
}
while (_PyDict_Next(iterable, &pos, &key, &oldvalue, &hash)) {
+ Py_INCREF(key);
+ Py_INCREF(value);
if (insertdict(mp, key, hash, value)) {
Py_DECREF(d);
return NULL;
@@ -1936,6 +1952,8 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
}
while (_PySet_NextEntry(iterable, &pos, &key, &hash)) {
+ Py_INCREF(key);
+ Py_INCREF(value);
if (insertdict(mp, key, hash, value)) {
Py_DECREF(d);
return NULL;
@@ -2562,11 +2580,16 @@ dict_merge(PyObject *a, PyObject *b, int override)
int err = 0;
Py_INCREF(key);
Py_INCREF(value);
- if (override == 1)
+ if (override == 1) {
+ Py_INCREF(key);
+ Py_INCREF(value);
err = insertdict(mp, key, hash, value);
+ }
else {
err = _PyDict_Contains_KnownHash(a, key, hash);
if (err == 0) {
+ Py_INCREF(key);
+ Py_INCREF(value);
err = insertdict(mp, key, hash, value);
}
else if (err > 0) {
@@ -2967,7 +2990,10 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
if (hash == -1)
return NULL;
}
+
if (mp->ma_keys == Py_EMPTY_KEYS) {
+ Py_INCREF(key);
+ Py_INCREF(defaultobj);
if (insert_to_emptydict(mp, key, hash, defaultobj) < 0) {
return NULL;
}