summaryrefslogtreecommitdiffstats
path: root/Objects/dictobject.c
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2016-12-27 13:19:20 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2016-12-27 13:19:20 (GMT)
commite10ca3a0fe10d825689179e9958c70aef01f4230 (patch)
treef7dc9b56ba188d143a616062ec9e47f434aa32a3 /Objects/dictobject.c
parent1fee5151f72e4e141eb37e7ab0da901d1b610f45 (diff)
downloadcpython-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.c81
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)
{