runtime: size a cloned map's direct index for its own keys

new Map(m) and new Set(s) copied the source's direct-index size, which
follows the source's peak. The copy now covers its largest live key, and
keys that are sparse for their count hash instead.
This commit is contained in:
Malte Ubl
2026-10-11 06:39:40 -07:00
parent 175d79ff01
commit 714afdcfe5
2 changed files with 25 additions and 3 deletions
+9 -3
View File
@@ -1248,9 +1248,14 @@ ScrMap *scr_map_clone(const ScrMap *source, bool keys_only) {
out->entries = malloc(count * sizeof(ScrMapEntry));
if (!out->entries) scr_map_oom();
out->ecap = count;
size_t top = 0;
for (size_t i = 0; i < source->nentries; i++) {
const ScrMapEntry *entry = &source->entries[i];
if (!entry->hash) continue;
if (source->ndense) {
size_t k = (size_t)scr_map_slot_to_f64(entry->key);
if (k > top) top = k;
}
ScrMapEntry *copy = &out->entries[out->nentries++];
*copy = *entry;
if (out->key_kind == SCR_MAP_KEY_STR) scr_str_retain(scr_map_slot_to_ptr(copy->key));
@@ -1259,9 +1264,10 @@ ScrMap *scr_map_clone(const ScrMap *source, bool keys_only) {
else if (out->val_kind == SCR_MAP_VAL_REF) out->val_retain(scr_map_slot_to_ptr(copy->val));
}
out->nlive = count;
if (source->ndense) {
/* Same keys, so the same table size; entry indices are compacted. */
scr_map_dense_alloc(out, source->ndense);
/* Size the copy's direct index for its own keys, not for the source's
* peak; keys that are sparse for their count hash instead. */
if (source->ndense && top / 2 < scr_map_dense_limit(count)) {
scr_map_dense_alloc(out, scr_map_dense_size(top));
scr_map_fill_dense(out);
return out;
}
+16
View File
@@ -372,6 +372,22 @@ static void delete_shrinks(void) {
assert(scr_map_size(map) == 20 && map->ndense && map->ndense <= 64);
for (size_t i = 0; i < 40; i++) assert(scr_map_has_f64(map, (double)i) == (i < 20));
scr_map_release(map);
/* A copy indexes its own keys, not the source's peak (here a quarter of
* the entries survive, too many to compact the source yet). */
map = scr_map_new(SCR_MAP_KEY_F64, SCR_MAP_VAL_F64, NULL, NULL, NULL);
for (size_t i = 0; i < 4096; i++) scr_map_set_f64_f64(map, (double)i, (double)i);
for (size_t i = 1024; i < 4096; i++) assert(scr_map_delete_f64(map, (double)i));
assert(map->ndense == 4096 && scr_map_iter_count(map) == 4096);
ScrMap *copy = scr_map_clone(map, false);
assert(copy->ndense == 1024 && scr_map_size(copy) == 1024);
double out;
for (size_t i = 0; i < 1100; i++) {
assert(scr_map_get_f64_f64(copy, (double)i, &out) == (i < 1024));
if (i < 1024) assert(out == (double)i);
}
scr_map_release(copy);
scr_map_release(map);
}
/* Grow-and-drain cycles against the ordered model: the map repeatedly