bpo-31954: Reuse oldkeys if oldkeys->dk_size == newsize. by serhiy-storchaka · Pull Request #4292 · python/cpython
Expand Up
@@ -417,11 +417,12 @@ dk_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix)
* (which cannot fail and thus can do no allocation).
*/
static PyDictKeysObject empty_keys_struct = {
1, /* dk_refcnt */
1, /* dk_size */
lookdict_split, /* dk_lookup */
0, /* dk_usable (immutable) */
0, /* dk_nentries */
.dk_refcnt = 1,
.dk_size = 1,
.dk_lookup = lookdict_split,
.dk_usable = 0,
.dk_nentries = 0,
.dk_clean = 0,
.dk_indices = { .as_1 = {DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY,
DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY}},
};
Expand Down
Expand Up
@@ -544,6 +545,7 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size)
dk->dk_usable = usable;
dk->dk_lookup = lookdict_unicode_nodummy;
dk->dk_nentries = 0;
dk->dk_clean = 0;
memset(&dk->dk_indices.as_1[0], 0xff, es * size);
memset(DK_ENTRIES(dk), 0, sizeof(PyDictKeyEntry) * usable);
return dk;
Expand Down
Expand Up
@@ -1078,27 +1080,24 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize)
}
oldkeys = mp->ma_keys;
/* NOTE: Current odict checks mp->ma_keys to detect resize happen. * So we can't reuse oldkeys even if oldkeys->dk_size == newsize. * TODO: Try reusing oldkeys when reimplement odict. */
/* Allocate a new table. */ mp->ma_keys = new_keys_object(newsize); if (mp->ma_keys == NULL) { mp->ma_keys = oldkeys; return -1; oldvalues = mp->ma_values; if (newsize != oldkeys->dk_size || oldvalues != NULL) { /* Allocate a new table. */ mp->ma_keys = new_keys_object(newsize); if (mp->ma_keys == NULL) { mp->ma_keys = oldkeys; return -1; } // New table must be large enough. assert(mp->ma_keys->dk_usable >= mp->ma_used); if (oldkeys->dk_lookup == lookdict) mp->ma_keys->dk_lookup = lookdict; } // New table must be large enough. assert(mp->ma_keys->dk_usable >= mp->ma_used); if (oldkeys->dk_lookup == lookdict) mp->ma_keys->dk_lookup = lookdict; mp->ma_keys->dk_clean = 0;
numentries = mp->ma_used; oldentries = DK_ENTRIES(oldkeys); newentries = DK_ENTRIES(mp->ma_keys); oldvalues = mp->ma_values; if (oldvalues != NULL) { /* Convert split table into new combined table. * We must incref keys; we can transfer values. Expand All @@ -1122,7 +1121,8 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize) } else { // combined table. if (oldkeys->dk_nentries == numentries) { memcpy(newentries, oldentries, numentries * sizeof(PyDictKeyEntry)); /* Source and destination can overlap if reuse an old table. */ memmove(newentries, oldentries, numentries * sizeof(PyDictKeyEntry)); } else { PyDictKeyEntry *ep = oldentries; Expand All @@ -1133,14 +1133,24 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize) } }
assert(oldkeys->dk_lookup != lookdict_split); assert(oldkeys->dk_refcnt == 1); if (oldkeys->dk_size == PyDict_MINSIZE && numfreekeys < PyDict_MAXFREELIST) { DK_DEBUG_DECREF keys_free_list[numfreekeys++] = oldkeys; if (oldkeys != mp->ma_keys) { assert(oldkeys->dk_lookup != lookdict_split); assert(oldkeys->dk_refcnt == 1); if (oldkeys->dk_size == PyDict_MINSIZE && numfreekeys < PyDict_MAXFREELIST) { DK_DEBUG_DECREF keys_free_list[numfreekeys++] = oldkeys; } else { DK_DEBUG_DECREF PyObject_FREE(oldkeys); } } else { DK_DEBUG_DECREF PyObject_FREE(oldkeys); oldkeys->dk_usable = USABLE_FRACTION(newsize); memset(&oldkeys->dk_indices.as_1[0], 0xff, DK_IXSIZE(oldkeys) * newsize); memset(newentries + numentries, 0, sizeof(PyDictKeyEntry) * (oldkeys->dk_usable - numentries)); } }
Expand Down
oldkeys = mp->ma_keys;
/* NOTE: Current odict checks mp->ma_keys to detect resize happen. * So we can't reuse oldkeys even if oldkeys->dk_size == newsize. * TODO: Try reusing oldkeys when reimplement odict. */
/* Allocate a new table. */ mp->ma_keys = new_keys_object(newsize); if (mp->ma_keys == NULL) { mp->ma_keys = oldkeys; return -1; oldvalues = mp->ma_values; if (newsize != oldkeys->dk_size || oldvalues != NULL) { /* Allocate a new table. */ mp->ma_keys = new_keys_object(newsize); if (mp->ma_keys == NULL) { mp->ma_keys = oldkeys; return -1; } // New table must be large enough. assert(mp->ma_keys->dk_usable >= mp->ma_used); if (oldkeys->dk_lookup == lookdict) mp->ma_keys->dk_lookup = lookdict; } // New table must be large enough. assert(mp->ma_keys->dk_usable >= mp->ma_used); if (oldkeys->dk_lookup == lookdict) mp->ma_keys->dk_lookup = lookdict; mp->ma_keys->dk_clean = 0;
numentries = mp->ma_used; oldentries = DK_ENTRIES(oldkeys); newentries = DK_ENTRIES(mp->ma_keys); oldvalues = mp->ma_values; if (oldvalues != NULL) { /* Convert split table into new combined table. * We must incref keys; we can transfer values. Expand All @@ -1122,7 +1121,8 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize) } else { // combined table. if (oldkeys->dk_nentries == numentries) { memcpy(newentries, oldentries, numentries * sizeof(PyDictKeyEntry)); /* Source and destination can overlap if reuse an old table. */ memmove(newentries, oldentries, numentries * sizeof(PyDictKeyEntry)); } else { PyDictKeyEntry *ep = oldentries; Expand All @@ -1133,14 +1133,24 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize) } }
assert(oldkeys->dk_lookup != lookdict_split); assert(oldkeys->dk_refcnt == 1); if (oldkeys->dk_size == PyDict_MINSIZE && numfreekeys < PyDict_MAXFREELIST) { DK_DEBUG_DECREF keys_free_list[numfreekeys++] = oldkeys; if (oldkeys != mp->ma_keys) { assert(oldkeys->dk_lookup != lookdict_split); assert(oldkeys->dk_refcnt == 1); if (oldkeys->dk_size == PyDict_MINSIZE && numfreekeys < PyDict_MAXFREELIST) { DK_DEBUG_DECREF keys_free_list[numfreekeys++] = oldkeys; } else { DK_DEBUG_DECREF PyObject_FREE(oldkeys); } } else { DK_DEBUG_DECREF PyObject_FREE(oldkeys); oldkeys->dk_usable = USABLE_FRACTION(newsize); memset(&oldkeys->dk_indices.as_1[0], 0xff, DK_IXSIZE(oldkeys) * newsize); memset(newentries + numentries, 0, sizeof(PyDictKeyEntry) * (oldkeys->dk_usable - numentries)); } }
Expand Down