From f2640ac8e7fb433b9ac7ec2a9ecd252570207d81 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Sun, 22 Sep 2024 11:14:27 +0200 Subject: [PATCH] Fix map resize --- sources/iron_map.c | 100 +++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/sources/iron_map.c b/sources/iron_map.c index 326a3fa1..22bf8694 100644 --- a/sources/iron_map.c +++ b/sources/iron_map.c @@ -3,8 +3,6 @@ #include "iron_gc.h" #include "iron_string.h" -static size_t index_map_set(any_map_t *m, char *k); - static size_t hash(const char *k) { // fnv1a size_t hash = 0x811c9dc5; @@ -15,33 +13,29 @@ static size_t hash(const char *k) { return hash; } -static void resize(any_map_t *m) { - int cap = m->keys->capacity == 0 ? 16 : m->keys->capacity * 2; - any_map_t *tmp = any_map_create(); - char_ptr_array_resize(tmp->keys, cap); - any_array_resize(tmp->values, cap); - - // For map, array values are spread across the whole capacity, not from 0 to length - gc_array(tmp->keys->buffer, NULL); - gc_array(tmp->values->buffer, NULL); - - any_array_t *old_keys = map_keys(m); - for (int i = 0; i < old_keys->length; ++i) { - char *k = old_keys->buffer[i]; - size_t j = index_map_set(tmp, k); - tmp->keys->buffer[j] = k; - tmp->values->buffer[j] = any_map_get(m, k); +static size_t index_set(any_map_t *m, char *k) { + size_t i = hash(k) & (m->keys->capacity - 1); // % m->keys->capacity + while (true) { + if (m->keys->buffer[i] == NULL) { + m->keys->length++; + break; + } + if (string_equals(k, m->keys->buffer[i])) { + break; + } + ++i; + if (i > m->keys->capacity - 1) { + i = 0; + } } - - m->keys = tmp->keys; - m->values = tmp->values; + return i; } -static size_t index_map_get(char_ptr_array_t *keys, char *k) { +static size_t index_get(char_ptr_array_t *keys, char *k) { if (k == NULL || keys->capacity == 0) { return -1; } - size_t i = hash(k) % keys->capacity; + size_t i = hash(k) & (keys->capacity - 1); while (!string_equals(k, keys->buffer[i])) { if (keys->buffer[i] == NULL) { return -1; @@ -54,62 +48,78 @@ static size_t index_map_get(char_ptr_array_t *keys, char *k) { return i; } -static size_t index_map_set(any_map_t *m, char *k) { - if (m->keys->length >= m->keys->capacity * 0.5) { - resize(m); +static void resize(any_map_t *m, int elem_size) { + if (m->keys->length < m->keys->capacity * 0.5) { + return; } - size_t i = hash(k) & (m->keys->capacity - 1); // % m->keys->capacity - while (true) { - if (m->keys->buffer[i] == NULL) { - m->keys->length++; - break; - } - if (string_equals(k, m->keys->buffer[i])) { - break; + + int cap = m->keys->capacity == 0 ? 16 : m->keys->capacity * 2; + any_map_t *tmp = any_map_create(); + tmp->keys->capacity = cap; + tmp->keys->buffer = gc_realloc(tmp->keys->buffer, cap * sizeof(void *)); + tmp->values->capacity = cap; + tmp->values->buffer = gc_realloc(tmp->values->buffer, cap * elem_size); + if (elem_size < 8) { + gc_leaf(tmp->values->buffer); + } + + any_array_t *old_keys = map_keys(m); + for (int i = 0; i < old_keys->length; ++i) { + char *k = old_keys->buffer[i]; + size_t j = index_set(tmp, k); + tmp->keys->buffer[j] = k; + if (elem_size == 8) { + void **buf = tmp->values->buffer; + buf[j] = any_map_get(m, k); } - ++i; - if (i > m->keys->capacity - 1) { - i = 0; + else { + int32_t *buf = tmp->values->buffer; + buf[j] = i32_map_get(m, k); } } - return i; + + m->keys = tmp->keys; + m->values = tmp->values; } void i32_map_set(i32_map_t *m, char *k, int v) { - size_t i = index_map_set(m, k); + resize(m, 4); + size_t i = index_set(m, k); m->keys->buffer[i] = k; m->values->buffer[i] = v; } void f32_map_set(f32_map_t *m, char *k, float v) { - size_t i = index_map_set(m, k); + resize(m, 4); + size_t i = index_set(m, k); m->keys->buffer[i] = k; m->values->buffer[i] = v; } void any_map_set(any_map_t *m, char *k, void *v) { - size_t i = index_map_set(m, k); + resize(m, 8); + size_t i = index_set(m, k); m->keys->buffer[i] = k; m->values->buffer[i] = v; } int32_t i32_map_get(i32_map_t *m, char *k) { - size_t i = index_map_get(m->keys, k); + size_t i = index_get(m->keys, k); return i == -1 ? -1 : m->values->buffer[i]; } float f32_map_get(f32_map_t *m, char *k) { - size_t i = index_map_get(m->keys, k); + size_t i = index_get(m->keys, k); return i == -1 ? -1.0 : m->values->buffer[i]; } void *any_map_get(any_map_t *m, char *k) { - size_t i = index_map_get(m->keys, k); + size_t i = index_get(m->keys, k); return i == -1 ? NULL : m->values->buffer[i]; } void map_delete(any_map_t *m, char *k) { - size_t i = index_map_get(m->keys, k); + size_t i = index_get(m->keys, k); if (i != -1) { m->keys->buffer[i] = NULL; m->keys->length--;