From d22245a2e360d2e708ca37169be8eb5a5899b98d Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:27 +0000 Subject: hashmap_entry_init takes "struct hashmap_entry *" C compilers do type checking to make life easier for us. So rely on that and update all hashmap_entry_init callers to take "struct hashmap_entry *" to avoid future bugs while improving safety and readability. Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- diffcore-rename.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'diffcore-rename.c') diff --git a/diffcore-rename.c b/diffcore-rename.c index 9624864858..44a3ab1e31 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -329,7 +329,7 @@ static void insert_file_table(struct repository *r, entry->index = index; entry->filespec = filespec; - hashmap_entry_init(entry, hash_filespec(r, filespec)); + hashmap_entry_init(&entry->entry, hash_filespec(r, filespec)); hashmap_add(table, entry); } -- cgit v1.3 From f6eb6bdcf2719defc3d38e0e2712fa3e18d29e91 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:28 +0000 Subject: hashmap_get_next takes "const struct hashmap_entry *" This is less error-prone than "const void *" as the compiler now detects invalid types being passed. Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- diff.c | 5 +++-- diffcore-rename.c | 2 +- hashmap.c | 5 +++-- hashmap.h | 3 ++- name-hash.c | 2 +- t/helper/test-hashmap.c | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) (limited to 'diffcore-rename.c') diff --git a/diff.c b/diff.c index 02491ee684..1168f0cbb9 100644 --- a/diff.c +++ b/diff.c @@ -1036,7 +1036,7 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o, int i; char *got_match = xcalloc(1, pmb_nr); - for (; match; match = hashmap_get_next(hm, match)) { + for (; match; match = hashmap_get_next(hm, &match->ent)) { for (i = 0; i < pmb_nr; i++) { struct moved_entry *prev = pmb[i].match; struct moved_entry *cur = (prev && prev->next_line) ? @@ -1189,7 +1189,8 @@ static void mark_color_as_moved(struct diff_options *o, * The current line is the start of a new block. * Setup the set of potential blocks. */ - for (; match; match = hashmap_get_next(hm, match)) { + for (; match; match = hashmap_get_next(hm, + &match->ent)) { ALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc); if (o->color_moved_ws_handling & COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) { diff --git a/diffcore-rename.c b/diffcore-rename.c index 44a3ab1e31..2a1449013b 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -285,7 +285,7 @@ static int find_identical_files(struct hashmap *srcs, p = hashmap_get_from_hash(srcs, hash_filespec(options->repo, target), NULL); - for (; p; p = hashmap_get_next(srcs, p)) { + for (; p; p = hashmap_get_next(srcs, &p->entry)) { int score; struct diff_filespec *source = p->filespec; diff --git a/hashmap.c b/hashmap.c index 6818c65174..c1de40eea0 100644 --- a/hashmap.c +++ b/hashmap.c @@ -191,9 +191,10 @@ void *hashmap_get(const struct hashmap *map, const void *key, const void *keydat return *find_entry_ptr(map, key, keydata); } -void *hashmap_get_next(const struct hashmap *map, const void *entry) +void *hashmap_get_next(const struct hashmap *map, + const struct hashmap_entry *entry) { - struct hashmap_entry *e = ((struct hashmap_entry *) entry)->next; + struct hashmap_entry *e = entry->next; for (; e; e = e->next) if (entry_equals(map, entry, e, NULL)) return e; diff --git a/hashmap.h b/hashmap.h index 54b0b8c698..93fb9599ca 100644 --- a/hashmap.h +++ b/hashmap.h @@ -318,7 +318,8 @@ static inline void *hashmap_get_from_hash(const struct hashmap *map, * `entry` is the hashmap_entry to start the search from, obtained via a previous * call to `hashmap_get` or `hashmap_get_next`. */ -void *hashmap_get_next(const struct hashmap *map, const void *entry); +void *hashmap_get_next(const struct hashmap *map, + const struct hashmap_entry *entry); /* * Adds a hashmap entry. This allows to add duplicate entries (i.e. diff --git a/name-hash.c b/name-hash.c index 1ce1417f7e..4d84326c58 100644 --- a/name-hash.c +++ b/name-hash.c @@ -710,7 +710,7 @@ struct cache_entry *index_file_exists(struct index_state *istate, const char *na while (ce) { if (same_name(ce, name, namelen, icase)) return ce; - ce = hashmap_get_next(&istate->name_hash, ce); + ce = hashmap_get_next(&istate->name_hash, &ce->ent); } return NULL; } diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index 0c9fd7c996..bf063a2521 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -203,7 +203,7 @@ int cmd__hashmap(int argc, const char **argv) puts("NULL"); while (entry) { puts(get_value(entry)); - entry = hashmap_get_next(&map, entry); + entry = hashmap_get_next(&map, &entry->ent); } } else if (!strcmp("remove", cmd) && p1) { -- cgit v1.3 From b94e5c1df674eb4ec8fdeaaae1ad8df552cb5d70 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:29 +0000 Subject: hashmap_add takes "struct hashmap_entry *" This is less error-prone than "void *" as the compiler now detects invalid types being passed. Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- attr.c | 2 +- blame.c | 2 +- builtin/describe.c | 2 +- builtin/difftool.c | 6 +++--- builtin/fetch.c | 2 +- config.c | 2 +- diff.c | 2 +- diffcore-rename.c | 2 +- hashmap.c | 6 +++--- hashmap.h | 4 ++-- merge-recursive.c | 4 ++-- name-hash.c | 8 ++++---- packfile.c | 2 +- patch-ids.c | 2 +- range-diff.c | 2 +- ref-filter.c | 2 +- sequencer.c | 2 +- sub-process.c | 2 +- submodule-config.c | 2 +- t/helper/test-hashmap.c | 6 +++--- 20 files changed, 31 insertions(+), 31 deletions(-) (limited to 'diffcore-rename.c') diff --git a/attr.c b/attr.c index a8be7a7b4f..fa26a3e3cb 100644 --- a/attr.c +++ b/attr.c @@ -122,7 +122,7 @@ static void attr_hashmap_add(struct attr_hashmap *map, e->keylen = keylen; e->value = value; - hashmap_add(&map->map, e); + hashmap_add(&map->map, &e->ent); } struct all_attrs_item { diff --git a/blame.c b/blame.c index 46059410cd..4d20aee435 100644 --- a/blame.c +++ b/blame.c @@ -424,7 +424,7 @@ static void get_fingerprint(struct fingerprint *result, found_entry->count += 1; } else { entry->count = 1; - hashmap_add(&result->map, entry); + hashmap_add(&result->map, &entry->entry); ++entry; } } diff --git a/builtin/describe.c b/builtin/describe.c index 596ddf89a5..f5e0a7e033 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -124,7 +124,7 @@ static void add_to_known_names(const char *path, e = xmalloc(sizeof(struct commit_name)); oidcpy(&e->peeled, peeled); hashmap_entry_init(&e->entry, oidhash(peeled)); - hashmap_add(&names, e); + hashmap_add(&names, &e->entry); e->path = NULL; } e->tag = tag; diff --git a/builtin/difftool.c b/builtin/difftool.c index 98ffc04c61..82c146718d 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -168,7 +168,7 @@ static void add_left_or_right(struct hashmap *map, const char *path, e = existing; } else { e->left[0] = e->right[0] = '\0'; - hashmap_add(map, e); + hashmap_add(map, &e->entry); } strlcpy(is_right ? e->right : e->left, content, PATH_MAX); } @@ -235,7 +235,7 @@ static void changed_files(struct hashmap *result, const char *index_path, struct path_entry *entry; FLEX_ALLOC_STR(entry, path, buf.buf); hashmap_entry_init(&entry->entry, strhash(buf.buf)); - hashmap_add(result, entry); + hashmap_add(result, &entry->entry); } fclose(fp); if (finish_command(&diff_files)) @@ -466,7 +466,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, free(entry); continue; } - hashmap_add(&working_tree_dups, entry); + hashmap_add(&working_tree_dups, &entry->entry); if (!use_wt_file(workdir, dst_path, &roid)) { if (checkout_path(rmode, &roid, dst_path, diff --git a/builtin/fetch.c b/builtin/fetch.c index b7d70eee70..909dbde909 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -278,7 +278,7 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map, FLEX_ALLOC_MEM(ent, refname, refname, len); hashmap_entry_init(&ent->ent, strhash(refname)); oidcpy(&ent->oid, oid); - hashmap_add(map, ent); + hashmap_add(map, &ent->ent); return ent; } diff --git a/config.c b/config.c index 08d866e7de..2243d7c3d6 100644 --- a/config.c +++ b/config.c @@ -1885,7 +1885,7 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha hashmap_entry_init(&e->ent, strhash(key)); e->key = xstrdup(key); string_list_init(&e->value_list, 1); - hashmap_add(&cs->config_hash, e); + hashmap_add(&cs->config_hash, &e->ent); } si = string_list_append_nodup(&e->value_list, xstrdup_or_null(value)); diff --git a/diff.c b/diff.c index 1168f0cbb9..cc7f06d10d 100644 --- a/diff.c +++ b/diff.c @@ -1003,7 +1003,7 @@ static void add_lines_to_move_detection(struct diff_options *o, if (prev_line && prev_line->es->s == o->emitted_symbols->buf[n].s) prev_line->next_line = key; - hashmap_add(hm, key); + hashmap_add(hm, &key->ent); prev_line = key; } } diff --git a/diffcore-rename.c b/diffcore-rename.c index 2a1449013b..4670a40179 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -330,7 +330,7 @@ static void insert_file_table(struct repository *r, entry->filespec = filespec; hashmap_entry_init(&entry->entry, hash_filespec(r, filespec)); - hashmap_add(table, entry); + hashmap_add(table, &entry->entry); } /* diff --git a/hashmap.c b/hashmap.c index c1de40eea0..9c2db3e0c8 100644 --- a/hashmap.c +++ b/hashmap.c @@ -201,12 +201,12 @@ void *hashmap_get_next(const struct hashmap *map, return NULL; } -void hashmap_add(struct hashmap *map, void *entry) +void hashmap_add(struct hashmap *map, struct hashmap_entry *entry) { unsigned int b = bucket(map, entry); /* add entry */ - ((struct hashmap_entry *) entry)->next = map->table[b]; + entry->next = map->table[b]; map->table[b] = entry; /* fix size and rehash if appropriate */ @@ -302,7 +302,7 @@ const void *memintern(const void *data, size_t len) FLEX_ALLOC_MEM(e, data, data, len); hashmap_entry_init(&e->ent, key.ent.hash); e->len = len; - hashmap_add(&map, e); + hashmap_add(&map, &e->ent); } return e->data; } diff --git a/hashmap.h b/hashmap.h index 93fb9599ca..47ee5c00d7 100644 --- a/hashmap.h +++ b/hashmap.h @@ -50,7 +50,7 @@ * FLEX_ALLOC_STR(e, value, value); * hashmap_entry_init(&e->ent, memhash(&key, sizeof(long))); * e->key = key; - * hashmap_add(&map, e); + * hashmap_add(&map, &e->ent); * } * * if (!strcmp("print_all_by_key", action)) { @@ -328,7 +328,7 @@ void *hashmap_get_next(const struct hashmap *map, * `map` is the hashmap structure. * `entry` is the entry to add. */ -void hashmap_add(struct hashmap *map, void *entry); +void hashmap_add(struct hashmap *map, struct hashmap_entry *entry); /* * Adds or replaces a hashmap entry. If the hashmap contains duplicate diff --git a/merge-recursive.c b/merge-recursive.c index 6bc4f14ff4..db9b247ece 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -455,7 +455,7 @@ static int save_files_dirs(const struct object_id *oid, FLEX_ALLOC_MEM(entry, path, base->buf, base->len); hashmap_entry_init(&entry->e, path_hash(entry->path)); - hashmap_add(&opt->current_file_dir_set, entry); + hashmap_add(&opt->current_file_dir_set, &entry->e); strbuf_setlen(base, baselen); return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0); @@ -732,7 +732,7 @@ static char *unique_path(struct merge_options *opt, const char *path, const char FLEX_ALLOC_MEM(entry, path, newpath.buf, newpath.len); hashmap_entry_init(&entry->e, path_hash(entry->path)); - hashmap_add(&opt->current_file_dir_set, entry); + hashmap_add(&opt->current_file_dir_set, &entry->e); return strbuf_detach(&newpath, NULL); } diff --git a/name-hash.c b/name-hash.c index 4d84326c58..faec682bc7 100644 --- a/name-hash.c +++ b/name-hash.c @@ -70,7 +70,7 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate, FLEX_ALLOC_MEM(dir, name, ce->name, namelen); hashmap_entry_init(&dir->ent, memihash(ce->name, namelen)); dir->namelen = namelen; - hashmap_add(&istate->dir_hash, dir); + hashmap_add(&istate->dir_hash, &dir->ent); /* recursively add missing parent directories */ dir->parent = hash_dir_entry(istate, ce, namelen); @@ -107,7 +107,7 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce) return; ce->ce_flags |= CE_HASHED; hashmap_entry_init(&ce->ent, memihash(ce->name, ce_namelen(ce))); - hashmap_add(&istate->name_hash, ce); + hashmap_add(&istate->name_hash, &ce->ent); if (ignore_case) add_dir_entry(istate, ce); @@ -283,7 +283,7 @@ static struct dir_entry *hash_dir_entry_with_parent_and_prefix( hashmap_entry_init(&dir->ent, hash); dir->namelen = prefix->len; dir->parent = parent; - hashmap_add(&istate->dir_hash, dir); + hashmap_add(&istate->dir_hash, &dir->ent); if (parent) { unlock_dir_mutex(lock_nr); @@ -473,7 +473,7 @@ static void *lazy_name_thread_proc(void *_data) struct cache_entry *ce_k = d->istate->cache[k]; ce_k->ce_flags |= CE_HASHED; hashmap_entry_init(&ce_k->ent, d->lazy_entries[k].hash_name); - hashmap_add(&d->istate->name_hash, ce_k); + hashmap_add(&d->istate->name_hash, &ce_k->ent); } return NULL; diff --git a/packfile.c b/packfile.c index 96535eb86b..f7402c470b 100644 --- a/packfile.c +++ b/packfile.c @@ -1488,7 +1488,7 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset, if (!delta_base_cache.cmpfn) hashmap_init(&delta_base_cache, delta_base_cache_hash_cmp, NULL, 0); hashmap_entry_init(&ent->ent, pack_entry_hash(p, base_offset)); - hashmap_add(&delta_base_cache, ent); + hashmap_add(&delta_base_cache, &ent->ent); } int packed_object_info(struct repository *r, struct packed_git *p, diff --git a/patch-ids.c b/patch-ids.c index a2da711678..f87b62bf58 100644 --- a/patch-ids.c +++ b/patch-ids.c @@ -116,6 +116,6 @@ struct patch_id *add_commit_patch_id(struct commit *commit, return NULL; } - hashmap_add(&ids->patches, key); + hashmap_add(&ids->patches, &key->ent); return key; } diff --git a/range-diff.c b/range-diff.c index 32b29f9594..96f955d84d 100644 --- a/range-diff.c +++ b/range-diff.c @@ -218,7 +218,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b) util->patch = a->items[i].string; util->diff = util->patch + util->diff_offset; hashmap_entry_init(&util->e, strhash(util->diff)); - hashmap_add(&map, util); + hashmap_add(&map, &util->e); } /* Now try to find exact matches in b */ diff --git a/ref-filter.c b/ref-filter.c index 206014c93d..d939ebc6bb 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -1568,7 +1568,7 @@ static void populate_worktree_map(struct hashmap *map, struct worktree **worktre hashmap_entry_init(&entry->ent, strhash(worktrees[i]->head_ref)); - hashmap_add(map, entry); + hashmap_add(map, &entry->ent); } } } diff --git a/sequencer.c b/sequencer.c index 1140cdf526..ee11cda7e7 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4539,7 +4539,7 @@ static const char *label_oid(struct object_id *oid, const char *label, FLEX_ALLOC_STR(labels_entry, label, label); hashmap_entry_init(&labels_entry->entry, strihash(label)); - hashmap_add(&state->labels, labels_entry); + hashmap_add(&state->labels, &labels_entry->entry); FLEX_ALLOC_STR(string_entry, string, label); oidcpy(&string_entry->entry.oid, oid); diff --git a/sub-process.c b/sub-process.c index 9847dad6fc..d58e069855 100644 --- a/sub-process.c +++ b/sub-process.c @@ -105,7 +105,7 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co return err; } - hashmap_add(hashmap, entry); + hashmap_add(hashmap, &entry->ent); return 0; } diff --git a/submodule-config.c b/submodule-config.c index 4aa02e280e..a3bbd9fd6f 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -149,7 +149,7 @@ static void cache_add(struct submodule_cache *cache, struct submodule_entry *e = xmalloc(sizeof(*e)); hashmap_entry_init(&e->ent, hash); e->config = submodule; - hashmap_add(&cache->for_name, e); + hashmap_add(&cache->for_name, &e->ent); } static const struct submodule *cache_lookup_path(struct submodule_cache *cache, diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index bf063a2521..49e715f1cd 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -104,7 +104,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) /* add entries */ for (i = 0; i < TEST_SIZE; i++) { hashmap_entry_init(&entries[i]->ent, hashes[i]); - hashmap_add(&map, entries[i]); + hashmap_add(&map, &entries[i]->ent); } hashmap_free(&map, 0); @@ -117,7 +117,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) j = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE; for (i = 0; i < j; i++) { hashmap_entry_init(&entries[i]->ent, hashes[i]); - hashmap_add(&map, entries[i]); + hashmap_add(&map, &entries[i]->ent); } for (j = 0; j < rounds; j++) { @@ -179,7 +179,7 @@ int cmd__hashmap(int argc, const char **argv) entry = alloc_test_entry(hash, p1, p2); /* add to hashmap */ - hashmap_add(&map, entry); + hashmap_add(&map, &entry->ent); } else if (!strcmp("put", cmd) && p1 && p2) { -- cgit v1.3 From 6bcbdfb277bdc81b5ad6996b3fb005382a35c2ee Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:34 +0000 Subject: hashmap_get_next returns "struct hashmap_entry *" This is a step towards removing the requirement for hashmap_entry being the first field of a struct. Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- diff.c | 19 ++++++++++++------- diffcore-rename.c | 11 +++++++---- hashmap.c | 2 +- hashmap.h | 12 ++++++++---- name-hash.c | 8 +++++--- t/helper/test-hashmap.c | 10 ++++++---- 6 files changed, 39 insertions(+), 23 deletions(-) (limited to 'diffcore-rename.c') diff --git a/diff.c b/diff.c index 72d3c6aa19..0978814086 100644 --- a/diff.c +++ b/diff.c @@ -1035,8 +1035,10 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o, { int i; char *got_match = xcalloc(1, pmb_nr); + struct hashmap_entry *ent; - for (; match; match = hashmap_get_next(hm, &match->ent)) { + for (ent = &match->ent; ent; ent = hashmap_get_next(hm, ent)) { + match = container_of(ent, struct moved_entry, ent); for (i = 0; i < pmb_nr; i++) { struct moved_entry *prev = pmb[i].match; struct moved_entry *cur = (prev && prev->next_line) ? @@ -1135,8 +1137,9 @@ static void mark_color_as_moved(struct diff_options *o, for (n = 0; n < o->emitted_symbols->nr; n++) { struct hashmap *hm = NULL; + struct hashmap_entry *ent = NULL; struct moved_entry *key; - struct moved_entry *match = NULL; + struct moved_entry *match; struct emitted_diff_symbol *l = &o->emitted_symbols->buf[n]; enum diff_symbol last_symbol = 0; @@ -1144,20 +1147,20 @@ static void mark_color_as_moved(struct diff_options *o, case DIFF_SYMBOL_PLUS: hm = del_lines; key = prepare_entry(o, n); - match = hashmap_get(hm, &key->ent, NULL); + ent = hashmap_get(hm, &key->ent, NULL); free(key); break; case DIFF_SYMBOL_MINUS: hm = add_lines; key = prepare_entry(o, n); - match = hashmap_get(hm, &key->ent, NULL); + ent = hashmap_get(hm, &key->ent, NULL); free(key); break; default: flipped_block = 0; } - if (!match) { + if (!ent) { int i; adjust_last_block(o, n, block_length); @@ -1169,6 +1172,7 @@ static void mark_color_as_moved(struct diff_options *o, last_symbol = l->s; continue; } + match = container_of(ent, struct moved_entry, ent); if (o->color_moved == COLOR_MOVED_PLAIN) { last_symbol = l->s; @@ -1189,8 +1193,9 @@ static void mark_color_as_moved(struct diff_options *o, * The current line is the start of a new block. * Setup the set of potential blocks. */ - for (; match; match = hashmap_get_next(hm, - &match->ent)) { + for (; ent; ent = hashmap_get_next(hm, ent)) { + match = container_of(ent, struct moved_entry, + ent); ALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc); if (o->color_moved_ws_handling & COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) { diff --git a/diffcore-rename.c b/diffcore-rename.c index 4670a40179..71aa240a68 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -274,7 +274,7 @@ static int find_identical_files(struct hashmap *srcs, struct diff_options *options) { int renames = 0; - + struct hashmap_entry *ent; struct diff_filespec *target = rename_dst[dst_index].two; struct file_similarity *p, *best = NULL; int i = 100, best_score = -1; @@ -282,12 +282,15 @@ static int find_identical_files(struct hashmap *srcs, /* * Find the best source match for specified destination. */ - p = hashmap_get_from_hash(srcs, + ent = hashmap_get_from_hash(srcs, hash_filespec(options->repo, target), NULL); - for (; p; p = hashmap_get_next(srcs, &p->entry)) { + for (; ent; ent = hashmap_get_next(srcs, ent)) { int score; - struct diff_filespec *source = p->filespec; + struct diff_filespec *source; + + p = container_of(ent, struct file_similarity, entry); + source = p->filespec; /* False hash collision? */ if (!oideq(&source->oid, &target->oid)) diff --git a/hashmap.c b/hashmap.c index 9b83e73d03..22bc7c5b3b 100644 --- a/hashmap.c +++ b/hashmap.c @@ -192,7 +192,7 @@ void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key, return *find_entry_ptr(map, key, keydata); } -void *hashmap_get_next(const struct hashmap *map, +struct hashmap_entry *hashmap_get_next(const struct hashmap *map, const struct hashmap_entry *entry) { struct hashmap_entry *e = entry->next; diff --git a/hashmap.h b/hashmap.h index d122c75d0f..21bc8aff2b 100644 --- a/hashmap.h +++ b/hashmap.h @@ -55,15 +55,19 @@ * * if (!strcmp("print_all_by_key", action)) { * struct long2string k, *e; + * struct hashmap_entry *ent; * hashmap_entry_init(&k->ent, memhash(&key, sizeof(long))); * k.key = key; * * flags &= ~COMPARE_VALUE; - * e = hashmap_get(&map, &k, NULL); - * if (e) { + * ent = hashmap_get(&map, &k, NULL); + * if (ent) { + * e = container_of(ent, struct long2string, ent); * printf("first: %ld %s\n", e->key, e->value); - * while ((e = hashmap_get_next(&map, e))) + * while ((ent = hashmap_get_next(&map, ent))) { + * e = container_of(ent, struct long2string, ent); * printf("found more: %ld %s\n", e->key, e->value); + * } * } * } * @@ -320,7 +324,7 @@ static inline void *hashmap_get_from_hash(const struct hashmap *map, * `entry` is the hashmap_entry to start the search from, obtained via a previous * call to `hashmap_get` or `hashmap_get_next`. */ -void *hashmap_get_next(const struct hashmap *map, +struct hashmap_entry *hashmap_get_next(const struct hashmap *map, const struct hashmap_entry *entry); /* diff --git a/name-hash.c b/name-hash.c index 44d788f1ce..dbacb34f50 100644 --- a/name-hash.c +++ b/name-hash.c @@ -702,15 +702,17 @@ void adjust_dirname_case(struct index_state *istate, char *name) struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase) { struct cache_entry *ce; + struct hashmap_entry *ent; lazy_init_name_hash(istate); - ce = hashmap_get_from_hash(&istate->name_hash, + ent = hashmap_get_from_hash(&istate->name_hash, memihash(name, namelen), NULL); - while (ce) { + while (ent) { + ce = container_of(ent, struct cache_entry, ent); if (same_name(ce, name, namelen, icase)) return ce; - ce = hashmap_get_next(&istate->name_hash, &ce->ent); + ent = hashmap_get_next(&istate->name_hash, ent); } return NULL; } diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index de2bd083b9..d85b8dc58e 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -194,16 +194,18 @@ int cmd__hashmap(int argc, const char **argv) free(entry); } else if (!strcmp("get", cmd) && p1) { + struct hashmap_entry *e; /* lookup entry in hashmap */ - entry = hashmap_get_from_hash(&map, hash, p1); + e = hashmap_get_from_hash(&map, hash, p1); /* print result */ - if (!entry) + if (!e) puts("NULL"); - while (entry) { + while (e) { + entry = container_of(e, struct test_entry, ent); puts(get_value(entry)); - entry = hashmap_get_next(&map, &entry->ent); + e = hashmap_get_next(&map, e); } } else if (!strcmp("remove", cmd) && p1) { -- cgit v1.3 From f0e63c41139f8982add435536d39aff6f3d4ca98 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:35 +0000 Subject: hashmap: use *_entry APIs to wrap container_of Using `container_of' can be verbose and choosing names for intermediate "struct hashmap_entry" pointers is a hard problem. So introduce "*_entry" APIs inspired by similar linked-list APIs in the Linux kernel. Unfortunately, `__typeof__' is not portable C, so we need an extra parameter to specify the type. Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- diff.c | 21 +++++++++------------ diffcore-rename.c | 14 +++++--------- git-compat-util.h | 15 +++++++++++++++ hashmap.h | 40 ++++++++++++++++++++++++++++++++++------ name-hash.c | 11 +++++------ t/helper/test-hashmap.c | 12 +++++------- 6 files changed, 73 insertions(+), 40 deletions(-) (limited to 'diffcore-rename.c') diff --git a/diff.c b/diff.c index 0978814086..66cdf4e9ca 100644 --- a/diff.c +++ b/diff.c @@ -1035,10 +1035,8 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o, { int i; char *got_match = xcalloc(1, pmb_nr); - struct hashmap_entry *ent; - for (ent = &match->ent; ent; ent = hashmap_get_next(hm, ent)) { - match = container_of(ent, struct moved_entry, ent); + hashmap_for_each_entry_from(hm, match, struct moved_entry, ent) { for (i = 0; i < pmb_nr; i++) { struct moved_entry *prev = pmb[i].match; struct moved_entry *cur = (prev && prev->next_line) ? @@ -1137,9 +1135,8 @@ static void mark_color_as_moved(struct diff_options *o, for (n = 0; n < o->emitted_symbols->nr; n++) { struct hashmap *hm = NULL; - struct hashmap_entry *ent = NULL; struct moved_entry *key; - struct moved_entry *match; + struct moved_entry *match = NULL; struct emitted_diff_symbol *l = &o->emitted_symbols->buf[n]; enum diff_symbol last_symbol = 0; @@ -1147,20 +1144,22 @@ static void mark_color_as_moved(struct diff_options *o, case DIFF_SYMBOL_PLUS: hm = del_lines; key = prepare_entry(o, n); - ent = hashmap_get(hm, &key->ent, NULL); + match = hashmap_get_entry(hm, key, NULL, + struct moved_entry, ent); free(key); break; case DIFF_SYMBOL_MINUS: hm = add_lines; key = prepare_entry(o, n); - ent = hashmap_get(hm, &key->ent, NULL); + match = hashmap_get_entry(hm, key, NULL, + struct moved_entry, ent); free(key); break; default: flipped_block = 0; } - if (!ent) { + if (!match) { int i; adjust_last_block(o, n, block_length); @@ -1172,7 +1171,6 @@ static void mark_color_as_moved(struct diff_options *o, last_symbol = l->s; continue; } - match = container_of(ent, struct moved_entry, ent); if (o->color_moved == COLOR_MOVED_PLAIN) { last_symbol = l->s; @@ -1193,9 +1191,8 @@ static void mark_color_as_moved(struct diff_options *o, * The current line is the start of a new block. * Setup the set of potential blocks. */ - for (; ent; ent = hashmap_get_next(hm, ent)) { - match = container_of(ent, struct moved_entry, - ent); + hashmap_for_each_entry_from(hm, match, + struct moved_entry, ent) { ALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc); if (o->color_moved_ws_handling & COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) { diff --git a/diffcore-rename.c b/diffcore-rename.c index 71aa240a68..611b08f463 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -274,23 +274,19 @@ static int find_identical_files(struct hashmap *srcs, struct diff_options *options) { int renames = 0; - struct hashmap_entry *ent; struct diff_filespec *target = rename_dst[dst_index].two; struct file_similarity *p, *best = NULL; int i = 100, best_score = -1; + unsigned int hash = hash_filespec(options->repo, target); /* * Find the best source match for specified destination. */ - ent = hashmap_get_from_hash(srcs, - hash_filespec(options->repo, target), - NULL); - for (; ent; ent = hashmap_get_next(srcs, ent)) { + p = hashmap_get_entry_from_hash(srcs, hash, NULL, + struct file_similarity, entry); + hashmap_for_each_entry_from(srcs, p, struct file_similarity, entry) { int score; - struct diff_filespec *source; - - p = container_of(ent, struct file_similarity, entry); - source = p->filespec; + struct diff_filespec *source = p->filespec; /* False hash collision? */ if (!oideq(&source->oid, &target->oid)) diff --git a/git-compat-util.h b/git-compat-util.h index 4cc2c8283a..4a23b9090b 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -1322,4 +1322,19 @@ void unleak_memory(const void *ptr, size_t len); #define container_of(ptr, type, member) \ ((type *) ((char *)(ptr) - offsetof(type, member))) +/* + * helper function for `container_of_or_null' to avoid multiple + * evaluation of @ptr + */ +static inline void *container_of_or_null_offset(void *ptr, size_t offset) +{ + return ptr ? (char *)ptr - offset : NULL; +} + +/* + * like `container_of', but allows returned value to be NULL + */ +#define container_of_or_null(ptr, type, member) \ + (type *)container_of_or_null_offset(ptr, offsetof(type, member)) + #endif diff --git a/hashmap.h b/hashmap.h index 21bc8aff2b..cd42dcc15c 100644 --- a/hashmap.h +++ b/hashmap.h @@ -55,17 +55,15 @@ * * if (!strcmp("print_all_by_key", action)) { * struct long2string k, *e; - * struct hashmap_entry *ent; * hashmap_entry_init(&k->ent, memhash(&key, sizeof(long))); * k.key = key; * * flags &= ~COMPARE_VALUE; - * ent = hashmap_get(&map, &k, NULL); - * if (ent) { - * e = container_of(ent, struct long2string, ent); + * e = hashmap_get_entry(&map, &k, NULL, struct long2string, ent); + * if (e) { * printf("first: %ld %s\n", e->key, e->value); - * while ((ent = hashmap_get_next(&map, ent))) { - * e = container_of(ent, struct long2string, ent); + * while ((e = hashmap_get_next_entry(&map, e, + * struct long2string, ent))) { * printf("found more: %ld %s\n", e->key, e->value); * } * } @@ -387,6 +385,36 @@ static inline void *hashmap_iter_first(struct hashmap *map, return hashmap_iter_next(iter); } +/* + * returns a @pointer of @type matching @keyvar, or NULL if nothing found. + * @keyvar is a pointer of @type + * @member is the name of the "struct hashmap_entry" field in @type + */ +#define hashmap_get_entry(map, keyvar, keydata, type, member) \ + container_of_or_null(hashmap_get(map, &(keyvar)->member, keydata), \ + type, member) + +#define hashmap_get_entry_from_hash(map, hash, keydata, type, member) \ + container_of_or_null(hashmap_get_from_hash(map, hash, keydata), \ + type, member) +/* + * returns the next equal @type pointer to @var, or NULL if not found. + * @var is a pointer of @type + * @member is the name of the "struct hashmap_entry" field in @type + */ +#define hashmap_get_next_entry(map, var, type, member) \ + container_of_or_null(hashmap_get_next(map, &(var)->member), \ + type, member) + +/* + * iterate @map starting from @var, where @var is a pointer of @type + * and @member is the name of the "struct hashmap_entry" field in @type + */ +#define hashmap_for_each_entry_from(map, var, type, member) \ + for (; \ + var; \ + var = hashmap_get_next_entry(map, var, type, member)) + /* * Disable item counting and automatic rehashing when adding/removing items. * diff --git a/name-hash.c b/name-hash.c index dbacb34f50..73b83adf3d 100644 --- a/name-hash.c +++ b/name-hash.c @@ -702,17 +702,16 @@ void adjust_dirname_case(struct index_state *istate, char *name) struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase) { struct cache_entry *ce; - struct hashmap_entry *ent; + unsigned int hash = memihash(name, namelen); lazy_init_name_hash(istate); - ent = hashmap_get_from_hash(&istate->name_hash, - memihash(name, namelen), NULL); - while (ent) { - ce = container_of(ent, struct cache_entry, ent); + ce = hashmap_get_entry_from_hash(&istate->name_hash, hash, NULL, + struct cache_entry, ent); + hashmap_for_each_entry_from(&istate->name_hash, ce, + struct cache_entry, ent) { if (same_name(ce, name, namelen, icase)) return ce; - ent = hashmap_get_next(&istate->name_hash, ent); } return NULL; } diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index d85b8dc58e..e82cbfdee2 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -194,18 +194,16 @@ int cmd__hashmap(int argc, const char **argv) free(entry); } else if (!strcmp("get", cmd) && p1) { - struct hashmap_entry *e; - /* lookup entry in hashmap */ - e = hashmap_get_from_hash(&map, hash, p1); + entry = hashmap_get_entry_from_hash(&map, hash, p1, + struct test_entry, ent); /* print result */ - if (!e) + if (!entry) puts("NULL"); - while (e) { - entry = container_of(e, struct test_entry, ent); + hashmap_for_each_entry_from(&map, entry, + struct test_entry, ent) { puts(get_value(entry)); - e = hashmap_get_next(&map, e); } } else if (!strcmp("remove", cmd) && p1) { -- cgit v1.3 From c8e424c9c94d97b18cd335be17f32a8ce94a5b7f Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:40 +0000 Subject: 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 Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- blame.c | 2 +- builtin/fetch.c | 6 +++--- config.c | 2 +- diff.c | 6 ++++-- diffcore-rename.c | 2 +- hashmap.c | 11 ++++++++--- hashmap.h | 19 +++++++++++++------ merge-recursive.c | 7 ++++--- name-hash.c | 4 ++-- oidmap.c | 4 +++- patch-ids.c | 2 +- range-diff.c | 2 +- ref-filter.c | 3 ++- revision.c | 2 +- sequencer.c | 4 ++-- submodule-config.c | 4 ++-- t/helper/test-hashmap.c | 6 +++--- 17 files changed, 52 insertions(+), 34 deletions(-) (limited to 'diffcore-rename.c') diff --git a/blame.c b/blame.c index 3d8accf902..f33af0da9f 100644 --- a/blame.c +++ b/blame.c @@ -433,7 +433,7 @@ static void get_fingerprint(struct fingerprint *result, 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 476c2416e3..09f7170616 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -366,7 +366,7 @@ static void find_non_local_tags(const struct ref *refs, 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 @@ static void find_non_local_tags(const struct ref *refs, **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 @@ static struct ref *get_ref_map(struct remote *remote, } } } - 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 8433f74371..4d05dbc15a 100644 --- a/config.c +++ b/config.c @@ -1948,7 +1948,7 @@ void git_configset_clear(struct config_set *cs) 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 5eaf689fcc..f94d9f96af 100644 --- a/diff.c +++ b/diff.c @@ -6236,8 +6236,10 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o) 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 611b08f463..994609ed58 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -358,7 +358,7 @@ static int find_exact_renames(struct diff_options *options) 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 1b60f97cf2..65b447f6cd 100644 --- a/hashmap.c +++ b/hashmap.c @@ -171,16 +171,21 @@ void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function, 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 bc3b10e097..171d6ddb76 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 @@ void hashmap_init(struct hashmap *map, 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 + */ +#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 */ -void hashmap_free(struct hashmap *map, int free_entries); +#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 73c7750448..34b3d54154 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -2633,7 +2633,7 @@ static struct string_list *get_renames(struct merge_options *opt, 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 @@ static void initial_cleanup_rename(struct diff_queue_struct *pairs, 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 @@ int merge_trees(struct merge_options *opt, 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 85a1ce982c..c86fe0f1df 100644 --- a/name-hash.c +++ b/name-hash.c @@ -728,6 +728,6 @@ void free_name_hash(struct index_state *istate) 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 4942599391..423aa014a3 100644 --- a/oidmap.c +++ b/oidmap.c @@ -25,7 +25,9 @@ void oidmap_free(struct oidmap *map, int free_entries) { 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 75f8c9f1a1..af17828e33 100644 --- a/patch-ids.c +++ b/patch-ids.c @@ -71,7 +71,7 @@ int init_patch_ids(struct repository *r, struct patch_ids *ids) 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 e5e7820bfe..9df53569bb 100644 --- a/range-diff.c +++ b/range-diff.c @@ -241,7 +241,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b) } } - 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 4613df8826..0950b789e3 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -2172,7 +2172,8 @@ void ref_array_clear(struct ref_array *array) 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 f28cbe5de8..8a5f866ae6 100644 --- a/revision.c +++ b/revision.c @@ -136,7 +136,7 @@ static void paths_and_oids_clear(struct hashmap *map) 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 b3e7319b55..694b463518 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4772,7 +4772,7 @@ static int make_script_with_merges(struct pretty_print_context *pp, 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 @@ int todo_list_rearrange_squash(struct todo_list *todo_list) 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 a289d195f6..5462acc8ec 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -103,8 +103,8 @@ static void submodule_cache_clear(struct submodule_cache *cache) 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 07a93a2aec..6f2530dcc8 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -109,7 +109,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) hashmap_add(&map, &entries[i]->ent); } - hashmap_free(&map, 0); + hashmap_free(&map); } } else { /* test map lookups */ @@ -129,7 +129,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) } } - hashmap_free(&map, 0); + hashmap_free(&map); } } @@ -266,6 +266,6 @@ int cmd__hashmap(int argc, const char **argv) } strbuf_release(&line); - hashmap_free(&map, 1); + hashmap_free_entries(&map, struct test_entry, ent); return 0; } -- cgit v1.3 From 23dee69f53cf5024ca79e0b707dcb03c63f33bef Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:41 +0000 Subject: OFFSETOF_VAR macro to simplify hashmap iterators While we cannot rely on a `__typeof__' operator being portable to use with `offsetof'; we can calculate the pointer offset using an existing pointer and the address of a member using pointer arithmetic for compilers without `__typeof__'. This allows us to simplify usage of hashmap iterator macros by not having to specify a type when a pointer of that type is already given. In the future, list iterator macros (e.g. list_for_each_entry) may also be implemented using OFFSETOF_VAR to save hackers the trouble of using container_of/list_entry macros and without relying on non-portable `__typeof__'. v3: use `__typeof__' to avoid clang warnings Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- attr.c | 1 - blame.c | 2 -- builtin/describe.c | 2 +- builtin/difftool.c | 4 ++-- config.c | 1 - diff.c | 5 ++--- diffcore-rename.c | 2 +- git-compat-util.h | 13 +++++++++++ hashmap.h | 44 +++++++++++++++++++++++++------------ merge-recursive.c | 5 ----- name-hash.c | 3 +-- revision.c | 8 ++----- submodule-config.c | 2 +- t/helper/test-hashmap.c | 5 +---- t/helper/test-lazy-init-name-hash.c | 4 ++-- 15 files changed, 56 insertions(+), 45 deletions(-) (limited to 'diffcore-rename.c') diff --git a/attr.c b/attr.c index ca8be46e8e..9849106627 100644 --- a/attr.c +++ b/attr.c @@ -168,7 +168,6 @@ static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check) check->all_attrs_nr = size; hashmap_for_each_entry(&map->map, &iter, e, - struct attr_hash_entry, ent /* member name */) { const struct git_attr *a = e->value; check->all_attrs[a->attr_nr].attr = a; diff --git a/blame.c b/blame.c index f33af0da9f..90b247abf9 100644 --- a/blame.c +++ b/blame.c @@ -451,7 +451,6 @@ static int fingerprint_similarity(struct fingerprint *a, struct fingerprint *b) const struct fingerprint_entry *entry_a, *entry_b; hashmap_for_each_entry(&b->map, &iter, entry_b, - const struct fingerprint_entry, entry /* member name */) { entry_a = hashmap_get_entry(&a->map, entry_b, NULL, struct fingerprint_entry, entry); @@ -474,7 +473,6 @@ static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b) hashmap_iter_init(&b->map, &iter); hashmap_for_each_entry(&b->map, &iter, entry_b, - const struct fingerprint_entry, entry /* member name */) { entry_a = hashmap_get_entry(&a->map, entry_b, NULL, struct fingerprint_entry, entry); diff --git a/builtin/describe.c b/builtin/describe.c index 8cf2cd992d..1caf98f716 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -333,7 +333,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst) struct commit_name *n; init_commit_names(&commit_names); - hashmap_for_each_entry(&names, &iter, n, struct commit_name, + hashmap_for_each_entry(&names, &iter, n, entry /* member name */) { c = lookup_commit_reference_gently(the_repository, &n->peeled, 1); diff --git a/builtin/difftool.c b/builtin/difftool.c index dd94179b68..f2d4d1e0f8 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -539,7 +539,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, * change in the recorded SHA1 for the submodule. */ hashmap_for_each_entry(&submodules, &iter, entry, - struct pair_entry, entry /* member name */) { + entry /* member name */) { if (*entry->left) { add_path(&ldir, ldir_len, entry->path); ensure_leading_directories(ldir.buf); @@ -558,7 +558,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, * This loop replicates that behavior. */ hashmap_for_each_entry(&symlinks2, &iter, entry, - struct pair_entry, entry /* member name */) { + entry /* member name */) { if (*entry->left) { add_path(&ldir, ldir_len, entry->path); ensure_leading_directories(ldir.buf); diff --git a/config.c b/config.c index 4d05dbc15a..77ed00bfbf 100644 --- a/config.c +++ b/config.c @@ -1943,7 +1943,6 @@ void git_configset_clear(struct config_set *cs) return; hashmap_for_each_entry(&cs->config_hash, &iter, entry, - struct config_set_element, ent /* member name */) { free(entry->key); string_list_clear(&entry->value_list, 1); diff --git a/diff.c b/diff.c index f94d9f96af..051de9832d 100644 --- a/diff.c +++ b/diff.c @@ -1038,7 +1038,7 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o, int i; char *got_match = xcalloc(1, pmb_nr); - hashmap_for_each_entry_from(hm, match, struct moved_entry, ent) { + hashmap_for_each_entry_from(hm, match, ent) { for (i = 0; i < pmb_nr; i++) { struct moved_entry *prev = pmb[i].match; struct moved_entry *cur = (prev && prev->next_line) ? @@ -1193,8 +1193,7 @@ static void mark_color_as_moved(struct diff_options *o, * The current line is the start of a new block. * Setup the set of potential blocks. */ - hashmap_for_each_entry_from(hm, match, - struct moved_entry, ent) { + hashmap_for_each_entry_from(hm, match, ent) { ALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc); if (o->color_moved_ws_handling & COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) { diff --git a/diffcore-rename.c b/diffcore-rename.c index 994609ed58..9ad4dc395a 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -284,7 +284,7 @@ static int find_identical_files(struct hashmap *srcs, */ p = hashmap_get_entry_from_hash(srcs, hash, NULL, struct file_similarity, entry); - hashmap_for_each_entry_from(srcs, p, struct file_similarity, entry) { + hashmap_for_each_entry_from(srcs, p, entry) { int score; struct diff_filespec *source = p->filespec; diff --git a/git-compat-util.h b/git-compat-util.h index 4a23b9090b..8605cb4202 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -1337,4 +1337,17 @@ static inline void *container_of_or_null_offset(void *ptr, size_t offset) #define container_of_or_null(ptr, type, member) \ (type *)container_of_or_null_offset(ptr, offsetof(type, member)) +/* + * like offsetof(), but takes a pointer to a a variable of type which + * contains @member, instead of a specified type. + * @ptr is subject to multiple evaluation since we can't rely on __typeof__ + * everywhere. + */ +#if defined(__GNUC__) /* clang sets this, too */ +#define OFFSETOF_VAR(ptr, member) offsetof(__typeof__(*ptr), member) +#else /* !__GNUC__ */ +#define OFFSETOF_VAR(ptr, member) \ + ((uintptr_t)&(ptr)->member - (uintptr_t)(ptr)) +#endif /* !__GNUC__ */ + #endif diff --git a/hashmap.h b/hashmap.h index 171d6ddb76..96786c724a 100644 --- a/hashmap.h +++ b/hashmap.h @@ -408,16 +408,32 @@ static inline struct hashmap_entry *hashmap_iter_first(struct hashmap *map, return hashmap_iter_next(iter); } -#define hashmap_iter_next_entry(iter, type, member) \ - container_of_or_null(hashmap_iter_next(iter), type, member) - +/* + * returns the first entry in @map using @iter, where the entry is of + * @type (e.g. "struct foo") and @member is the name of the + * "struct hashmap_entry" in @type + */ #define hashmap_iter_first_entry(map, iter, type, member) \ container_of_or_null(hashmap_iter_first(map, iter), type, member) -#define hashmap_for_each_entry(map, iter, var, type, member) \ - for (var = hashmap_iter_first_entry(map, iter, type, member); \ +/* internal macro for hashmap_for_each_entry */ +#define hashmap_iter_next_entry_offset(iter, offset) \ + container_of_or_null_offset(hashmap_iter_next(iter), offset) + +/* internal macro for hashmap_for_each_entry */ +#define hashmap_iter_first_entry_offset(map, iter, offset) \ + container_of_or_null_offset(hashmap_iter_first(map, iter), offset) + +/* + * iterate through @map using @iter, @var is a pointer to a type + * containing a @member which is a "struct hashmap_entry" + */ +#define hashmap_for_each_entry(map, iter, var, member) \ + for (var = hashmap_iter_first_entry_offset(map, iter, \ + OFFSETOF_VAR(var, member)); \ var; \ - var = hashmap_iter_next_entry(iter, type, member)) + var = hashmap_iter_next_entry_offset(iter, \ + OFFSETOF_VAR(var, member))) /* * returns a @pointer of @type matching @keyvar, or NULL if nothing found. @@ -432,22 +448,22 @@ static inline struct hashmap_entry *hashmap_iter_first(struct hashmap *map, container_of_or_null(hashmap_get_from_hash(map, hash, keydata), \ type, member) /* - * returns the next equal @type pointer to @var, or NULL if not found. - * @var is a pointer of @type - * @member is the name of the "struct hashmap_entry" field in @type + * returns the next equal pointer to @var, or NULL if not found. + * @var is a pointer of any type containing "struct hashmap_entry" + * @member is the name of the "struct hashmap_entry" field */ -#define hashmap_get_next_entry(map, var, type, member) \ - container_of_or_null(hashmap_get_next(map, &(var)->member), \ - type, member) +#define hashmap_get_next_entry(map, var, member) \ + container_of_or_null_offset(hashmap_get_next(map, &(var)->member), \ + OFFSETOF_VAR(var, member)) /* * iterate @map starting from @var, where @var is a pointer of @type * and @member is the name of the "struct hashmap_entry" field in @type */ -#define hashmap_for_each_entry_from(map, var, type, member) \ +#define hashmap_for_each_entry_from(map, var, member) \ for (; \ var; \ - var = hashmap_get_next_entry(map, var, type, member)) + var = hashmap_get_next_entry(map, var, member)) /* * Disable item counting and automatic rehashing when adding/removing items. diff --git a/merge-recursive.c b/merge-recursive.c index 34b3d54154..3abba3a618 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -2136,7 +2136,6 @@ static void handle_directory_level_conflicts(struct merge_options *opt, struct string_list remove_from_merge = STRING_LIST_INIT_NODUP; hashmap_for_each_entry(dir_re_head, &iter, head_ent, - struct dir_rename_entry, ent /* member name */) { merge_ent = dir_rename_find_entry(dir_re_merge, head_ent->dir); if (merge_ent && @@ -2162,7 +2161,6 @@ static void handle_directory_level_conflicts(struct merge_options *opt, remove_hashmap_entries(dir_re_merge, &remove_from_merge); hashmap_for_each_entry(dir_re_merge, &iter, merge_ent, - struct dir_rename_entry, ent /* member name */) { head_ent = dir_rename_find_entry(dir_re_head, merge_ent->dir); if (tree_has_path(opt->repo, merge, merge_ent->dir)) { @@ -2268,7 +2266,6 @@ static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs) * that there is no winner), we no longer need possible_new_dirs. */ hashmap_for_each_entry(dir_renames, &iter, entry, - struct dir_rename_entry, ent /* member name */) { int max = 0; int bad_max = 0; @@ -2628,7 +2625,6 @@ static struct string_list *get_renames(struct merge_options *opt, } hashmap_for_each_entry(&collisions, &iter, e, - struct collision_entry, ent /* member name */) { free(e->target_file); string_list_clear(&e->source_files, 0); @@ -2847,7 +2843,6 @@ static void initial_cleanup_rename(struct diff_queue_struct *pairs, struct dir_rename_entry *e; hashmap_for_each_entry(dir_renames, &iter, e, - struct dir_rename_entry, ent /* member name */) { free(e->dir); strbuf_release(&e->new_dir); diff --git a/name-hash.c b/name-hash.c index c86fe0f1df..3cda22b657 100644 --- a/name-hash.c +++ b/name-hash.c @@ -714,8 +714,7 @@ struct cache_entry *index_file_exists(struct index_state *istate, const char *na ce = hashmap_get_entry_from_hash(&istate->name_hash, hash, NULL, struct cache_entry, ent); - hashmap_for_each_entry_from(&istate->name_hash, ce, - struct cache_entry, ent) { + hashmap_for_each_entry_from(&istate->name_hash, ce, ent) { if (same_name(ce, name, namelen, icase)) return ce; } diff --git a/revision.c b/revision.c index 8a5f866ae6..5abd4a1fe7 100644 --- a/revision.c +++ b/revision.c @@ -129,9 +129,7 @@ static void paths_and_oids_clear(struct hashmap *map) struct hashmap_iter iter; struct path_and_oids_entry *entry; - hashmap_for_each_entry(map, &iter, entry, - struct path_and_oids_entry, - ent /* member name */) { + hashmap_for_each_entry(map, &iter, entry, ent /* member name */) { oidset_clear(&entry->trees); free(entry->path); } @@ -243,9 +241,7 @@ void mark_trees_uninteresting_sparse(struct repository *r, add_children_by_path(r, tree, &map); } - hashmap_for_each_entry(&map, &map_iter, entry, - struct path_and_oids_entry, - ent /* member name */) + hashmap_for_each_entry(&map, &map_iter, entry, ent /* member name */) mark_trees_uninteresting_sparse(r, &entry->trees); paths_and_oids_clear(&map); diff --git a/submodule-config.c b/submodule-config.c index 5462acc8ec..c22855cd38 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -100,7 +100,7 @@ static void submodule_cache_clear(struct submodule_cache *cache) * their .gitmodules blob sha1 and submodule name. */ hashmap_for_each_entry(&cache->for_name, &iter, entry, - struct submodule_entry, ent /* member name */) + ent /* member name */) free_one_config(entry); hashmap_free_entries(&cache->for_path, struct submodule_entry, ent); diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index 6f2530dcc8..f89d1194ef 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -205,10 +205,8 @@ int cmd__hashmap(int argc, const char **argv) /* print result */ if (!entry) puts("NULL"); - hashmap_for_each_entry_from(&map, entry, - struct test_entry, ent) { + hashmap_for_each_entry_from(&map, entry, ent) puts(get_value(entry)); - } } else if (!strcmp("remove", cmd) && p1) { @@ -230,7 +228,6 @@ int cmd__hashmap(int argc, const char **argv) struct hashmap_iter iter; hashmap_for_each_entry(&map, &iter, entry, - struct test_entry, ent /* member name */) printf("%s %s\n", entry->key, get_value(entry)); diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c index 9d4664d6a4..cd1b4c9736 100644 --- a/t/helper/test-lazy-init-name-hash.c +++ b/t/helper/test-lazy-init-name-hash.c @@ -42,11 +42,11 @@ static void dump_run(void) } hashmap_for_each_entry(&the_index.dir_hash, &iter_dir, dir, - struct dir_entry, ent /* member name */) + ent /* member name */) printf("dir %08x %7d %s\n", dir->ent.hash, dir->nr, dir->name); hashmap_for_each_entry(&the_index.name_hash, &iter_cache, ce, - struct cache_entry, ent /* member name */) + ent /* member name */) printf("name %08x %s\n", ce->ent.hash, ce->name); discard_cache(); -- cgit v1.3