summaryrefslogtreecommitdiffhomepage
path: root/types.c
diff options
context:
space:
mode:
Diffstat (limited to 'types.c')
-rw-r--r--types.c39
1 files changed, 37 insertions, 2 deletions
diff --git a/types.c b/types.c
index 84a7b17..c4bc456 100644
--- a/types.c
+++ b/types.c
@@ -896,8 +896,8 @@ ucv_free_object_entry(struct lh_entry *entry)
uc_list_foreach(item, &uc_object_iterators) {
uc_object_iterator_t *iter = (uc_object_iterator_t *)item;
- if (iter->pos == entry)
- iter->pos = entry->next;
+ if (iter->u.pos == entry)
+ iter->u.pos = entry->next;
}
free(lh_entry_k(entry));
@@ -946,6 +946,24 @@ ucv_object_add(uc_value_t *uv, const char *key, uc_value_t *val)
existing_entry = lh_table_lookup_entry_w_hash(object->table, (const void *)key, hash);
if (existing_entry == NULL) {
+ bool rehash = (object->table->count >= object->table->size * LH_LOAD_FACTOR);
+
+ /* insert will rehash table, backup affected iterator states */
+ if (rehash) {
+ uc_list_foreach(item, &uc_object_iterators) {
+ uc_object_iterator_t *iter = (uc_object_iterator_t *)item;
+
+ if (iter->table != object->table)
+ continue;
+
+ if (iter->u.pos == NULL)
+ continue;
+
+ iter->u.kh.k = iter->u.pos->k;
+ iter->u.kh.hash = lh_get_hash(iter->table, iter->u.kh.k);
+ }
+ }
+
k = xstrdup(key);
if (lh_table_insert_w_hash(object->table, k, val, hash, 0) != 0) {
@@ -954,6 +972,23 @@ ucv_object_add(uc_value_t *uv, const char *key, uc_value_t *val)
return false;
}
+ /* restore affected iterator state pointer after rehash */
+ if (rehash) {
+ uc_list_foreach(item, &uc_object_iterators) {
+ uc_object_iterator_t *iter = (uc_object_iterator_t *)item;
+
+ if (iter->table != object->table)
+ continue;
+
+ if (iter->u.kh.k == NULL)
+ continue;
+
+ iter->u.pos = lh_table_lookup_entry_w_hash(iter->table,
+ iter->u.kh.k,
+ iter->u.kh.hash);
+ }
+ }
+
return true;
}