hashmap: introduce hashmap_free_entries
`hashmap_free_entries' behaves like `container_of' and passes
the offset of the hashmap_entry struct to the internal
`hashmap_free_' function, allowing the function to free any
struct pointer regardless of where the hashmap_entry field
is located.
`hashmap_free' no longer takes any arguments aside from
the hashmap itself.
Signed-off-by: Eric Wong <e@80x24.org>
Reviewed-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/blame.c b/blame.c
index 3d8accf..f33af0d 100644
--- a/blame.c
+++ b/blame.c
@@ -433,7 +433,7 @@
static void free_fingerprint(struct fingerprint *f)
{
- hashmap_free(&f->map, 0);
+ hashmap_free(&f->map);
free(f->entries);
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 476c241..09f7170 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -366,7 +366,7 @@
item = refname_hash_add(&remote_refs, ref->name, &ref->old_oid);
string_list_insert(&remote_refs_list, ref->name);
}
- hashmap_free(&existing_refs, 1);
+ hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
/*
* We may have a final lightweight tag that needs to be
@@ -401,7 +401,7 @@
**tail = rm;
*tail = &rm->next;
}
- hashmap_free(&remote_refs, 1);
+ hashmap_free_entries(&remote_refs, struct refname_hash_entry, ent);
string_list_clear(&remote_refs_list, 0);
}
@@ -530,7 +530,7 @@
}
}
}
- hashmap_free(&existing_refs, 1);
+ hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
return ref_map;
}
diff --git a/config.c b/config.c
index 8433f74..4d05dbc 100644
--- a/config.c
+++ b/config.c
@@ -1948,7 +1948,7 @@
free(entry->key);
string_list_clear(&entry->value_list, 1);
}
- hashmap_free(&cs->config_hash, 1);
+ hashmap_free_entries(&cs->config_hash, struct config_set_element, ent);
cs->hash_initialized = 0;
free(cs->list.items);
cs->list.nr = 0;
diff --git a/diff.c b/diff.c
index 5eaf689..f94d9f9 100644
--- a/diff.c
+++ b/diff.c
@@ -6236,8 +6236,10 @@
if (o->color_moved == COLOR_MOVED_ZEBRA_DIM)
dim_moved_lines(o);
- hashmap_free(&add_lines, 1);
- hashmap_free(&del_lines, 1);
+ hashmap_free_entries(&add_lines, struct moved_entry,
+ ent);
+ hashmap_free_entries(&del_lines, struct moved_entry,
+ ent);
}
for (i = 0; i < esm.nr; i++)
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 611b08f..994609e 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -358,7 +358,7 @@
renames += find_identical_files(&file_table, i, options);
/* Free the hash data structure and entries */
- hashmap_free(&file_table, 1);
+ hashmap_free_entries(&file_table, struct file_similarity, entry);
return renames;
}
diff --git a/hashmap.c b/hashmap.c
index 1b60f97..65b447f 100644
--- a/hashmap.c
+++ b/hashmap.c
@@ -171,16 +171,21 @@
map->do_count_items = 1;
}
-void hashmap_free(struct hashmap *map, int free_entries)
+void hashmap_free_(struct hashmap *map, ssize_t entry_offset)
{
if (!map || !map->table)
return;
- if (free_entries) {
+ if (entry_offset >= 0) { /* called by hashmap_free_entries */
struct hashmap_iter iter;
struct hashmap_entry *e;
+
hashmap_iter_init(map, &iter);
while ((e = hashmap_iter_next(&iter)))
- free(e);
+ /*
+ * like container_of, but using caller-calculated
+ * offset (caller being hashmap_free_entries)
+ */
+ free((char *)e - entry_offset);
}
free(map->table);
memset(map, 0, sizeof(*map));
diff --git a/hashmap.h b/hashmap.h
index bc3b10e..171d6dd 100644
--- a/hashmap.h
+++ b/hashmap.h
@@ -96,7 +96,7 @@
* }
*
* if (!strcmp("end", action)) {
- * hashmap_free(&map, 1);
+ * hashmap_free_entries(&map, struct long2string, ent);
* break;
* }
* }
@@ -232,13 +232,20 @@
const void *equals_function_data,
size_t initial_size);
+/* internal function for freeing hashmap */
+void hashmap_free_(struct hashmap *map, ssize_t offset);
+
/*
- * Frees a hashmap structure and allocated memory.
- *
- * If `free_entries` is true, each hashmap_entry in the map is freed as well
- * using stdlibs free().
+ * Frees a hashmap structure and allocated memory, leaves entries undisturbed
*/
-void hashmap_free(struct hashmap *map, int free_entries);
+#define hashmap_free(map) hashmap_free_(map, -1)
+
+/*
+ * Frees @map and all entries. @type is the struct type of the entry
+ * where @member is the hashmap_entry struct used to associate with @map
+ */
+#define hashmap_free_entries(map, type, member) \
+ hashmap_free_(map, offsetof(type, member));
/* hashmap_entry functions */
diff --git a/merge-recursive.c b/merge-recursive.c
index 73c7750..34b3d54 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -2633,7 +2633,7 @@
free(e->target_file);
string_list_clear(&e->source_files, 0);
}
- hashmap_free(&collisions, 1);
+ hashmap_free_entries(&collisions, struct collision_entry, ent);
return renames;
}
@@ -2853,7 +2853,7 @@
strbuf_release(&e->new_dir);
/* possible_new_dirs already cleared in get_directory_renames */
}
- hashmap_free(dir_renames, 1);
+ hashmap_free_entries(dir_renames, struct dir_rename_entry, ent);
free(dir_renames);
free(pairs->queue);
@@ -3482,7 +3482,8 @@
string_list_clear(entries, 1);
free(entries);
- hashmap_free(&opt->current_file_dir_set, 1);
+ hashmap_free_entries(&opt->current_file_dir_set,
+ struct path_hashmap_entry, e);
if (clean < 0) {
unpack_trees_finish(opt);
diff --git a/name-hash.c b/name-hash.c
index 85a1ce9..c86fe0f 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -728,6 +728,6 @@
return;
istate->name_hash_initialized = 0;
- hashmap_free(&istate->name_hash, 0);
- hashmap_free(&istate->dir_hash, 1);
+ hashmap_free(&istate->name_hash);
+ hashmap_free_entries(&istate->dir_hash, struct dir_entry, ent);
}
diff --git a/oidmap.c b/oidmap.c
index 4942599..423aa01 100644
--- a/oidmap.c
+++ b/oidmap.c
@@ -25,7 +25,9 @@
{
if (!map)
return;
- hashmap_free(&map->map, free_entries);
+
+ /* TODO: make oidmap itself not depend on struct layouts */
+ hashmap_free_(&map->map, free_entries ? 0 : -1);
}
void *oidmap_get(const struct oidmap *map, const struct object_id *key)
diff --git a/patch-ids.c b/patch-ids.c
index 75f8c9f..af17828 100644
--- a/patch-ids.c
+++ b/patch-ids.c
@@ -71,7 +71,7 @@
int free_patch_ids(struct patch_ids *ids)
{
- hashmap_free(&ids->patches, 1);
+ hashmap_free_entries(&ids->patches, struct patch_id, ent);
return 0;
}
diff --git a/range-diff.c b/range-diff.c
index e5e7820..9df5356 100644
--- a/range-diff.c
+++ b/range-diff.c
@@ -241,7 +241,7 @@
}
}
- hashmap_free(&map, 0);
+ hashmap_free(&map);
}
static void diffsize_consume(void *data, char *line, unsigned long len)
diff --git a/ref-filter.c b/ref-filter.c
index 4613df8..0950b78 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -2172,7 +2172,8 @@
used_atom_cnt = 0;
if (ref_to_worktree_map.worktrees) {
- hashmap_free(&(ref_to_worktree_map.map), 1);
+ hashmap_free_entries(&(ref_to_worktree_map.map),
+ struct ref_to_worktree_entry, ent);
free_worktrees(ref_to_worktree_map.worktrees);
ref_to_worktree_map.worktrees = NULL;
}
diff --git a/revision.c b/revision.c
index f28cbe5..8a5f866 100644
--- a/revision.c
+++ b/revision.c
@@ -136,7 +136,7 @@
free(entry->path);
}
- hashmap_free(map, 1);
+ hashmap_free_entries(map, struct path_and_oids_entry, ent);
}
static void paths_and_oids_insert(struct hashmap *map,
diff --git a/sequencer.c b/sequencer.c
index b3e7319..694b463 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -4772,7 +4772,7 @@
oidmap_free(&commit2todo, 1);
oidmap_free(&state.commit2label, 1);
- hashmap_free(&state.labels, 1);
+ hashmap_free_entries(&state.labels, struct labels_entry, entry);
strbuf_release(&state.buf);
return 0;
@@ -5301,7 +5301,7 @@
for (i = 0; i < todo_list->nr; i++)
free(subjects[i]);
free(subjects);
- hashmap_free(&subject2item, 1);
+ hashmap_free_entries(&subject2item, struct subject2item_entry, entry);
clear_commit_todo_item(&commit_todo);
diff --git a/submodule-config.c b/submodule-config.c
index a289d19..5462acc 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -103,8 +103,8 @@
struct submodule_entry, ent /* member name */)
free_one_config(entry);
- hashmap_free(&cache->for_path, 1);
- hashmap_free(&cache->for_name, 1);
+ hashmap_free_entries(&cache->for_path, struct submodule_entry, ent);
+ hashmap_free_entries(&cache->for_name, struct submodule_entry, ent);
cache->initialized = 0;
cache->gitmodules_read = 0;
}
diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c
index 07a93a2..6f2530d 100644
--- a/t/helper/test-hashmap.c
+++ b/t/helper/test-hashmap.c
@@ -109,7 +109,7 @@
hashmap_add(&map, &entries[i]->ent);
}
- hashmap_free(&map, 0);
+ hashmap_free(&map);
}
} else {
/* test map lookups */
@@ -129,7 +129,7 @@
}
}
- hashmap_free(&map, 0);
+ hashmap_free(&map);
}
}
@@ -266,6 +266,6 @@
}
strbuf_release(&line);
- hashmap_free(&map, 1);
+ hashmap_free_entries(&map, struct test_entry, ent);
return 0;
}