map: Fix removal of entries from the table

Removing entries from an open addressed hash table creates holes in the
collision chains, preventing previous colliding entries to be found.  By
inserting tombstones, rather than clearing deleted entries makes it
possible to distinguish the end of a chain from a hole.

Reviewed-by: Arun Kumar Neelakantam <aneela@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
This commit is contained in:
Bjorn Andersson
2019-02-28 08:56:37 -08:00
parent c1bdfb37db
commit 111403fe72

View File

@@ -31,6 +31,9 @@ struct map_entry {
struct map_item *item;
};
/* Marker for deleted items */
static struct map_item deleted;
void map_destroy(struct map *map)
{
free(map->data);
@@ -43,7 +46,8 @@ void map_clear(struct map *map, void (*release)(struct map_item *))
for (i = 0; i < map->size; ++i){
if (!map->data[i].item)
continue;
(* release)(map->data[i].item);
if (map->data[i].item != &deleted)
(* release)(map->data[i].item);
map->data[i].item = NULL;
}
map->count = 0;
@@ -69,7 +73,7 @@ static int map_hash(struct map *map, unsigned int key)
for (i = 0; i < map->size; ++i) {
e = &map->data[idx];
if (!e->item) {
if (!e->item || e->item == &deleted) {
++map->count;
return idx;
}
@@ -94,8 +98,12 @@ int map_reput(struct map *map, unsigned int key, struct map_item *value,
return rc;
}
if (old)
*old = map->data[rc].item;
if (old) {
if (map->data[rc].item == &deleted)
*old = NULL;
else
*old = map->data[rc].item;
}
map->data[rc].item = value;
if (value)
map->data[rc].item->key = key;
@@ -126,7 +134,7 @@ static int map_rehash(struct map *map)
map->count = 0;
for (i = 0; i < o_size; ++i){
if (!oldt[i].item)
if (!oldt[i].item || oldt[i].item == &deleted)
continue;
rc = map_put(map, oldt[i].item->key, oldt[i].item);
if (rc < 0)
@@ -150,11 +158,14 @@ static struct map_entry *map_find(const struct map *map, unsigned int key)
for (i = 0; i < map->size; ++i) {
e = &map->data[idx];
idx = (idx + 1) % map->size;
if (!e->item)
break;
if (e->item == &deleted)
continue;
if (e->item->key == key)
return e;
idx = (idx + 1) % map->size;
}
return NULL;
}
@@ -180,7 +191,7 @@ int map_remove(struct map *map, unsigned int key)
e = map_find(map, key);
if (e) {
e->item = NULL;
e->item = &deleted;
--map->count;
}
return !e;
@@ -196,7 +207,7 @@ static struct map_entry *map_iter_from(const struct map *map, unsigned int start
unsigned int i = start;
for (; i < map->size; ++i) {
if (map->data[i].item)
if (map->data[i].item && map->data[i].item != &deleted)
return &map->data[i];
}
return NULL;