diff -r 89b2a83728b1 -r 2946e13c89a4 src/hash_map.c --- a/src/hash_map.c Thu May 19 14:30:20 2022 +0200 +++ b/src/hash_map.c Sat May 21 11:22:47 2022 +0200 @@ -175,6 +175,25 @@ return 0; } +static void cx_hash_map_unlink( + struct cx_hash_map_s *hash_map, + size_t slot, + struct cx_hash_map_element_s *prev, + struct cx_hash_map_element_s *elm +) { + // unlink + if (prev == NULL) { + hash_map->buckets[slot] = elm->next; + } else { + prev->next = elm->next; + } + // free element + cxFree(hash_map->base.allocator, elm->key.data); + cxFree(hash_map->base.allocator, elm); + // decrease size + hash_map->base.size--; +} + /** * Helper function to avoid code duplication. * @@ -200,17 +219,7 @@ if (memcmp(elm->key.data, key.data, key.len) == 0) { void *data = elm->data; if (remove) { - // unlink - if (prev) { - prev->next = elm->next; - } else { - hash_map->buckets[slot] = elm->next; - } - // free element - cxFree(map->allocator, elm->key.data); - cxFree(map->allocator, elm); - // decrease size - map->size--; + cx_hash_map_unlink(hash_map, slot, prev, elm); } return data; } @@ -237,21 +246,120 @@ return cx_hash_map_get_remove(map, key, true); } -static CxIterator cx_hash_map_iterator(CxMap const *map) { +static void *cx_hash_map_iter_current_entry(CxIterator const *iter) { + // struct has to have a compatible signature + struct cx_map_entry_s *entry = (struct cx_map_entry_s *) &(iter->kv_data); + return entry; +} + +static void *cx_hash_map_iter_current_key(CxIterator const *iter) { + struct cx_hash_map_element_s *elm = iter->elem_handle; + return &elm->key; +} + +static void *cx_hash_map_iter_current_value(CxIterator const *iter) { + struct cx_hash_map_element_s *elm = iter->elem_handle; + // TODO: return a pointer to data if this map is storing copies + return elm->data; +} + +static bool cx_hash_map_iter_valid(CxIterator const *iter) { + return iter->elem_handle != NULL; +} + +static void cx_hash_map_iter_next(CxIterator *iter) { + struct cx_hash_map_s *map = iter->src_handle; + struct cx_hash_map_element_s *elm = iter->elem_handle; + + // remove current element, if asked + if (iter->remove) { + // clear the flag + iter->remove = false; + + // determine the next element + struct cx_hash_map_element_s *next = elm->next; + + // search the previous element + struct cx_hash_map_element_s *prev = NULL; + if (map->buckets[iter->slot] != elm) { + prev = map->buckets[iter->slot]; + while (prev->next != elm) { + prev = prev->next; + } + } + + // unlink + cx_hash_map_unlink(map, iter->slot, prev, elm); + + // advance + elm = next; + } else { + // just advance + elm = elm->next; + } + + // do we leave the bucket? + if (elm == NULL) { + // search the next bucket + for (; elm == NULL && iter->slot < map->bucket_count; iter->slot++) { + elm = map->buckets[iter->slot]; + } + } + + // advance the index in any case + iter->index++; + + // fill the struct with the current element + iter->elem_handle = elm; + if (elm == NULL) { + iter->kv_data.key = NULL; + iter->kv_data.value = NULL; + } else { + iter->kv_data.key = &elm->key; + // TODO: pointer to data if this map is storing copies + iter->kv_data.value = elm->data; + } +} + +static CxIterator cx_hash_map_iterator(CxMap *map) { CxIterator iter; - // TODO: initialize iter + + iter.src_handle = map; + iter.valid = cx_hash_map_iter_valid; + iter.next = cx_hash_map_iter_next; + iter.current = cx_hash_map_iter_current_entry; + + iter.slot = 0; + iter.index = 0; + iter.remove = false; + + if (map->size > 0) { + struct cx_hash_map_s *hash_map = (struct cx_hash_map_s *) map; + struct cx_hash_map_element_s *elem = NULL; + for (; elem == NULL; iter.slot++) { + elem = hash_map->buckets[iter.slot]; + } + iter.elem_handle = elem; + iter.kv_data.key = NULL; + iter.kv_data.value = NULL; + } else { + iter.elem_handle = NULL; + iter.kv_data.key = NULL; + iter.kv_data.value = NULL; + } + return iter; } -static CxIterator cx_hash_map_iterator_keys(CxMap const *map) { - CxIterator iter; - // TODO: initialize iter +static CxIterator cx_hash_map_iterator_keys(CxMap *map) { + CxIterator iter = cx_hash_map_iterator(map); + iter.current = cx_hash_map_iter_current_key; return iter; } -static CxIterator cx_hash_map_iterator_values(CxMap const *map) { - CxIterator iter; - // TODO: initialize iter +static CxIterator cx_hash_map_iterator_values(CxMap *map) { + CxIterator iter = cx_hash_map_iterator(map); + iter.current = cx_hash_map_iter_current_value; return iter; }