diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2016-12-27 13:19:20 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2016-12-27 13:19:20 (GMT) |
commit | e10ca3a0fe10d825689179e9958c70aef01f4230 (patch) | |
tree | f7dc9b56ba188d143a616062ec9e47f434aa32a3 /Objects/dictobject.c | |
parent | 1fee5151f72e4e141eb37e7ab0da901d1b610f45 (diff) | |
download | cpython-e10ca3a0fe10d825689179e9958c70aef01f4230.zip cpython-e10ca3a0fe10d825689179e9958c70aef01f4230.tar.gz cpython-e10ca3a0fe10d825689179e9958c70aef01f4230.tar.bz2 |
Issue #28427: old keys should not remove new values from
WeakValueDictionary when collecting from another thread.
Diffstat (limited to 'Objects/dictobject.c')
-rw-r--r-- | Objects/dictobject.c | 81 |
1 files changed, 56 insertions, 25 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 795c1f6..747d218 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1246,13 +1246,31 @@ _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value, return insertdict(mp, key, hash, value); } +static int +delitem_common(PyDictObject *mp, PyDictKeyEntry *ep, PyObject **value_addr) +{ + PyObject *old_key, *old_value; + + old_value = *value_addr; + *value_addr = NULL; + mp->ma_used--; + if (!_PyDict_HasSplitTable(mp)) { + ENSURE_ALLOWS_DELETIONS(mp); + old_key = ep->me_key; + Py_INCREF(dummy); + ep->me_key = dummy; + Py_DECREF(old_key); + } + Py_DECREF(old_value); + return 0; +} + int PyDict_DelItem(PyObject *op, PyObject *key) { PyDictObject *mp; Py_hash_t hash; PyDictKeyEntry *ep; - PyObject *old_key, *old_value; PyObject **value_addr; if (!PyDict_Check(op)) { @@ -1274,18 +1292,7 @@ PyDict_DelItem(PyObject *op, PyObject *key) _PyErr_SetKeyError(key); return -1; } - old_value = *value_addr; - *value_addr = NULL; - mp->ma_used--; - if (!_PyDict_HasSplitTable(mp)) { - ENSURE_ALLOWS_DELETIONS(mp); - old_key = ep->me_key; - Py_INCREF(dummy); - ep->me_key = dummy; - Py_DECREF(old_key); - } - Py_DECREF(old_value); - return 0; + return delitem_common(mp, ep, value_addr); } int @@ -1293,7 +1300,6 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) { PyDictObject *mp; PyDictKeyEntry *ep; - PyObject *old_key, *old_value; PyObject **value_addr; if (!PyDict_Check(op)) { @@ -1310,20 +1316,45 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) _PyErr_SetKeyError(key); return -1; } - old_value = *value_addr; - *value_addr = NULL; - mp->ma_used--; - if (!_PyDict_HasSplitTable(mp)) { - ENSURE_ALLOWS_DELETIONS(mp); - old_key = ep->me_key; - Py_INCREF(dummy); - ep->me_key = dummy; - Py_DECREF(old_key); + return delitem_common(mp, ep, value_addr); +} + +int +_PyDict_DelItemIf(PyObject *op, PyObject *key, + int (*predicate)(PyObject *value)) +{ + PyDictObject *mp; + Py_hash_t hash; + PyDictKeyEntry *ep; + PyObject **value_addr; + int res; + + if (!PyDict_Check(op)) { + PyErr_BadInternalCall(); + return -1; } - Py_DECREF(old_value); - return 0; + assert(key); + hash = PyObject_Hash(key); + if (hash == -1) + return -1; + mp = (PyDictObject *)op; + ep = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr); + if (ep == NULL) + return -1; + if (*value_addr == NULL) { + _PyErr_SetKeyError(key); + return -1; + } + res = predicate(*value_addr); + if (res == -1) + return -1; + if (res > 0) + return delitem_common(mp, ep, value_addr); + else + return 0; } + void PyDict_Clear(PyObject *op) { |