Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2ddc7f6

Browse files
authored
bpo-30040: optimize inserting into empty dict (GH-12307)
1 parent 09a9f17 commit 2ddc7f6

1 file changed

Lines changed: 49 additions & 2 deletions

File tree

Objects/dictobject.c

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,41 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
11021102
return -1;
11031103
}
11041104

1105+
// Same to insertdict but specialized for ma_keys = Py_EMPTY_KEYS.
1106+
static int
1107+
insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash,
1108+
PyObject *value)
1109+
{
1110+
assert(mp->ma_keys == Py_EMPTY_KEYS);
1111+
1112+
PyDictKeysObject *newkeys = new_keys_object(PyDict_MINSIZE);
1113+
if (newkeys == NULL) {
1114+
return -1;
1115+
}
1116+
if (!PyUnicode_CheckExact(key)) {
1117+
newkeys->dk_lookup = lookdict;
1118+
}
1119+
dictkeys_decref(Py_EMPTY_KEYS);
1120+
mp->ma_keys = newkeys;
1121+
mp->ma_values = NULL;
1122+
1123+
Py_INCREF(key);
1124+
Py_INCREF(value);
1125+
MAINTAIN_TRACKING(mp, key, value);
1126+
1127+
size_t hashpos = (size_t)hash & (PyDict_MINSIZE-1);
1128+
PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[0];
1129+
dictkeys_set_index(mp->ma_keys, hashpos, 0);
1130+
ep->me_key = key;
1131+
ep->me_hash = hash;
1132+
ep->me_value = value;
1133+
mp->ma_used++;
1134+
mp->ma_version_tag = DICT_NEXT_VERSION();
1135+
mp->ma_keys->dk_usable--;
1136+
mp->ma_keys->dk_nentries++;
1137+
return 0;
1138+
}
1139+
11051140
/*
11061141
Internal routine used by dictresize() to build a hashtable of entries.
11071142
*/
@@ -1274,7 +1309,7 @@ _PyDict_NewPresized(Py_ssize_t minused)
12741309
Py_ssize_t newsize;
12751310
PyDictKeysObject *new_keys;
12761311

1277-
if (minused == 0) {
1312+
if (minused <= USABLE_FRACTION(PyDict_MINSIZE)) {
12781313
return PyDict_New();
12791314
}
12801315
/* There are no strict guarantee that returned dict can contain minused
@@ -1286,7 +1321,7 @@ _PyDict_NewPresized(Py_ssize_t minused)
12861321
}
12871322
else {
12881323
Py_ssize_t minsize = ESTIMATE_SIZE(minused);
1289-
newsize = PyDict_MINSIZE;
1324+
newsize = PyDict_MINSIZE*2;
12901325
while (newsize < minsize) {
12911326
newsize <<= 1;
12921327
}
@@ -1495,6 +1530,9 @@ PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value)
14951530
return -1;
14961531
}
14971532

1533+
if (mp->ma_keys == Py_EMPTY_KEYS) {
1534+
return insert_to_emptydict(mp, key, hash, value);
1535+
}
14981536
/* insertdict() handles any resizing that might be necessary */
14991537
return insertdict(mp, key, hash, value);
15001538
}
@@ -1514,6 +1552,9 @@ _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
15141552
assert(hash != -1);
15151553
mp = (PyDictObject *)op;
15161554

1555+
if (mp->ma_keys == Py_EMPTY_KEYS) {
1556+
return insert_to_emptydict(mp, key, hash, value);
1557+
}
15171558
/* insertdict() handles any resizing that might be necessary */
15181559
return insertdict(mp, key, hash, value);
15191560
}
@@ -2844,6 +2885,12 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
28442885
if (hash == -1)
28452886
return NULL;
28462887
}
2888+
if (mp->ma_keys == Py_EMPTY_KEYS) {
2889+
if (insert_to_emptydict(mp, key, hash, defaultobj) < 0) {
2890+
return NULL;
2891+
}
2892+
return defaultobj;
2893+
}
28472894

28482895
if (mp->ma_values != NULL && !PyUnicode_CheckExact(key)) {
28492896
if (insertion_resize(mp) < 0)

0 commit comments

Comments
 (0)