diff options
Diffstat (limited to 'Objects/dictobject.c')
-rw-r--r-- | Objects/dictobject.c | 68 |
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; } |