Skip to content

Commit 9f90451

Browse files
tompngnobu
authored andcommitted
st.c: skip all deleted entries [Bug #17779]
Update the start entry skipping all already deleted entries. Fixes performance issue of `Hash#first` in a certain case.
1 parent 60bdf03 commit 9f90451

2 files changed

Lines changed: 18 additions & 2 deletions

File tree

benchmark/hash_first.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
prelude: |
2+
hash1 = 1_000_000.times.to_h { [rand, true]}
3+
hash2 = hash1.dup
4+
hash2.keys[1..100_000].each { hash2.delete _1 }
5+
hash2.delete hash2.first[0]
6+
7+
benchmark:
8+
hash1: hash1.first
9+
hash2: hash2.first
10+
11+
loop_count: 100_000

st.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,8 +1244,13 @@ update_range_for_deleted(st_table *tab, st_index_t n)
12441244
{
12451245
/* Do not update entries_bound here. Otherwise, we can fill all
12461246
bins by deleted entry value before rebuilding the table. */
1247-
if (tab->entries_start == n)
1248-
tab->entries_start = n + 1;
1247+
if (tab->entries_start == n) {
1248+
st_index_t start = n + 1;
1249+
st_index_t bound = tab->entries_bound;
1250+
st_table_entry *entries = tab->entries;
1251+
while (start < bound && DELETED_ENTRY_P(&entries[start])) start++;
1252+
tab->entries_start = start;
1253+
}
12491254
}
12501255

12511256
/* Delete entry with KEY from table TAB, set up *VALUE (unless

0 commit comments

Comments
 (0)