Skip to content

Commit 8dc666e

Browse files
asvetlovwebknjaz
andauthored
Don't allocate new memory for htkeys on adding new item if the dict has deleted slots (#1200)
It is an optimization that eliminates `malloc()`/`free()` calls for the keys structure if it could be collapsed in-place. --------- Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) <[email protected]>
1 parent af83fc3 commit 8dc666e

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

CHANGES/1200.feature.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Stopped reallocating memory for the internal ``htkeys_t`` structure when inserting new items if the
2+
multidict has deleted items and it could be collapsed in-place. Removal of
3+
``malloc()``/``free()`` improves the performance slightly.
4+
5+
The change affects C implementation only, pure Python code is not changed.
6+
7+
Patch by :user:`asvetlov`.

multidict/_multilib/hashtable.h

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,8 @@ _md_resize(MultiDictObject *md, uint8_t log2_newsize, bool update)
209209
} else {
210210
entry_t *new_ep = newentries;
211211
entry_t *old_ep = oldentries;
212-
for (Py_ssize_t i = 0; i < oldkeys->nentries; ++i, ++old_ep) {
212+
Py_ssize_t oldnumentries = oldkeys->nentries;
213+
for (Py_ssize_t i = 0; i < oldnumentries; ++i, ++old_ep) {
213214
if (old_ep->identity != NULL) {
214215
*new_ep++ = *old_ep;
215216
}
@@ -232,16 +233,52 @@ _md_resize(MultiDictObject *md, uint8_t log2_newsize, bool update)
232233
return 0;
233234
}
234235

236+
static inline int
237+
_md_shrink(MultiDictObject *md, bool update)
238+
{
239+
htkeys_t *keys = md->keys;
240+
Py_ssize_t nentries = keys->nentries;
241+
entry_t *entries = htkeys_entries(keys);
242+
entry_t *new_ep = entries;
243+
entry_t *old_ep = entries;
244+
Py_ssize_t newnentries = nentries;
245+
for (Py_ssize_t i = 0; i < nentries; ++i, ++old_ep) {
246+
if (old_ep->identity != NULL) {
247+
if (new_ep != old_ep) {
248+
*new_ep++ = *old_ep;
249+
}
250+
} else {
251+
newnentries -= 1;
252+
}
253+
}
254+
keys->nentries = newnentries;
255+
keys->usable += nentries - newnentries;
256+
memset(&keys->indices[0], 0xff, ((size_t)1 << keys->log2_index_bytes));
257+
if (htkeys_build_indices(keys, entries, newnentries, update) < 0) {
258+
return -1;
259+
}
260+
ASSERT_CONSISTENT(md, update);
261+
return 0;
262+
}
263+
235264
static inline int
236265
_md_resize_for_insert(MultiDictObject *md)
237266
{
238-
return _md_resize(md, calculate_log2_keysize(GROWTH_RATE(md)), false);
267+
if (md->used < md->keys->nentries) {
268+
return _md_shrink(md, false);
269+
} else {
270+
return _md_resize(md, calculate_log2_keysize(GROWTH_RATE(md)), false);
271+
}
239272
}
240273

241274
static inline int
242275
_md_resize_for_update(MultiDictObject *md)
243276
{
244-
return _md_resize(md, calculate_log2_keysize(GROWTH_RATE(md)), true);
277+
if (md->used < md->keys->nentries) {
278+
return _md_shrink(md, true);
279+
} else {
280+
return _md_resize(md, calculate_log2_keysize(GROWTH_RATE(md)), true);
281+
}
245282
}
246283

247284
static inline int

0 commit comments

Comments
 (0)