diff options
author | Inada Naoki <songofacandy@gmail.com> | 2019-03-18 11:38:33 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-18 11:38:33 (GMT) |
commit | 2ddc7f6d6223840c9971b36b30da4b3371d6e52b (patch) | |
tree | b0975aa2e6f70ac5764da0544542097da6beabd4 /Objects | |
parent | 09a9f1799c8c58f573c50cb2d526422436b8658b (diff) | |
download | cpython-2ddc7f6d6223840c9971b36b30da4b3371d6e52b.zip cpython-2ddc7f6d6223840c9971b36b30da4b3371d6e52b.tar.gz cpython-2ddc7f6d6223840c9971b36b30da4b3371d6e52b.tar.bz2 |
bpo-30040: optimize inserting into empty dict (GH-12307)
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/dictobject.c | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 108c612..524ff67 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1102,6 +1102,41 @@ Fail: return -1; } +// Same to insertdict but specialized for ma_keys = Py_EMPTY_KEYS. +static int +insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash, + PyObject *value) +{ + assert(mp->ma_keys == Py_EMPTY_KEYS); + + PyDictKeysObject *newkeys = new_keys_object(PyDict_MINSIZE); + if (newkeys == NULL) { + return -1; + } + if (!PyUnicode_CheckExact(key)) { + newkeys->dk_lookup = lookdict; + } + dictkeys_decref(Py_EMPTY_KEYS); + mp->ma_keys = newkeys; + mp->ma_values = NULL; + + Py_INCREF(key); + Py_INCREF(value); + MAINTAIN_TRACKING(mp, key, value); + + size_t hashpos = (size_t)hash & (PyDict_MINSIZE-1); + PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[0]; + dictkeys_set_index(mp->ma_keys, hashpos, 0); + ep->me_key = key; + ep->me_hash = hash; + ep->me_value = value; + mp->ma_used++; + mp->ma_version_tag = DICT_NEXT_VERSION(); + mp->ma_keys->dk_usable--; + mp->ma_keys->dk_nentries++; + return 0; +} + /* Internal routine used by dictresize() to build a hashtable of entries. */ @@ -1274,7 +1309,7 @@ _PyDict_NewPresized(Py_ssize_t minused) Py_ssize_t newsize; PyDictKeysObject *new_keys; - if (minused == 0) { + if (minused <= USABLE_FRACTION(PyDict_MINSIZE)) { return PyDict_New(); } /* There are no strict guarantee that returned dict can contain minused @@ -1286,7 +1321,7 @@ _PyDict_NewPresized(Py_ssize_t minused) } else { Py_ssize_t minsize = ESTIMATE_SIZE(minused); - newsize = PyDict_MINSIZE; + newsize = PyDict_MINSIZE*2; while (newsize < minsize) { newsize <<= 1; } @@ -1495,6 +1530,9 @@ PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value) return -1; } + if (mp->ma_keys == Py_EMPTY_KEYS) { + return insert_to_emptydict(mp, key, hash, value); + } /* insertdict() handles any resizing that might be necessary */ return insertdict(mp, key, hash, value); } @@ -1514,6 +1552,9 @@ _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value, assert(hash != -1); mp = (PyDictObject *)op; + if (mp->ma_keys == Py_EMPTY_KEYS) { + return insert_to_emptydict(mp, key, hash, value); + } /* insertdict() handles any resizing that might be necessary */ return insertdict(mp, key, hash, value); } @@ -2844,6 +2885,12 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) if (hash == -1) return NULL; } + if (mp->ma_keys == Py_EMPTY_KEYS) { + if (insert_to_emptydict(mp, key, hash, defaultobj) < 0) { + return NULL; + } + return defaultobj; + } if (mp->ma_values != NULL && !PyUnicode_CheckExact(key)) { if (insertion_resize(mp) < 0) |