Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1475,6 +1475,17 @@ _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
return insertdict(mp, key, hash, value);
}

// Resize dict if dk_size is too large.
static int
after_removed(PyDictObject *mp)
{
if (mp->ma_keys->dk_size > PyDict_MINSIZE &&

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I hesitated to propose the same test in your previous PR #5297, but I wasn't sure if it was required in practice since MINSIZE=8.

I like the idea of being explicit here, check size > MINSIZE.

mp->ma_used < mp->ma_keys->dk_size / 8) {
return insertion_resize(mp);
}
return 0;
}

static int
delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
PyObject *old_value)
Expand All @@ -1497,7 +1508,7 @@ delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
Py_DECREF(old_value);

assert(_PyDict_CheckConsistency(mp));
return 0;
return after_removed(mp);
}

int
Expand Down Expand Up @@ -1767,6 +1778,10 @@ _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *d
Py_DECREF(old_key);

assert(_PyDict_CheckConsistency(mp));
if (after_removed(mp) < 0) {
Py_DECREF(old_value);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that it's ok to drop the popped value here :-(

If shrinking the dict fails, I suggest to ignore the error and return the old value anyway. The next del/pop will try again to shrink the dict.

return NULL;
}
return old_value;
}

Expand Down Expand Up @@ -2950,6 +2965,10 @@ dict_popitem(PyDictObject *mp)
mp->ma_used--;
mp->ma_version_tag = DICT_NEXT_VERSION();
assert(_PyDict_CheckConsistency(mp));
if (after_removed(mp) < 0) {
Py_DECREF(res);
return NULL;
}
return res;
}

Expand Down