{"thread":{"id":"51736","subject":"[PATCH 00/11] hashmap: bugfixes, safety fixes, and WIP improvements","startedAt":"2019-08-26T02:43:34Z","lastAt":"2019-10-06T00:04:13Z","messageCount":71,"participants":["Eric Wong","Johannes Schindelin","Derrick Stolee","Junio C Hamano","Phillip Wood"],"isPatch":true,"patchVersion":1,"patchTotal":11},"messages":[{"id":"381153","messageId":"20190826024332.3403-1-e@80x24.org","threadId":"51736","inReplyTo":null,"subject":"[PATCH 00/11] hashmap: bugfixes, safety fixes, and WIP improvements","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-26T02:43:21Z","receivedAt":"2019-08-26T02:43:34Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This started out as yak-shaving exercise to introduce the\n\"container_of\" macro to make hashmap more flexible and\nless error-prone.\n\nSo far I've ended up finding and fixing two real bugs in\npatches 1/11 and 2/11 which should be fast-tracked.\n\nPatches 3-9 are straightforward safety fixes to prevent future\nbugs of the same type.\n\n10-11 are work-in-progress changes to remove the limitation\nof hashmap_entry being the first member of a struct.  It's\nalso part of my ongoing agenda to spread Linux kernel idioms\ninto userspace and maybe get git.git hackers more comfortable\nwith kernel hacking (and vice-versa :>)\n\nI'll try to continue the rest within the next few days.\n\n\nThe following changes since commit 745f6812895b31c02b29bdfe4ae8e5498f776c26:\n\n  First batch after Git 2.23 (2019-08-22 12:41:04 -0700)\n\nare available in the Git repository at:\n\n  https://80x24.org/git-svn.git hashmap-wip-v1\n\nfor you to fetch changes up to 4d9857917670218cba447caddec15a2734c86e2c:\n\n  hashmap_get_next returns \"struct hashmap_entry *\" (2019-08-26 02:25:35 +0000)\n\n----------------------------------------------------------------\nEric Wong (11):\n      diff: use hashmap_entry_init on moved_entry.ent\n      packfile: use hashmap_entry in delta_base_cache_entry\n      hashmap_entry_init takes \"struct hashmap_entry *\"\n      hashmap_entry: detect improper initialization\n      hashmap_get_next takes \"const struct hashmap_entry *\"\n      hashmap_add takes \"struct hashmap_entry *\"\n      hashmap_get takes \"const struct hashmap_entry *\"\n      hashmap_remove takes \"const struct hashmap_entry *\"\n      hashmap_put takes \"struct hashmap_entry *\"\n      introduce container_of macro\n      hashmap_get_next returns \"struct hashmap_entry *\"\n\n attr.c                              |  8 +++----\n blame.c                             | 12 +++++-----\n builtin/describe.c                  |  4 ++--\n builtin/difftool.c                  | 17 +++++++-------\n builtin/fast-export.c               |  9 ++++----\n builtin/fetch.c                     |  4 ++--\n config.c                            |  8 +++----\n diff.c                              | 23 ++++++++++++-------\n diffcore-rename.c                   | 15 ++++++++-----\n git-compat-util.h                   | 10 +++++++++\n hashmap.c                           | 30 ++++++++++++++-----------\n hashmap.h                           | 45 +++++++++++++++++++++----------------\n merge-recursive.c                   | 27 +++++++++++-----------\n name-hash.c                         | 41 +++++++++++++++++----------------\n oidmap.c                            |  2 +-\n packfile.c                          |  8 +++----\n patch-ids.c                         |  6 ++---\n range-diff.c                        |  8 +++----\n ref-filter.c                        |  5 +++--\n refs.c                              |  7 ++++--\n remote.c                            |  8 ++++---\n revision.c                          |  9 ++++----\n sequencer.c                         |  9 ++++----\n sub-process.c                       | 10 ++++-----\n submodule-config.c                  | 20 ++++++++---------\n t/helper/test-hashmap.c             | 24 +++++++++++---------\n t/helper/test-lazy-init-name-hash.c |  4 ++--\n 27 files changed, 210 insertions(+), 163 deletions(-)\n"},{"id":"381154","messageId":"20190826024332.3403-2-e@80x24.org","threadId":"51736","inReplyTo":"20190826024332.3403-1-e@80x24.org","subject":"[PATCH 01/11] diff: use hashmap_entry_init on moved_entry.ent","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-26T02:43:22Z","receivedAt":"2019-08-26T02:43:39Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Otherwise, the hashmap_entry.next field appears to remain\nuninitialized, which can lead to problems when\nadd_lines_to_move_detection calls hashmap_add.\n\nI found this through manual inspection when converting\nhashmap_add callers to take \"struct hashmap_entry *\".\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n diff.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/diff.c b/diff.c\nindex efe42b341a..02491ee684 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -964,8 +964,9 @@ static struct moved_entry *prepare_entry(struct diff_options *o,\n \tstruct moved_entry *ret = xmalloc(sizeof(*ret));\n \tstruct emitted_diff_symbol *l = &o->emitted_symbols->buf[line_no];\n \tunsigned flags = o->color_moved_ws_handling & XDF_WHITESPACE_FLAGS;\n+\tunsigned int hash = xdiff_hash_string(l->line, l->len, flags);\n \n-\tret->ent.hash = xdiff_hash_string(l->line, l->len, flags);\n+\thashmap_entry_init(&ret->ent, hash);\n \tret->es = l;\n \tret->next_line = NULL;\n \n-- \nEW\n\n"},{"id":"381155","messageId":"20190826024332.3403-3-e@80x24.org","threadId":"51736","inReplyTo":"20190826024332.3403-1-e@80x24.org","subject":"[PATCH 02/11] packfile: use hashmap_entry in delta_base_cache_entry","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-26T02:43:23Z","receivedAt":"2019-08-26T02:43:39Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This hashmap_entry_init function is intended to take a\nhashmap_entry struct pointer, not a hashmap struct pointer.\n\nThis was not noticed because hashmap_entry_init takes a \"void *\"\narg instead of \"struct hashmap_entry *\", and the hashmap struct\nis larger and can be cast into a hashmap_entry struct without\ndata corruption.\n\nThis has the beneficial side effect of reducing the size of\na delta_base_cache_entry from 104 bytes to 72 bytes on 64-bit\nsystems.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n packfile.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/packfile.c b/packfile.c\nindex fc43a6c52c..37fe0b73a6 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1361,7 +1361,7 @@ struct delta_base_cache_key {\n };\n \n struct delta_base_cache_entry {\n-\tstruct hashmap hash;\n+\tstruct hashmap_entry ent;\n \tstruct delta_base_cache_key key;\n \tstruct list_head lru;\n \tvoid *data;\n-- \nEW\n\n"},{"id":"381156","messageId":"20190826024332.3403-4-e@80x24.org","threadId":"51736","inReplyTo":"20190826024332.3403-1-e@80x24.org","subject":"[PATCH 03/11] hashmap_entry_init takes \"struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-26T02:43:24Z","receivedAt":"2019-08-26T02:43:43Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"C compilers do type checking to make life easier for us.  So\nrely on that and update all hashmap_entry_init callers to take\n\"struct hashmap_entry *\" to avoid future bugs while improving\nsafety and readability.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n attr.c                  |  4 ++--\n blame.c                 |  2 +-\n builtin/describe.c      |  2 +-\n builtin/difftool.c      |  6 +++---\n builtin/fast-export.c   |  2 +-\n builtin/fetch.c         |  2 +-\n config.c                |  4 ++--\n diffcore-rename.c       |  2 +-\n hashmap.c               |  4 ++--\n hashmap.h               | 12 ++++++------\n merge-recursive.c       | 13 +++++++------\n name-hash.c             | 10 +++++-----\n packfile.c              |  2 +-\n patch-ids.c             |  2 +-\n range-diff.c            |  4 ++--\n ref-filter.c            |  3 ++-\n refs.c                  |  2 +-\n remote.c                |  2 +-\n revision.c              |  4 ++--\n sequencer.c             |  5 +++--\n sub-process.c           |  4 ++--\n submodule-config.c      | 10 +++++-----\n t/helper/test-hashmap.c |  6 +++---\n 23 files changed, 55 insertions(+), 52 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex 93dc16b59c..a8be7a7b4f 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -98,7 +98,7 @@ static void *attr_hashmap_get(struct attr_hashmap *map,\n \tif (!map->map.tablesize)\n \t\tattr_hashmap_init(map);\n \n-\thashmap_entry_init(&k, memhash(key, keylen));\n+\thashmap_entry_init(&k.ent, memhash(key, keylen));\n \tk.key = key;\n \tk.keylen = keylen;\n \te = hashmap_get(&map->map, &k, NULL);\n@@ -117,7 +117,7 @@ static void attr_hashmap_add(struct attr_hashmap *map,\n \t\tattr_hashmap_init(map);\n \n \te = xmalloc(sizeof(struct attr_hash_entry));\n-\thashmap_entry_init(e, memhash(key, keylen));\n+\thashmap_entry_init(&e->ent, memhash(key, keylen));\n \te->key = key;\n \te->keylen = keylen;\n \te->value = value;\ndiff --git a/blame.c b/blame.c\nindex 36a2e7ef11..46059410cd 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -417,7 +417,7 @@ static void get_fingerprint(struct fingerprint *result,\n \t\t/* Ignore whitespace pairs */\n \t\tif (hash == 0)\n \t\t\tcontinue;\n-\t\thashmap_entry_init(entry, hash);\n+\t\thashmap_entry_init(&entry->entry, hash);\n \n \t\tfound_entry = hashmap_get(&result->map, entry, NULL);\n \t\tif (found_entry) {\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 200154297d..596ddf89a5 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -123,7 +123,7 @@ static void add_to_known_names(const char *path,\n \t\tif (!e) {\n \t\t\te = xmalloc(sizeof(struct commit_name));\n \t\t\toidcpy(&e->peeled, peeled);\n-\t\t\thashmap_entry_init(e, oidhash(peeled));\n+\t\t\thashmap_entry_init(&e->entry, oidhash(peeled));\n \t\t\thashmap_add(&names, e);\n \t\t\te->path = NULL;\n \t\t}\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 16eb8b70ea..98ffc04c61 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -161,7 +161,7 @@ static void add_left_or_right(struct hashmap *map, const char *path,\n \tstruct pair_entry *e, *existing;\n \n \tFLEX_ALLOC_STR(e, path, path);\n-\thashmap_entry_init(e, strhash(path));\n+\thashmap_entry_init(&e->entry, strhash(path));\n \texisting = hashmap_get(map, e, NULL);\n \tif (existing) {\n \t\tfree(e);\n@@ -234,7 +234,7 @@ static void changed_files(struct hashmap *result, const char *index_path,\n \twhile (!strbuf_getline_nul(&buf, fp)) {\n \t\tstruct path_entry *entry;\n \t\tFLEX_ALLOC_STR(entry, path, buf.buf);\n-\t\thashmap_entry_init(entry, strhash(buf.buf));\n+\t\thashmap_entry_init(&entry->entry, strhash(buf.buf));\n \t\thashmap_add(result, entry);\n \t}\n \tfclose(fp);\n@@ -461,7 +461,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \n \t\t\t/* Avoid duplicate working_tree entries */\n \t\t\tFLEX_ALLOC_STR(entry, path, dst_path);\n-\t\t\thashmap_entry_init(entry, strhash(dst_path));\n+\t\t\thashmap_entry_init(&entry->entry, strhash(dst_path));\n \t\t\tif (hashmap_get(&working_tree_dups, entry, NULL)) {\n \t\t\t\tfree(entry);\n \t\t\t\tcontinue;\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex f541f55d33..287dbd24a3 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -148,7 +148,7 @@ static const void *anonymize_mem(struct hashmap *map,\n \tif (!map->cmpfn)\n \t\thashmap_init(map, anonymized_entry_cmp, NULL, 0);\n \n-\thashmap_entry_init(&key, memhash(orig, *len));\n+\thashmap_entry_init(&key.hash, memhash(orig, *len));\n \tkey.orig = orig;\n \tkey.orig_len = *len;\n \tret = hashmap_get(map, &key, NULL);\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 717dd14e89..b7d70eee70 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -276,7 +276,7 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map,\n \tsize_t len = strlen(refname);\n \n \tFLEX_ALLOC_MEM(ent, refname, refname, len);\n-\thashmap_entry_init(ent, strhash(refname));\n+\thashmap_entry_init(&ent->ent, strhash(refname));\n \toidcpy(&ent->oid, oid);\n \thashmap_add(map, ent);\n \treturn ent;\ndiff --git a/config.c b/config.c\nindex 3900e4947b..08d866e7de 100644\n--- a/config.c\n+++ b/config.c\n@@ -1861,7 +1861,7 @@ static struct config_set_element *configset_find_element(struct config_set *cs,\n \tif (git_config_parse_key(key, &normalized_key, NULL))\n \t\treturn NULL;\n \n-\thashmap_entry_init(&k, strhash(normalized_key));\n+\thashmap_entry_init(&k.ent, strhash(normalized_key));\n \tk.key = normalized_key;\n \tfound_entry = hashmap_get(&cs->config_hash, &k, NULL);\n \tfree(normalized_key);\n@@ -1882,7 +1882,7 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha\n \t */\n \tif (!e) {\n \t\te = xmalloc(sizeof(*e));\n-\t\thashmap_entry_init(e, strhash(key));\n+\t\thashmap_entry_init(&e->ent, strhash(key));\n \t\te->key = xstrdup(key);\n \t\tstring_list_init(&e->value_list, 1);\n \t\thashmap_add(&cs->config_hash, e);\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 9624864858..44a3ab1e31 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -329,7 +329,7 @@ static void insert_file_table(struct repository *r,\n \tentry->index = index;\n \tentry->filespec = filespec;\n \n-\thashmap_entry_init(entry, hash_filespec(r, filespec));\n+\thashmap_entry_init(&entry->entry, hash_filespec(r, filespec));\n \thashmap_add(table, entry);\n }\n \ndiff --git a/hashmap.c b/hashmap.c\nindex d42f01ff5a..6818c65174 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -293,13 +293,13 @@ const void *memintern(const void *data, size_t len)\n \t\thashmap_init(&map, (hashmap_cmp_fn) pool_entry_cmp, NULL, 0);\n \n \t/* lookup interned string in pool */\n-\thashmap_entry_init(&key, memhash(data, len));\n+\thashmap_entry_init(&key.ent, memhash(data, len));\n \tkey.len = len;\n \te = hashmap_get(&map, &key, data);\n \tif (!e) {\n \t\t/* not found: create it */\n \t\tFLEX_ALLOC_MEM(e, data, data, len);\n-\t\thashmap_entry_init(e, key.ent.hash);\n+\t\thashmap_entry_init(&e->ent, key.ent.hash);\n \t\te->len = len;\n \t\thashmap_add(&map, e);\n \t}\ndiff --git a/hashmap.h b/hashmap.h\nindex 8424911566..3d7939c291 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -48,14 +48,14 @@\n  *         if (!strcmp(\"add\", action)) {\n  *             struct long2string *e;\n  *             FLEX_ALLOC_STR(e, value, value);\n- *             hashmap_entry_init(e, memhash(&key, sizeof(long)));\n+ *             hashmap_entry_init(&e->ent, memhash(&key, sizeof(long)));\n  *             e->key = key;\n  *             hashmap_add(&map, e);\n  *         }\n  *\n  *         if (!strcmp(\"print_all_by_key\", action)) {\n  *             struct long2string k, *e;\n- *             hashmap_entry_init(&k, memhash(&key, sizeof(long)));\n+ *             hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));\n  *             k.key = key;\n  *\n  *             flags &= ~COMPARE_VALUE;\n@@ -70,7 +70,7 @@\n  *         if (!strcmp(\"has_exact_match\", action)) {\n  *             struct long2string *e;\n  *             FLEX_ALLOC_STR(e, value, value);\n- *             hashmap_entry_init(e, memhash(&key, sizeof(long)));\n+ *             hashmap_entry_init(&e->ent, memhash(&key, sizeof(long)));\n  *             e->key = key;\n  *\n  *             flags |= COMPARE_VALUE;\n@@ -80,7 +80,7 @@\n  *\n  *         if (!strcmp(\"has_exact_match_no_heap_alloc\", action)) {\n  *             struct long2string k;\n- *             hashmap_entry_init(&k, memhash(&key, sizeof(long)));\n+ *             hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));\n  *             k.key = key;\n  *\n  *             flags |= COMPARE_VALUE;\n@@ -244,9 +244,9 @@ void hashmap_free(struct hashmap *map, int free_entries);\n  * your structure was allocated with xmalloc(), you can just free(3) it,\n  * and if it is on stack, you can just let it go out of scope).\n  */\n-static inline void hashmap_entry_init(void *entry, unsigned int hash)\n+static inline void\n+hashmap_entry_init(struct hashmap_entry *e, unsigned int hash)\n {\n-\tstruct hashmap_entry *e = entry;\n \te->hash = hash;\n \te->next = NULL;\n }\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 6b812d67e3..6bc4f14ff4 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -61,7 +61,7 @@ static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,\n \n \tif (dir == NULL)\n \t\treturn NULL;\n-\thashmap_entry_init(&key, strhash(dir));\n+\thashmap_entry_init(&key.ent, strhash(dir));\n \tkey.dir = dir;\n \treturn hashmap_get(hashmap, &key, NULL);\n }\n@@ -85,7 +85,7 @@ static void dir_rename_init(struct hashmap *map)\n static void dir_rename_entry_init(struct dir_rename_entry *entry,\n \t\t\t\t  char *directory)\n {\n-\thashmap_entry_init(entry, strhash(directory));\n+\thashmap_entry_init(&entry->ent, strhash(directory));\n \tentry->dir = directory;\n \tentry->non_unique_new_dir = 0;\n \tstrbuf_init(&entry->new_dir, 0);\n@@ -97,7 +97,7 @@ static struct collision_entry *collision_find_entry(struct hashmap *hashmap,\n {\n \tstruct collision_entry key;\n \n-\thashmap_entry_init(&key, strhash(target_file));\n+\thashmap_entry_init(&key.ent, strhash(target_file));\n \tkey.target_file = target_file;\n \treturn hashmap_get(hashmap, &key, NULL);\n }\n@@ -454,7 +454,7 @@ static int save_files_dirs(const struct object_id *oid,\n \tstrbuf_addstr(base, path);\n \n \tFLEX_ALLOC_MEM(entry, path, base->buf, base->len);\n-\thashmap_entry_init(entry, path_hash(entry->path));\n+\thashmap_entry_init(&entry->e, path_hash(entry->path));\n \thashmap_add(&opt->current_file_dir_set, entry);\n \n \tstrbuf_setlen(base, baselen);\n@@ -731,7 +731,7 @@ static char *unique_path(struct merge_options *opt, const char *path, const char\n \t}\n \n \tFLEX_ALLOC_MEM(entry, path, newpath.buf, newpath.len);\n-\thashmap_entry_init(entry, path_hash(entry->path));\n+\thashmap_entry_init(&entry->e, path_hash(entry->path));\n \thashmap_add(&opt->current_file_dir_set, entry);\n \treturn strbuf_detach(&newpath, NULL);\n }\n@@ -2358,7 +2358,8 @@ static void compute_collisions(struct hashmap *collisions,\n \t\tif (!collision_ent) {\n \t\t\tcollision_ent = xcalloc(1,\n \t\t\t\t\t\tsizeof(struct collision_entry));\n-\t\t\thashmap_entry_init(collision_ent, strhash(new_path));\n+\t\t\thashmap_entry_init(&collision_ent->ent,\n+\t\t\t\t\t\tstrhash(new_path));\n \t\t\thashmap_put(collisions, collision_ent);\n \t\t\tcollision_ent->target_file = new_path;\n \t\t} else {\ndiff --git a/name-hash.c b/name-hash.c\nindex 695908609f..1ce1417f7e 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -33,7 +33,7 @@ static struct dir_entry *find_dir_entry__hash(struct index_state *istate,\n \t\tconst char *name, unsigned int namelen, unsigned int hash)\n {\n \tstruct dir_entry key;\n-\thashmap_entry_init(&key, hash);\n+\thashmap_entry_init(&key.ent, hash);\n \tkey.namelen = namelen;\n \treturn hashmap_get(&istate->dir_hash, &key, name);\n }\n@@ -68,7 +68,7 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,\n \tif (!dir) {\n \t\t/* not found, create it and add to hash table */\n \t\tFLEX_ALLOC_MEM(dir, name, ce->name, namelen);\n-\t\thashmap_entry_init(dir, memihash(ce->name, namelen));\n+\t\thashmap_entry_init(&dir->ent, memihash(ce->name, namelen));\n \t\tdir->namelen = namelen;\n \t\thashmap_add(&istate->dir_hash, dir);\n \n@@ -106,7 +106,7 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)\n \tif (ce->ce_flags & CE_HASHED)\n \t\treturn;\n \tce->ce_flags |= CE_HASHED;\n-\thashmap_entry_init(ce, memihash(ce->name, ce_namelen(ce)));\n+\thashmap_entry_init(&ce->ent, memihash(ce->name, ce_namelen(ce)));\n \thashmap_add(&istate->name_hash, ce);\n \n \tif (ignore_case)\n@@ -280,7 +280,7 @@ static struct dir_entry *hash_dir_entry_with_parent_and_prefix(\n \tdir = find_dir_entry__hash(istate, prefix->buf, prefix->len, hash);\n \tif (!dir) {\n \t\tFLEX_ALLOC_MEM(dir, name, prefix->buf, prefix->len);\n-\t\thashmap_entry_init(dir, hash);\n+\t\thashmap_entry_init(&dir->ent, hash);\n \t\tdir->namelen = prefix->len;\n \t\tdir->parent = parent;\n \t\thashmap_add(&istate->dir_hash, dir);\n@@ -472,7 +472,7 @@ static void *lazy_name_thread_proc(void *_data)\n \tfor (k = 0; k < d->istate->cache_nr; k++) {\n \t\tstruct cache_entry *ce_k = d->istate->cache[k];\n \t\tce_k->ce_flags |= CE_HASHED;\n-\t\thashmap_entry_init(ce_k, d->lazy_entries[k].hash_name);\n+\t\thashmap_entry_init(&ce_k->ent, d->lazy_entries[k].hash_name);\n \t\thashmap_add(&d->istate->name_hash, ce_k);\n \t}\n \ndiff --git a/packfile.c b/packfile.c\nindex 37fe0b73a6..96535eb86b 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1487,7 +1487,7 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,\n \n \tif (!delta_base_cache.cmpfn)\n \t\thashmap_init(&delta_base_cache, delta_base_cache_hash_cmp, NULL, 0);\n-\thashmap_entry_init(ent, pack_entry_hash(p, base_offset));\n+\thashmap_entry_init(&ent->ent, pack_entry_hash(p, base_offset));\n \thashmap_add(&delta_base_cache, ent);\n }\n \ndiff --git a/patch-ids.c b/patch-ids.c\nindex e8c150d0c9..a2da711678 100644\n--- a/patch-ids.c\n+++ b/patch-ids.c\n@@ -83,7 +83,7 @@ static int init_patch_id_entry(struct patch_id *patch,\n \tif (commit_patch_id(commit, &ids->diffopts, &header_only_patch_id, 1, 0))\n \t\treturn -1;\n \n-\thashmap_entry_init(patch, oidhash(&header_only_patch_id));\n+\thashmap_entry_init(&patch->ent, oidhash(&header_only_patch_id));\n \treturn 0;\n }\n \ndiff --git a/range-diff.c b/range-diff.c\nindex ba1e9a4265..32b29f9594 100644\n--- a/range-diff.c\n+++ b/range-diff.c\n@@ -217,7 +217,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n \t\tutil->i = i;\n \t\tutil->patch = a->items[i].string;\n \t\tutil->diff = util->patch + util->diff_offset;\n-\t\thashmap_entry_init(util, strhash(util->diff));\n+\t\thashmap_entry_init(&util->e, strhash(util->diff));\n \t\thashmap_add(&map, util);\n \t}\n \n@@ -228,7 +228,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n \t\tutil->i = i;\n \t\tutil->patch = b->items[i].string;\n \t\tutil->diff = util->patch + util->diff_offset;\n-\t\thashmap_entry_init(util, strhash(util->diff));\n+\t\thashmap_entry_init(&util->e, strhash(util->diff));\n \t\tother = hashmap_remove(&map, util, NULL);\n \t\tif (other) {\n \t\t\tif (other->matching >= 0)\ndiff --git a/ref-filter.c b/ref-filter.c\nindex f27cfc8c3e..206014c93d 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1565,7 +1565,8 @@ static void populate_worktree_map(struct hashmap *map, struct worktree **worktre\n \t\t\tstruct ref_to_worktree_entry *entry;\n \t\t\tentry = xmalloc(sizeof(*entry));\n \t\t\tentry->wt = worktrees[i];\n-\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n+\t\t\thashmap_entry_init(&entry->ent,\n+\t\t\t\t\tstrhash(worktrees[i]->head_ref));\n \n \t\t\thashmap_add(map, entry);\n \t\t}\ndiff --git a/refs.c b/refs.c\nindex cd297ee4bd..c43ec59c6e 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1796,7 +1796,7 @@ static struct ref_store_hash_entry *alloc_ref_store_hash_entry(\n \tstruct ref_store_hash_entry *entry;\n \n \tFLEX_ALLOC_STR(entry, name, name);\n-\thashmap_entry_init(entry, strhash(name));\n+\thashmap_entry_init(&entry->ent, strhash(name));\n \tentry->refs = refs;\n \treturn entry;\n }\ndiff --git a/remote.c b/remote.c\nindex e50f7602ed..bd81cb71bc 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -158,7 +158,7 @@ static struct remote *make_remote(const char *name, int len)\n \tALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);\n \tremotes[remotes_nr++] = ret;\n \n-\thashmap_entry_init(ret, lookup_entry.hash);\n+\thashmap_entry_init(&ret->ent, lookup_entry.hash);\n \treplaced = hashmap_put(&remotes_hash, ret);\n \tassert(replaced == NULL);  /* no previous entry overwritten */\n \treturn ret;\ndiff --git a/revision.c b/revision.c\nindex 07412297f0..3461c78883 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -141,7 +141,7 @@ static void paths_and_oids_insert(struct hashmap *map,\n \tstruct path_and_oids_entry key;\n \tstruct path_and_oids_entry *entry;\n \n-\thashmap_entry_init(&key, hash);\n+\thashmap_entry_init(&key.ent, hash);\n \n \t/* use a shallow copy for the lookup */\n \tkey.path = (char *)path;\n@@ -149,7 +149,7 @@ static void paths_and_oids_insert(struct hashmap *map,\n \n \tif (!(entry = (struct path_and_oids_entry *)hashmap_get(map, &key, NULL))) {\n \t\tentry = xcalloc(1, sizeof(struct path_and_oids_entry));\n-\t\thashmap_entry_init(entry, hash);\n+\t\thashmap_entry_init(&entry->ent, hash);\n \t\tentry->path = xstrdup(key.path);\n \t\toidset_init(&entry->trees, 16);\n \t\thashmap_put(map, entry);\ndiff --git a/sequencer.c b/sequencer.c\nindex 34ebf8ed94..1140cdf526 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4538,7 +4538,7 @@ static const char *label_oid(struct object_id *oid, const char *label,\n \t}\n \n \tFLEX_ALLOC_STR(labels_entry, label, label);\n-\thashmap_entry_init(labels_entry, strihash(label));\n+\thashmap_entry_init(&labels_entry->entry, strihash(label));\n \thashmap_add(&state->labels, labels_entry);\n \n \tFLEX_ALLOC_STR(string_entry, string, label);\n@@ -5252,7 +5252,8 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\t\t\t\t\tstrhash(subject), subject)) {\n \t\t\tFLEX_ALLOC_MEM(entry, subject, subject, subject_len);\n \t\t\tentry->i = i;\n-\t\t\thashmap_entry_init(entry, strhash(entry->subject));\n+\t\t\thashmap_entry_init(&entry->entry,\n+\t\t\t\t\tstrhash(entry->subject));\n \t\t\thashmap_put(&subject2item, entry);\n \t\t}\n \t}\ndiff --git a/sub-process.c b/sub-process.c\nindex 3f4af93555..9847dad6fc 100644\n--- a/sub-process.c\n+++ b/sub-process.c\n@@ -20,7 +20,7 @@ struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const ch\n {\n \tstruct subprocess_entry key;\n \n-\thashmap_entry_init(&key, strhash(cmd));\n+\thashmap_entry_init(&key.ent, strhash(cmd));\n \tkey.cmd = cmd;\n \treturn hashmap_get(hashmap, &key, NULL);\n }\n@@ -96,7 +96,7 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co\n \t\treturn err;\n \t}\n \n-\thashmap_entry_init(entry, strhash(cmd));\n+\thashmap_entry_init(&entry->ent, strhash(cmd));\n \n \terr = startfn(entry);\n \tif (err) {\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 4264ee216f..4aa02e280e 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -123,7 +123,7 @@ static void cache_put_path(struct submodule_cache *cache,\n \tunsigned int hash = hash_oid_string(&submodule->gitmodules_oid,\n \t\t\t\t\t    submodule->path);\n \tstruct submodule_entry *e = xmalloc(sizeof(*e));\n-\thashmap_entry_init(e, hash);\n+\thashmap_entry_init(&e->ent, hash);\n \te->config = submodule;\n \thashmap_put(&cache->for_path, e);\n }\n@@ -135,7 +135,7 @@ static void cache_remove_path(struct submodule_cache *cache,\n \t\t\t\t\t    submodule->path);\n \tstruct submodule_entry e;\n \tstruct submodule_entry *removed;\n-\thashmap_entry_init(&e, hash);\n+\thashmap_entry_init(&e.ent, hash);\n \te.config = submodule;\n \tremoved = hashmap_remove(&cache->for_path, &e, NULL);\n \tfree(removed);\n@@ -147,7 +147,7 @@ static void cache_add(struct submodule_cache *cache,\n \tunsigned int hash = hash_oid_string(&submodule->gitmodules_oid,\n \t\t\t\t\t    submodule->name);\n \tstruct submodule_entry *e = xmalloc(sizeof(*e));\n-\thashmap_entry_init(e, hash);\n+\thashmap_entry_init(&e->ent, hash);\n \te->config = submodule;\n \thashmap_add(&cache->for_name, e);\n }\n@@ -163,7 +163,7 @@ static const struct submodule *cache_lookup_path(struct submodule_cache *cache,\n \toidcpy(&key_config.gitmodules_oid, gitmodules_oid);\n \tkey_config.path = path;\n \n-\thashmap_entry_init(&key, hash);\n+\thashmap_entry_init(&key.ent, hash);\n \tkey.config = &key_config;\n \n \tentry = hashmap_get(&cache->for_path, &key, NULL);\n@@ -183,7 +183,7 @@ static struct submodule *cache_lookup_name(struct submodule_cache *cache,\n \toidcpy(&key_config.gitmodules_oid, gitmodules_oid);\n \tkey_config.name = name;\n \n-\thashmap_entry_init(&key, hash);\n+\thashmap_entry_init(&key.ent, hash);\n \tkey.config = &key_config;\n \n \tentry = hashmap_get(&cache->for_name, &key, NULL);\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex aaf17b0ddf..0c9fd7c996 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -37,7 +37,7 @@ static struct test_entry *alloc_test_entry(unsigned int hash,\n \tsize_t klen = strlen(key);\n \tsize_t vlen = strlen(value);\n \tstruct test_entry *entry = xmalloc(st_add4(sizeof(*entry), klen, vlen, 2));\n-\thashmap_entry_init(entry, hash);\n+\thashmap_entry_init(&entry->ent, hash);\n \tmemcpy(entry->key, key, klen + 1);\n \tmemcpy(entry->key + klen + 1, value, vlen + 1);\n \treturn entry;\n@@ -103,7 +103,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)\n \n \t\t\t/* add entries */\n \t\t\tfor (i = 0; i < TEST_SIZE; i++) {\n-\t\t\t\thashmap_entry_init(entries[i], hashes[i]);\n+\t\t\t\thashmap_entry_init(&entries[i]->ent, hashes[i]);\n \t\t\t\thashmap_add(&map, entries[i]);\n \t\t\t}\n \n@@ -116,7 +116,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)\n \t\t/* fill the map (sparsely if specified) */\n \t\tj = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE;\n \t\tfor (i = 0; i < j; i++) {\n-\t\t\thashmap_entry_init(entries[i], hashes[i]);\n+\t\t\thashmap_entry_init(&entries[i]->ent, hashes[i]);\n \t\t\thashmap_add(&map, entries[i]);\n \t\t}\n \n-- \nEW\n\n"},{"id":"381157","messageId":"20190826024332.3403-5-e@80x24.org","threadId":"51736","inReplyTo":"20190826024332.3403-1-e@80x24.org","subject":"[PATCH 04/11] hashmap_entry: detect improper initialization","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-26T02:43:25Z","receivedAt":"2019-08-26T02:43:45Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"By renaming the \"hash\" field to \"_hash\", it's easy to spot\nimproper initialization of hashmap_entry structs which\ncan leave \"hashmap_entry.next\" uninitialized.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n builtin/fast-export.c               | 5 +++--\n hashmap.c                           | 9 +++++----\n hashmap.h                           | 4 ++--\n name-hash.c                         | 9 +++++----\n remote.c                            | 6 ++++--\n t/helper/test-lazy-init-name-hash.c | 4 ++--\n 6 files changed, 21 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 287dbd24a3..f30a92a4d3 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -144,18 +144,19 @@ static const void *anonymize_mem(struct hashmap *map,\n \t\t\t\t const void *orig, size_t *len)\n {\n \tstruct anonymized_entry key, *ret;\n+\tunsigned int hash = memhash(orig, *len);\n \n \tif (!map->cmpfn)\n \t\thashmap_init(map, anonymized_entry_cmp, NULL, 0);\n \n-\thashmap_entry_init(&key.hash, memhash(orig, *len));\n+\thashmap_entry_init(&key.hash, hash);\n \tkey.orig = orig;\n \tkey.orig_len = *len;\n \tret = hashmap_get(map, &key, NULL);\n \n \tif (!ret) {\n \t\tret = xmalloc(sizeof(*ret));\n-\t\thashmap_entry_init(&ret->hash, key.hash.hash);\n+\t\thashmap_entry_init(&ret->hash, hash);\n \t\tret->orig = xstrdup(orig);\n \t\tret->orig_len = *len;\n \t\tret->anon = generate(orig, len);\ndiff --git a/hashmap.c b/hashmap.c\nindex 6818c65174..777beda347 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -96,14 +96,14 @@ static inline int entry_equals(const struct hashmap *map,\n \t\tconst void *keydata)\n {\n \treturn (e1 == e2) ||\n-\t       (e1->hash == e2->hash &&\n+\t       (e1->_hash == e2->_hash &&\n \t\t!map->cmpfn(map->cmpfn_data, e1, e2, keydata));\n }\n \n static inline unsigned int bucket(const struct hashmap *map,\n \t\tconst struct hashmap_entry *key)\n {\n-\treturn key->hash & (map->tablesize - 1);\n+\treturn key->_hash & (map->tablesize - 1);\n }\n \n int hashmap_bucket(const struct hashmap *map, unsigned int hash)\n@@ -287,19 +287,20 @@ const void *memintern(const void *data, size_t len)\n {\n \tstatic struct hashmap map;\n \tstruct pool_entry key, *e;\n+\tunsigned int hash = memhash(data, len);\n \n \t/* initialize string pool hashmap */\n \tif (!map.tablesize)\n \t\thashmap_init(&map, (hashmap_cmp_fn) pool_entry_cmp, NULL, 0);\n \n \t/* lookup interned string in pool */\n-\thashmap_entry_init(&key.ent, memhash(data, len));\n+\thashmap_entry_init(&key.ent, hash);\n \tkey.len = len;\n \te = hashmap_get(&map, &key, data);\n \tif (!e) {\n \t\t/* not found: create it */\n \t\tFLEX_ALLOC_MEM(e, data, data, len);\n-\t\thashmap_entry_init(&e->ent, key.ent.hash);\n+\t\thashmap_entry_init(&e->ent, hash);\n \t\te->len = len;\n \t\thashmap_add(&map, e);\n \t}\ndiff --git a/hashmap.h b/hashmap.h\nindex 3d7939c291..d635e0815a 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -145,7 +145,7 @@ struct hashmap_entry {\n \tstruct hashmap_entry *next;\n \n \t/* entry's hash code */\n-\tunsigned int hash;\n+\tunsigned int _hash;\n };\n \n /*\n@@ -247,7 +247,7 @@ void hashmap_free(struct hashmap *map, int free_entries);\n static inline void\n hashmap_entry_init(struct hashmap_entry *e, unsigned int hash)\n {\n-\te->hash = hash;\n+\te->_hash = hash;\n \te->next = NULL;\n }\n \ndiff --git a/name-hash.c b/name-hash.c\nindex 1ce1417f7e..8b33c5cb59 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -268,7 +268,7 @@ static struct dir_entry *hash_dir_entry_with_parent_and_prefix(\n \tassert((parent != NULL) ^ (strchr(prefix->buf, '/') == NULL));\n \n \tif (parent)\n-\t\thash = memihash_cont(parent->ent.hash,\n+\t\thash = memihash_cont(parent->ent._hash,\n \t\t\tprefix->buf + parent->namelen,\n \t\t\tprefix->len - parent->namelen);\n \telse\n@@ -289,7 +289,8 @@ static struct dir_entry *hash_dir_entry_with_parent_and_prefix(\n \t\t\tunlock_dir_mutex(lock_nr);\n \n \t\t\t/* All I really need here is an InterlockedIncrement(&(parent->nr)) */\n-\t\t\tlock_nr = compute_dir_lock_nr(&istate->dir_hash, parent->ent.hash);\n+\t\t\tlock_nr = compute_dir_lock_nr(&istate->dir_hash,\n+\t\t\t\t\t\t\tparent->ent._hash);\n \t\t\tlock_dir_mutex(lock_nr);\n \t\t\tparent->nr++;\n \t\t}\n@@ -427,10 +428,10 @@ static int handle_range_1(\n \t\tlazy_entries[k].dir = parent;\n \t\tif (parent) {\n \t\t\tlazy_entries[k].hash_name = memihash_cont(\n-\t\t\t\tparent->ent.hash,\n+\t\t\t\tparent->ent._hash,\n \t\t\t\tce_k->name + parent->namelen,\n \t\t\t\tce_namelen(ce_k) - parent->namelen);\n-\t\t\tlazy_entries[k].hash_dir = parent->ent.hash;\n+\t\t\tlazy_entries[k].hash_dir = parent->ent._hash;\n \t\t} else {\n \t\t\tlazy_entries[k].hash_name = memihash(ce_k->name, ce_namelen(ce_k));\n \t\t}\ndiff --git a/remote.c b/remote.c\nindex bd81cb71bc..dc09172e9d 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -136,6 +136,7 @@ static struct remote *make_remote(const char *name, int len)\n \tstruct remote *ret, *replaced;\n \tstruct remotes_hash_key lookup;\n \tstruct hashmap_entry lookup_entry;\n+\tunsigned int hash;\n \n \tif (!len)\n \t\tlen = strlen(name);\n@@ -143,7 +144,8 @@ static struct remote *make_remote(const char *name, int len)\n \tinit_remotes_hash();\n \tlookup.str = name;\n \tlookup.len = len;\n-\thashmap_entry_init(&lookup_entry, memhash(name, len));\n+\thash = memhash(name, len);\n+\thashmap_entry_init(&lookup_entry, hash);\n \n \tif ((ret = hashmap_get(&remotes_hash, &lookup_entry, &lookup)) != NULL)\n \t\treturn ret;\n@@ -158,7 +160,7 @@ static struct remote *make_remote(const char *name, int len)\n \tALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);\n \tremotes[remotes_nr++] = ret;\n \n-\thashmap_entry_init(&ret->ent, lookup_entry.hash);\n+\thashmap_entry_init(&ret->ent, hash);\n \treplaced = hashmap_put(&remotes_hash, ret);\n \tassert(replaced == NULL);  /* no previous entry overwritten */\n \treturn ret;\ndiff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c\nindex b99a37080d..d01ea0e526 100644\n--- a/t/helper/test-lazy-init-name-hash.c\n+++ b/t/helper/test-lazy-init-name-hash.c\n@@ -43,13 +43,13 @@ static void dump_run(void)\n \n \tdir = hashmap_iter_first(&the_index.dir_hash, &iter_dir);\n \twhile (dir) {\n-\t\tprintf(\"dir %08x %7d %s\\n\", dir->ent.hash, dir->nr, dir->name);\n+\t\tprintf(\"dir %08x %7d %s\\n\", dir->ent._hash, dir->nr, dir->name);\n \t\tdir = hashmap_iter_next(&iter_dir);\n \t}\n \n \tce = hashmap_iter_first(&the_index.name_hash, &iter_cache);\n \twhile (ce) {\n-\t\tprintf(\"name %08x %s\\n\", ce->ent.hash, ce->name);\n+\t\tprintf(\"name %08x %s\\n\", ce->ent._hash, ce->name);\n \t\tce = hashmap_iter_next(&iter_cache);\n \t}\n \n-- \nEW\n\n"},{"id":"381158","messageId":"20190826024332.3403-6-e@80x24.org","threadId":"51736","inReplyTo":"20190826024332.3403-1-e@80x24.org","subject":"[PATCH 05/11] hashmap_get_next takes \"const struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-26T02:43:26Z","receivedAt":"2019-08-26T02:43:48Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is less error-prone than \"const void *\" as the compiler\nnow detects invalid types being passed.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n diff.c                  | 5 +++--\n diffcore-rename.c       | 2 +-\n hashmap.c               | 5 +++--\n hashmap.h               | 3 ++-\n name-hash.c             | 2 +-\n t/helper/test-hashmap.c | 2 +-\n 6 files changed, 11 insertions(+), 8 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 02491ee684..1168f0cbb9 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1036,7 +1036,7 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,\n \tint i;\n \tchar *got_match = xcalloc(1, pmb_nr);\n \n-\tfor (; match; match = hashmap_get_next(hm, match)) {\n+\tfor (; match; match = hashmap_get_next(hm, &match->ent)) {\n \t\tfor (i = 0; i < pmb_nr; i++) {\n \t\t\tstruct moved_entry *prev = pmb[i].match;\n \t\t\tstruct moved_entry *cur = (prev && prev->next_line) ?\n@@ -1189,7 +1189,8 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\t\t * The current line is the start of a new block.\n \t\t\t * Setup the set of potential blocks.\n \t\t\t */\n-\t\t\tfor (; match; match = hashmap_get_next(hm, match)) {\n+\t\t\tfor (; match; match = hashmap_get_next(hm,\n+\t\t\t\t\t\t\t\t&match->ent)) {\n \t\t\t\tALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);\n \t\t\t\tif (o->color_moved_ws_handling &\n \t\t\t\t    COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 44a3ab1e31..2a1449013b 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -285,7 +285,7 @@ static int find_identical_files(struct hashmap *srcs,\n \tp = hashmap_get_from_hash(srcs,\n \t\t\t\t  hash_filespec(options->repo, target),\n \t\t\t\t  NULL);\n-\tfor (; p; p = hashmap_get_next(srcs, p)) {\n+\tfor (; p; p = hashmap_get_next(srcs, &p->entry)) {\n \t\tint score;\n \t\tstruct diff_filespec *source = p->filespec;\n \ndiff --git a/hashmap.c b/hashmap.c\nindex 777beda347..958a7dfe14 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -191,9 +191,10 @@ void *hashmap_get(const struct hashmap *map, const void *key, const void *keydat\n \treturn *find_entry_ptr(map, key, keydata);\n }\n \n-void *hashmap_get_next(const struct hashmap *map, const void *entry)\n+void *hashmap_get_next(const struct hashmap *map,\n+\t\t\tconst struct hashmap_entry *entry)\n {\n-\tstruct hashmap_entry *e = ((struct hashmap_entry *) entry)->next;\n+\tstruct hashmap_entry *e = entry->next;\n \tfor (; e; e = e->next)\n \t\tif (entry_equals(map, entry, e, NULL))\n \t\t\treturn e;\ndiff --git a/hashmap.h b/hashmap.h\nindex d635e0815a..8f55782dc9 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -318,7 +318,8 @@ static inline void *hashmap_get_from_hash(const struct hashmap *map,\n  * `entry` is the hashmap_entry to start the search from, obtained via a previous\n  * call to `hashmap_get` or `hashmap_get_next`.\n  */\n-void *hashmap_get_next(const struct hashmap *map, const void *entry);\n+void *hashmap_get_next(const struct hashmap *map,\n+\t\t\tconst struct hashmap_entry *entry);\n \n /*\n  * Adds a hashmap entry. This allows to add duplicate entries (i.e.\ndiff --git a/name-hash.c b/name-hash.c\nindex 8b33c5cb59..e90660c94f 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -711,7 +711,7 @@ struct cache_entry *index_file_exists(struct index_state *istate, const char *na\n \twhile (ce) {\n \t\tif (same_name(ce, name, namelen, icase))\n \t\t\treturn ce;\n-\t\tce = hashmap_get_next(&istate->name_hash, ce);\n+\t\tce = hashmap_get_next(&istate->name_hash, &ce->ent);\n \t}\n \treturn NULL;\n }\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex 0c9fd7c996..bf063a2521 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -203,7 +203,7 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\t\tputs(\"NULL\");\n \t\t\twhile (entry) {\n \t\t\t\tputs(get_value(entry));\n-\t\t\t\tentry = hashmap_get_next(&map, entry);\n+\t\t\t\tentry = hashmap_get_next(&map, &entry->ent);\n \t\t\t}\n \n \t\t} else if (!strcmp(\"remove\", cmd) && p1) {\n-- \nEW\n\n"},{"id":"381159","messageId":"20190826024332.3403-7-e@80x24.org","threadId":"51736","inReplyTo":"20190826024332.3403-1-e@80x24.org","subject":"[PATCH 06/11] hashmap_add takes \"struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-26T02:43:27Z","receivedAt":"2019-08-26T02:43:52Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is less error-prone than \"void *\" as the compiler now\ndetects invalid types being passed.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n attr.c                  | 2 +-\n blame.c                 | 2 +-\n builtin/describe.c      | 2 +-\n builtin/difftool.c      | 6 +++---\n builtin/fetch.c         | 2 +-\n config.c                | 2 +-\n diff.c                  | 2 +-\n diffcore-rename.c       | 2 +-\n hashmap.c               | 6 +++---\n hashmap.h               | 4 ++--\n merge-recursive.c       | 4 ++--\n name-hash.c             | 8 ++++----\n packfile.c              | 2 +-\n patch-ids.c             | 2 +-\n range-diff.c            | 2 +-\n ref-filter.c            | 2 +-\n sequencer.c             | 2 +-\n sub-process.c           | 2 +-\n submodule-config.c      | 2 +-\n t/helper/test-hashmap.c | 6 +++---\n 20 files changed, 31 insertions(+), 31 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex a8be7a7b4f..fa26a3e3cb 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -122,7 +122,7 @@ static void attr_hashmap_add(struct attr_hashmap *map,\n \te->keylen = keylen;\n \te->value = value;\n \n-\thashmap_add(&map->map, e);\n+\thashmap_add(&map->map, &e->ent);\n }\n \n struct all_attrs_item {\ndiff --git a/blame.c b/blame.c\nindex 46059410cd..4d20aee435 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -424,7 +424,7 @@ static void get_fingerprint(struct fingerprint *result,\n \t\t\tfound_entry->count += 1;\n \t\t} else {\n \t\t\tentry->count = 1;\n-\t\t\thashmap_add(&result->map, entry);\n+\t\t\thashmap_add(&result->map, &entry->entry);\n \t\t\t++entry;\n \t\t}\n \t}\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 596ddf89a5..f5e0a7e033 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -124,7 +124,7 @@ static void add_to_known_names(const char *path,\n \t\t\te = xmalloc(sizeof(struct commit_name));\n \t\t\toidcpy(&e->peeled, peeled);\n \t\t\thashmap_entry_init(&e->entry, oidhash(peeled));\n-\t\t\thashmap_add(&names, e);\n+\t\t\thashmap_add(&names, &e->entry);\n \t\t\te->path = NULL;\n \t\t}\n \t\te->tag = tag;\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 98ffc04c61..82c146718d 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -168,7 +168,7 @@ static void add_left_or_right(struct hashmap *map, const char *path,\n \t\te = existing;\n \t} else {\n \t\te->left[0] = e->right[0] = '\\0';\n-\t\thashmap_add(map, e);\n+\t\thashmap_add(map, &e->entry);\n \t}\n \tstrlcpy(is_right ? e->right : e->left, content, PATH_MAX);\n }\n@@ -235,7 +235,7 @@ static void changed_files(struct hashmap *result, const char *index_path,\n \t\tstruct path_entry *entry;\n \t\tFLEX_ALLOC_STR(entry, path, buf.buf);\n \t\thashmap_entry_init(&entry->entry, strhash(buf.buf));\n-\t\thashmap_add(result, entry);\n+\t\thashmap_add(result, &entry->entry);\n \t}\n \tfclose(fp);\n \tif (finish_command(&diff_files))\n@@ -466,7 +466,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\t\t\tfree(entry);\n \t\t\t\tcontinue;\n \t\t\t}\n-\t\t\thashmap_add(&working_tree_dups, entry);\n+\t\t\thashmap_add(&working_tree_dups, &entry->entry);\n \n \t\t\tif (!use_wt_file(workdir, dst_path, &roid)) {\n \t\t\t\tif (checkout_path(rmode, &roid, dst_path,\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex b7d70eee70..909dbde909 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -278,7 +278,7 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map,\n \tFLEX_ALLOC_MEM(ent, refname, refname, len);\n \thashmap_entry_init(&ent->ent, strhash(refname));\n \toidcpy(&ent->oid, oid);\n-\thashmap_add(map, ent);\n+\thashmap_add(map, &ent->ent);\n \treturn ent;\n }\n \ndiff --git a/config.c b/config.c\nindex 08d866e7de..2243d7c3d6 100644\n--- a/config.c\n+++ b/config.c\n@@ -1885,7 +1885,7 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha\n \t\thashmap_entry_init(&e->ent, strhash(key));\n \t\te->key = xstrdup(key);\n \t\tstring_list_init(&e->value_list, 1);\n-\t\thashmap_add(&cs->config_hash, e);\n+\t\thashmap_add(&cs->config_hash, &e->ent);\n \t}\n \tsi = string_list_append_nodup(&e->value_list, xstrdup_or_null(value));\n \ndiff --git a/diff.c b/diff.c\nindex 1168f0cbb9..cc7f06d10d 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1003,7 +1003,7 @@ static void add_lines_to_move_detection(struct diff_options *o,\n \t\tif (prev_line && prev_line->es->s == o->emitted_symbols->buf[n].s)\n \t\t\tprev_line->next_line = key;\n \n-\t\thashmap_add(hm, key);\n+\t\thashmap_add(hm, &key->ent);\n \t\tprev_line = key;\n \t}\n }\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 2a1449013b..4670a40179 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -330,7 +330,7 @@ static void insert_file_table(struct repository *r,\n \tentry->filespec = filespec;\n \n \thashmap_entry_init(&entry->entry, hash_filespec(r, filespec));\n-\thashmap_add(table, entry);\n+\thashmap_add(table, &entry->entry);\n }\n \n /*\ndiff --git a/hashmap.c b/hashmap.c\nindex 958a7dfe14..1aa1324c3e 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -201,12 +201,12 @@ void *hashmap_get_next(const struct hashmap *map,\n \treturn NULL;\n }\n \n-void hashmap_add(struct hashmap *map, void *entry)\n+void hashmap_add(struct hashmap *map, struct hashmap_entry *entry)\n {\n \tunsigned int b = bucket(map, entry);\n \n \t/* add entry */\n-\t((struct hashmap_entry *) entry)->next = map->table[b];\n+\tentry->next = map->table[b];\n \tmap->table[b] = entry;\n \n \t/* fix size and rehash if appropriate */\n@@ -303,7 +303,7 @@ const void *memintern(const void *data, size_t len)\n \t\tFLEX_ALLOC_MEM(e, data, data, len);\n \t\thashmap_entry_init(&e->ent, hash);\n \t\te->len = len;\n-\t\thashmap_add(&map, e);\n+\t\thashmap_add(&map, &e->ent);\n \t}\n \treturn e->data;\n }\ndiff --git a/hashmap.h b/hashmap.h\nindex 8f55782dc9..6a2fdf451b 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -50,7 +50,7 @@\n  *             FLEX_ALLOC_STR(e, value, value);\n  *             hashmap_entry_init(&e->ent, memhash(&key, sizeof(long)));\n  *             e->key = key;\n- *             hashmap_add(&map, e);\n+ *             hashmap_add(&map, &e->ent);\n  *         }\n  *\n  *         if (!strcmp(\"print_all_by_key\", action)) {\n@@ -328,7 +328,7 @@ void *hashmap_get_next(const struct hashmap *map,\n  * `map` is the hashmap structure.\n  * `entry` is the entry to add.\n  */\n-void hashmap_add(struct hashmap *map, void *entry);\n+void hashmap_add(struct hashmap *map, struct hashmap_entry *entry);\n \n /*\n  * Adds or replaces a hashmap entry. If the hashmap contains duplicate\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 6bc4f14ff4..db9b247ece 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -455,7 +455,7 @@ static int save_files_dirs(const struct object_id *oid,\n \n \tFLEX_ALLOC_MEM(entry, path, base->buf, base->len);\n \thashmap_entry_init(&entry->e, path_hash(entry->path));\n-\thashmap_add(&opt->current_file_dir_set, entry);\n+\thashmap_add(&opt->current_file_dir_set, &entry->e);\n \n \tstrbuf_setlen(base, baselen);\n \treturn (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);\n@@ -732,7 +732,7 @@ static char *unique_path(struct merge_options *opt, const char *path, const char\n \n \tFLEX_ALLOC_MEM(entry, path, newpath.buf, newpath.len);\n \thashmap_entry_init(&entry->e, path_hash(entry->path));\n-\thashmap_add(&opt->current_file_dir_set, entry);\n+\thashmap_add(&opt->current_file_dir_set, &entry->e);\n \treturn strbuf_detach(&newpath, NULL);\n }\n \ndiff --git a/name-hash.c b/name-hash.c\nindex e90660c94f..def3576a8b 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -70,7 +70,7 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,\n \t\tFLEX_ALLOC_MEM(dir, name, ce->name, namelen);\n \t\thashmap_entry_init(&dir->ent, memihash(ce->name, namelen));\n \t\tdir->namelen = namelen;\n-\t\thashmap_add(&istate->dir_hash, dir);\n+\t\thashmap_add(&istate->dir_hash, &dir->ent);\n \n \t\t/* recursively add missing parent directories */\n \t\tdir->parent = hash_dir_entry(istate, ce, namelen);\n@@ -107,7 +107,7 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)\n \t\treturn;\n \tce->ce_flags |= CE_HASHED;\n \thashmap_entry_init(&ce->ent, memihash(ce->name, ce_namelen(ce)));\n-\thashmap_add(&istate->name_hash, ce);\n+\thashmap_add(&istate->name_hash, &ce->ent);\n \n \tif (ignore_case)\n \t\tadd_dir_entry(istate, ce);\n@@ -283,7 +283,7 @@ static struct dir_entry *hash_dir_entry_with_parent_and_prefix(\n \t\thashmap_entry_init(&dir->ent, hash);\n \t\tdir->namelen = prefix->len;\n \t\tdir->parent = parent;\n-\t\thashmap_add(&istate->dir_hash, dir);\n+\t\thashmap_add(&istate->dir_hash, &dir->ent);\n \n \t\tif (parent) {\n \t\t\tunlock_dir_mutex(lock_nr);\n@@ -474,7 +474,7 @@ static void *lazy_name_thread_proc(void *_data)\n \t\tstruct cache_entry *ce_k = d->istate->cache[k];\n \t\tce_k->ce_flags |= CE_HASHED;\n \t\thashmap_entry_init(&ce_k->ent, d->lazy_entries[k].hash_name);\n-\t\thashmap_add(&d->istate->name_hash, ce_k);\n+\t\thashmap_add(&d->istate->name_hash, &ce_k->ent);\n \t}\n \n \treturn NULL;\ndiff --git a/packfile.c b/packfile.c\nindex 96535eb86b..f7402c470b 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1488,7 +1488,7 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,\n \tif (!delta_base_cache.cmpfn)\n \t\thashmap_init(&delta_base_cache, delta_base_cache_hash_cmp, NULL, 0);\n \thashmap_entry_init(&ent->ent, pack_entry_hash(p, base_offset));\n-\thashmap_add(&delta_base_cache, ent);\n+\thashmap_add(&delta_base_cache, &ent->ent);\n }\n \n int packed_object_info(struct repository *r, struct packed_git *p,\ndiff --git a/patch-ids.c b/patch-ids.c\nindex a2da711678..f87b62bf58 100644\n--- a/patch-ids.c\n+++ b/patch-ids.c\n@@ -116,6 +116,6 @@ struct patch_id *add_commit_patch_id(struct commit *commit,\n \t\treturn NULL;\n \t}\n \n-\thashmap_add(&ids->patches, key);\n+\thashmap_add(&ids->patches, &key->ent);\n \treturn key;\n }\ndiff --git a/range-diff.c b/range-diff.c\nindex 32b29f9594..96f955d84d 100644\n--- a/range-diff.c\n+++ b/range-diff.c\n@@ -218,7 +218,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n \t\tutil->patch = a->items[i].string;\n \t\tutil->diff = util->patch + util->diff_offset;\n \t\thashmap_entry_init(&util->e, strhash(util->diff));\n-\t\thashmap_add(&map, util);\n+\t\thashmap_add(&map, &util->e);\n \t}\n \n \t/* Now try to find exact matches in b */\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 206014c93d..d939ebc6bb 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1568,7 +1568,7 @@ static void populate_worktree_map(struct hashmap *map, struct worktree **worktre\n \t\t\thashmap_entry_init(&entry->ent,\n \t\t\t\t\tstrhash(worktrees[i]->head_ref));\n \n-\t\t\thashmap_add(map, entry);\n+\t\t\thashmap_add(map, &entry->ent);\n \t\t}\n \t}\n }\ndiff --git a/sequencer.c b/sequencer.c\nindex 1140cdf526..ee11cda7e7 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4539,7 +4539,7 @@ static const char *label_oid(struct object_id *oid, const char *label,\n \n \tFLEX_ALLOC_STR(labels_entry, label, label);\n \thashmap_entry_init(&labels_entry->entry, strihash(label));\n-\thashmap_add(&state->labels, labels_entry);\n+\thashmap_add(&state->labels, &labels_entry->entry);\n \n \tFLEX_ALLOC_STR(string_entry, string, label);\n \toidcpy(&string_entry->entry.oid, oid);\ndiff --git a/sub-process.c b/sub-process.c\nindex 9847dad6fc..d58e069855 100644\n--- a/sub-process.c\n+++ b/sub-process.c\n@@ -105,7 +105,7 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co\n \t\treturn err;\n \t}\n \n-\thashmap_add(hashmap, entry);\n+\thashmap_add(hashmap, &entry->ent);\n \treturn 0;\n }\n \ndiff --git a/submodule-config.c b/submodule-config.c\nindex 4aa02e280e..a3bbd9fd6f 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -149,7 +149,7 @@ static void cache_add(struct submodule_cache *cache,\n \tstruct submodule_entry *e = xmalloc(sizeof(*e));\n \thashmap_entry_init(&e->ent, hash);\n \te->config = submodule;\n-\thashmap_add(&cache->for_name, e);\n+\thashmap_add(&cache->for_name, &e->ent);\n }\n \n static const struct submodule *cache_lookup_path(struct submodule_cache *cache,\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex bf063a2521..49e715f1cd 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -104,7 +104,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)\n \t\t\t/* add entries */\n \t\t\tfor (i = 0; i < TEST_SIZE; i++) {\n \t\t\t\thashmap_entry_init(&entries[i]->ent, hashes[i]);\n-\t\t\t\thashmap_add(&map, entries[i]);\n+\t\t\t\thashmap_add(&map, &entries[i]->ent);\n \t\t\t}\n \n \t\t\thashmap_free(&map, 0);\n@@ -117,7 +117,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)\n \t\tj = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE;\n \t\tfor (i = 0; i < j; i++) {\n \t\t\thashmap_entry_init(&entries[i]->ent, hashes[i]);\n-\t\t\thashmap_add(&map, entries[i]);\n+\t\t\thashmap_add(&map, &entries[i]->ent);\n \t\t}\n \n \t\tfor (j = 0; j < rounds; j++) {\n@@ -179,7 +179,7 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\tentry = alloc_test_entry(hash, p1, p2);\n \n \t\t\t/* add to hashmap */\n-\t\t\thashmap_add(&map, entry);\n+\t\t\thashmap_add(&map, &entry->ent);\n \n \t\t} else if (!strcmp(\"put\", cmd) && p1 && p2) {\n \n-- \nEW\n\n"},{"id":"381160","messageId":"20190826024332.3403-8-e@80x24.org","threadId":"51736","inReplyTo":"20190826024332.3403-1-e@80x24.org","subject":"[PATCH 07/11] hashmap_get takes \"const struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-26T02:43:28Z","receivedAt":"2019-08-26T02:43:55Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is less error-prone than \"const void *\" as the compiler\nnow detects invalid types being passed.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n attr.c                | 2 +-\n blame.c               | 6 +++---\n builtin/difftool.c    | 5 +++--\n builtin/fast-export.c | 2 +-\n config.c              | 2 +-\n diff.c                | 4 ++--\n hashmap.c             | 5 +++--\n hashmap.h             | 8 +++++---\n merge-recursive.c     | 4 ++--\n name-hash.c           | 2 +-\n patch-ids.c           | 2 +-\n revision.c            | 3 ++-\n sub-process.c         | 2 +-\n submodule-config.c    | 4 ++--\n 14 files changed, 28 insertions(+), 23 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex fa26a3e3cb..9bdef61cc3 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -101,7 +101,7 @@ static void *attr_hashmap_get(struct attr_hashmap *map,\n \thashmap_entry_init(&k.ent, memhash(key, keylen));\n \tk.key = key;\n \tk.keylen = keylen;\n-\te = hashmap_get(&map->map, &k, NULL);\n+\te = hashmap_get(&map->map, &k.ent, NULL);\n \n \treturn e ? e->value : NULL;\n }\ndiff --git a/blame.c b/blame.c\nindex 4d20aee435..73ffb59403 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -419,7 +419,7 @@ static void get_fingerprint(struct fingerprint *result,\n \t\t\tcontinue;\n \t\thashmap_entry_init(&entry->entry, hash);\n \n-\t\tfound_entry = hashmap_get(&result->map, entry, NULL);\n+\t\tfound_entry = hashmap_get(&result->map, &entry->entry, NULL);\n \t\tif (found_entry) {\n \t\t\tfound_entry->count += 1;\n \t\t} else {\n@@ -452,7 +452,7 @@ static int fingerprint_similarity(struct fingerprint *a, struct fingerprint *b)\n \thashmap_iter_init(&b->map, &iter);\n \n \twhile ((entry_b = hashmap_iter_next(&iter))) {\n-\t\tif ((entry_a = hashmap_get(&a->map, entry_b, NULL))) {\n+\t\tif ((entry_a = hashmap_get(&a->map, &entry_b->entry, NULL))) {\n \t\t\tintersection += entry_a->count < entry_b->count ?\n \t\t\t\t\tentry_a->count : entry_b->count;\n \t\t}\n@@ -471,7 +471,7 @@ static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b)\n \thashmap_iter_init(&b->map, &iter);\n \n \twhile ((entry_b = hashmap_iter_next(&iter))) {\n-\t\tif ((entry_a = hashmap_get(&a->map, entry_b, NULL))) {\n+\t\tif ((entry_a = hashmap_get(&a->map, &entry_b->entry, NULL))) {\n \t\t\tif (entry_a->count <= entry_b->count)\n \t\t\t\thashmap_remove(&a->map, entry_b, NULL);\n \t\t\telse\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 82c146718d..f41298d199 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -162,7 +162,7 @@ static void add_left_or_right(struct hashmap *map, const char *path,\n \n \tFLEX_ALLOC_STR(e, path, path);\n \thashmap_entry_init(&e->entry, strhash(path));\n-\texisting = hashmap_get(map, e, NULL);\n+\texisting = hashmap_get(map, &e->entry, NULL);\n \tif (existing) {\n \t\tfree(e);\n \t\te = existing;\n@@ -462,7 +462,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\t\t/* Avoid duplicate working_tree entries */\n \t\t\tFLEX_ALLOC_STR(entry, path, dst_path);\n \t\t\thashmap_entry_init(&entry->entry, strhash(dst_path));\n-\t\t\tif (hashmap_get(&working_tree_dups, entry, NULL)) {\n+\t\t\tif (hashmap_get(&working_tree_dups, &entry->entry,\n+\t\t\t\t\tNULL)) {\n \t\t\t\tfree(entry);\n \t\t\t\tcontinue;\n \t\t\t}\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex f30a92a4d3..081cdd70c9 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -152,7 +152,7 @@ static const void *anonymize_mem(struct hashmap *map,\n \thashmap_entry_init(&key.hash, hash);\n \tkey.orig = orig;\n \tkey.orig_len = *len;\n-\tret = hashmap_get(map, &key, NULL);\n+\tret = hashmap_get(map, &key.hash, NULL);\n \n \tif (!ret) {\n \t\tret = xmalloc(sizeof(*ret));\ndiff --git a/config.c b/config.c\nindex 2243d7c3d6..1a1b6675fd 100644\n--- a/config.c\n+++ b/config.c\n@@ -1863,7 +1863,7 @@ static struct config_set_element *configset_find_element(struct config_set *cs,\n \n \thashmap_entry_init(&k.ent, strhash(normalized_key));\n \tk.key = normalized_key;\n-\tfound_entry = hashmap_get(&cs->config_hash, &k, NULL);\n+\tfound_entry = hashmap_get(&cs->config_hash, &k.ent, NULL);\n \tfree(normalized_key);\n \treturn found_entry;\n }\ndiff --git a/diff.c b/diff.c\nindex cc7f06d10d..72d3c6aa19 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1144,13 +1144,13 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\tcase DIFF_SYMBOL_PLUS:\n \t\t\thm = del_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tmatch = hashmap_get(hm, key, NULL);\n+\t\t\tmatch = hashmap_get(hm, &key->ent, NULL);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tcase DIFF_SYMBOL_MINUS:\n \t\t\thm = add_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tmatch = hashmap_get(hm, key, NULL);\n+\t\t\tmatch = hashmap_get(hm, &key->ent, NULL);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tdefault:\ndiff --git a/hashmap.c b/hashmap.c\nindex 1aa1324c3e..f02ac41758 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -186,7 +186,8 @@ void hashmap_free(struct hashmap *map, int free_entries)\n \tmemset(map, 0, sizeof(*map));\n }\n \n-void *hashmap_get(const struct hashmap *map, const void *key, const void *keydata)\n+void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n+\t\tconst void *keydata)\n {\n \treturn *find_entry_ptr(map, key, keydata);\n }\n@@ -297,7 +298,7 @@ const void *memintern(const void *data, size_t len)\n \t/* lookup interned string in pool */\n \thashmap_entry_init(&key.ent, hash);\n \tkey.len = len;\n-\te = hashmap_get(&map, &key, data);\n+\te = hashmap_get(&map, &key.ent, data);\n \tif (!e) {\n \t\t/* not found: create it */\n \t\tFLEX_ALLOC_MEM(e, data, data, len);\ndiff --git a/hashmap.h b/hashmap.h\nindex 6a2fdf451b..dea369868d 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -74,7 +74,8 @@\n  *             e->key = key;\n  *\n  *             flags |= COMPARE_VALUE;\n- *             printf(\"%sfound\\n\", hashmap_get(&map, e, NULL) ? \"\" : \"not \");\n+ *             printf(\"%sfound\\n\",\n+ *                    hashmap_get(&map, &e->ent, NULL) ? \"\" : \"not \");\n  *             free(e);\n  *         }\n  *\n@@ -84,7 +85,8 @@\n  *             k.key = key;\n  *\n  *             flags |= COMPARE_VALUE;\n- *             printf(\"%sfound\\n\", hashmap_get(&map, &k, value) ? \"\" : \"not \");\n+ *             printf(\"%sfound\\n\",\n+ *                    hashmap_get(&map, &k->ent, value) ? \"\" : \"not \");\n  *         }\n  *\n  *         if (!strcmp(\"end\", action)) {\n@@ -286,7 +288,7 @@ static inline unsigned int hashmap_get_size(struct hashmap *map)\n  * If an entry with matching hash code is found, `key` and `keydata` are passed\n  * to `hashmap_cmp_fn` to decide whether the entry matches the key.\n  */\n-void *hashmap_get(const struct hashmap *map, const void *key,\n+void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n \t\t\t const void *keydata);\n \n /*\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex db9b247ece..2d31a3e279 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -63,7 +63,7 @@ static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,\n \t\treturn NULL;\n \thashmap_entry_init(&key.ent, strhash(dir));\n \tkey.dir = dir;\n-\treturn hashmap_get(hashmap, &key, NULL);\n+\treturn hashmap_get(hashmap, &key.ent, NULL);\n }\n \n static int dir_rename_cmp(const void *unused_cmp_data,\n@@ -99,7 +99,7 @@ static struct collision_entry *collision_find_entry(struct hashmap *hashmap,\n \n \thashmap_entry_init(&key.ent, strhash(target_file));\n \tkey.target_file = target_file;\n-\treturn hashmap_get(hashmap, &key, NULL);\n+\treturn hashmap_get(hashmap, &key.ent, NULL);\n }\n \n static int collision_cmp(void *unused_cmp_data,\ndiff --git a/name-hash.c b/name-hash.c\nindex def3576a8b..7368913613 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -35,7 +35,7 @@ static struct dir_entry *find_dir_entry__hash(struct index_state *istate,\n \tstruct dir_entry key;\n \thashmap_entry_init(&key.ent, hash);\n \tkey.namelen = namelen;\n-\treturn hashmap_get(&istate->dir_hash, &key, name);\n+\treturn hashmap_get(&istate->dir_hash, &key.ent, name);\n }\n \n static struct dir_entry *find_dir_entry(struct index_state *istate,\ndiff --git a/patch-ids.c b/patch-ids.c\nindex f87b62bf58..437f29e42c 100644\n--- a/patch-ids.c\n+++ b/patch-ids.c\n@@ -99,7 +99,7 @@ struct patch_id *has_commit_patch_id(struct commit *commit,\n \tif (init_patch_id_entry(&patch, commit, ids))\n \t\treturn NULL;\n \n-\treturn hashmap_get(&ids->patches, &patch, NULL);\n+\treturn hashmap_get(&ids->patches, &patch.ent, NULL);\n }\n \n struct patch_id *add_commit_patch_id(struct commit *commit,\ndiff --git a/revision.c b/revision.c\nindex 3461c78883..4336281286 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -147,7 +147,8 @@ static void paths_and_oids_insert(struct hashmap *map,\n \tkey.path = (char *)path;\n \toidset_init(&key.trees, 0);\n \n-\tif (!(entry = (struct path_and_oids_entry *)hashmap_get(map, &key, NULL))) {\n+\tentry = hashmap_get(map, &key.ent, NULL);\n+\tif (!entry) {\n \t\tentry = xcalloc(1, sizeof(struct path_and_oids_entry));\n \t\thashmap_entry_init(&entry->ent, hash);\n \t\tentry->path = xstrdup(key.path);\ndiff --git a/sub-process.c b/sub-process.c\nindex d58e069855..debd86bb68 100644\n--- a/sub-process.c\n+++ b/sub-process.c\n@@ -22,7 +22,7 @@ struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const ch\n \n \thashmap_entry_init(&key.ent, strhash(cmd));\n \tkey.cmd = cmd;\n-\treturn hashmap_get(hashmap, &key, NULL);\n+\treturn hashmap_get(hashmap, &key.ent, NULL);\n }\n \n int subprocess_read_status(int fd, struct strbuf *status)\ndiff --git a/submodule-config.c b/submodule-config.c\nindex a3bbd9fd6f..58d585cd7d 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -166,7 +166,7 @@ static const struct submodule *cache_lookup_path(struct submodule_cache *cache,\n \thashmap_entry_init(&key.ent, hash);\n \tkey.config = &key_config;\n \n-\tentry = hashmap_get(&cache->for_path, &key, NULL);\n+\tentry = hashmap_get(&cache->for_path, &key.ent, NULL);\n \tif (entry)\n \t\treturn entry->config;\n \treturn NULL;\n@@ -186,7 +186,7 @@ static struct submodule *cache_lookup_name(struct submodule_cache *cache,\n \thashmap_entry_init(&key.ent, hash);\n \tkey.config = &key_config;\n \n-\tentry = hashmap_get(&cache->for_name, &key, NULL);\n+\tentry = hashmap_get(&cache->for_name, &key.ent, NULL);\n \tif (entry)\n \t\treturn entry->config;\n \treturn NULL;\n-- \nEW\n\n"},{"id":"381161","messageId":"20190826024332.3403-9-e@80x24.org","threadId":"51736","inReplyTo":"20190826024332.3403-1-e@80x24.org","subject":"[PATCH 08/11] hashmap_remove takes \"const struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-26T02:43:29Z","receivedAt":"2019-08-26T02:43:57Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is less error-prone than \"const void *\" as the compiler\nnow detects invalid types being passed.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n blame.c            | 2 +-\n hashmap.c          | 3 ++-\n hashmap.h          | 2 +-\n merge-recursive.c  | 2 +-\n name-hash.c        | 4 ++--\n packfile.c         | 2 +-\n range-diff.c       | 2 +-\n sub-process.c      | 2 +-\n submodule-config.c | 2 +-\n 9 files changed, 11 insertions(+), 10 deletions(-)\n\ndiff --git a/blame.c b/blame.c\nindex 73ffb59403..00f8f3fb0a 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -473,7 +473,7 @@ static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b)\n \twhile ((entry_b = hashmap_iter_next(&iter))) {\n \t\tif ((entry_a = hashmap_get(&a->map, &entry_b->entry, NULL))) {\n \t\t\tif (entry_a->count <= entry_b->count)\n-\t\t\t\thashmap_remove(&a->map, entry_b, NULL);\n+\t\t\t\thashmap_remove(&a->map, &entry_b->entry, NULL);\n \t\t\telse\n \t\t\t\tentry_a->count -= entry_b->count;\n \t\t}\ndiff --git a/hashmap.c b/hashmap.c\nindex f02ac41758..efcb6420fc 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -218,7 +218,8 @@ void hashmap_add(struct hashmap *map, struct hashmap_entry *entry)\n \t}\n }\n \n-void *hashmap_remove(struct hashmap *map, const void *key, const void *keydata)\n+void *hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n+\t\tconst void *keydata)\n {\n \tstruct hashmap_entry *old;\n \tstruct hashmap_entry **e = find_entry_ptr(map, key, keydata);\ndiff --git a/hashmap.h b/hashmap.h\nindex dea369868d..c8d5314667 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -349,7 +349,7 @@ void *hashmap_put(struct hashmap *map, void *entry);\n  *\n  * Argument explanation is the same as in `hashmap_get`.\n  */\n-void *hashmap_remove(struct hashmap *map, const void *key,\n+void *hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n \t\tconst void *keydata);\n \n /*\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 2d31a3e279..f60451d396 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2001,7 +2001,7 @@ static void remove_hashmap_entries(struct hashmap *dir_renames,\n \n \tfor (i = 0; i < items_to_remove->nr; i++) {\n \t\tentry = items_to_remove->items[i].util;\n-\t\thashmap_remove(dir_renames, entry, NULL);\n+\t\thashmap_remove(dir_renames, &entry->ent, NULL);\n \t}\n \tstring_list_clear(items_to_remove, 0);\n }\ndiff --git a/name-hash.c b/name-hash.c\nindex 7368913613..f64c52bfa2 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -95,7 +95,7 @@ static void remove_dir_entry(struct index_state *istate, struct cache_entry *ce)\n \tstruct dir_entry *dir = hash_dir_entry(istate, ce, ce_namelen(ce));\n \twhile (dir && !(--dir->nr)) {\n \t\tstruct dir_entry *parent = dir->parent;\n-\t\thashmap_remove(&istate->dir_hash, dir, NULL);\n+\t\thashmap_remove(&istate->dir_hash, &dir->ent, NULL);\n \t\tfree(dir);\n \t\tdir = parent;\n \t}\n@@ -626,7 +626,7 @@ void remove_name_hash(struct index_state *istate, struct cache_entry *ce)\n \tif (!istate->name_hash_initialized || !(ce->ce_flags & CE_HASHED))\n \t\treturn;\n \tce->ce_flags &= ~CE_HASHED;\n-\thashmap_remove(&istate->name_hash, ce, ce);\n+\thashmap_remove(&istate->name_hash, &ce->ent, ce);\n \n \tif (ignore_case)\n \t\tremove_dir_entry(istate, ce);\ndiff --git a/packfile.c b/packfile.c\nindex f7402c470b..3edd648de0 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1423,7 +1423,7 @@ static int in_delta_base_cache(struct packed_git *p, off_t base_offset)\n  */\n static void detach_delta_base_cache_entry(struct delta_base_cache_entry *ent)\n {\n-\thashmap_remove(&delta_base_cache, ent, &ent->key);\n+\thashmap_remove(&delta_base_cache, &ent->ent, &ent->key);\n \tlist_del(&ent->lru);\n \tdelta_base_cached -= ent->size;\n \tfree(ent);\ndiff --git a/range-diff.c b/range-diff.c\nindex 96f955d84d..c51cfd5556 100644\n--- a/range-diff.c\n+++ b/range-diff.c\n@@ -229,7 +229,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n \t\tutil->patch = b->items[i].string;\n \t\tutil->diff = util->patch + util->diff_offset;\n \t\thashmap_entry_init(&util->e, strhash(util->diff));\n-\t\tother = hashmap_remove(&map, util, NULL);\n+\t\tother = hashmap_remove(&map, &util->e, NULL);\n \t\tif (other) {\n \t\t\tif (other->matching >= 0)\n \t\t\t\tBUG(\"already assigned!\");\ndiff --git a/sub-process.c b/sub-process.c\nindex debd86bb68..99fccef592 100644\n--- a/sub-process.c\n+++ b/sub-process.c\n@@ -58,7 +58,7 @@ void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry)\n \tkill(entry->process.pid, SIGTERM);\n \tfinish_command(&entry->process);\n \n-\thashmap_remove(hashmap, entry, NULL);\n+\thashmap_remove(hashmap, &entry->ent, NULL);\n }\n \n static void subprocess_exit_handler(struct child_process *process)\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 58d585cd7d..7486745a6a 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -137,7 +137,7 @@ static void cache_remove_path(struct submodule_cache *cache,\n \tstruct submodule_entry *removed;\n \thashmap_entry_init(&e.ent, hash);\n \te.config = submodule;\n-\tremoved = hashmap_remove(&cache->for_path, &e, NULL);\n+\tremoved = hashmap_remove(&cache->for_path, &e.ent, NULL);\n \tfree(removed);\n }\n \n-- \nEW\n\n"},{"id":"381162","messageId":"20190826024332.3403-10-e@80x24.org","threadId":"51736","inReplyTo":"20190826024332.3403-1-e@80x24.org","subject":"[PATCH 09/11] hashmap_put takes \"struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-26T02:43:30Z","receivedAt":"2019-08-26T02:44:00Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is less error-prone than \"void *\" as the compiler now\ndetects invalid types being passed.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n builtin/fast-export.c   | 2 +-\n hashmap.c               | 2 +-\n hashmap.h               | 2 +-\n merge-recursive.c       | 4 ++--\n oidmap.c                | 2 +-\n refs.c                  | 5 ++++-\n remote.c                | 2 +-\n revision.c              | 2 +-\n sequencer.c             | 2 +-\n submodule-config.c      | 2 +-\n t/helper/test-hashmap.c | 2 +-\n 11 files changed, 15 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 081cdd70c9..654bfce8d5 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -161,7 +161,7 @@ static const void *anonymize_mem(struct hashmap *map,\n \t\tret->orig_len = *len;\n \t\tret->anon = generate(orig, len);\n \t\tret->anon_len = *len;\n-\t\thashmap_put(map, ret);\n+\t\thashmap_put(map, &ret->hash);\n \t}\n \n \t*len = ret->anon_len;\ndiff --git a/hashmap.c b/hashmap.c\nindex efcb6420fc..2dd9912e13 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -241,7 +241,7 @@ void *hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n \treturn old;\n }\n \n-void *hashmap_put(struct hashmap *map, void *entry)\n+void *hashmap_put(struct hashmap *map, struct hashmap_entry *entry)\n {\n \tstruct hashmap_entry *old = hashmap_remove(map, entry, NULL);\n \thashmap_add(map, entry);\ndiff --git a/hashmap.h b/hashmap.h\nindex c8d5314667..b62ee2e7b9 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -340,7 +340,7 @@ void hashmap_add(struct hashmap *map, struct hashmap_entry *entry);\n  * `entry` is the entry to add or replace.\n  * Returns the replaced entry, or NULL if not found (i.e. the entry was added).\n  */\n-void *hashmap_put(struct hashmap *map, void *entry);\n+void *hashmap_put(struct hashmap *map, struct hashmap_entry *entry);\n \n /*\n  * Removes a hashmap entry matching the specified key. If the hashmap contains\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex f60451d396..a685b4fb69 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2229,7 +2229,7 @@ static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs)\n \t\tif (!entry) {\n \t\t\tentry = xmalloc(sizeof(*entry));\n \t\t\tdir_rename_entry_init(entry, old_dir);\n-\t\t\thashmap_put(dir_renames, entry);\n+\t\t\thashmap_put(dir_renames, &entry->ent);\n \t\t} else {\n \t\t\tfree(old_dir);\n \t\t}\n@@ -2360,7 +2360,7 @@ static void compute_collisions(struct hashmap *collisions,\n \t\t\t\t\t\tsizeof(struct collision_entry));\n \t\t\thashmap_entry_init(&collision_ent->ent,\n \t\t\t\t\t\tstrhash(new_path));\n-\t\t\thashmap_put(collisions, collision_ent);\n+\t\t\thashmap_put(collisions, &collision_ent->ent);\n \t\t\tcollision_ent->target_file = new_path;\n \t\t} else {\n \t\t\tfree(new_path);\ndiff --git a/oidmap.c b/oidmap.c\nindex 6d6e840d03..cd22b3a8bf 100644\n--- a/oidmap.c\n+++ b/oidmap.c\n@@ -51,5 +51,5 @@ void *oidmap_put(struct oidmap *map, void *entry)\n \t\toidmap_init(map, 0);\n \n \thashmap_entry_init(&to_put->internal_entry, oidhash(&to_put->oid));\n-\treturn hashmap_put(&map->map, to_put);\n+\treturn hashmap_put(&map->map, &to_put->internal_entry);\n }\ndiff --git a/refs.c b/refs.c\nindex c43ec59c6e..3e55031256 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1863,10 +1863,13 @@ static void register_ref_store_map(struct hashmap *map,\n \t\t\t\t   struct ref_store *refs,\n \t\t\t\t   const char *name)\n {\n+\tstruct ref_store_hash_entry *entry;\n+\n \tif (!map->tablesize)\n \t\thashmap_init(map, ref_store_hash_cmp, NULL, 0);\n \n-\tif (hashmap_put(map, alloc_ref_store_hash_entry(name, refs)))\n+\tentry = alloc_ref_store_hash_entry(name, refs);\n+\tif (hashmap_put(map, &entry->ent))\n \t\tBUG(\"%s ref_store '%s' initialized twice\", type, name);\n }\n \ndiff --git a/remote.c b/remote.c\nindex dc09172e9d..248d60e0ad 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -161,7 +161,7 @@ static struct remote *make_remote(const char *name, int len)\n \tremotes[remotes_nr++] = ret;\n \n \thashmap_entry_init(&ret->ent, hash);\n-\treplaced = hashmap_put(&remotes_hash, ret);\n+\treplaced = hashmap_put(&remotes_hash, &ret->ent);\n \tassert(replaced == NULL);  /* no previous entry overwritten */\n \treturn ret;\n }\ndiff --git a/revision.c b/revision.c\nindex 4336281286..a7e2339064 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -153,7 +153,7 @@ static void paths_and_oids_insert(struct hashmap *map,\n \t\thashmap_entry_init(&entry->ent, hash);\n \t\tentry->path = xstrdup(key.path);\n \t\toidset_init(&entry->trees, 16);\n-\t\thashmap_put(map, entry);\n+\t\thashmap_put(map, &entry->ent);\n \t}\n \n \toidset_insert(&entry->trees, oid);\ndiff --git a/sequencer.c b/sequencer.c\nindex ee11cda7e7..b4ef70e260 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -5254,7 +5254,7 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\t\tentry->i = i;\n \t\t\thashmap_entry_init(&entry->entry,\n \t\t\t\t\tstrhash(entry->subject));\n-\t\t\thashmap_put(&subject2item, entry);\n+\t\t\thashmap_put(&subject2item, &entry->entry);\n \t\t}\n \t}\n \ndiff --git a/submodule-config.c b/submodule-config.c\nindex 7486745a6a..9248c5ea5b 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -125,7 +125,7 @@ static void cache_put_path(struct submodule_cache *cache,\n \tstruct submodule_entry *e = xmalloc(sizeof(*e));\n \thashmap_entry_init(&e->ent, hash);\n \te->config = submodule;\n-\thashmap_put(&cache->for_path, e);\n+\thashmap_put(&cache->for_path, &e->ent);\n }\n \n static void cache_remove_path(struct submodule_cache *cache,\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex 49e715f1cd..de2bd083b9 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -187,7 +187,7 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\tentry = alloc_test_entry(hash, p1, p2);\n \n \t\t\t/* add / replace entry */\n-\t\t\tentry = hashmap_put(&map, entry);\n+\t\t\tentry = hashmap_put(&map, &entry->ent);\n \n \t\t\t/* print and free replaced entry, if any */\n \t\t\tputs(entry ? get_value(entry) : \"NULL\");\n-- \nEW\n\n"},{"id":"381163","messageId":"20190826024332.3403-11-e@80x24.org","threadId":"51736","inReplyTo":"20190826024332.3403-1-e@80x24.org","subject":"[PATCH 10/11] introduce container_of macro","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-26T02:43:31Z","receivedAt":"2019-08-26T02:44:04Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This macro is popular within the Linux kernel for supporting\nintrusive data structures such as linked lists, red-black trees,\nand chained hash tables while allowing the compiler to do\ntype checking.\n\nI intend to use this to remove the limitation of \"hashmap_entry\"\nbeing location-dependent and to allow more compile-time type\nchecking.\n\nThis macro already exists in our source as \"list_entry\" in\nlist.h and making \"list_entry\" an alias to \"container_of\"\nas the Linux kernel has done is a possibility.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n git-compat-util.h | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 83be89de0a..4cc2c8283a 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -1312,4 +1312,14 @@ void unleak_memory(const void *ptr, size_t len);\n  */\n #include \"banned.h\"\n \n+/*\n+ * container_of - Get the address of an object containing a field.\n+ *\n+ * @ptr: pointer to the field.\n+ * @type: type of the object.\n+ * @member: name of the field within the object.\n+ */\n+#define container_of(ptr, type, member) \\\n+\t((type *) ((char *)(ptr) - offsetof(type, member)))\n+\n #endif\n-- \nEW\n\n"},{"id":"381164","messageId":"20190826024332.3403-12-e@80x24.org","threadId":"51736","inReplyTo":"20190826024332.3403-1-e@80x24.org","subject":"[PATCH 11/11] hashmap_get_next returns \"struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-26T02:43:32Z","receivedAt":"2019-08-26T02:44:07Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is a step towards removing the requirement for\nhashmap_entry being the first field of a struct.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n diff.c                  | 19 ++++++++++++-------\n diffcore-rename.c       | 11 +++++++----\n hashmap.c               |  2 +-\n hashmap.h               | 12 ++++++++----\n name-hash.c             |  8 +++++---\n t/helper/test-hashmap.c | 10 ++++++----\n 6 files changed, 39 insertions(+), 23 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 72d3c6aa19..663b5d01f8 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1035,8 +1035,10 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,\n {\n \tint i;\n \tchar *got_match = xcalloc(1, pmb_nr);\n+\tstruct hashmap_entry *ent = &match->ent;\n \n-\tfor (; match; match = hashmap_get_next(hm, &match->ent)) {\n+\tfor (; ent; ent = hashmap_get_next(hm, ent)) {\n+\t\tmatch = container_of(ent, struct moved_entry, ent);\n \t\tfor (i = 0; i < pmb_nr; i++) {\n \t\t\tstruct moved_entry *prev = pmb[i].match;\n \t\t\tstruct moved_entry *cur = (prev && prev->next_line) ?\n@@ -1135,8 +1137,9 @@ static void mark_color_as_moved(struct diff_options *o,\n \n \tfor (n = 0; n < o->emitted_symbols->nr; n++) {\n \t\tstruct hashmap *hm = NULL;\n+\t\tstruct hashmap_entry *ent = NULL;\n \t\tstruct moved_entry *key;\n-\t\tstruct moved_entry *match = NULL;\n+\t\tstruct moved_entry *match;\n \t\tstruct emitted_diff_symbol *l = &o->emitted_symbols->buf[n];\n \t\tenum diff_symbol last_symbol = 0;\n \n@@ -1144,20 +1147,20 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\tcase DIFF_SYMBOL_PLUS:\n \t\t\thm = del_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tmatch = hashmap_get(hm, &key->ent, NULL);\n+\t\t\tent = hashmap_get(hm, &key->ent, NULL);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tcase DIFF_SYMBOL_MINUS:\n \t\t\thm = add_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tmatch = hashmap_get(hm, &key->ent, NULL);\n+\t\t\tent = hashmap_get(hm, &key->ent, NULL);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tflipped_block = 0;\n \t\t}\n \n-\t\tif (!match) {\n+\t\tif (!ent) {\n \t\t\tint i;\n \n \t\t\tadjust_last_block(o, n, block_length);\n@@ -1169,6 +1172,7 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\t\tlast_symbol = l->s;\n \t\t\tcontinue;\n \t\t}\n+\t\tmatch = container_of(ent, struct moved_entry, ent);\n \n \t\tif (o->color_moved == COLOR_MOVED_PLAIN) {\n \t\t\tlast_symbol = l->s;\n@@ -1189,8 +1193,9 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\t\t * The current line is the start of a new block.\n \t\t\t * Setup the set of potential blocks.\n \t\t\t */\n-\t\t\tfor (; match; match = hashmap_get_next(hm,\n-\t\t\t\t\t\t\t\t&match->ent)) {\n+\t\t\tfor (; ent; ent = hashmap_get_next(hm, ent)) {\n+\t\t\t\tmatch = container_of(ent, struct moved_entry,\n+\t\t\t\t\t\t\tent);\n \t\t\t\tALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);\n \t\t\t\tif (o->color_moved_ws_handling &\n \t\t\t\t    COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 4670a40179..71aa240a68 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -274,7 +274,7 @@ static int find_identical_files(struct hashmap *srcs,\n \t\t\t\tstruct diff_options *options)\n {\n \tint renames = 0;\n-\n+\tstruct hashmap_entry *ent;\n \tstruct diff_filespec *target = rename_dst[dst_index].two;\n \tstruct file_similarity *p, *best = NULL;\n \tint i = 100, best_score = -1;\n@@ -282,12 +282,15 @@ static int find_identical_files(struct hashmap *srcs,\n \t/*\n \t * Find the best source match for specified destination.\n \t */\n-\tp = hashmap_get_from_hash(srcs,\n+\tent = hashmap_get_from_hash(srcs,\n \t\t\t\t  hash_filespec(options->repo, target),\n \t\t\t\t  NULL);\n-\tfor (; p; p = hashmap_get_next(srcs, &p->entry)) {\n+\tfor (; ent; ent = hashmap_get_next(srcs, ent)) {\n \t\tint score;\n-\t\tstruct diff_filespec *source = p->filespec;\n+\t\tstruct diff_filespec *source;\n+\n+\t\tp = container_of(ent, struct file_similarity, entry);\n+\t\tsource = p->filespec;\n \n \t\t/* False hash collision? */\n \t\tif (!oideq(&source->oid, &target->oid))\ndiff --git a/hashmap.c b/hashmap.c\nindex 2dd9912e13..d6434d9ca4 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -192,7 +192,7 @@ void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n \treturn *find_entry_ptr(map, key, keydata);\n }\n \n-void *hashmap_get_next(const struct hashmap *map,\n+struct hashmap_entry *hashmap_get_next(const struct hashmap *map,\n \t\t\tconst struct hashmap_entry *entry)\n {\n \tstruct hashmap_entry *e = entry->next;\ndiff --git a/hashmap.h b/hashmap.h\nindex b62ee2e7b9..25643dcdc4 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -55,15 +55,19 @@\n  *\n  *         if (!strcmp(\"print_all_by_key\", action)) {\n  *             struct long2string k, *e;\n+ *             struct hashmap_entry *ent;\n  *             hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));\n  *             k.key = key;\n  *\n  *             flags &= ~COMPARE_VALUE;\n- *             e = hashmap_get(&map, &k, NULL);\n- *             if (e) {\n+ *             ent = hashmap_get(&map, &k, NULL);\n+ *             if (ent) {\n+ *                 e = container_of(ent, struct long2string, ent);\n  *                 printf(\"first: %ld %s\\n\", e->key, e->value);\n- *                 while ((e = hashmap_get_next(&map, e)))\n+ *                 while ((ent = hashmap_get_next(&map, ent))) {\n+ *                     e = container_of(ent, struct long2string, ent);\n  *                     printf(\"found more: %ld %s\\n\", e->key, e->value);\n+ *                 }\n  *             }\n  *         }\n  *\n@@ -320,7 +324,7 @@ static inline void *hashmap_get_from_hash(const struct hashmap *map,\n  * `entry` is the hashmap_entry to start the search from, obtained via a previous\n  * call to `hashmap_get` or `hashmap_get_next`.\n  */\n-void *hashmap_get_next(const struct hashmap *map,\n+struct hashmap_entry *hashmap_get_next(const struct hashmap *map,\n \t\t\tconst struct hashmap_entry *entry);\n \n /*\ndiff --git a/name-hash.c b/name-hash.c\nindex f64c52bfa2..6f2779934f 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -703,15 +703,17 @@ void adjust_dirname_case(struct index_state *istate, char *name)\n struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase)\n {\n \tstruct cache_entry *ce;\n+\tstruct hashmap_entry *ent;\n \n \tlazy_init_name_hash(istate);\n \n-\tce = hashmap_get_from_hash(&istate->name_hash,\n+\tent = hashmap_get_from_hash(&istate->name_hash,\n \t\t\t\t   memihash(name, namelen), NULL);\n-\twhile (ce) {\n+\twhile (ent) {\n+\t\tce = container_of(ent, struct cache_entry, ent);\n \t\tif (same_name(ce, name, namelen, icase))\n \t\t\treturn ce;\n-\t\tce = hashmap_get_next(&istate->name_hash, &ce->ent);\n+\t\tent = hashmap_get_next(&istate->name_hash, ent);\n \t}\n \treturn NULL;\n }\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex de2bd083b9..d85b8dc58e 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -194,16 +194,18 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\tfree(entry);\n \n \t\t} else if (!strcmp(\"get\", cmd) && p1) {\n+\t\t\tstruct hashmap_entry *e;\n \n \t\t\t/* lookup entry in hashmap */\n-\t\t\tentry = hashmap_get_from_hash(&map, hash, p1);\n+\t\t\te = hashmap_get_from_hash(&map, hash, p1);\n \n \t\t\t/* print result */\n-\t\t\tif (!entry)\n+\t\t\tif (!e)\n \t\t\t\tputs(\"NULL\");\n-\t\t\twhile (entry) {\n+\t\t\twhile (e) {\n+\t\t\t\tentry = container_of(e, struct test_entry, ent);\n \t\t\t\tputs(get_value(entry));\n-\t\t\t\tentry = hashmap_get_next(&map, &entry->ent);\n+\t\t\t\te = hashmap_get_next(&map, e);\n \t\t\t}\n \n \t\t} else if (!strcmp(\"remove\", cmd) && p1) {\n-- \nEW\n\n"},{"id":"381327","messageId":"nycvar.QRO.7.76.6.1908271108410.46@tvgsbejvaqbjf.bet","threadId":"51736","inReplyTo":"20190826024332.3403-5-e@80x24.org","subject":"Re: [PATCH 04/11] hashmap_entry: detect improper initialization","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-08-27T09:10:20Z","receivedAt":"2019-08-27T09:10:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Eric,\n\nOn Mon, 26 Aug 2019, Eric Wong wrote:\n\n> By renaming the \"hash\" field to \"_hash\", it's easy to spot\n> improper initialization of hashmap_entry structs which\n> can leave \"hashmap_entry.next\" uninitialized.\n\nWould you mind elaborating a bit? This explanation does not enlighten\nme, sadly, all I see is that it makes it (slightly) harder for me to\nmaintain Git for Windows' patches on top of `pu`, as the FSCache patches\naccess that field directly (so even if they rebase cleanly, the build\nbreaks).\n\nCiao,\nDscho\n"},{"id":"381332","messageId":"20190827094923.6qhwqosiucsi43td@whir","threadId":"51736","inReplyTo":"nycvar.QRO.7.76.6.1908271108410.46@tvgsbejvaqbjf.bet","subject":"Re: [PATCH 04/11] hashmap_entry: detect improper initialization","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-27T09:49:23Z","receivedAt":"2019-08-27T09:49:24Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> Hi Eric,\n> \n> On Mon, 26 Aug 2019, Eric Wong wrote:\n> \n> > By renaming the \"hash\" field to \"_hash\", it's easy to spot\n> > improper initialization of hashmap_entry structs which\n> > can leave \"hashmap_entry.next\" uninitialized.\n> \n> Would you mind elaborating a bit? This explanation does not enlighten\n> me, sadly, all I see is that it makes it (slightly) harder for me to\n> maintain Git for Windows' patches on top of `pu`, as the FSCache patches\n> access that field directly (so even if they rebase cleanly, the build\n> breaks).\n\nI renamed it to intentionally break my build.\n\nThat way I could easily spot if there were any other improper\ninitializations of the .hash field.  It's fine to revert,\nactually, it could be more of a \"showing my work\" patch.\n\n(AFAIK, it's a pretty common practice, but maybe not here :x)\n\nI've also pondered adding a\n\"hashmap_entry_hash(const struct hashmap_entry *)\"\naccessor method for reading the field value (but not setting\nit), but it's a bit verbose...\n\nI'm also wondering where/if hashmap offers a real benefit over\nkhash nowadays; the latter ought to have better locality.\nWould like benchmark at some point in the future;\nbut safety fixes first :)\n"},{"id":"381360","messageId":"6414b671-db5b-4422-664d-ffbb8ee1a39a@gmail.com","threadId":"51736","inReplyTo":"20190826024332.3403-2-e@80x24.org","subject":"Re: [PATCH 01/11] diff: use hashmap_entry_init on moved_entry.ent","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-08-27T13:31:03Z","receivedAt":"2019-08-27T13:31:10Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 8/25/2019 10:43 PM, Eric Wong wrote:\n> Otherwise, the hashmap_entry.next field appears to remain\n> uninitialized, which can lead to problems when\n> add_lines_to_move_detection calls hashmap_add.\n> \n> I found this through manual inspection when converting\n> hashmap_add callers to take \"struct hashmap_entry *\".\n> \n> Signed-off-by: Eric Wong <e@80x24.org>\n> ---\n>  diff.c | 3 ++-\n>  1 file changed, 2 insertions(+), 1 deletion(-)\n> \n> diff --git a/diff.c b/diff.c\n> index efe42b341a..02491ee684 100644\n> --- a/diff.c\n> +++ b/diff.c\n> @@ -964,8 +964,9 @@ static struct moved_entry *prepare_entry(struct diff_options *o,\n>  \tstruct moved_entry *ret = xmalloc(sizeof(*ret));\n>  \tstruct emitted_diff_symbol *l = &o->emitted_symbols->buf[line_no];\n>  \tunsigned flags = o->color_moved_ws_handling & XDF_WHITESPACE_FLAGS;\n> +\tunsigned int hash = xdiff_hash_string(l->line, l->len, flags);\n>  \n> -\tret->ent.hash = xdiff_hash_string(l->line, l->len, flags);\n> +\thashmap_entry_init(&ret->ent, hash);\n\nI've typically seen these hashmap_entry_init() calls include the\nhash function in-line instead of saving to a variable. But, this\nlooks fine and is obviously correct.\n\nThanks,\n-Stolee\n"},{"id":"381361","messageId":"557b6f18-c346-f3c8-b623-d97752586670@gmail.com","threadId":"51736","inReplyTo":"20190826024332.3403-4-e@80x24.org","subject":"Re: [PATCH 03/11] hashmap_entry_init takes \"struct hashmap_entry *\"","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-08-27T13:35:57Z","receivedAt":"2019-08-27T13:36:03Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 8/25/2019 10:43 PM, Eric Wong wrote:\n> C compilers do type checking to make life easier for us.  So\n> rely on that and update all hashmap_entry_init callers to take\n> \"struct hashmap_entry *\" to avoid future bugs while improving\n> safety and readability.\n\nOverall I like this change. I'll need to keep it in mind with my\nsparse-checkout work that is adding more hashmap types.\n\nOne _might_ think that this change is relaxing the condition on\nwhere the hashmap_entry appears within the super-struct, but\nthe hashmap internals will still use void* and perform a cast\nto hashmap_entry for hash comparisons.\n \n> Signed-off-by: Eric Wong <e@80x24.org>\n> ---\n>  attr.c                  |  4 ++--\n>  blame.c                 |  2 +-\n>  builtin/describe.c      |  2 +-\n>  builtin/difftool.c      |  6 +++---\n>  builtin/fast-export.c   |  2 +-\n>  builtin/fetch.c         |  2 +-\n>  config.c                |  4 ++--\n>  diffcore-rename.c       |  2 +-\n>  hashmap.c               |  4 ++--\n>  hashmap.h               | 12 ++++++------\n>  merge-recursive.c       | 13 +++++++------\n>  name-hash.c             | 10 +++++-----\n>  packfile.c              |  2 +-\n>  patch-ids.c             |  2 +-\n>  range-diff.c            |  4 ++--\n>  ref-filter.c            |  3 ++-\n>  refs.c                  |  2 +-\n>  remote.c                |  2 +-\n>  revision.c              |  4 ++--\n>  sequencer.c             |  5 +++--\n>  sub-process.c           |  4 ++--\n>  submodule-config.c      | 10 +++++-----\n>  t/helper/test-hashmap.c |  6 +++---\n>  23 files changed, 55 insertions(+), 52 deletions(-)\n> \n> diff --git a/attr.c b/attr.c\n> index 93dc16b59c..a8be7a7b4f 100644\n> --- a/attr.c\n> +++ b/attr.c\n> @@ -98,7 +98,7 @@ static void *attr_hashmap_get(struct attr_hashmap *map,\n>  \tif (!map->map.tablesize)\n>  \t\tattr_hashmap_init(map);\n>  \n> -\thashmap_entry_init(&k, memhash(key, keylen));\n> +\thashmap_entry_init(&k.ent, memhash(key, keylen));\n>  \tk.key = key;\n>  \tk.keylen = keylen;\n>  \te = hashmap_get(&map->map, &k, NULL);\n> @@ -117,7 +117,7 @@ static void attr_hashmap_add(struct attr_hashmap *map,\n>  \t\tattr_hashmap_init(map);\n>  \n>  \te = xmalloc(sizeof(struct attr_hash_entry));\n> -\thashmap_entry_init(e, memhash(key, keylen));\n> +\thashmap_entry_init(&e->ent, memhash(key, keylen));\n>  \te->key = key;\n>  \te->keylen = keylen;\n>  \te->value = value;\n> diff --git a/blame.c b/blame.c\n> index 36a2e7ef11..46059410cd 100644\n> --- a/blame.c\n> +++ b/blame.c\n> @@ -417,7 +417,7 @@ static void get_fingerprint(struct fingerprint *result,\n>  \t\t/* Ignore whitespace pairs */\n>  \t\tif (hash == 0)\n>  \t\t\tcontinue;\n> -\t\thashmap_entry_init(entry, hash);\n> +\t\thashmap_entry_init(&entry->entry, hash);\n>  \n>  \t\tfound_entry = hashmap_get(&result->map, entry, NULL);\n>  \t\tif (found_entry) {\n> diff --git a/builtin/describe.c b/builtin/describe.c\n> index 200154297d..596ddf89a5 100644\n> --- a/builtin/describe.c\n> +++ b/builtin/describe.c\n> @@ -123,7 +123,7 @@ static void add_to_known_names(const char *path,\n>  \t\tif (!e) {\n>  \t\t\te = xmalloc(sizeof(struct commit_name));\n>  \t\t\toidcpy(&e->peeled, peeled);\n> -\t\t\thashmap_entry_init(e, oidhash(peeled));\n> +\t\t\thashmap_entry_init(&e->entry, oidhash(peeled));\n>  \t\t\thashmap_add(&names, e);\n>  \t\t\te->path = NULL;\n>  \t\t}\n> diff --git a/builtin/difftool.c b/builtin/difftool.c\n> index 16eb8b70ea..98ffc04c61 100644\n> --- a/builtin/difftool.c\n> +++ b/builtin/difftool.c\n> @@ -161,7 +161,7 @@ static void add_left_or_right(struct hashmap *map, const char *path,\n>  \tstruct pair_entry *e, *existing;\n>  \n>  \tFLEX_ALLOC_STR(e, path, path);\n> -\thashmap_entry_init(e, strhash(path));\n> +\thashmap_entry_init(&e->entry, strhash(path));\n>  \texisting = hashmap_get(map, e, NULL);\n>  \tif (existing) {\n>  \t\tfree(e);\n> @@ -234,7 +234,7 @@ static void changed_files(struct hashmap *result, const char *index_path,\n>  \twhile (!strbuf_getline_nul(&buf, fp)) {\n>  \t\tstruct path_entry *entry;\n>  \t\tFLEX_ALLOC_STR(entry, path, buf.buf);\n> -\t\thashmap_entry_init(entry, strhash(buf.buf));\n> +\t\thashmap_entry_init(&entry->entry, strhash(buf.buf));\n>  \t\thashmap_add(result, entry);\n>  \t}\n>  \tfclose(fp);\n> @@ -461,7 +461,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n>  \n>  \t\t\t/* Avoid duplicate working_tree entries */\n>  \t\t\tFLEX_ALLOC_STR(entry, path, dst_path);\n> -\t\t\thashmap_entry_init(entry, strhash(dst_path));\n> +\t\t\thashmap_entry_init(&entry->entry, strhash(dst_path));\n>  \t\t\tif (hashmap_get(&working_tree_dups, entry, NULL)) {\n>  \t\t\t\tfree(entry);\n>  \t\t\t\tcontinue;\n> diff --git a/builtin/fast-export.c b/builtin/fast-export.c\n> index f541f55d33..287dbd24a3 100644\n> --- a/builtin/fast-export.c\n> +++ b/builtin/fast-export.c\n> @@ -148,7 +148,7 @@ static const void *anonymize_mem(struct hashmap *map,\n>  \tif (!map->cmpfn)\n>  \t\thashmap_init(map, anonymized_entry_cmp, NULL, 0);\n>  \n> -\thashmap_entry_init(&key, memhash(orig, *len));\n> +\thashmap_entry_init(&key.hash, memhash(orig, *len));\n>  \tkey.orig = orig;\n>  \tkey.orig_len = *len;\n>  \tret = hashmap_get(map, &key, NULL);\n> diff --git a/builtin/fetch.c b/builtin/fetch.c\n> index 717dd14e89..b7d70eee70 100644\n> --- a/builtin/fetch.c\n> +++ b/builtin/fetch.c\n> @@ -276,7 +276,7 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map,\n>  \tsize_t len = strlen(refname);\n>  \n>  \tFLEX_ALLOC_MEM(ent, refname, refname, len);\n> -\thashmap_entry_init(ent, strhash(refname));\n> +\thashmap_entry_init(&ent->ent, strhash(refname));\n>  \toidcpy(&ent->oid, oid);\n>  \thashmap_add(map, ent);\n>  \treturn ent;\n> diff --git a/config.c b/config.c\n> index 3900e4947b..08d866e7de 100644\n> --- a/config.c\n> +++ b/config.c\n> @@ -1861,7 +1861,7 @@ static struct config_set_element *configset_find_element(struct config_set *cs,\n>  \tif (git_config_parse_key(key, &normalized_key, NULL))\n>  \t\treturn NULL;\n>  \n> -\thashmap_entry_init(&k, strhash(normalized_key));\n> +\thashmap_entry_init(&k.ent, strhash(normalized_key));\n>  \tk.key = normalized_key;\n>  \tfound_entry = hashmap_get(&cs->config_hash, &k, NULL);\n>  \tfree(normalized_key);\n> @@ -1882,7 +1882,7 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha\n>  \t */\n>  \tif (!e) {\n>  \t\te = xmalloc(sizeof(*e));\n> -\t\thashmap_entry_init(e, strhash(key));\n> +\t\thashmap_entry_init(&e->ent, strhash(key));\n>  \t\te->key = xstrdup(key);\n>  \t\tstring_list_init(&e->value_list, 1);\n>  \t\thashmap_add(&cs->config_hash, e);\n> diff --git a/diffcore-rename.c b/diffcore-rename.c\n> index 9624864858..44a3ab1e31 100644\n> --- a/diffcore-rename.c\n> +++ b/diffcore-rename.c\n> @@ -329,7 +329,7 @@ static void insert_file_table(struct repository *r,\n>  \tentry->index = index;\n>  \tentry->filespec = filespec;\n>  \n> -\thashmap_entry_init(entry, hash_filespec(r, filespec));\n> +\thashmap_entry_init(&entry->entry, hash_filespec(r, filespec));\n>  \thashmap_add(table, entry);\n>  }\n>  \n> diff --git a/hashmap.c b/hashmap.c\n> index d42f01ff5a..6818c65174 100644\n> --- a/hashmap.c\n> +++ b/hashmap.c\n> @@ -293,13 +293,13 @@ const void *memintern(const void *data, size_t len)\n>  \t\thashmap_init(&map, (hashmap_cmp_fn) pool_entry_cmp, NULL, 0);\n>  \n>  \t/* lookup interned string in pool */\n> -\thashmap_entry_init(&key, memhash(data, len));\n> +\thashmap_entry_init(&key.ent, memhash(data, len));\n>  \tkey.len = len;\n>  \te = hashmap_get(&map, &key, data);\n>  \tif (!e) {\n>  \t\t/* not found: create it */\n>  \t\tFLEX_ALLOC_MEM(e, data, data, len);\n> -\t\thashmap_entry_init(e, key.ent.hash);\n> +\t\thashmap_entry_init(&e->ent, key.ent.hash);\n>  \t\te->len = len;\n>  \t\thashmap_add(&map, e);\n>  \t}\n> diff --git a/hashmap.h b/hashmap.h\n> index 8424911566..3d7939c291 100644\n> --- a/hashmap.h\n> +++ b/hashmap.h\n> @@ -48,14 +48,14 @@\n>   *         if (!strcmp(\"add\", action)) {\n>   *             struct long2string *e;\n>   *             FLEX_ALLOC_STR(e, value, value);\n> - *             hashmap_entry_init(e, memhash(&key, sizeof(long)));\n> + *             hashmap_entry_init(&e->ent, memhash(&key, sizeof(long)));\n>   *             e->key = key;\n>   *             hashmap_add(&map, e);\n>   *         }\n>   *\n>   *         if (!strcmp(\"print_all_by_key\", action)) {\n>   *             struct long2string k, *e;\n> - *             hashmap_entry_init(&k, memhash(&key, sizeof(long)));\n> + *             hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));\n>   *             k.key = key;\n>   *\n>   *             flags &= ~COMPARE_VALUE;\n> @@ -70,7 +70,7 @@\n>   *         if (!strcmp(\"has_exact_match\", action)) {\n>   *             struct long2string *e;\n>   *             FLEX_ALLOC_STR(e, value, value);\n> - *             hashmap_entry_init(e, memhash(&key, sizeof(long)));\n> + *             hashmap_entry_init(&e->ent, memhash(&key, sizeof(long)));\n>   *             e->key = key;\n>   *\n>   *             flags |= COMPARE_VALUE;\n> @@ -80,7 +80,7 @@\n>   *\n>   *         if (!strcmp(\"has_exact_match_no_heap_alloc\", action)) {\n>   *             struct long2string k;\n> - *             hashmap_entry_init(&k, memhash(&key, sizeof(long)));\n> + *             hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));\n>   *             k.key = key;\n>   *\n>   *             flags |= COMPARE_VALUE;\n> @@ -244,9 +244,9 @@ void hashmap_free(struct hashmap *map, int free_entries);\n>   * your structure was allocated with xmalloc(), you can just free(3) it,\n>   * and if it is on stack, you can just let it go out of scope).\n>   */\n> -static inline void hashmap_entry_init(void *entry, unsigned int hash)\n> +static inline void\n> +hashmap_entry_init(struct hashmap_entry *e, unsigned int hash)\n>  {\n> -\tstruct hashmap_entry *e = entry;\n>  \te->hash = hash;\n>  \te->next = NULL;\n>  }\n> diff --git a/merge-recursive.c b/merge-recursive.c\n> index 6b812d67e3..6bc4f14ff4 100644\n> --- a/merge-recursive.c\n> +++ b/merge-recursive.c\n> @@ -61,7 +61,7 @@ static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,\n>  \n>  \tif (dir == NULL)\n>  \t\treturn NULL;\n> -\thashmap_entry_init(&key, strhash(dir));\n> +\thashmap_entry_init(&key.ent, strhash(dir));\n>  \tkey.dir = dir;\n>  \treturn hashmap_get(hashmap, &key, NULL);\n>  }\n> @@ -85,7 +85,7 @@ static void dir_rename_init(struct hashmap *map)\n>  static void dir_rename_entry_init(struct dir_rename_entry *entry,\n>  \t\t\t\t  char *directory)\n>  {\n> -\thashmap_entry_init(entry, strhash(directory));\n> +\thashmap_entry_init(&entry->ent, strhash(directory));\n>  \tentry->dir = directory;\n>  \tentry->non_unique_new_dir = 0;\n>  \tstrbuf_init(&entry->new_dir, 0);\n> @@ -97,7 +97,7 @@ static struct collision_entry *collision_find_entry(struct hashmap *hashmap,\n>  {\n>  \tstruct collision_entry key;\n>  \n> -\thashmap_entry_init(&key, strhash(target_file));\n> +\thashmap_entry_init(&key.ent, strhash(target_file));\n>  \tkey.target_file = target_file;\n>  \treturn hashmap_get(hashmap, &key, NULL);\n>  }\n> @@ -454,7 +454,7 @@ static int save_files_dirs(const struct object_id *oid,\n>  \tstrbuf_addstr(base, path);\n>  \n>  \tFLEX_ALLOC_MEM(entry, path, base->buf, base->len);\n> -\thashmap_entry_init(entry, path_hash(entry->path));\n> +\thashmap_entry_init(&entry->e, path_hash(entry->path));\n>  \thashmap_add(&opt->current_file_dir_set, entry);\n>  \n>  \tstrbuf_setlen(base, baselen);\n> @@ -731,7 +731,7 @@ static char *unique_path(struct merge_options *opt, const char *path, const char\n>  \t}\n>  \n>  \tFLEX_ALLOC_MEM(entry, path, newpath.buf, newpath.len);\n> -\thashmap_entry_init(entry, path_hash(entry->path));\n> +\thashmap_entry_init(&entry->e, path_hash(entry->path));\n>  \thashmap_add(&opt->current_file_dir_set, entry);\n>  \treturn strbuf_detach(&newpath, NULL);\n>  }\n> @@ -2358,7 +2358,8 @@ static void compute_collisions(struct hashmap *collisions,\n>  \t\tif (!collision_ent) {\n>  \t\t\tcollision_ent = xcalloc(1,\n>  \t\t\t\t\t\tsizeof(struct collision_entry));\n> -\t\t\thashmap_entry_init(collision_ent, strhash(new_path));\n> +\t\t\thashmap_entry_init(&collision_ent->ent,\n> +\t\t\t\t\t\tstrhash(new_path));\n>  \t\t\thashmap_put(collisions, collision_ent);\n>  \t\t\tcollision_ent->target_file = new_path;\n>  \t\t} else {\n> diff --git a/name-hash.c b/name-hash.c\n> index 695908609f..1ce1417f7e 100644\n> --- a/name-hash.c\n> +++ b/name-hash.c\n> @@ -33,7 +33,7 @@ static struct dir_entry *find_dir_entry__hash(struct index_state *istate,\n>  \t\tconst char *name, unsigned int namelen, unsigned int hash)\n>  {\n>  \tstruct dir_entry key;\n> -\thashmap_entry_init(&key, hash);\n> +\thashmap_entry_init(&key.ent, hash);\n>  \tkey.namelen = namelen;\n>  \treturn hashmap_get(&istate->dir_hash, &key, name);\n>  }\n> @@ -68,7 +68,7 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,\n>  \tif (!dir) {\n>  \t\t/* not found, create it and add to hash table */\n>  \t\tFLEX_ALLOC_MEM(dir, name, ce->name, namelen);\n> -\t\thashmap_entry_init(dir, memihash(ce->name, namelen));\n> +\t\thashmap_entry_init(&dir->ent, memihash(ce->name, namelen));\n>  \t\tdir->namelen = namelen;\n>  \t\thashmap_add(&istate->dir_hash, dir);\n>  \n> @@ -106,7 +106,7 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)\n>  \tif (ce->ce_flags & CE_HASHED)\n>  \t\treturn;\n>  \tce->ce_flags |= CE_HASHED;\n> -\thashmap_entry_init(ce, memihash(ce->name, ce_namelen(ce)));\n> +\thashmap_entry_init(&ce->ent, memihash(ce->name, ce_namelen(ce)));\n>  \thashmap_add(&istate->name_hash, ce);\n>  \n>  \tif (ignore_case)\n> @@ -280,7 +280,7 @@ static struct dir_entry *hash_dir_entry_with_parent_and_prefix(\n>  \tdir = find_dir_entry__hash(istate, prefix->buf, prefix->len, hash);\n>  \tif (!dir) {\n>  \t\tFLEX_ALLOC_MEM(dir, name, prefix->buf, prefix->len);\n> -\t\thashmap_entry_init(dir, hash);\n> +\t\thashmap_entry_init(&dir->ent, hash);\n>  \t\tdir->namelen = prefix->len;\n>  \t\tdir->parent = parent;\n>  \t\thashmap_add(&istate->dir_hash, dir);\n> @@ -472,7 +472,7 @@ static void *lazy_name_thread_proc(void *_data)\n>  \tfor (k = 0; k < d->istate->cache_nr; k++) {\n>  \t\tstruct cache_entry *ce_k = d->istate->cache[k];\n>  \t\tce_k->ce_flags |= CE_HASHED;\n> -\t\thashmap_entry_init(ce_k, d->lazy_entries[k].hash_name);\n> +\t\thashmap_entry_init(&ce_k->ent, d->lazy_entries[k].hash_name);\n>  \t\thashmap_add(&d->istate->name_hash, ce_k);\n>  \t}\n>  \n> diff --git a/packfile.c b/packfile.c\n> index 37fe0b73a6..96535eb86b 100644\n> --- a/packfile.c\n> +++ b/packfile.c\n> @@ -1487,7 +1487,7 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,\n>  \n>  \tif (!delta_base_cache.cmpfn)\n>  \t\thashmap_init(&delta_base_cache, delta_base_cache_hash_cmp, NULL, 0);\n> -\thashmap_entry_init(ent, pack_entry_hash(p, base_offset));\n> +\thashmap_entry_init(&ent->ent, pack_entry_hash(p, base_offset));\n>  \thashmap_add(&delta_base_cache, ent);\n>  }\n>  \n> diff --git a/patch-ids.c b/patch-ids.c\n> index e8c150d0c9..a2da711678 100644\n> --- a/patch-ids.c\n> +++ b/patch-ids.c\n> @@ -83,7 +83,7 @@ static int init_patch_id_entry(struct patch_id *patch,\n>  \tif (commit_patch_id(commit, &ids->diffopts, &header_only_patch_id, 1, 0))\n>  \t\treturn -1;\n>  \n> -\thashmap_entry_init(patch, oidhash(&header_only_patch_id));\n> +\thashmap_entry_init(&patch->ent, oidhash(&header_only_patch_id));\n>  \treturn 0;\n>  }\n>  \n> diff --git a/range-diff.c b/range-diff.c\n> index ba1e9a4265..32b29f9594 100644\n> --- a/range-diff.c\n> +++ b/range-diff.c\n> @@ -217,7 +217,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n>  \t\tutil->i = i;\n>  \t\tutil->patch = a->items[i].string;\n>  \t\tutil->diff = util->patch + util->diff_offset;\n> -\t\thashmap_entry_init(util, strhash(util->diff));\n> +\t\thashmap_entry_init(&util->e, strhash(util->diff));\n>  \t\thashmap_add(&map, util);\n>  \t}\n>  \n> @@ -228,7 +228,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n>  \t\tutil->i = i;\n>  \t\tutil->patch = b->items[i].string;\n>  \t\tutil->diff = util->patch + util->diff_offset;\n> -\t\thashmap_entry_init(util, strhash(util->diff));\n> +\t\thashmap_entry_init(&util->e, strhash(util->diff));\n>  \t\tother = hashmap_remove(&map, util, NULL);\n>  \t\tif (other) {\n>  \t\t\tif (other->matching >= 0)\n> diff --git a/ref-filter.c b/ref-filter.c\n> index f27cfc8c3e..206014c93d 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -1565,7 +1565,8 @@ static void populate_worktree_map(struct hashmap *map, struct worktree **worktre\n>  \t\t\tstruct ref_to_worktree_entry *entry;\n>  \t\t\tentry = xmalloc(sizeof(*entry));\n>  \t\t\tentry->wt = worktrees[i];\n> -\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n> +\t\t\thashmap_entry_init(&entry->ent,\n> +\t\t\t\t\tstrhash(worktrees[i]->head_ref));\n>  \n>  \t\t\thashmap_add(map, entry);\n>  \t\t}\n> diff --git a/refs.c b/refs.c\n> index cd297ee4bd..c43ec59c6e 100644\n> --- a/refs.c\n> +++ b/refs.c\n> @@ -1796,7 +1796,7 @@ static struct ref_store_hash_entry *alloc_ref_store_hash_entry(\n>  \tstruct ref_store_hash_entry *entry;\n>  \n>  \tFLEX_ALLOC_STR(entry, name, name);\n> -\thashmap_entry_init(entry, strhash(name));\n> +\thashmap_entry_init(&entry->ent, strhash(name));\n>  \tentry->refs = refs;\n>  \treturn entry;\n>  }\n> diff --git a/remote.c b/remote.c\n> index e50f7602ed..bd81cb71bc 100644\n> --- a/remote.c\n> +++ b/remote.c\n> @@ -158,7 +158,7 @@ static struct remote *make_remote(const char *name, int len)\n>  \tALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);\n>  \tremotes[remotes_nr++] = ret;\n>  \n> -\thashmap_entry_init(ret, lookup_entry.hash);\n> +\thashmap_entry_init(&ret->ent, lookup_entry.hash);\n>  \treplaced = hashmap_put(&remotes_hash, ret);\n>  \tassert(replaced == NULL);  /* no previous entry overwritten */\n>  \treturn ret;\n> diff --git a/revision.c b/revision.c\n> index 07412297f0..3461c78883 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -141,7 +141,7 @@ static void paths_and_oids_insert(struct hashmap *map,\n>  \tstruct path_and_oids_entry key;\n>  \tstruct path_and_oids_entry *entry;\n>  \n> -\thashmap_entry_init(&key, hash);\n> +\thashmap_entry_init(&key.ent, hash);\n>  \n>  \t/* use a shallow copy for the lookup */\n>  \tkey.path = (char *)path;\n> @@ -149,7 +149,7 @@ static void paths_and_oids_insert(struct hashmap *map,\n>  \n>  \tif (!(entry = (struct path_and_oids_entry *)hashmap_get(map, &key, NULL))) {\n>  \t\tentry = xcalloc(1, sizeof(struct path_and_oids_entry));\n> -\t\thashmap_entry_init(entry, hash);\n> +\t\thashmap_entry_init(&entry->ent, hash);\n>  \t\tentry->path = xstrdup(key.path);\n>  \t\toidset_init(&entry->trees, 16);\n>  \t\thashmap_put(map, entry);\n> diff --git a/sequencer.c b/sequencer.c\n> index 34ebf8ed94..1140cdf526 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -4538,7 +4538,7 @@ static const char *label_oid(struct object_id *oid, const char *label,\n>  \t}\n>  \n>  \tFLEX_ALLOC_STR(labels_entry, label, label);\n> -\thashmap_entry_init(labels_entry, strihash(label));\n> +\thashmap_entry_init(&labels_entry->entry, strihash(label));\n>  \thashmap_add(&state->labels, labels_entry);\n>  \n>  \tFLEX_ALLOC_STR(string_entry, string, label);\n> @@ -5252,7 +5252,8 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n>  \t\t\t\t\t\tstrhash(subject), subject)) {\n>  \t\t\tFLEX_ALLOC_MEM(entry, subject, subject, subject_len);\n>  \t\t\tentry->i = i;\n> -\t\t\thashmap_entry_init(entry, strhash(entry->subject));\n> +\t\t\thashmap_entry_init(&entry->entry,\n> +\t\t\t\t\tstrhash(entry->subject));\n>  \t\t\thashmap_put(&subject2item, entry);\n>  \t\t}\n>  \t}\n> diff --git a/sub-process.c b/sub-process.c\n> index 3f4af93555..9847dad6fc 100644\n> --- a/sub-process.c\n> +++ b/sub-process.c\n> @@ -20,7 +20,7 @@ struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const ch\n>  {\n>  \tstruct subprocess_entry key;\n>  \n> -\thashmap_entry_init(&key, strhash(cmd));\n> +\thashmap_entry_init(&key.ent, strhash(cmd));\n>  \tkey.cmd = cmd;\n>  \treturn hashmap_get(hashmap, &key, NULL);\n>  }\n> @@ -96,7 +96,7 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co\n>  \t\treturn err;\n>  \t}\n>  \n> -\thashmap_entry_init(entry, strhash(cmd));\n> +\thashmap_entry_init(&entry->ent, strhash(cmd));\n>  \n>  \terr = startfn(entry);\n>  \tif (err) {\n> diff --git a/submodule-config.c b/submodule-config.c\n> index 4264ee216f..4aa02e280e 100644\n> --- a/submodule-config.c\n> +++ b/submodule-config.c\n> @@ -123,7 +123,7 @@ static void cache_put_path(struct submodule_cache *cache,\n>  \tunsigned int hash = hash_oid_string(&submodule->gitmodules_oid,\n>  \t\t\t\t\t    submodule->path);\n>  \tstruct submodule_entry *e = xmalloc(sizeof(*e));\n> -\thashmap_entry_init(e, hash);\n> +\thashmap_entry_init(&e->ent, hash);\n>  \te->config = submodule;\n>  \thashmap_put(&cache->for_path, e);\n>  }\n> @@ -135,7 +135,7 @@ static void cache_remove_path(struct submodule_cache *cache,\n>  \t\t\t\t\t    submodule->path);\n>  \tstruct submodule_entry e;\n>  \tstruct submodule_entry *removed;\n> -\thashmap_entry_init(&e, hash);\n> +\thashmap_entry_init(&e.ent, hash);\n>  \te.config = submodule;\n>  \tremoved = hashmap_remove(&cache->for_path, &e, NULL);\n>  \tfree(removed);\n> @@ -147,7 +147,7 @@ static void cache_add(struct submodule_cache *cache,\n>  \tunsigned int hash = hash_oid_string(&submodule->gitmodules_oid,\n>  \t\t\t\t\t    submodule->name);\n>  \tstruct submodule_entry *e = xmalloc(sizeof(*e));\n> -\thashmap_entry_init(e, hash);\n> +\thashmap_entry_init(&e->ent, hash);\n>  \te->config = submodule;\n>  \thashmap_add(&cache->for_name, e);\n>  }\n> @@ -163,7 +163,7 @@ static const struct submodule *cache_lookup_path(struct submodule_cache *cache,\n>  \toidcpy(&key_config.gitmodules_oid, gitmodules_oid);\n>  \tkey_config.path = path;\n>  \n> -\thashmap_entry_init(&key, hash);\n> +\thashmap_entry_init(&key.ent, hash);\n>  \tkey.config = &key_config;\n>  \n>  \tentry = hashmap_get(&cache->for_path, &key, NULL);\n> @@ -183,7 +183,7 @@ static struct submodule *cache_lookup_name(struct submodule_cache *cache,\n>  \toidcpy(&key_config.gitmodules_oid, gitmodules_oid);\n>  \tkey_config.name = name;\n>  \n> -\thashmap_entry_init(&key, hash);\n> +\thashmap_entry_init(&key.ent, hash);\n>  \tkey.config = &key_config;\n>  \n>  \tentry = hashmap_get(&cache->for_name, &key, NULL);\n> diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\n> index aaf17b0ddf..0c9fd7c996 100644\n> --- a/t/helper/test-hashmap.c\n> +++ b/t/helper/test-hashmap.c\n> @@ -37,7 +37,7 @@ static struct test_entry *alloc_test_entry(unsigned int hash,\n>  \tsize_t klen = strlen(key);\n>  \tsize_t vlen = strlen(value);\n>  \tstruct test_entry *entry = xmalloc(st_add4(sizeof(*entry), klen, vlen, 2));\n> -\thashmap_entry_init(entry, hash);\n> +\thashmap_entry_init(&entry->ent, hash);\n>  \tmemcpy(entry->key, key, klen + 1);\n>  \tmemcpy(entry->key + klen + 1, value, vlen + 1);\n>  \treturn entry;\n> @@ -103,7 +103,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)\n>  \n>  \t\t\t/* add entries */\n>  \t\t\tfor (i = 0; i < TEST_SIZE; i++) {\n> -\t\t\t\thashmap_entry_init(entries[i], hashes[i]);\n> +\t\t\t\thashmap_entry_init(&entries[i]->ent, hashes[i]);\n>  \t\t\t\thashmap_add(&map, entries[i]);\n>  \t\t\t}\n>  \n> @@ -116,7 +116,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)\n>  \t\t/* fill the map (sparsely if specified) */\n>  \t\tj = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE;\n>  \t\tfor (i = 0; i < j; i++) {\n> -\t\t\thashmap_entry_init(entries[i], hashes[i]);\n> +\t\t\thashmap_entry_init(&entries[i]->ent, hashes[i]);\n>  \t\t\thashmap_add(&map, entries[i]);\n>  \t\t}\n>  \n> \n\n"},{"id":"381368","messageId":"381dd52f-f7d4-3e6c-24b8-22c8a0710f25@gmail.com","threadId":"51736","inReplyTo":"20190826024332.3403-11-e@80x24.org","subject":"Re: [PATCH 10/11] introduce container_of macro","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-08-27T14:49:11Z","receivedAt":"2019-08-27T14:49:16Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 8/25/2019 10:43 PM, Eric Wong wrote:\n> This macro is popular within the Linux kernel for supporting\n> intrusive data structures such as linked lists, red-black trees,\n> and chained hash tables while allowing the compiler to do\n> type checking.\n> \n> I intend to use this to remove the limitation of \"hashmap_entry\"\n> being location-dependent and to allow more compile-time type\n> checking.\n> \n> This macro already exists in our source as \"list_entry\" in\n> list.h and making \"list_entry\" an alias to \"container_of\"\n> as the Linux kernel has done is a possibility.\n[snip]\n> +/*\n> + * container_of - Get the address of an object containing a field.\n> + *\n> + * @ptr: pointer to the field.\n> + * @type: type of the object.\n> + * @member: name of the field within the object.\n> + */\n> +#define container_of(ptr, type, member) \\\n> +\t((type *) ((char *)(ptr) - offsetof(type, member)))\n> +\n>  #endif\n\nI think it would be good to include at least one use of this\nmacro in this patch. As it stands, I need to look at the next\npatch to make sense of what this is doing.\n\nIt took me a little while to parse what is happening here.\n'ptr' is a pointer to the generic struct (in our case,\n'struct hashmap_entry *'), while 'type' is the parent type,\nand 'member' is the name of the member in 'type' that is\nof type typeof(*ptr).\n\nPerhaps this is easier to grok for others than it was for me.\n\n-Stolee\n"},{"id":"381369","messageId":"2f22841c-779e-6d6e-19b7-0a119088e343@gmail.com","threadId":"51736","inReplyTo":"20190826024332.3403-12-e@80x24.org","subject":"Re: [PATCH 11/11] hashmap_get_next returns \"struct hashmap_entry *\"","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-08-27T14:53:18Z","receivedAt":"2019-08-27T14:53:22Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 8/25/2019 10:43 PM, Eric Wong wrote:\n> This is a step towards removing the requirement for\n> hashmap_entry being the first field of a struct.\n> \n> Signed-off-by: Eric Wong <e@80x24.org>\n> ---\n>  diff.c                  | 19 ++++++++++++-------\n>  diffcore-rename.c       | 11 +++++++----\n>  hashmap.c               |  2 +-\n>  hashmap.h               | 12 ++++++++----\n>  name-hash.c             |  8 +++++---\n>  t/helper/test-hashmap.c | 10 ++++++----\n>  6 files changed, 39 insertions(+), 23 deletions(-)\n> \n> diff --git a/diff.c b/diff.c\n> index 72d3c6aa19..663b5d01f8 100644\n> --- a/diff.c\n> +++ b/diff.c\n> @@ -1035,8 +1035,10 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,\n>  {\n>  \tint i;\n>  \tchar *got_match = xcalloc(1, pmb_nr);\n> +\tstruct hashmap_entry *ent = &match->ent;\n>  \n> -\tfor (; match; match = hashmap_get_next(hm, &match->ent)) {\n> +\tfor (; ent; ent = hashmap_get_next(hm, ent)) {\n> +\t\tmatch = container_of(ent, struct moved_entry, ent);\n\nLines like this are very difficult to parse. In this\ncontainer_of() macro, 'ent' is taking both the 'ptr' and\n'member' values.\n\nI would prefer that you make your local member be named\nsomething different, for instance:\n\n\tstruct hashmap_entry *match_ent = &match->ent;\n\nand\n\n\tmatch = container_of(match_ent, struct moved_entry, ent);\n\n>  \t\tfor (i = 0; i < pmb_nr; i++) {\n>  \t\t\tstruct moved_entry *prev = pmb[i].match;\n>  \t\t\tstruct moved_entry *cur = (prev && prev->next_line) ?\n> @@ -1135,8 +1137,9 @@ static void mark_color_as_moved(struct diff_options *o,\n>  \n>  \tfor (n = 0; n < o->emitted_symbols->nr; n++) {\n>  \t\tstruct hashmap *hm = NULL;\n> +\t\tstruct hashmap_entry *ent = NULL;\n>  \t\tstruct moved_entry *key;\n> -\t\tstruct moved_entry *match = NULL;\n> +\t\tstruct moved_entry *match;\n>  \t\tstruct emitted_diff_symbol *l = &o->emitted_symbols->buf[n];\n>  \t\tenum diff_symbol last_symbol = 0;\n>  \n> @@ -1144,20 +1147,20 @@ static void mark_color_as_moved(struct diff_options *o,\n>  \t\tcase DIFF_SYMBOL_PLUS:\n>  \t\t\thm = del_lines;\n>  \t\t\tkey = prepare_entry(o, n);\n> -\t\t\tmatch = hashmap_get(hm, &key->ent, NULL);\n> +\t\t\tent = hashmap_get(hm, &key->ent, NULL);\n>  \t\t\tfree(key);\n>  \t\t\tbreak;\n>  \t\tcase DIFF_SYMBOL_MINUS:\n>  \t\t\thm = add_lines;\n>  \t\t\tkey = prepare_entry(o, n);\n> -\t\t\tmatch = hashmap_get(hm, &key->ent, NULL);\n> +\t\t\tent = hashmap_get(hm, &key->ent, NULL);\n>  \t\t\tfree(key);\n>  \t\t\tbreak;\n>  \t\tdefault:\n>  \t\t\tflipped_block = 0;\n>  \t\t}\n>  \n> -\t\tif (!match) {\n> +\t\tif (!ent) {\n>  \t\t\tint i;\n>  \n>  \t\t\tadjust_last_block(o, n, block_length);\n> @@ -1169,6 +1172,7 @@ static void mark_color_as_moved(struct diff_options *o,\n>  \t\t\tlast_symbol = l->s;\n>  \t\t\tcontinue;\n>  \t\t}\n> +\t\tmatch = container_of(ent, struct moved_entry, ent);\n>  \n>  \t\tif (o->color_moved == COLOR_MOVED_PLAIN) {\n>  \t\t\tlast_symbol = l->s;\n> @@ -1189,8 +1193,9 @@ static void mark_color_as_moved(struct diff_options *o,\n>  \t\t\t * The current line is the start of a new block.\n>  \t\t\t * Setup the set of potential blocks.\n>  \t\t\t */\n> -\t\t\tfor (; match; match = hashmap_get_next(hm,\n> -\t\t\t\t\t\t\t\t&match->ent)) {\n> +\t\t\tfor (; ent; ent = hashmap_get_next(hm, ent)) {\n> +\t\t\t\tmatch = container_of(ent, struct moved_entry,\n> +\t\t\t\t\t\t\tent);\n\nSame complaint here.\n\n>  \t\t\t\tALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);\n>  \t\t\t\tif (o->color_moved_ws_handling &\n>  \t\t\t\t    COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {\n> diff --git a/diffcore-rename.c b/diffcore-rename.c\n> index 4670a40179..71aa240a68 100644\n> --- a/diffcore-rename.c\n> +++ b/diffcore-rename.c\n> @@ -274,7 +274,7 @@ static int find_identical_files(struct hashmap *srcs,\n>  \t\t\t\tstruct diff_options *options)\n>  {\n>  \tint renames = 0;\n> -\n> +\tstruct hashmap_entry *ent;\n>  \tstruct diff_filespec *target = rename_dst[dst_index].two;\n>  \tstruct file_similarity *p, *best = NULL;\n>  \tint i = 100, best_score = -1;\n> @@ -282,12 +282,15 @@ static int find_identical_files(struct hashmap *srcs,\n>  \t/*\n>  \t * Find the best source match for specified destination.\n>  \t */\n> -\tp = hashmap_get_from_hash(srcs,\n> +\tent = hashmap_get_from_hash(srcs,\n>  \t\t\t\t  hash_filespec(options->repo, target),\n>  \t\t\t\t  NULL);\n> -\tfor (; p; p = hashmap_get_next(srcs, &p->entry)) {\n> +\tfor (; ent; ent = hashmap_get_next(srcs, ent)) {\n>  \t\tint score;\n> -\t\tstruct diff_filespec *source = p->filespec;\n> +\t\tstruct diff_filespec *source;\n> +\n> +\t\tp = container_of(ent, struct file_similarity, entry);\n\nThis is slightly better, but still a bit confusing.\n\n> +\t\tsource = p->filespec;\n>  \n>  \t\t/* False hash collision? */\n>  \t\tif (!oideq(&source->oid, &target->oid))\n> diff --git a/hashmap.c b/hashmap.c\n> index 2dd9912e13..d6434d9ca4 100644\n> --- a/hashmap.c\n> +++ b/hashmap.c\n> @@ -192,7 +192,7 @@ void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n>  \treturn *find_entry_ptr(map, key, keydata);\n>  }\n>  \n> -void *hashmap_get_next(const struct hashmap *map,\n> +struct hashmap_entry *hashmap_get_next(const struct hashmap *map,\n>  \t\t\tconst struct hashmap_entry *entry)\n>  {\n>  \tstruct hashmap_entry *e = entry->next;\n> diff --git a/hashmap.h b/hashmap.h\n> index b62ee2e7b9..25643dcdc4 100644\n> --- a/hashmap.h\n> +++ b/hashmap.h\n> @@ -55,15 +55,19 @@\n>   *\n>   *         if (!strcmp(\"print_all_by_key\", action)) {\n>   *             struct long2string k, *e;\n> + *             struct hashmap_entry *ent;\n>   *             hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));\n>   *             k.key = key;\n>   *\n>   *             flags &= ~COMPARE_VALUE;\n> - *             e = hashmap_get(&map, &k, NULL);\n> - *             if (e) {\n> + *             ent = hashmap_get(&map, &k, NULL);\n> + *             if (ent) {\n> + *                 e = container_of(ent, struct long2string, ent);\n>   *                 printf(\"first: %ld %s\\n\", e->key, e->value);\n> - *                 while ((e = hashmap_get_next(&map, e)))\n> + *                 while ((ent = hashmap_get_next(&map, ent))) {\n> + *                     e = container_of(ent, struct long2string, ent);\n>   *                     printf(\"found more: %ld %s\\n\", e->key, e->value);\n> + *                 }\n>   *             }\n>   *         }\n>   *\n> @@ -320,7 +324,7 @@ static inline void *hashmap_get_from_hash(const struct hashmap *map,\n>   * `entry` is the hashmap_entry to start the search from, obtained via a previous\n>   * call to `hashmap_get` or `hashmap_get_next`.\n>   */\n> -void *hashmap_get_next(const struct hashmap *map,\n> +struct hashmap_entry *hashmap_get_next(const struct hashmap *map,\n>  \t\t\tconst struct hashmap_entry *entry);\n>  \n>  /*\n> diff --git a/name-hash.c b/name-hash.c\n> index f64c52bfa2..6f2779934f 100644\n> --- a/name-hash.c\n> +++ b/name-hash.c\n> @@ -703,15 +703,17 @@ void adjust_dirname_case(struct index_state *istate, char *name)\n>  struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase)\n>  {\n>  \tstruct cache_entry *ce;\n> +\tstruct hashmap_entry *ent;\n>  \n>  \tlazy_init_name_hash(istate);\n>  \n> -\tce = hashmap_get_from_hash(&istate->name_hash,\n> +\tent = hashmap_get_from_hash(&istate->name_hash,\n>  \t\t\t\t   memihash(name, namelen), NULL);\n> -\twhile (ce) {\n> +\twhile (ent) {\n> +\t\tce = container_of(ent, struct cache_entry, ent);\n>  \t\tif (same_name(ce, name, namelen, icase))\n>  \t\t\treturn ce;\n> -\t\tce = hashmap_get_next(&istate->name_hash, &ce->ent);\n> +\t\tent = hashmap_get_next(&istate->name_hash, ent);\n>  \t}\n>  \treturn NULL;\n>  }\n> diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\n> index de2bd083b9..d85b8dc58e 100644\n> --- a/t/helper/test-hashmap.c\n> +++ b/t/helper/test-hashmap.c\n> @@ -194,16 +194,18 @@ int cmd__hashmap(int argc, const char **argv)\n>  \t\t\tfree(entry);\n>  \n>  \t\t} else if (!strcmp(\"get\", cmd) && p1) {\n> +\t\t\tstruct hashmap_entry *e;\n>  \n>  \t\t\t/* lookup entry in hashmap */\n> -\t\t\tentry = hashmap_get_from_hash(&map, hash, p1);\n> +\t\t\te = hashmap_get_from_hash(&map, hash, p1);\n>  \n>  \t\t\t/* print result */\n> -\t\t\tif (!entry)\n> +\t\t\tif (!e)\n>  \t\t\t\tputs(\"NULL\");\n> -\t\t\twhile (entry) {\n> +\t\t\twhile (e) {\n> +\t\t\t\tentry = container_of(e, struct test_entry, ent);\n>  \t\t\t\tputs(get_value(entry));\n> -\t\t\t\tentry = hashmap_get_next(&map, &entry->ent);\n> +\t\t\t\te = hashmap_get_next(&map, e);\n>  \t\t\t}\n>  \n>  \t\t} else if (!strcmp(\"remove\", cmd) && p1) {\n\nI didn't comment on them all, but essentially every use of\ncontainer_of() here is pretty confusing with the names. Perhaps\nsome pattern of \"type_member\" could be helpful, so you can use\n\n\ttype_p = container_of(type_member, struct type, member);\n\nto be really clear about each name.\n\nThanks,\n-Stolee\n\n"},{"id":"381399","messageId":"xmqqa7bu2r01.fsf@gitster-ct.c.googlers.com","threadId":"51736","inReplyTo":"20190827094923.6qhwqosiucsi43td@whir","subject":"Re: [PATCH 04/11] hashmap_entry: detect improper initialization","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-08-27T22:16:46Z","receivedAt":"2019-08-27T22:16:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Wong <e@80x24.org> writes:\n\n> I renamed it to intentionally break my build.\n\nThis cuts both ways.  If you work without any throw-away merges, it\nis GOOD to make sure any new use other people added will be spotted\nby the compiler by breaking the build.  It will force you to resolve\nall such breakages until you can move on to other topics, and it\nwill also force you to commit to your topic that deliberately breaks\nthe build by renaming.\n\nIf you want to avoid committing to the current iteration of topic,\nhowever, then that would mean you'd need a reliable way to rebuild\nevil merges (aka resolution of semantic conflicts) so that you can\nkeep parts of more recent history more flexible (similar to how 'pu'\nis managed).\n\nMy plan is to have ew/hashmap topic for a few days while ejecting\nthe js/add-i topic which semantically conflicts with the changed way\nhashmaps ought to be used temporarily, and when I have enough time\nand concentration, try to see if I can come up with a good semantic\nconflict resolution that I can keep reusing (aka refs/merge-fix/).\nIf it happens, we'll see both topics, and if it doesn't, I'll then\ndrop ew/hashmap and queue js/add-i and rinse and repeat from there\n;-)\n"},{"id":"381425","messageId":"8beefab6-b7ef-28d3-41d6-c5a5c042ae9a@gmail.com","threadId":"51736","inReplyTo":"20190827094923.6qhwqosiucsi43td@whir","subject":"Re: [PATCH 04/11] hashmap_entry: detect improper initialization","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-08-28T09:03:56Z","receivedAt":"2019-08-28T09:04:03Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Eric\n\nOn 27/08/2019 10:49, Eric Wong wrote:\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n>> Hi Eric,\n>>\n>> On Mon, 26 Aug 2019, Eric Wong wrote:\n>>\n>>> By renaming the \"hash\" field to \"_hash\", it's easy to spot\n>>> improper initialization of hashmap_entry structs which\n>>> can leave \"hashmap_entry.next\" uninitialized.\n>>\n>> Would you mind elaborating a bit? This explanation does not enlighten\n>> me, sadly, all I see is that it makes it (slightly) harder for me to\n>> maintain Git for Windows' patches on top of `pu`, as the FSCache patches\n>> access that field directly (so even if they rebase cleanly, the build\n>> breaks).\n> \n> I renamed it to intentionally break my build.\n> \n> That way I could easily spot if there were any other improper\n> initializations of the .hash field.  It's fine to revert,\n> actually, it could be more of a \"showing my work\" patch.\n\nI'm still a bit confused as the changed initializations already used \nhashmap_entry_init() and so presumably were already initializing \nhashmap_entry.next correctly. Is there a way to get 'make coccicheck' \ndetect incorrect initializations, this renaming wont prevent bad code \nbeing added in the future.\n\nBest Wishes\n\nPhillip\n\n> (AFAIK, it's a pretty common practice, but maybe not here :x)\n> \n> I've also pondered adding a\n> \"hashmap_entry_hash(const struct hashmap_entry *)\"\n> accessor method for reading the field value (but not setting\n> it), but it's a bit verbose...\n> \n> I'm also wondering where/if hashmap offers a real benefit over\n> khash nowadays; the latter ought to have better locality.\n> Would like benchmark at some point in the future;\n> but safety fixes first :)\n> \n"},{"id":"381427","messageId":"a7b3b9f4-58aa-0d09-fe43-8094e3a255b8@gmail.com","threadId":"51736","inReplyTo":"381dd52f-f7d4-3e6c-24b8-22c8a0710f25@gmail.com","subject":"Re: [PATCH 10/11] introduce container_of macro","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-08-28T09:11:42Z","receivedAt":"2019-08-28T09:11:47Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 27/08/2019 15:49, Derrick Stolee wrote:\n> On 8/25/2019 10:43 PM, Eric Wong wrote:\n>> This macro is popular within the Linux kernel for supporting\n>> intrusive data structures such as linked lists, red-black trees,\n>> and chained hash tables while allowing the compiler to do\n>> type checking.\n>>\n>> I intend to use this to remove the limitation of \"hashmap_entry\"\n>> being location-dependent and to allow more compile-time type\n>> checking.\n>>\n>> This macro already exists in our source as \"list_entry\" in\n>> list.h and making \"list_entry\" an alias to \"container_of\"\n>> as the Linux kernel has done is a possibility.\n> [snip]\n>> +/*\n>> + * container_of - Get the address of an object containing a field.\n>> + *\n>> + * @ptr: pointer to the field.\n>> + * @type: type of the object.\n>> + * @member: name of the field within the object.\n>> + */\n>> +#define container_of(ptr, type, member) \\\n>> +\t((type *) ((char *)(ptr) - offsetof(type, member)))\n>> +\n>>   #endif\n> \n> I think it would be good to include at least one use of this\n> macro in this patch. As it stands, I need to look at the next\n> patch to make sense of what this is doing.\n> \n> It took me a little while to parse what is happening here.\n> 'ptr' is a pointer to the generic struct (in our case,\n> 'struct hashmap_entry *'), while 'type' is the parent type,\n> and 'member' is the name of the member in 'type' that is\n> of type typeof(*ptr).\n\nIt took me a couple of minutes to figure it out as well. The rest of \nthis patch series adds some very welcome type safety changes, at first \nsight this patch threatens to undermine that as there is no check (and \nno compiler independent way to check) that type == typeof(*ptr). It \nwould also be helpful if the commit message could explain how this can \nbe used to improve type safety.\n\nBest Wishes\n\nPhillip\n\n> Perhaps this is easier to grok for others than it was for me.\n> \n> -Stolee\n> \n"},{"id":"381443","messageId":"nycvar.QRO.7.76.6.1908281655190.46@tvgsbejvaqbjf.bet","threadId":"51736","inReplyTo":"557b6f18-c346-f3c8-b623-d97752586670@gmail.com","subject":"Re: [PATCH 03/11] hashmap_entry_init takes \"struct hashmap_entry *\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-08-28T15:01:01Z","receivedAt":"2019-08-28T15:01:11Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Stolee,\n\nOn Tue, 27 Aug 2019, Derrick Stolee wrote:\n\n> On 8/25/2019 10:43 PM, Eric Wong wrote:\n> > C compilers do type checking to make life easier for us.  So\n> > rely on that and update all hashmap_entry_init callers to take\n> > \"struct hashmap_entry *\" to avoid future bugs while improving\n> > safety and readability.\n>\n> Overall I like this change. I'll need to keep it in mind with my\n> sparse-checkout work that is adding more hashmap types.\n>\n> One _might_ think that this change is relaxing the condition on\n> where the hashmap_entry appears within the super-struct, but\n> the hashmap internals will still use void* and perform a cast\n> to hashmap_entry for hash comparisons.\n\nI thought precisely the same.\n\nMaybe we can get a Coccinelle rule that verifies that `struct\nhashmap_entryh` fields are always the first ones?\n\nCiao,\nDscho\n"},{"id":"381444","messageId":"nycvar.QRO.7.76.6.1908281703191.46@tvgsbejvaqbjf.bet","threadId":"51736","inReplyTo":"xmqqa7bu2r01.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 04/11] hashmap_entry: detect improper initialization","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-08-28T15:04:04Z","receivedAt":"2019-08-28T15:04:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 27 Aug 2019, Junio C Hamano wrote:\n\n> My plan is to have ew/hashmap topic for a few days while ejecting\n> the js/add-i topic which semantically conflicts with the changed way\n> hashmaps ought to be used temporarily, and when I have enough time\n> and concentration, try to see if I can come up with a good semantic\n> conflict resolution that I can keep reusing (aka refs/merge-fix/).\n> If it happens, we'll see both topics, and if it doesn't, I'll then\n> drop ew/hashmap and queue js/add-i and rinse and repeat from there\n> ;-)\n\nFWIW I crafted my latest iteration such that you would only need to do\nthe `hash` => `_hash` rename in one line to merge `js/builtin-add-i`.\n\nCiao,\nDscho\n"},{"id":"381601","messageId":"20190830193636.xg6pcd5hjcgk3nob@dcvr","threadId":"51736","inReplyTo":"2f22841c-779e-6d6e-19b7-0a119088e343@gmail.com","subject":"Re: [PATCH 11/11] hashmap_get_next returns \"struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-30T19:36:36Z","receivedAt":"2019-08-30T19:36:38Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Derrick Stolee <stolee@gmail.com> wrote:\n> On 8/25/2019 10:43 PM, Eric Wong wrote:\n> > --- a/diff.c\n> > +++ b/diff.c\n> > @@ -1035,8 +1035,10 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,\n> >  {\n> >  \tint i;\n> >  \tchar *got_match = xcalloc(1, pmb_nr);\n> > +\tstruct hashmap_entry *ent = &match->ent;\n> >  \n> > -\tfor (; match; match = hashmap_get_next(hm, &match->ent)) {\n> > +\tfor (; ent; ent = hashmap_get_next(hm, ent)) {\n> > +\t\tmatch = container_of(ent, struct moved_entry, ent);\n> \n> Lines like this are very difficult to parse. In this\n> container_of() macro, 'ent' is taking both the 'ptr' and\n> 'member' values.\n\nAgreed, naming is hard :<\n\nIn the Linux kernel list.h implementation, there's actually\nlist_for_each_entry, list_next_entry and a bunch of other\nmacros which allow the caller to avoid using container_of.\nWe only have list_first_entry, so far.\n\nWe can draw inspiration from those macros by creating\nhashmap_get_next_entry and hashmap_for_each_entry macros\nwhich allow callers specify the type once; and there'd\nbe no need for callers to specify the hashmap_entry\npointer name at all :)\n\nUnlike the kernel, it looks like we can't rely on __typeof__ in\ngit, but I think we can let the caller specify the type once...\n\n\n"},{"id":"381602","messageId":"20190830194308.skgeqzj7goh6y6nm@dcvr","threadId":"51736","inReplyTo":"381dd52f-f7d4-3e6c-24b8-22c8a0710f25@gmail.com","subject":"Re: [PATCH 10/11] introduce container_of macro","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-30T19:43:08Z","receivedAt":"2019-08-30T19:43:10Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Derrick Stolee <stolee@gmail.com> wrote:\n> On 8/25/2019 10:43 PM, Eric Wong wrote:\n> > + * container_of - Get the address of an object containing a field.\n> > + *\n> > + * @ptr: pointer to the field.\n> > + * @type: type of the object.\n> > + * @member: name of the field within the object.\n> > + */\n> > +#define container_of(ptr, type, member) \\\n> > +\t((type *) ((char *)(ptr) - offsetof(type, member)))\n> > +\n> >  #endif\n> \n> I think it would be good to include at least one use of this\n> macro in this patch. As it stands, I need to look at the next\n> patch to make sense of what this is doing.\n\nYeah, I considered making list_entry an alias of this.\nBut I wasn't sure about including git-compat-util.h in\nlist.h...\n\n> It took me a little while to parse what is happening here.\n> 'ptr' is a pointer to the generic struct (in our case,\n> 'struct hashmap_entry *'), while 'type' is the parent type,\n> and 'member' is the name of the member in 'type' that is\n> of type typeof(*ptr).\n> \n> Perhaps this is easier to grok for others than it was for me.\n\n*shrug*  I only dabble in C, but I've been using it for a good\nwhile.  I'm probably drawn to it because I'm not a great C\nprogrammer like having it to prevent mistakes.  I also find\nopen-coded linked lists (even singly-linked ones!)\nhard-to-follow, so I always reach for something like urcu/list.h\nor ccan/list.h.\n"},{"id":"381606","messageId":"20190830194855.45jwupvp5uqcg46y@dcvr","threadId":"51736","inReplyTo":"nycvar.QRO.7.76.6.1908281655190.46@tvgsbejvaqbjf.bet","subject":"Re: [PATCH 03/11] hashmap_entry_init takes \"struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-30T19:48:55Z","receivedAt":"2019-08-30T19:48:57Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> Hi Stolee,\n> \n> On Tue, 27 Aug 2019, Derrick Stolee wrote:\n> \n> > On 8/25/2019 10:43 PM, Eric Wong wrote:\n> > > C compilers do type checking to make life easier for us.  So\n> > > rely on that and update all hashmap_entry_init callers to take\n> > > \"struct hashmap_entry *\" to avoid future bugs while improving\n> > > safety and readability.\n> >\n> > Overall I like this change. I'll need to keep it in mind with my\n> > sparse-checkout work that is adding more hashmap types.\n> >\n> > One _might_ think that this change is relaxing the condition on\n> > where the hashmap_entry appears within the super-struct, but\n> > the hashmap internals will still use void* and perform a cast\n> > to hashmap_entry for hash comparisons.\n> \n> I thought precisely the same.\n\nYes, that's the goal I'm working towards as mentioned in patches\n10 and 11 :)\n\n> Maybe we can get a Coccinelle rule that verifies that `struct\n> hashmap_entryh` fields are always the first ones?\n\nAt this point, why?  Given the goal is to remove that requirement\nentirely.\n"},{"id":"381608","messageId":"20190830195240.ephg6r6zjbrkabvp@dcvr","threadId":"51736","inReplyTo":"8beefab6-b7ef-28d3-41d6-c5a5c042ae9a@gmail.com","subject":"Re: [PATCH 04/11] hashmap_entry: detect improper initialization","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-08-30T19:52:40Z","receivedAt":"2019-08-30T19:52:42Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Phillip Wood <phillip.wood123@gmail.com> wrote:\n> Hi Eric\n> \n> On 27/08/2019 10:49, Eric Wong wrote:\n> > Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> > > Hi Eric,\n> > > \n> > > On Mon, 26 Aug 2019, Eric Wong wrote:\n> > > \n> > > > By renaming the \"hash\" field to \"_hash\", it's easy to spot\n> > > > improper initialization of hashmap_entry structs which\n> > > > can leave \"hashmap_entry.next\" uninitialized.\n> > > \n> > > Would you mind elaborating a bit? This explanation does not enlighten\n> > > me, sadly, all I see is that it makes it (slightly) harder for me to\n> > > maintain Git for Windows' patches on top of `pu`, as the FSCache patches\n> > > access that field directly (so even if they rebase cleanly, the build\n> > > breaks).\n> > \n> > I renamed it to intentionally break my build.\n> > \n> > That way I could easily spot if there were any other improper\n> > initializations of the .hash field.  It's fine to revert,\n> > actually, it could be more of a \"showing my work\" patch.\n> \n> I'm still a bit confused as the changed initializations already used\n> hashmap_entry_init() and so presumably were already initializing\n> hashmap_entry.next correctly. Is there a way to get 'make coccicheck' detect\n> incorrect initializations, this renaming wont prevent bad code being added\n> in the future.\n\nYeah I forgot we had coccicheck :x\n\nI think this patch to rename the field can be dropped entirely.\nI changed some usages of hashmap_entry_init to avoid reading the\n.hash field entirely, since the result of memhash() could be\nstored locally for multiple uses of hashmap_entry_init.\n"},{"id":"381647","messageId":"nycvar.QRO.7.76.6.1909021542160.46@tvgsbejvaqbjf.bet","threadId":"51736","inReplyTo":"20190830194855.45jwupvp5uqcg46y@dcvr","subject":"Re: [PATCH 03/11] hashmap_entry_init takes \"struct hashmap_entry *\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-09-02T13:46:03Z","receivedAt":"2019-09-02T13:46:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Eric,\n\nOn Fri, 30 Aug 2019, Eric Wong wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> >\n> > On Tue, 27 Aug 2019, Derrick Stolee wrote:\n> >\n> > > On 8/25/2019 10:43 PM, Eric Wong wrote:\n> > > > C compilers do type checking to make life easier for us.  So\n> > > > rely on that and update all hashmap_entry_init callers to take\n> > > > \"struct hashmap_entry *\" to avoid future bugs while improving\n> > > > safety and readability.\n> > >\n> > > Overall I like this change. I'll need to keep it in mind with my\n> > > sparse-checkout work that is adding more hashmap types.\n> > >\n> > > One _might_ think that this change is relaxing the condition on\n> > > where the hashmap_entry appears within the super-struct, but\n> > > the hashmap internals will still use void* and perform a cast\n> > > to hashmap_entry for hash comparisons.\n> >\n> > I thought precisely the same.\n>\n> Yes, that's the goal I'm working towards as mentioned in patches\n> 10 and 11 :)\n\nWell, it is not exactly clear to me how memory management would work (I\nhave not read patch 10 or 11 due to lack of time). At the moment,\nreleasing a hashmap means we can simply `free()` the stored pointers. If\nyou drop the requirement to make the `hashmap_entry` field the first\nfield of the enclosing `struct`, that is no longer possible.\n\nOf course, you could add an `offsetof` value to the hashmap that says\nwhat number we have to subtract from the stored pointer before calling\n`free()`, but that sounds quite a bit more fragile to me than the\ncurrent design.\n\n> > Maybe we can get a Coccinelle rule that verifies that `struct\n> > hashmap_entryh` fields are always the first ones?\n>\n> At this point, why?  Given the goal is to remove that requirement\n> entirely.\n\nWith a Coccinelle rule, we could maintain a simple design *and* be\ncertain that no user violates the assumption that the `hashmap_entry`\nfield is the first one in the enclosing `struct`.\n\nCiao,\nDscho\n"},{"id":"382038","messageId":"20190908074953.kux7zz4y7iolqko4@whir","threadId":"51736","inReplyTo":"20190826024332.3403-5-e@80x24.org","subject":"[RFC 04/11] coccicheck: detect hashmap_entry.hash assignment","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-08T07:49:53Z","receivedAt":"2019-09-08T07:49:56Z","isPatch":false,"sender":{"key":"e@80x24.org","avatar":null},"body":"Eric Wong <e@80x24.org> wrote:\n> By renaming the \"hash\" field to \"_hash\", it's easy to spot\n> improper initialization of hashmap_entry structs which\n> can leave \"hashmap_entry.next\" uninitialized.\n\nJunio, I'm planning to reroll this series.\n(Sorry for not following up sooner)\n\nWould you prefer I drop 04/11 \"hashmap_entry: detect improper initialization\"\nin favor of the following?  Thanks.\n\n---------8<--------\nSubject: [PATCH 4/11] coccicheck: detect hashmap_entry.hash assignment\n\nAssigning hashmap_entry.hash manually leaves hashmap_entry.next\nuninitialized, which can be dangerous once the hashmap_entry is\ninserted into a hashmap.   Detect those assignments and use\nhashmap_entry_init, instead.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n contrib/coccinelle/hashmap.cocci | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)\n create mode 100644 contrib/coccinelle/hashmap.cocci\n\ndiff --git a/contrib/coccinelle/hashmap.cocci b/contrib/coccinelle/hashmap.cocci\nnew file mode 100644\nindex 0000000000..d69e120ccf\n--- /dev/null\n+++ b/contrib/coccinelle/hashmap.cocci\n@@ -0,0 +1,16 @@\n+@ hashmap_entry_init_usage @\n+expression E;\n+struct hashmap_entry HME;\n+@@\n+- HME.hash = E;\n++ hashmap_entry_init(&HME, E);\n+\n+@@\n+identifier f !~ \"^hashmap_entry_init$\";\n+expression E;\n+struct hashmap_entry *HMEP;\n+@@\n+  f(...) {<...\n+- HMEP->hash = E;\n++ hashmap_entry_init(HMEP, E);\n+  ...>}\n"},{"id":"382083","messageId":"xmqqsgp5jpyx.fsf@gitster-ct.c.googlers.com","threadId":"51736","inReplyTo":"20190908074953.kux7zz4y7iolqko4@whir","subject":"Re: [RFC 04/11] coccicheck: detect hashmap_entry.hash assignment","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-09-09T18:15:34Z","receivedAt":"2019-09-09T18:15:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Wong <e@80x24.org> writes:\n\n> Eric Wong <e@80x24.org> wrote:\n>> By renaming the \"hash\" field to \"_hash\", it's easy to spot\n>> improper initialization of hashmap_entry structs which\n>> can leave \"hashmap_entry.next\" uninitialized.\n>\n> Junio, I'm planning to reroll this series.\n> (Sorry for not following up sooner)\n>\n> Would you prefer I drop 04/11 \"hashmap_entry: detect improper initialization\"\n> in favor of the following?  Thanks.\n\nAutomation is good ;-)\nFWIW, I do not mind the original 04/11 myself too much, though.\n\nThanks.\n\n> ---------8<--------\n> Subject: [PATCH 4/11] coccicheck: detect hashmap_entry.hash assignment\n>\n> Assigning hashmap_entry.hash manually leaves hashmap_entry.next\n> uninitialized, which can be dangerous once the hashmap_entry is\n> inserted into a hashmap.   Detect those assignments and use\n> hashmap_entry_init, instead.\n>\n> Signed-off-by: Eric Wong <e@80x24.org>\n> ---\n>  contrib/coccinelle/hashmap.cocci | 16 ++++++++++++++++\n>  1 file changed, 16 insertions(+)\n>  create mode 100644 contrib/coccinelle/hashmap.cocci\n>\n> diff --git a/contrib/coccinelle/hashmap.cocci b/contrib/coccinelle/hashmap.cocci\n> new file mode 100644\n> index 0000000000..d69e120ccf\n> --- /dev/null\n> +++ b/contrib/coccinelle/hashmap.cocci\n> @@ -0,0 +1,16 @@\n> +@ hashmap_entry_init_usage @\n> +expression E;\n> +struct hashmap_entry HME;\n> +@@\n> +- HME.hash = E;\n> ++ hashmap_entry_init(&HME, E);\n> +\n> +@@\n> +identifier f !~ \"^hashmap_entry_init$\";\n> +expression E;\n> +struct hashmap_entry *HMEP;\n> +@@\n> +  f(...) {<...\n> +- HMEP->hash = E;\n> ++ hashmap_entry_init(HMEP, E);\n> +  ...>}\n"},{"id":"382808","messageId":"20190924010324.22619-1-e@80x24.org","threadId":"51736","inReplyTo":"20190826024332.3403-1-e@80x24.org","subject":"[PATCH v2 00/19] hashmap bug/safety/ease-of-use fixes","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:05Z","receivedAt":"2019-09-24T01:03:26Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Patches 1-11 are largely unchanged from the original series with the\nexception of 2, which is new and posted at:\n\n\thttps://public-inbox.org/git/20190908074953.kux7zz4y7iolqko4@whir/\n\n12-17 take further steps to get us away from hashmap_entry being\nthe first element, but they're also a bit ugly because __typeof__\nisn't portable\n\n18-19 finally brings me to the APIs I want to expose without\nrelying on __typeof :)\n\nApologies for the delays, been busy with other stuff...\n\nPrevious discussion starts at:\n\n\thttps://public-inbox.org/git/20190826024332.3403-1-e@80x24.org/\n\nThe following changes since commit 745f6812895b31c02b29bdfe4ae8e5498f776c26:\n\n  First batch after Git 2.23 (2019-08-22 12:41:04 -0700)\n\nare available in the Git repository at:\n\n  https://80x24.org/git-svn.git hashmap-wip-v2\n\nfor you to fetch changes up to 212a596edd99169b284912b7b70b6280e2fb90e6:\n\n  hashmap: remove type arg from hashmap_{get,put,remove}_entry (2019-09-24 00:42:22 +0000)\n\n----------------------------------------------------------------\nEric Wong (19):\n      diff: use hashmap_entry_init on moved_entry.ent\n      coccicheck: detect hashmap_entry.hash assignment\n      packfile: use hashmap_entry in delta_base_cache_entry\n      hashmap_entry_init takes \"struct hashmap_entry *\"\n      hashmap_get_next takes \"const struct hashmap_entry *\"\n      hashmap_add takes \"struct hashmap_entry *\"\n      hashmap_get takes \"const struct hashmap_entry *\"\n      hashmap_remove takes \"const struct hashmap_entry *\"\n      hashmap_put takes \"struct hashmap_entry *\"\n      introduce container_of macro\n      hashmap_get_next returns \"struct hashmap_entry *\"\n      hashmap: use *_entry APIs to wrap container_of\n      hashmap_get{,_from_hash} return \"struct hashmap_entry *\"\n      hashmap_cmp_fn takes hashmap_entry params\n      hashmap: use *_entry APIs for iteration\n      hashmap: hashmap_{put,remove} return hashmap_entry *\n      hashmap: introduce hashmap_free_entries\n      OFFSETOF_VAR macro to simplify hashmap iterators\n      hashmap: remove type arg from hashmap_{get,put,remove}_entry\n\n attr.c                              |  22 ++---\n blame.c                             |  25 +++---\n builtin/describe.c                  |  21 +++--\n builtin/difftool.c                  |  56 ++++++------\n builtin/fast-export.c               |  15 ++--\n builtin/fetch.c                     |  30 ++++---\n config.c                            |  24 +++---\n contrib/coccinelle/hashmap.cocci    |  16 ++++\n diff.c                              |  31 ++++---\n diffcore-rename.c                   |  15 ++--\n git-compat-util.h                   |  33 ++++++++\n hashmap.c                           |  58 ++++++++-----\n hashmap.h                           | 164 +++++++++++++++++++++++++++++-------\n merge-recursive.c                   |  87 ++++++++++---------\n name-hash.c                         |  57 +++++++------\n oidmap.c                            |  20 +++--\n oidmap.h                            |   6 +-\n packfile.c                          |  22 +++--\n patch-ids.c                         |  18 ++--\n range-diff.c                        |  10 +--\n ref-filter.c                        |  31 ++++---\n refs.c                              |  23 +++--\n remote.c                            |  21 +++--\n revision.c                          |  28 +++---\n sequencer.c                         |  44 ++++++----\n sub-process.c                       |  20 +++--\n sub-process.h                       |   4 +-\n submodule-config.c                  |  52 +++++++-----\n t/helper/test-hashmap.c             |  49 ++++++-----\n t/helper/test-lazy-init-name-hash.c |  12 +--\n 30 files changed, 647 insertions(+), 367 deletions(-)\n create mode 100644 contrib/coccinelle/hashmap.cocci\n\nEric Wong (19):\n  diff: use hashmap_entry_init on moved_entry.ent\n  coccicheck: detect hashmap_entry.hash assignment\n  packfile: use hashmap_entry in delta_base_cache_entry\n  hashmap_entry_init takes \"struct hashmap_entry *\"\n  hashmap_get_next takes \"const struct hashmap_entry *\"\n  hashmap_add takes \"struct hashmap_entry *\"\n  hashmap_get takes \"const struct hashmap_entry *\"\n  hashmap_remove takes \"const struct hashmap_entry *\"\n  hashmap_put takes \"struct hashmap_entry *\"\n  introduce container_of macro\n  hashmap_get_next returns \"struct hashmap_entry *\"\n  hashmap: use *_entry APIs to wrap container_of\n  hashmap_get{,_from_hash} return \"struct hashmap_entry *\"\n  hashmap_cmp_fn takes hashmap_entry params\n  hashmap: use *_entry APIs for iteration\n  hashmap: hashmap_{put,remove} return hashmap_entry *\n  hashmap: introduce hashmap_free_entries\n  OFFSETOF_VAR macro to simplify hashmap iterators\n  hashmap: remove type arg from hashmap_{get,put,remove}_entry\n\n attr.c                              |  22 ++--\n blame.c                             |  25 +++--\n builtin/describe.c                  |  21 ++--\n builtin/difftool.c                  |  56 ++++++----\n builtin/fast-export.c               |  15 ++-\n builtin/fetch.c                     |  30 ++---\n config.c                            |  24 ++--\n contrib/coccinelle/hashmap.cocci    |  16 +++\n diff.c                              |  31 +++---\n diffcore-rename.c                   |  15 ++-\n git-compat-util.h                   |  33 ++++++\n hashmap.c                           |  58 ++++++----\n hashmap.h                           | 164 +++++++++++++++++++++++-----\n merge-recursive.c                   |  87 ++++++++-------\n name-hash.c                         |  57 +++++-----\n oidmap.c                            |  20 ++--\n oidmap.h                            |   6 +-\n packfile.c                          |  22 ++--\n patch-ids.c                         |  18 +--\n range-diff.c                        |  10 +-\n ref-filter.c                        |  31 ++++--\n refs.c                              |  23 +++-\n remote.c                            |  21 ++--\n revision.c                          |  28 +++--\n sequencer.c                         |  44 +++++---\n sub-process.c                       |  20 ++--\n sub-process.h                       |   4 +-\n submodule-config.c                  |  52 +++++----\n t/helper/test-hashmap.c             |  49 +++++----\n t/helper/test-lazy-init-name-hash.c |  12 +-\n 30 files changed, 647 insertions(+), 367 deletions(-)\n create mode 100644 contrib/coccinelle/hashmap.cocci\n\n\nbase-commit: 745f6812895b31c02b29bdfe4ae8e5498f776c26\n"},{"id":"382809","messageId":"20190924010324.22619-2-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 01/19] diff: use hashmap_entry_init on moved_entry.ent","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:06Z","receivedAt":"2019-09-24T01:03:28Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Otherwise, the hashmap_entry.next field appears to remain\nuninitialized, which can lead to problems when\nadd_lines_to_move_detection calls hashmap_add.\n\nI found this through manual inspection when converting\nhashmap_add callers to take \"struct hashmap_entry *\".\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n diff.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/diff.c b/diff.c\nindex efe42b341a..02491ee684 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -964,8 +964,9 @@ static struct moved_entry *prepare_entry(struct diff_options *o,\n \tstruct moved_entry *ret = xmalloc(sizeof(*ret));\n \tstruct emitted_diff_symbol *l = &o->emitted_symbols->buf[line_no];\n \tunsigned flags = o->color_moved_ws_handling & XDF_WHITESPACE_FLAGS;\n+\tunsigned int hash = xdiff_hash_string(l->line, l->len, flags);\n \n-\tret->ent.hash = xdiff_hash_string(l->line, l->len, flags);\n+\thashmap_entry_init(&ret->ent, hash);\n \tret->es = l;\n \tret->next_line = NULL;\n \n"},{"id":"382810","messageId":"20190924010324.22619-3-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 02/19] coccicheck: detect hashmap_entry.hash assignment","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:07Z","receivedAt":"2019-09-24T01:03:30Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Assigning hashmap_entry.hash manually leaves hashmap_entry.next\nuninitialized, which can be dangerous once the hashmap_entry is\ninserted into a hashmap.   Detect those assignments and use\nhashmap_entry_init, instead.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n contrib/coccinelle/hashmap.cocci | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)\n create mode 100644 contrib/coccinelle/hashmap.cocci\n\ndiff --git a/contrib/coccinelle/hashmap.cocci b/contrib/coccinelle/hashmap.cocci\nnew file mode 100644\nindex 0000000000..d69e120ccf\n--- /dev/null\n+++ b/contrib/coccinelle/hashmap.cocci\n@@ -0,0 +1,16 @@\n+@ hashmap_entry_init_usage @\n+expression E;\n+struct hashmap_entry HME;\n+@@\n+- HME.hash = E;\n++ hashmap_entry_init(&HME, E);\n+\n+@@\n+identifier f !~ \"^hashmap_entry_init$\";\n+expression E;\n+struct hashmap_entry *HMEP;\n+@@\n+  f(...) {<...\n+- HMEP->hash = E;\n++ hashmap_entry_init(HMEP, E);\n+  ...>}\n"},{"id":"382812","messageId":"20190924010324.22619-4-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 03/19] packfile: use hashmap_entry in delta_base_cache_entry","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:08Z","receivedAt":"2019-09-24T01:03:33Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This hashmap_entry_init function is intended to take a\nhashmap_entry struct pointer, not a hashmap struct pointer.\n\nThis was not noticed because hashmap_entry_init takes a \"void *\"\narg instead of \"struct hashmap_entry *\", and the hashmap struct\nis larger and can be cast into a hashmap_entry struct without\ndata corruption.\n\nThis has the beneficial side effect of reducing the size of\na delta_base_cache_entry from 104 bytes to 72 bytes on 64-bit\nsystems.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n packfile.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/packfile.c b/packfile.c\nindex fc43a6c52c..37fe0b73a6 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1361,7 +1361,7 @@ struct delta_base_cache_key {\n };\n \n struct delta_base_cache_entry {\n-\tstruct hashmap hash;\n+\tstruct hashmap_entry ent;\n \tstruct delta_base_cache_key key;\n \tstruct list_head lru;\n \tvoid *data;\n"},{"id":"382811","messageId":"20190924010324.22619-5-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 04/19] hashmap_entry_init takes \"struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:09Z","receivedAt":"2019-09-24T01:03:35Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"C compilers do type checking to make life easier for us.  So\nrely on that and update all hashmap_entry_init callers to take\n\"struct hashmap_entry *\" to avoid future bugs while improving\nsafety and readability.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n attr.c                  |  4 ++--\n blame.c                 |  2 +-\n builtin/describe.c      |  2 +-\n builtin/difftool.c      |  6 +++---\n builtin/fast-export.c   |  2 +-\n builtin/fetch.c         |  2 +-\n config.c                |  4 ++--\n diffcore-rename.c       |  2 +-\n hashmap.c               |  4 ++--\n hashmap.h               | 12 ++++++------\n merge-recursive.c       | 13 +++++++------\n name-hash.c             | 10 +++++-----\n packfile.c              |  2 +-\n patch-ids.c             |  2 +-\n range-diff.c            |  4 ++--\n ref-filter.c            |  3 ++-\n refs.c                  |  2 +-\n remote.c                |  2 +-\n revision.c              |  4 ++--\n sequencer.c             |  5 +++--\n sub-process.c           |  4 ++--\n submodule-config.c      | 10 +++++-----\n t/helper/test-hashmap.c |  6 +++---\n 23 files changed, 55 insertions(+), 52 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex 93dc16b59c..a8be7a7b4f 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -98,7 +98,7 @@ static void *attr_hashmap_get(struct attr_hashmap *map,\n \tif (!map->map.tablesize)\n \t\tattr_hashmap_init(map);\n \n-\thashmap_entry_init(&k, memhash(key, keylen));\n+\thashmap_entry_init(&k.ent, memhash(key, keylen));\n \tk.key = key;\n \tk.keylen = keylen;\n \te = hashmap_get(&map->map, &k, NULL);\n@@ -117,7 +117,7 @@ static void attr_hashmap_add(struct attr_hashmap *map,\n \t\tattr_hashmap_init(map);\n \n \te = xmalloc(sizeof(struct attr_hash_entry));\n-\thashmap_entry_init(e, memhash(key, keylen));\n+\thashmap_entry_init(&e->ent, memhash(key, keylen));\n \te->key = key;\n \te->keylen = keylen;\n \te->value = value;\ndiff --git a/blame.c b/blame.c\nindex 36a2e7ef11..46059410cd 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -417,7 +417,7 @@ static void get_fingerprint(struct fingerprint *result,\n \t\t/* Ignore whitespace pairs */\n \t\tif (hash == 0)\n \t\t\tcontinue;\n-\t\thashmap_entry_init(entry, hash);\n+\t\thashmap_entry_init(&entry->entry, hash);\n \n \t\tfound_entry = hashmap_get(&result->map, entry, NULL);\n \t\tif (found_entry) {\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 200154297d..596ddf89a5 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -123,7 +123,7 @@ static void add_to_known_names(const char *path,\n \t\tif (!e) {\n \t\t\te = xmalloc(sizeof(struct commit_name));\n \t\t\toidcpy(&e->peeled, peeled);\n-\t\t\thashmap_entry_init(e, oidhash(peeled));\n+\t\t\thashmap_entry_init(&e->entry, oidhash(peeled));\n \t\t\thashmap_add(&names, e);\n \t\t\te->path = NULL;\n \t\t}\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 16eb8b70ea..98ffc04c61 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -161,7 +161,7 @@ static void add_left_or_right(struct hashmap *map, const char *path,\n \tstruct pair_entry *e, *existing;\n \n \tFLEX_ALLOC_STR(e, path, path);\n-\thashmap_entry_init(e, strhash(path));\n+\thashmap_entry_init(&e->entry, strhash(path));\n \texisting = hashmap_get(map, e, NULL);\n \tif (existing) {\n \t\tfree(e);\n@@ -234,7 +234,7 @@ static void changed_files(struct hashmap *result, const char *index_path,\n \twhile (!strbuf_getline_nul(&buf, fp)) {\n \t\tstruct path_entry *entry;\n \t\tFLEX_ALLOC_STR(entry, path, buf.buf);\n-\t\thashmap_entry_init(entry, strhash(buf.buf));\n+\t\thashmap_entry_init(&entry->entry, strhash(buf.buf));\n \t\thashmap_add(result, entry);\n \t}\n \tfclose(fp);\n@@ -461,7 +461,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \n \t\t\t/* Avoid duplicate working_tree entries */\n \t\t\tFLEX_ALLOC_STR(entry, path, dst_path);\n-\t\t\thashmap_entry_init(entry, strhash(dst_path));\n+\t\t\thashmap_entry_init(&entry->entry, strhash(dst_path));\n \t\t\tif (hashmap_get(&working_tree_dups, entry, NULL)) {\n \t\t\t\tfree(entry);\n \t\t\t\tcontinue;\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex f541f55d33..287dbd24a3 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -148,7 +148,7 @@ static const void *anonymize_mem(struct hashmap *map,\n \tif (!map->cmpfn)\n \t\thashmap_init(map, anonymized_entry_cmp, NULL, 0);\n \n-\thashmap_entry_init(&key, memhash(orig, *len));\n+\thashmap_entry_init(&key.hash, memhash(orig, *len));\n \tkey.orig = orig;\n \tkey.orig_len = *len;\n \tret = hashmap_get(map, &key, NULL);\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 717dd14e89..b7d70eee70 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -276,7 +276,7 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map,\n \tsize_t len = strlen(refname);\n \n \tFLEX_ALLOC_MEM(ent, refname, refname, len);\n-\thashmap_entry_init(ent, strhash(refname));\n+\thashmap_entry_init(&ent->ent, strhash(refname));\n \toidcpy(&ent->oid, oid);\n \thashmap_add(map, ent);\n \treturn ent;\ndiff --git a/config.c b/config.c\nindex 3900e4947b..08d866e7de 100644\n--- a/config.c\n+++ b/config.c\n@@ -1861,7 +1861,7 @@ static struct config_set_element *configset_find_element(struct config_set *cs,\n \tif (git_config_parse_key(key, &normalized_key, NULL))\n \t\treturn NULL;\n \n-\thashmap_entry_init(&k, strhash(normalized_key));\n+\thashmap_entry_init(&k.ent, strhash(normalized_key));\n \tk.key = normalized_key;\n \tfound_entry = hashmap_get(&cs->config_hash, &k, NULL);\n \tfree(normalized_key);\n@@ -1882,7 +1882,7 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha\n \t */\n \tif (!e) {\n \t\te = xmalloc(sizeof(*e));\n-\t\thashmap_entry_init(e, strhash(key));\n+\t\thashmap_entry_init(&e->ent, strhash(key));\n \t\te->key = xstrdup(key);\n \t\tstring_list_init(&e->value_list, 1);\n \t\thashmap_add(&cs->config_hash, e);\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 9624864858..44a3ab1e31 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -329,7 +329,7 @@ static void insert_file_table(struct repository *r,\n \tentry->index = index;\n \tentry->filespec = filespec;\n \n-\thashmap_entry_init(entry, hash_filespec(r, filespec));\n+\thashmap_entry_init(&entry->entry, hash_filespec(r, filespec));\n \thashmap_add(table, entry);\n }\n \ndiff --git a/hashmap.c b/hashmap.c\nindex d42f01ff5a..6818c65174 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -293,13 +293,13 @@ const void *memintern(const void *data, size_t len)\n \t\thashmap_init(&map, (hashmap_cmp_fn) pool_entry_cmp, NULL, 0);\n \n \t/* lookup interned string in pool */\n-\thashmap_entry_init(&key, memhash(data, len));\n+\thashmap_entry_init(&key.ent, memhash(data, len));\n \tkey.len = len;\n \te = hashmap_get(&map, &key, data);\n \tif (!e) {\n \t\t/* not found: create it */\n \t\tFLEX_ALLOC_MEM(e, data, data, len);\n-\t\thashmap_entry_init(e, key.ent.hash);\n+\t\thashmap_entry_init(&e->ent, key.ent.hash);\n \t\te->len = len;\n \t\thashmap_add(&map, e);\n \t}\ndiff --git a/hashmap.h b/hashmap.h\nindex 8424911566..3d7939c291 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -48,14 +48,14 @@\n  *         if (!strcmp(\"add\", action)) {\n  *             struct long2string *e;\n  *             FLEX_ALLOC_STR(e, value, value);\n- *             hashmap_entry_init(e, memhash(&key, sizeof(long)));\n+ *             hashmap_entry_init(&e->ent, memhash(&key, sizeof(long)));\n  *             e->key = key;\n  *             hashmap_add(&map, e);\n  *         }\n  *\n  *         if (!strcmp(\"print_all_by_key\", action)) {\n  *             struct long2string k, *e;\n- *             hashmap_entry_init(&k, memhash(&key, sizeof(long)));\n+ *             hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));\n  *             k.key = key;\n  *\n  *             flags &= ~COMPARE_VALUE;\n@@ -70,7 +70,7 @@\n  *         if (!strcmp(\"has_exact_match\", action)) {\n  *             struct long2string *e;\n  *             FLEX_ALLOC_STR(e, value, value);\n- *             hashmap_entry_init(e, memhash(&key, sizeof(long)));\n+ *             hashmap_entry_init(&e->ent, memhash(&key, sizeof(long)));\n  *             e->key = key;\n  *\n  *             flags |= COMPARE_VALUE;\n@@ -80,7 +80,7 @@\n  *\n  *         if (!strcmp(\"has_exact_match_no_heap_alloc\", action)) {\n  *             struct long2string k;\n- *             hashmap_entry_init(&k, memhash(&key, sizeof(long)));\n+ *             hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));\n  *             k.key = key;\n  *\n  *             flags |= COMPARE_VALUE;\n@@ -244,9 +244,9 @@ void hashmap_free(struct hashmap *map, int free_entries);\n  * your structure was allocated with xmalloc(), you can just free(3) it,\n  * and if it is on stack, you can just let it go out of scope).\n  */\n-static inline void hashmap_entry_init(void *entry, unsigned int hash)\n+static inline void\n+hashmap_entry_init(struct hashmap_entry *e, unsigned int hash)\n {\n-\tstruct hashmap_entry *e = entry;\n \te->hash = hash;\n \te->next = NULL;\n }\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 6b812d67e3..6bc4f14ff4 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -61,7 +61,7 @@ static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,\n \n \tif (dir == NULL)\n \t\treturn NULL;\n-\thashmap_entry_init(&key, strhash(dir));\n+\thashmap_entry_init(&key.ent, strhash(dir));\n \tkey.dir = dir;\n \treturn hashmap_get(hashmap, &key, NULL);\n }\n@@ -85,7 +85,7 @@ static void dir_rename_init(struct hashmap *map)\n static void dir_rename_entry_init(struct dir_rename_entry *entry,\n \t\t\t\t  char *directory)\n {\n-\thashmap_entry_init(entry, strhash(directory));\n+\thashmap_entry_init(&entry->ent, strhash(directory));\n \tentry->dir = directory;\n \tentry->non_unique_new_dir = 0;\n \tstrbuf_init(&entry->new_dir, 0);\n@@ -97,7 +97,7 @@ static struct collision_entry *collision_find_entry(struct hashmap *hashmap,\n {\n \tstruct collision_entry key;\n \n-\thashmap_entry_init(&key, strhash(target_file));\n+\thashmap_entry_init(&key.ent, strhash(target_file));\n \tkey.target_file = target_file;\n \treturn hashmap_get(hashmap, &key, NULL);\n }\n@@ -454,7 +454,7 @@ static int save_files_dirs(const struct object_id *oid,\n \tstrbuf_addstr(base, path);\n \n \tFLEX_ALLOC_MEM(entry, path, base->buf, base->len);\n-\thashmap_entry_init(entry, path_hash(entry->path));\n+\thashmap_entry_init(&entry->e, path_hash(entry->path));\n \thashmap_add(&opt->current_file_dir_set, entry);\n \n \tstrbuf_setlen(base, baselen);\n@@ -731,7 +731,7 @@ static char *unique_path(struct merge_options *opt, const char *path, const char\n \t}\n \n \tFLEX_ALLOC_MEM(entry, path, newpath.buf, newpath.len);\n-\thashmap_entry_init(entry, path_hash(entry->path));\n+\thashmap_entry_init(&entry->e, path_hash(entry->path));\n \thashmap_add(&opt->current_file_dir_set, entry);\n \treturn strbuf_detach(&newpath, NULL);\n }\n@@ -2358,7 +2358,8 @@ static void compute_collisions(struct hashmap *collisions,\n \t\tif (!collision_ent) {\n \t\t\tcollision_ent = xcalloc(1,\n \t\t\t\t\t\tsizeof(struct collision_entry));\n-\t\t\thashmap_entry_init(collision_ent, strhash(new_path));\n+\t\t\thashmap_entry_init(&collision_ent->ent,\n+\t\t\t\t\t\tstrhash(new_path));\n \t\t\thashmap_put(collisions, collision_ent);\n \t\t\tcollision_ent->target_file = new_path;\n \t\t} else {\ndiff --git a/name-hash.c b/name-hash.c\nindex 695908609f..1ce1417f7e 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -33,7 +33,7 @@ static struct dir_entry *find_dir_entry__hash(struct index_state *istate,\n \t\tconst char *name, unsigned int namelen, unsigned int hash)\n {\n \tstruct dir_entry key;\n-\thashmap_entry_init(&key, hash);\n+\thashmap_entry_init(&key.ent, hash);\n \tkey.namelen = namelen;\n \treturn hashmap_get(&istate->dir_hash, &key, name);\n }\n@@ -68,7 +68,7 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,\n \tif (!dir) {\n \t\t/* not found, create it and add to hash table */\n \t\tFLEX_ALLOC_MEM(dir, name, ce->name, namelen);\n-\t\thashmap_entry_init(dir, memihash(ce->name, namelen));\n+\t\thashmap_entry_init(&dir->ent, memihash(ce->name, namelen));\n \t\tdir->namelen = namelen;\n \t\thashmap_add(&istate->dir_hash, dir);\n \n@@ -106,7 +106,7 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)\n \tif (ce->ce_flags & CE_HASHED)\n \t\treturn;\n \tce->ce_flags |= CE_HASHED;\n-\thashmap_entry_init(ce, memihash(ce->name, ce_namelen(ce)));\n+\thashmap_entry_init(&ce->ent, memihash(ce->name, ce_namelen(ce)));\n \thashmap_add(&istate->name_hash, ce);\n \n \tif (ignore_case)\n@@ -280,7 +280,7 @@ static struct dir_entry *hash_dir_entry_with_parent_and_prefix(\n \tdir = find_dir_entry__hash(istate, prefix->buf, prefix->len, hash);\n \tif (!dir) {\n \t\tFLEX_ALLOC_MEM(dir, name, prefix->buf, prefix->len);\n-\t\thashmap_entry_init(dir, hash);\n+\t\thashmap_entry_init(&dir->ent, hash);\n \t\tdir->namelen = prefix->len;\n \t\tdir->parent = parent;\n \t\thashmap_add(&istate->dir_hash, dir);\n@@ -472,7 +472,7 @@ static void *lazy_name_thread_proc(void *_data)\n \tfor (k = 0; k < d->istate->cache_nr; k++) {\n \t\tstruct cache_entry *ce_k = d->istate->cache[k];\n \t\tce_k->ce_flags |= CE_HASHED;\n-\t\thashmap_entry_init(ce_k, d->lazy_entries[k].hash_name);\n+\t\thashmap_entry_init(&ce_k->ent, d->lazy_entries[k].hash_name);\n \t\thashmap_add(&d->istate->name_hash, ce_k);\n \t}\n \ndiff --git a/packfile.c b/packfile.c\nindex 37fe0b73a6..96535eb86b 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1487,7 +1487,7 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,\n \n \tif (!delta_base_cache.cmpfn)\n \t\thashmap_init(&delta_base_cache, delta_base_cache_hash_cmp, NULL, 0);\n-\thashmap_entry_init(ent, pack_entry_hash(p, base_offset));\n+\thashmap_entry_init(&ent->ent, pack_entry_hash(p, base_offset));\n \thashmap_add(&delta_base_cache, ent);\n }\n \ndiff --git a/patch-ids.c b/patch-ids.c\nindex e8c150d0c9..a2da711678 100644\n--- a/patch-ids.c\n+++ b/patch-ids.c\n@@ -83,7 +83,7 @@ static int init_patch_id_entry(struct patch_id *patch,\n \tif (commit_patch_id(commit, &ids->diffopts, &header_only_patch_id, 1, 0))\n \t\treturn -1;\n \n-\thashmap_entry_init(patch, oidhash(&header_only_patch_id));\n+\thashmap_entry_init(&patch->ent, oidhash(&header_only_patch_id));\n \treturn 0;\n }\n \ndiff --git a/range-diff.c b/range-diff.c\nindex ba1e9a4265..32b29f9594 100644\n--- a/range-diff.c\n+++ b/range-diff.c\n@@ -217,7 +217,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n \t\tutil->i = i;\n \t\tutil->patch = a->items[i].string;\n \t\tutil->diff = util->patch + util->diff_offset;\n-\t\thashmap_entry_init(util, strhash(util->diff));\n+\t\thashmap_entry_init(&util->e, strhash(util->diff));\n \t\thashmap_add(&map, util);\n \t}\n \n@@ -228,7 +228,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n \t\tutil->i = i;\n \t\tutil->patch = b->items[i].string;\n \t\tutil->diff = util->patch + util->diff_offset;\n-\t\thashmap_entry_init(util, strhash(util->diff));\n+\t\thashmap_entry_init(&util->e, strhash(util->diff));\n \t\tother = hashmap_remove(&map, util, NULL);\n \t\tif (other) {\n \t\t\tif (other->matching >= 0)\ndiff --git a/ref-filter.c b/ref-filter.c\nindex f27cfc8c3e..206014c93d 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1565,7 +1565,8 @@ static void populate_worktree_map(struct hashmap *map, struct worktree **worktre\n \t\t\tstruct ref_to_worktree_entry *entry;\n \t\t\tentry = xmalloc(sizeof(*entry));\n \t\t\tentry->wt = worktrees[i];\n-\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n+\t\t\thashmap_entry_init(&entry->ent,\n+\t\t\t\t\tstrhash(worktrees[i]->head_ref));\n \n \t\t\thashmap_add(map, entry);\n \t\t}\ndiff --git a/refs.c b/refs.c\nindex cd297ee4bd..c43ec59c6e 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1796,7 +1796,7 @@ static struct ref_store_hash_entry *alloc_ref_store_hash_entry(\n \tstruct ref_store_hash_entry *entry;\n \n \tFLEX_ALLOC_STR(entry, name, name);\n-\thashmap_entry_init(entry, strhash(name));\n+\thashmap_entry_init(&entry->ent, strhash(name));\n \tentry->refs = refs;\n \treturn entry;\n }\ndiff --git a/remote.c b/remote.c\nindex e50f7602ed..bd81cb71bc 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -158,7 +158,7 @@ static struct remote *make_remote(const char *name, int len)\n \tALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);\n \tremotes[remotes_nr++] = ret;\n \n-\thashmap_entry_init(ret, lookup_entry.hash);\n+\thashmap_entry_init(&ret->ent, lookup_entry.hash);\n \treplaced = hashmap_put(&remotes_hash, ret);\n \tassert(replaced == NULL);  /* no previous entry overwritten */\n \treturn ret;\ndiff --git a/revision.c b/revision.c\nindex 07412297f0..3461c78883 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -141,7 +141,7 @@ static void paths_and_oids_insert(struct hashmap *map,\n \tstruct path_and_oids_entry key;\n \tstruct path_and_oids_entry *entry;\n \n-\thashmap_entry_init(&key, hash);\n+\thashmap_entry_init(&key.ent, hash);\n \n \t/* use a shallow copy for the lookup */\n \tkey.path = (char *)path;\n@@ -149,7 +149,7 @@ static void paths_and_oids_insert(struct hashmap *map,\n \n \tif (!(entry = (struct path_and_oids_entry *)hashmap_get(map, &key, NULL))) {\n \t\tentry = xcalloc(1, sizeof(struct path_and_oids_entry));\n-\t\thashmap_entry_init(entry, hash);\n+\t\thashmap_entry_init(&entry->ent, hash);\n \t\tentry->path = xstrdup(key.path);\n \t\toidset_init(&entry->trees, 16);\n \t\thashmap_put(map, entry);\ndiff --git a/sequencer.c b/sequencer.c\nindex 34ebf8ed94..1140cdf526 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4538,7 +4538,7 @@ static const char *label_oid(struct object_id *oid, const char *label,\n \t}\n \n \tFLEX_ALLOC_STR(labels_entry, label, label);\n-\thashmap_entry_init(labels_entry, strihash(label));\n+\thashmap_entry_init(&labels_entry->entry, strihash(label));\n \thashmap_add(&state->labels, labels_entry);\n \n \tFLEX_ALLOC_STR(string_entry, string, label);\n@@ -5252,7 +5252,8 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\t\t\t\t\tstrhash(subject), subject)) {\n \t\t\tFLEX_ALLOC_MEM(entry, subject, subject, subject_len);\n \t\t\tentry->i = i;\n-\t\t\thashmap_entry_init(entry, strhash(entry->subject));\n+\t\t\thashmap_entry_init(&entry->entry,\n+\t\t\t\t\tstrhash(entry->subject));\n \t\t\thashmap_put(&subject2item, entry);\n \t\t}\n \t}\ndiff --git a/sub-process.c b/sub-process.c\nindex 3f4af93555..9847dad6fc 100644\n--- a/sub-process.c\n+++ b/sub-process.c\n@@ -20,7 +20,7 @@ struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const ch\n {\n \tstruct subprocess_entry key;\n \n-\thashmap_entry_init(&key, strhash(cmd));\n+\thashmap_entry_init(&key.ent, strhash(cmd));\n \tkey.cmd = cmd;\n \treturn hashmap_get(hashmap, &key, NULL);\n }\n@@ -96,7 +96,7 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co\n \t\treturn err;\n \t}\n \n-\thashmap_entry_init(entry, strhash(cmd));\n+\thashmap_entry_init(&entry->ent, strhash(cmd));\n \n \terr = startfn(entry);\n \tif (err) {\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 4264ee216f..4aa02e280e 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -123,7 +123,7 @@ static void cache_put_path(struct submodule_cache *cache,\n \tunsigned int hash = hash_oid_string(&submodule->gitmodules_oid,\n \t\t\t\t\t    submodule->path);\n \tstruct submodule_entry *e = xmalloc(sizeof(*e));\n-\thashmap_entry_init(e, hash);\n+\thashmap_entry_init(&e->ent, hash);\n \te->config = submodule;\n \thashmap_put(&cache->for_path, e);\n }\n@@ -135,7 +135,7 @@ static void cache_remove_path(struct submodule_cache *cache,\n \t\t\t\t\t    submodule->path);\n \tstruct submodule_entry e;\n \tstruct submodule_entry *removed;\n-\thashmap_entry_init(&e, hash);\n+\thashmap_entry_init(&e.ent, hash);\n \te.config = submodule;\n \tremoved = hashmap_remove(&cache->for_path, &e, NULL);\n \tfree(removed);\n@@ -147,7 +147,7 @@ static void cache_add(struct submodule_cache *cache,\n \tunsigned int hash = hash_oid_string(&submodule->gitmodules_oid,\n \t\t\t\t\t    submodule->name);\n \tstruct submodule_entry *e = xmalloc(sizeof(*e));\n-\thashmap_entry_init(e, hash);\n+\thashmap_entry_init(&e->ent, hash);\n \te->config = submodule;\n \thashmap_add(&cache->for_name, e);\n }\n@@ -163,7 +163,7 @@ static const struct submodule *cache_lookup_path(struct submodule_cache *cache,\n \toidcpy(&key_config.gitmodules_oid, gitmodules_oid);\n \tkey_config.path = path;\n \n-\thashmap_entry_init(&key, hash);\n+\thashmap_entry_init(&key.ent, hash);\n \tkey.config = &key_config;\n \n \tentry = hashmap_get(&cache->for_path, &key, NULL);\n@@ -183,7 +183,7 @@ static struct submodule *cache_lookup_name(struct submodule_cache *cache,\n \toidcpy(&key_config.gitmodules_oid, gitmodules_oid);\n \tkey_config.name = name;\n \n-\thashmap_entry_init(&key, hash);\n+\thashmap_entry_init(&key.ent, hash);\n \tkey.config = &key_config;\n \n \tentry = hashmap_get(&cache->for_name, &key, NULL);\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex aaf17b0ddf..0c9fd7c996 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -37,7 +37,7 @@ static struct test_entry *alloc_test_entry(unsigned int hash,\n \tsize_t klen = strlen(key);\n \tsize_t vlen = strlen(value);\n \tstruct test_entry *entry = xmalloc(st_add4(sizeof(*entry), klen, vlen, 2));\n-\thashmap_entry_init(entry, hash);\n+\thashmap_entry_init(&entry->ent, hash);\n \tmemcpy(entry->key, key, klen + 1);\n \tmemcpy(entry->key + klen + 1, value, vlen + 1);\n \treturn entry;\n@@ -103,7 +103,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)\n \n \t\t\t/* add entries */\n \t\t\tfor (i = 0; i < TEST_SIZE; i++) {\n-\t\t\t\thashmap_entry_init(entries[i], hashes[i]);\n+\t\t\t\thashmap_entry_init(&entries[i]->ent, hashes[i]);\n \t\t\t\thashmap_add(&map, entries[i]);\n \t\t\t}\n \n@@ -116,7 +116,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)\n \t\t/* fill the map (sparsely if specified) */\n \t\tj = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE;\n \t\tfor (i = 0; i < j; i++) {\n-\t\t\thashmap_entry_init(entries[i], hashes[i]);\n+\t\t\thashmap_entry_init(&entries[i]->ent, hashes[i]);\n \t\t\thashmap_add(&map, entries[i]);\n \t\t}\n \n"},{"id":"382815","messageId":"20190924010324.22619-6-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 05/19] hashmap_get_next takes \"const struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:10Z","receivedAt":"2019-09-24T01:03:38Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is less error-prone than \"const void *\" as the compiler\nnow detects invalid types being passed.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n diff.c                  | 5 +++--\n diffcore-rename.c       | 2 +-\n hashmap.c               | 5 +++--\n hashmap.h               | 3 ++-\n name-hash.c             | 2 +-\n t/helper/test-hashmap.c | 2 +-\n 6 files changed, 11 insertions(+), 8 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 02491ee684..1168f0cbb9 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1036,7 +1036,7 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,\n \tint i;\n \tchar *got_match = xcalloc(1, pmb_nr);\n \n-\tfor (; match; match = hashmap_get_next(hm, match)) {\n+\tfor (; match; match = hashmap_get_next(hm, &match->ent)) {\n \t\tfor (i = 0; i < pmb_nr; i++) {\n \t\t\tstruct moved_entry *prev = pmb[i].match;\n \t\t\tstruct moved_entry *cur = (prev && prev->next_line) ?\n@@ -1189,7 +1189,8 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\t\t * The current line is the start of a new block.\n \t\t\t * Setup the set of potential blocks.\n \t\t\t */\n-\t\t\tfor (; match; match = hashmap_get_next(hm, match)) {\n+\t\t\tfor (; match; match = hashmap_get_next(hm,\n+\t\t\t\t\t\t\t\t&match->ent)) {\n \t\t\t\tALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);\n \t\t\t\tif (o->color_moved_ws_handling &\n \t\t\t\t    COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 44a3ab1e31..2a1449013b 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -285,7 +285,7 @@ static int find_identical_files(struct hashmap *srcs,\n \tp = hashmap_get_from_hash(srcs,\n \t\t\t\t  hash_filespec(options->repo, target),\n \t\t\t\t  NULL);\n-\tfor (; p; p = hashmap_get_next(srcs, p)) {\n+\tfor (; p; p = hashmap_get_next(srcs, &p->entry)) {\n \t\tint score;\n \t\tstruct diff_filespec *source = p->filespec;\n \ndiff --git a/hashmap.c b/hashmap.c\nindex 6818c65174..c1de40eea0 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -191,9 +191,10 @@ void *hashmap_get(const struct hashmap *map, const void *key, const void *keydat\n \treturn *find_entry_ptr(map, key, keydata);\n }\n \n-void *hashmap_get_next(const struct hashmap *map, const void *entry)\n+void *hashmap_get_next(const struct hashmap *map,\n+\t\t\tconst struct hashmap_entry *entry)\n {\n-\tstruct hashmap_entry *e = ((struct hashmap_entry *) entry)->next;\n+\tstruct hashmap_entry *e = entry->next;\n \tfor (; e; e = e->next)\n \t\tif (entry_equals(map, entry, e, NULL))\n \t\t\treturn e;\ndiff --git a/hashmap.h b/hashmap.h\nindex 3d7939c291..d607da525b 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -318,7 +318,8 @@ static inline void *hashmap_get_from_hash(const struct hashmap *map,\n  * `entry` is the hashmap_entry to start the search from, obtained via a previous\n  * call to `hashmap_get` or `hashmap_get_next`.\n  */\n-void *hashmap_get_next(const struct hashmap *map, const void *entry);\n+void *hashmap_get_next(const struct hashmap *map,\n+\t\t\tconst struct hashmap_entry *entry);\n \n /*\n  * Adds a hashmap entry. This allows to add duplicate entries (i.e.\ndiff --git a/name-hash.c b/name-hash.c\nindex 1ce1417f7e..4d84326c58 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -710,7 +710,7 @@ struct cache_entry *index_file_exists(struct index_state *istate, const char *na\n \twhile (ce) {\n \t\tif (same_name(ce, name, namelen, icase))\n \t\t\treturn ce;\n-\t\tce = hashmap_get_next(&istate->name_hash, ce);\n+\t\tce = hashmap_get_next(&istate->name_hash, &ce->ent);\n \t}\n \treturn NULL;\n }\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex 0c9fd7c996..bf063a2521 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -203,7 +203,7 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\t\tputs(\"NULL\");\n \t\t\twhile (entry) {\n \t\t\t\tputs(get_value(entry));\n-\t\t\t\tentry = hashmap_get_next(&map, entry);\n+\t\t\t\tentry = hashmap_get_next(&map, &entry->ent);\n \t\t\t}\n \n \t\t} else if (!strcmp(\"remove\", cmd) && p1) {\n"},{"id":"382814","messageId":"20190924010324.22619-7-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 06/19] hashmap_add takes \"struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:11Z","receivedAt":"2019-09-24T01:03:41Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is less error-prone than \"void *\" as the compiler now\ndetects invalid types being passed.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n attr.c                  | 2 +-\n blame.c                 | 2 +-\n builtin/describe.c      | 2 +-\n builtin/difftool.c      | 6 +++---\n builtin/fetch.c         | 2 +-\n config.c                | 2 +-\n diff.c                  | 2 +-\n diffcore-rename.c       | 2 +-\n hashmap.c               | 6 +++---\n hashmap.h               | 4 ++--\n merge-recursive.c       | 4 ++--\n name-hash.c             | 8 ++++----\n packfile.c              | 2 +-\n patch-ids.c             | 2 +-\n range-diff.c            | 2 +-\n ref-filter.c            | 2 +-\n sequencer.c             | 2 +-\n sub-process.c           | 2 +-\n submodule-config.c      | 2 +-\n t/helper/test-hashmap.c | 6 +++---\n 20 files changed, 31 insertions(+), 31 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex a8be7a7b4f..fa26a3e3cb 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -122,7 +122,7 @@ static void attr_hashmap_add(struct attr_hashmap *map,\n \te->keylen = keylen;\n \te->value = value;\n \n-\thashmap_add(&map->map, e);\n+\thashmap_add(&map->map, &e->ent);\n }\n \n struct all_attrs_item {\ndiff --git a/blame.c b/blame.c\nindex 46059410cd..4d20aee435 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -424,7 +424,7 @@ static void get_fingerprint(struct fingerprint *result,\n \t\t\tfound_entry->count += 1;\n \t\t} else {\n \t\t\tentry->count = 1;\n-\t\t\thashmap_add(&result->map, entry);\n+\t\t\thashmap_add(&result->map, &entry->entry);\n \t\t\t++entry;\n \t\t}\n \t}\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 596ddf89a5..f5e0a7e033 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -124,7 +124,7 @@ static void add_to_known_names(const char *path,\n \t\t\te = xmalloc(sizeof(struct commit_name));\n \t\t\toidcpy(&e->peeled, peeled);\n \t\t\thashmap_entry_init(&e->entry, oidhash(peeled));\n-\t\t\thashmap_add(&names, e);\n+\t\t\thashmap_add(&names, &e->entry);\n \t\t\te->path = NULL;\n \t\t}\n \t\te->tag = tag;\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 98ffc04c61..82c146718d 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -168,7 +168,7 @@ static void add_left_or_right(struct hashmap *map, const char *path,\n \t\te = existing;\n \t} else {\n \t\te->left[0] = e->right[0] = '\\0';\n-\t\thashmap_add(map, e);\n+\t\thashmap_add(map, &e->entry);\n \t}\n \tstrlcpy(is_right ? e->right : e->left, content, PATH_MAX);\n }\n@@ -235,7 +235,7 @@ static void changed_files(struct hashmap *result, const char *index_path,\n \t\tstruct path_entry *entry;\n \t\tFLEX_ALLOC_STR(entry, path, buf.buf);\n \t\thashmap_entry_init(&entry->entry, strhash(buf.buf));\n-\t\thashmap_add(result, entry);\n+\t\thashmap_add(result, &entry->entry);\n \t}\n \tfclose(fp);\n \tif (finish_command(&diff_files))\n@@ -466,7 +466,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\t\t\tfree(entry);\n \t\t\t\tcontinue;\n \t\t\t}\n-\t\t\thashmap_add(&working_tree_dups, entry);\n+\t\t\thashmap_add(&working_tree_dups, &entry->entry);\n \n \t\t\tif (!use_wt_file(workdir, dst_path, &roid)) {\n \t\t\t\tif (checkout_path(rmode, &roid, dst_path,\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex b7d70eee70..909dbde909 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -278,7 +278,7 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map,\n \tFLEX_ALLOC_MEM(ent, refname, refname, len);\n \thashmap_entry_init(&ent->ent, strhash(refname));\n \toidcpy(&ent->oid, oid);\n-\thashmap_add(map, ent);\n+\thashmap_add(map, &ent->ent);\n \treturn ent;\n }\n \ndiff --git a/config.c b/config.c\nindex 08d866e7de..2243d7c3d6 100644\n--- a/config.c\n+++ b/config.c\n@@ -1885,7 +1885,7 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha\n \t\thashmap_entry_init(&e->ent, strhash(key));\n \t\te->key = xstrdup(key);\n \t\tstring_list_init(&e->value_list, 1);\n-\t\thashmap_add(&cs->config_hash, e);\n+\t\thashmap_add(&cs->config_hash, &e->ent);\n \t}\n \tsi = string_list_append_nodup(&e->value_list, xstrdup_or_null(value));\n \ndiff --git a/diff.c b/diff.c\nindex 1168f0cbb9..cc7f06d10d 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1003,7 +1003,7 @@ static void add_lines_to_move_detection(struct diff_options *o,\n \t\tif (prev_line && prev_line->es->s == o->emitted_symbols->buf[n].s)\n \t\t\tprev_line->next_line = key;\n \n-\t\thashmap_add(hm, key);\n+\t\thashmap_add(hm, &key->ent);\n \t\tprev_line = key;\n \t}\n }\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 2a1449013b..4670a40179 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -330,7 +330,7 @@ static void insert_file_table(struct repository *r,\n \tentry->filespec = filespec;\n \n \thashmap_entry_init(&entry->entry, hash_filespec(r, filespec));\n-\thashmap_add(table, entry);\n+\thashmap_add(table, &entry->entry);\n }\n \n /*\ndiff --git a/hashmap.c b/hashmap.c\nindex c1de40eea0..9c2db3e0c8 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -201,12 +201,12 @@ void *hashmap_get_next(const struct hashmap *map,\n \treturn NULL;\n }\n \n-void hashmap_add(struct hashmap *map, void *entry)\n+void hashmap_add(struct hashmap *map, struct hashmap_entry *entry)\n {\n \tunsigned int b = bucket(map, entry);\n \n \t/* add entry */\n-\t((struct hashmap_entry *) entry)->next = map->table[b];\n+\tentry->next = map->table[b];\n \tmap->table[b] = entry;\n \n \t/* fix size and rehash if appropriate */\n@@ -302,7 +302,7 @@ const void *memintern(const void *data, size_t len)\n \t\tFLEX_ALLOC_MEM(e, data, data, len);\n \t\thashmap_entry_init(&e->ent, key.ent.hash);\n \t\te->len = len;\n-\t\thashmap_add(&map, e);\n+\t\thashmap_add(&map, &e->ent);\n \t}\n \treturn e->data;\n }\ndiff --git a/hashmap.h b/hashmap.h\nindex d607da525b..40bcc64289 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -50,7 +50,7 @@\n  *             FLEX_ALLOC_STR(e, value, value);\n  *             hashmap_entry_init(&e->ent, memhash(&key, sizeof(long)));\n  *             e->key = key;\n- *             hashmap_add(&map, e);\n+ *             hashmap_add(&map, &e->ent);\n  *         }\n  *\n  *         if (!strcmp(\"print_all_by_key\", action)) {\n@@ -328,7 +328,7 @@ void *hashmap_get_next(const struct hashmap *map,\n  * `map` is the hashmap structure.\n  * `entry` is the entry to add.\n  */\n-void hashmap_add(struct hashmap *map, void *entry);\n+void hashmap_add(struct hashmap *map, struct hashmap_entry *entry);\n \n /*\n  * Adds or replaces a hashmap entry. If the hashmap contains duplicate\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 6bc4f14ff4..db9b247ece 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -455,7 +455,7 @@ static int save_files_dirs(const struct object_id *oid,\n \n \tFLEX_ALLOC_MEM(entry, path, base->buf, base->len);\n \thashmap_entry_init(&entry->e, path_hash(entry->path));\n-\thashmap_add(&opt->current_file_dir_set, entry);\n+\thashmap_add(&opt->current_file_dir_set, &entry->e);\n \n \tstrbuf_setlen(base, baselen);\n \treturn (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);\n@@ -732,7 +732,7 @@ static char *unique_path(struct merge_options *opt, const char *path, const char\n \n \tFLEX_ALLOC_MEM(entry, path, newpath.buf, newpath.len);\n \thashmap_entry_init(&entry->e, path_hash(entry->path));\n-\thashmap_add(&opt->current_file_dir_set, entry);\n+\thashmap_add(&opt->current_file_dir_set, &entry->e);\n \treturn strbuf_detach(&newpath, NULL);\n }\n \ndiff --git a/name-hash.c b/name-hash.c\nindex 4d84326c58..faec682bc7 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -70,7 +70,7 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,\n \t\tFLEX_ALLOC_MEM(dir, name, ce->name, namelen);\n \t\thashmap_entry_init(&dir->ent, memihash(ce->name, namelen));\n \t\tdir->namelen = namelen;\n-\t\thashmap_add(&istate->dir_hash, dir);\n+\t\thashmap_add(&istate->dir_hash, &dir->ent);\n \n \t\t/* recursively add missing parent directories */\n \t\tdir->parent = hash_dir_entry(istate, ce, namelen);\n@@ -107,7 +107,7 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)\n \t\treturn;\n \tce->ce_flags |= CE_HASHED;\n \thashmap_entry_init(&ce->ent, memihash(ce->name, ce_namelen(ce)));\n-\thashmap_add(&istate->name_hash, ce);\n+\thashmap_add(&istate->name_hash, &ce->ent);\n \n \tif (ignore_case)\n \t\tadd_dir_entry(istate, ce);\n@@ -283,7 +283,7 @@ static struct dir_entry *hash_dir_entry_with_parent_and_prefix(\n \t\thashmap_entry_init(&dir->ent, hash);\n \t\tdir->namelen = prefix->len;\n \t\tdir->parent = parent;\n-\t\thashmap_add(&istate->dir_hash, dir);\n+\t\thashmap_add(&istate->dir_hash, &dir->ent);\n \n \t\tif (parent) {\n \t\t\tunlock_dir_mutex(lock_nr);\n@@ -473,7 +473,7 @@ static void *lazy_name_thread_proc(void *_data)\n \t\tstruct cache_entry *ce_k = d->istate->cache[k];\n \t\tce_k->ce_flags |= CE_HASHED;\n \t\thashmap_entry_init(&ce_k->ent, d->lazy_entries[k].hash_name);\n-\t\thashmap_add(&d->istate->name_hash, ce_k);\n+\t\thashmap_add(&d->istate->name_hash, &ce_k->ent);\n \t}\n \n \treturn NULL;\ndiff --git a/packfile.c b/packfile.c\nindex 96535eb86b..f7402c470b 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1488,7 +1488,7 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,\n \tif (!delta_base_cache.cmpfn)\n \t\thashmap_init(&delta_base_cache, delta_base_cache_hash_cmp, NULL, 0);\n \thashmap_entry_init(&ent->ent, pack_entry_hash(p, base_offset));\n-\thashmap_add(&delta_base_cache, ent);\n+\thashmap_add(&delta_base_cache, &ent->ent);\n }\n \n int packed_object_info(struct repository *r, struct packed_git *p,\ndiff --git a/patch-ids.c b/patch-ids.c\nindex a2da711678..f87b62bf58 100644\n--- a/patch-ids.c\n+++ b/patch-ids.c\n@@ -116,6 +116,6 @@ struct patch_id *add_commit_patch_id(struct commit *commit,\n \t\treturn NULL;\n \t}\n \n-\thashmap_add(&ids->patches, key);\n+\thashmap_add(&ids->patches, &key->ent);\n \treturn key;\n }\ndiff --git a/range-diff.c b/range-diff.c\nindex 32b29f9594..96f955d84d 100644\n--- a/range-diff.c\n+++ b/range-diff.c\n@@ -218,7 +218,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n \t\tutil->patch = a->items[i].string;\n \t\tutil->diff = util->patch + util->diff_offset;\n \t\thashmap_entry_init(&util->e, strhash(util->diff));\n-\t\thashmap_add(&map, util);\n+\t\thashmap_add(&map, &util->e);\n \t}\n \n \t/* Now try to find exact matches in b */\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 206014c93d..d939ebc6bb 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1568,7 +1568,7 @@ static void populate_worktree_map(struct hashmap *map, struct worktree **worktre\n \t\t\thashmap_entry_init(&entry->ent,\n \t\t\t\t\tstrhash(worktrees[i]->head_ref));\n \n-\t\t\thashmap_add(map, entry);\n+\t\t\thashmap_add(map, &entry->ent);\n \t\t}\n \t}\n }\ndiff --git a/sequencer.c b/sequencer.c\nindex 1140cdf526..ee11cda7e7 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4539,7 +4539,7 @@ static const char *label_oid(struct object_id *oid, const char *label,\n \n \tFLEX_ALLOC_STR(labels_entry, label, label);\n \thashmap_entry_init(&labels_entry->entry, strihash(label));\n-\thashmap_add(&state->labels, labels_entry);\n+\thashmap_add(&state->labels, &labels_entry->entry);\n \n \tFLEX_ALLOC_STR(string_entry, string, label);\n \toidcpy(&string_entry->entry.oid, oid);\ndiff --git a/sub-process.c b/sub-process.c\nindex 9847dad6fc..d58e069855 100644\n--- a/sub-process.c\n+++ b/sub-process.c\n@@ -105,7 +105,7 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co\n \t\treturn err;\n \t}\n \n-\thashmap_add(hashmap, entry);\n+\thashmap_add(hashmap, &entry->ent);\n \treturn 0;\n }\n \ndiff --git a/submodule-config.c b/submodule-config.c\nindex 4aa02e280e..a3bbd9fd6f 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -149,7 +149,7 @@ static void cache_add(struct submodule_cache *cache,\n \tstruct submodule_entry *e = xmalloc(sizeof(*e));\n \thashmap_entry_init(&e->ent, hash);\n \te->config = submodule;\n-\thashmap_add(&cache->for_name, e);\n+\thashmap_add(&cache->for_name, &e->ent);\n }\n \n static const struct submodule *cache_lookup_path(struct submodule_cache *cache,\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex bf063a2521..49e715f1cd 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -104,7 +104,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)\n \t\t\t/* add entries */\n \t\t\tfor (i = 0; i < TEST_SIZE; i++) {\n \t\t\t\thashmap_entry_init(&entries[i]->ent, hashes[i]);\n-\t\t\t\thashmap_add(&map, entries[i]);\n+\t\t\t\thashmap_add(&map, &entries[i]->ent);\n \t\t\t}\n \n \t\t\thashmap_free(&map, 0);\n@@ -117,7 +117,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)\n \t\tj = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE;\n \t\tfor (i = 0; i < j; i++) {\n \t\t\thashmap_entry_init(&entries[i]->ent, hashes[i]);\n-\t\t\thashmap_add(&map, entries[i]);\n+\t\t\thashmap_add(&map, &entries[i]->ent);\n \t\t}\n \n \t\tfor (j = 0; j < rounds; j++) {\n@@ -179,7 +179,7 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\tentry = alloc_test_entry(hash, p1, p2);\n \n \t\t\t/* add to hashmap */\n-\t\t\thashmap_add(&map, entry);\n+\t\t\thashmap_add(&map, &entry->ent);\n \n \t\t} else if (!strcmp(\"put\", cmd) && p1 && p2) {\n \n"},{"id":"382813","messageId":"20190924010324.22619-8-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 07/19] hashmap_get takes \"const struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:12Z","receivedAt":"2019-09-24T01:03:44Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is less error-prone than \"const void *\" as the compiler\nnow detects invalid types being passed.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n attr.c                | 2 +-\n blame.c               | 6 +++---\n builtin/difftool.c    | 5 +++--\n builtin/fast-export.c | 2 +-\n config.c              | 2 +-\n diff.c                | 4 ++--\n hashmap.c             | 5 +++--\n hashmap.h             | 8 +++++---\n merge-recursive.c     | 4 ++--\n name-hash.c           | 2 +-\n patch-ids.c           | 2 +-\n revision.c            | 3 ++-\n sub-process.c         | 2 +-\n submodule-config.c    | 4 ++--\n 14 files changed, 28 insertions(+), 23 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex fa26a3e3cb..9bdef61cc3 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -101,7 +101,7 @@ static void *attr_hashmap_get(struct attr_hashmap *map,\n \thashmap_entry_init(&k.ent, memhash(key, keylen));\n \tk.key = key;\n \tk.keylen = keylen;\n-\te = hashmap_get(&map->map, &k, NULL);\n+\te = hashmap_get(&map->map, &k.ent, NULL);\n \n \treturn e ? e->value : NULL;\n }\ndiff --git a/blame.c b/blame.c\nindex 4d20aee435..73ffb59403 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -419,7 +419,7 @@ static void get_fingerprint(struct fingerprint *result,\n \t\t\tcontinue;\n \t\thashmap_entry_init(&entry->entry, hash);\n \n-\t\tfound_entry = hashmap_get(&result->map, entry, NULL);\n+\t\tfound_entry = hashmap_get(&result->map, &entry->entry, NULL);\n \t\tif (found_entry) {\n \t\t\tfound_entry->count += 1;\n \t\t} else {\n@@ -452,7 +452,7 @@ static int fingerprint_similarity(struct fingerprint *a, struct fingerprint *b)\n \thashmap_iter_init(&b->map, &iter);\n \n \twhile ((entry_b = hashmap_iter_next(&iter))) {\n-\t\tif ((entry_a = hashmap_get(&a->map, entry_b, NULL))) {\n+\t\tif ((entry_a = hashmap_get(&a->map, &entry_b->entry, NULL))) {\n \t\t\tintersection += entry_a->count < entry_b->count ?\n \t\t\t\t\tentry_a->count : entry_b->count;\n \t\t}\n@@ -471,7 +471,7 @@ static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b)\n \thashmap_iter_init(&b->map, &iter);\n \n \twhile ((entry_b = hashmap_iter_next(&iter))) {\n-\t\tif ((entry_a = hashmap_get(&a->map, entry_b, NULL))) {\n+\t\tif ((entry_a = hashmap_get(&a->map, &entry_b->entry, NULL))) {\n \t\t\tif (entry_a->count <= entry_b->count)\n \t\t\t\thashmap_remove(&a->map, entry_b, NULL);\n \t\t\telse\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 82c146718d..f41298d199 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -162,7 +162,7 @@ static void add_left_or_right(struct hashmap *map, const char *path,\n \n \tFLEX_ALLOC_STR(e, path, path);\n \thashmap_entry_init(&e->entry, strhash(path));\n-\texisting = hashmap_get(map, e, NULL);\n+\texisting = hashmap_get(map, &e->entry, NULL);\n \tif (existing) {\n \t\tfree(e);\n \t\te = existing;\n@@ -462,7 +462,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\t\t/* Avoid duplicate working_tree entries */\n \t\t\tFLEX_ALLOC_STR(entry, path, dst_path);\n \t\t\thashmap_entry_init(&entry->entry, strhash(dst_path));\n-\t\t\tif (hashmap_get(&working_tree_dups, entry, NULL)) {\n+\t\t\tif (hashmap_get(&working_tree_dups, &entry->entry,\n+\t\t\t\t\tNULL)) {\n \t\t\t\tfree(entry);\n \t\t\t\tcontinue;\n \t\t\t}\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 287dbd24a3..c693cf6a8c 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -151,7 +151,7 @@ static const void *anonymize_mem(struct hashmap *map,\n \thashmap_entry_init(&key.hash, memhash(orig, *len));\n \tkey.orig = orig;\n \tkey.orig_len = *len;\n-\tret = hashmap_get(map, &key, NULL);\n+\tret = hashmap_get(map, &key.hash, NULL);\n \n \tif (!ret) {\n \t\tret = xmalloc(sizeof(*ret));\ndiff --git a/config.c b/config.c\nindex 2243d7c3d6..1a1b6675fd 100644\n--- a/config.c\n+++ b/config.c\n@@ -1863,7 +1863,7 @@ static struct config_set_element *configset_find_element(struct config_set *cs,\n \n \thashmap_entry_init(&k.ent, strhash(normalized_key));\n \tk.key = normalized_key;\n-\tfound_entry = hashmap_get(&cs->config_hash, &k, NULL);\n+\tfound_entry = hashmap_get(&cs->config_hash, &k.ent, NULL);\n \tfree(normalized_key);\n \treturn found_entry;\n }\ndiff --git a/diff.c b/diff.c\nindex cc7f06d10d..72d3c6aa19 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1144,13 +1144,13 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\tcase DIFF_SYMBOL_PLUS:\n \t\t\thm = del_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tmatch = hashmap_get(hm, key, NULL);\n+\t\t\tmatch = hashmap_get(hm, &key->ent, NULL);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tcase DIFF_SYMBOL_MINUS:\n \t\t\thm = add_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tmatch = hashmap_get(hm, key, NULL);\n+\t\t\tmatch = hashmap_get(hm, &key->ent, NULL);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tdefault:\ndiff --git a/hashmap.c b/hashmap.c\nindex 9c2db3e0c8..092236c09a 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -186,7 +186,8 @@ void hashmap_free(struct hashmap *map, int free_entries)\n \tmemset(map, 0, sizeof(*map));\n }\n \n-void *hashmap_get(const struct hashmap *map, const void *key, const void *keydata)\n+void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n+\t\tconst void *keydata)\n {\n \treturn *find_entry_ptr(map, key, keydata);\n }\n@@ -296,7 +297,7 @@ const void *memintern(const void *data, size_t len)\n \t/* lookup interned string in pool */\n \thashmap_entry_init(&key.ent, memhash(data, len));\n \tkey.len = len;\n-\te = hashmap_get(&map, &key, data);\n+\te = hashmap_get(&map, &key.ent, data);\n \tif (!e) {\n \t\t/* not found: create it */\n \t\tFLEX_ALLOC_MEM(e, data, data, len);\ndiff --git a/hashmap.h b/hashmap.h\nindex 40bcc64289..2a4b4a3954 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -74,7 +74,8 @@\n  *             e->key = key;\n  *\n  *             flags |= COMPARE_VALUE;\n- *             printf(\"%sfound\\n\", hashmap_get(&map, e, NULL) ? \"\" : \"not \");\n+ *             printf(\"%sfound\\n\",\n+ *                    hashmap_get(&map, &e->ent, NULL) ? \"\" : \"not \");\n  *             free(e);\n  *         }\n  *\n@@ -84,7 +85,8 @@\n  *             k.key = key;\n  *\n  *             flags |= COMPARE_VALUE;\n- *             printf(\"%sfound\\n\", hashmap_get(&map, &k, value) ? \"\" : \"not \");\n+ *             printf(\"%sfound\\n\",\n+ *                    hashmap_get(&map, &k->ent, value) ? \"\" : \"not \");\n  *         }\n  *\n  *         if (!strcmp(\"end\", action)) {\n@@ -286,7 +288,7 @@ static inline unsigned int hashmap_get_size(struct hashmap *map)\n  * If an entry with matching hash code is found, `key` and `keydata` are passed\n  * to `hashmap_cmp_fn` to decide whether the entry matches the key.\n  */\n-void *hashmap_get(const struct hashmap *map, const void *key,\n+void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n \t\t\t const void *keydata);\n \n /*\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex db9b247ece..2d31a3e279 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -63,7 +63,7 @@ static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,\n \t\treturn NULL;\n \thashmap_entry_init(&key.ent, strhash(dir));\n \tkey.dir = dir;\n-\treturn hashmap_get(hashmap, &key, NULL);\n+\treturn hashmap_get(hashmap, &key.ent, NULL);\n }\n \n static int dir_rename_cmp(const void *unused_cmp_data,\n@@ -99,7 +99,7 @@ static struct collision_entry *collision_find_entry(struct hashmap *hashmap,\n \n \thashmap_entry_init(&key.ent, strhash(target_file));\n \tkey.target_file = target_file;\n-\treturn hashmap_get(hashmap, &key, NULL);\n+\treturn hashmap_get(hashmap, &key.ent, NULL);\n }\n \n static int collision_cmp(void *unused_cmp_data,\ndiff --git a/name-hash.c b/name-hash.c\nindex faec682bc7..4eaeded775 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -35,7 +35,7 @@ static struct dir_entry *find_dir_entry__hash(struct index_state *istate,\n \tstruct dir_entry key;\n \thashmap_entry_init(&key.ent, hash);\n \tkey.namelen = namelen;\n-\treturn hashmap_get(&istate->dir_hash, &key, name);\n+\treturn hashmap_get(&istate->dir_hash, &key.ent, name);\n }\n \n static struct dir_entry *find_dir_entry(struct index_state *istate,\ndiff --git a/patch-ids.c b/patch-ids.c\nindex f87b62bf58..437f29e42c 100644\n--- a/patch-ids.c\n+++ b/patch-ids.c\n@@ -99,7 +99,7 @@ struct patch_id *has_commit_patch_id(struct commit *commit,\n \tif (init_patch_id_entry(&patch, commit, ids))\n \t\treturn NULL;\n \n-\treturn hashmap_get(&ids->patches, &patch, NULL);\n+\treturn hashmap_get(&ids->patches, &patch.ent, NULL);\n }\n \n struct patch_id *add_commit_patch_id(struct commit *commit,\ndiff --git a/revision.c b/revision.c\nindex 3461c78883..4336281286 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -147,7 +147,8 @@ static void paths_and_oids_insert(struct hashmap *map,\n \tkey.path = (char *)path;\n \toidset_init(&key.trees, 0);\n \n-\tif (!(entry = (struct path_and_oids_entry *)hashmap_get(map, &key, NULL))) {\n+\tentry = hashmap_get(map, &key.ent, NULL);\n+\tif (!entry) {\n \t\tentry = xcalloc(1, sizeof(struct path_and_oids_entry));\n \t\thashmap_entry_init(&entry->ent, hash);\n \t\tentry->path = xstrdup(key.path);\ndiff --git a/sub-process.c b/sub-process.c\nindex d58e069855..debd86bb68 100644\n--- a/sub-process.c\n+++ b/sub-process.c\n@@ -22,7 +22,7 @@ struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const ch\n \n \thashmap_entry_init(&key.ent, strhash(cmd));\n \tkey.cmd = cmd;\n-\treturn hashmap_get(hashmap, &key, NULL);\n+\treturn hashmap_get(hashmap, &key.ent, NULL);\n }\n \n int subprocess_read_status(int fd, struct strbuf *status)\ndiff --git a/submodule-config.c b/submodule-config.c\nindex a3bbd9fd6f..58d585cd7d 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -166,7 +166,7 @@ static const struct submodule *cache_lookup_path(struct submodule_cache *cache,\n \thashmap_entry_init(&key.ent, hash);\n \tkey.config = &key_config;\n \n-\tentry = hashmap_get(&cache->for_path, &key, NULL);\n+\tentry = hashmap_get(&cache->for_path, &key.ent, NULL);\n \tif (entry)\n \t\treturn entry->config;\n \treturn NULL;\n@@ -186,7 +186,7 @@ static struct submodule *cache_lookup_name(struct submodule_cache *cache,\n \thashmap_entry_init(&key.ent, hash);\n \tkey.config = &key_config;\n \n-\tentry = hashmap_get(&cache->for_name, &key, NULL);\n+\tentry = hashmap_get(&cache->for_name, &key.ent, NULL);\n \tif (entry)\n \t\treturn entry->config;\n \treturn NULL;\n"},{"id":"382816","messageId":"20190924010324.22619-9-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 08/19] hashmap_remove takes \"const struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:13Z","receivedAt":"2019-09-24T01:03:47Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is less error-prone than \"const void *\" as the compiler\nnow detects invalid types being passed.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n blame.c            | 2 +-\n hashmap.c          | 3 ++-\n hashmap.h          | 2 +-\n merge-recursive.c  | 2 +-\n name-hash.c        | 4 ++--\n packfile.c         | 2 +-\n range-diff.c       | 2 +-\n sub-process.c      | 2 +-\n submodule-config.c | 2 +-\n 9 files changed, 11 insertions(+), 10 deletions(-)\n\ndiff --git a/blame.c b/blame.c\nindex 73ffb59403..00f8f3fb0a 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -473,7 +473,7 @@ static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b)\n \twhile ((entry_b = hashmap_iter_next(&iter))) {\n \t\tif ((entry_a = hashmap_get(&a->map, &entry_b->entry, NULL))) {\n \t\t\tif (entry_a->count <= entry_b->count)\n-\t\t\t\thashmap_remove(&a->map, entry_b, NULL);\n+\t\t\t\thashmap_remove(&a->map, &entry_b->entry, NULL);\n \t\t\telse\n \t\t\t\tentry_a->count -= entry_b->count;\n \t\t}\ndiff --git a/hashmap.c b/hashmap.c\nindex 092236c09a..bdf33e0381 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -218,7 +218,8 @@ void hashmap_add(struct hashmap *map, struct hashmap_entry *entry)\n \t}\n }\n \n-void *hashmap_remove(struct hashmap *map, const void *key, const void *keydata)\n+void *hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n+\t\tconst void *keydata)\n {\n \tstruct hashmap_entry *old;\n \tstruct hashmap_entry **e = find_entry_ptr(map, key, keydata);\ndiff --git a/hashmap.h b/hashmap.h\nindex 2a4b4a3954..5e0818c134 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -349,7 +349,7 @@ void *hashmap_put(struct hashmap *map, void *entry);\n  *\n  * Argument explanation is the same as in `hashmap_get`.\n  */\n-void *hashmap_remove(struct hashmap *map, const void *key,\n+void *hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n \t\tconst void *keydata);\n \n /*\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 2d31a3e279..f60451d396 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2001,7 +2001,7 @@ static void remove_hashmap_entries(struct hashmap *dir_renames,\n \n \tfor (i = 0; i < items_to_remove->nr; i++) {\n \t\tentry = items_to_remove->items[i].util;\n-\t\thashmap_remove(dir_renames, entry, NULL);\n+\t\thashmap_remove(dir_renames, &entry->ent, NULL);\n \t}\n \tstring_list_clear(items_to_remove, 0);\n }\ndiff --git a/name-hash.c b/name-hash.c\nindex 4eaeded775..44d788f1ce 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -95,7 +95,7 @@ static void remove_dir_entry(struct index_state *istate, struct cache_entry *ce)\n \tstruct dir_entry *dir = hash_dir_entry(istate, ce, ce_namelen(ce));\n \twhile (dir && !(--dir->nr)) {\n \t\tstruct dir_entry *parent = dir->parent;\n-\t\thashmap_remove(&istate->dir_hash, dir, NULL);\n+\t\thashmap_remove(&istate->dir_hash, &dir->ent, NULL);\n \t\tfree(dir);\n \t\tdir = parent;\n \t}\n@@ -625,7 +625,7 @@ void remove_name_hash(struct index_state *istate, struct cache_entry *ce)\n \tif (!istate->name_hash_initialized || !(ce->ce_flags & CE_HASHED))\n \t\treturn;\n \tce->ce_flags &= ~CE_HASHED;\n-\thashmap_remove(&istate->name_hash, ce, ce);\n+\thashmap_remove(&istate->name_hash, &ce->ent, ce);\n \n \tif (ignore_case)\n \t\tremove_dir_entry(istate, ce);\ndiff --git a/packfile.c b/packfile.c\nindex f7402c470b..3edd648de0 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1423,7 +1423,7 @@ static int in_delta_base_cache(struct packed_git *p, off_t base_offset)\n  */\n static void detach_delta_base_cache_entry(struct delta_base_cache_entry *ent)\n {\n-\thashmap_remove(&delta_base_cache, ent, &ent->key);\n+\thashmap_remove(&delta_base_cache, &ent->ent, &ent->key);\n \tlist_del(&ent->lru);\n \tdelta_base_cached -= ent->size;\n \tfree(ent);\ndiff --git a/range-diff.c b/range-diff.c\nindex 96f955d84d..c51cfd5556 100644\n--- a/range-diff.c\n+++ b/range-diff.c\n@@ -229,7 +229,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n \t\tutil->patch = b->items[i].string;\n \t\tutil->diff = util->patch + util->diff_offset;\n \t\thashmap_entry_init(&util->e, strhash(util->diff));\n-\t\tother = hashmap_remove(&map, util, NULL);\n+\t\tother = hashmap_remove(&map, &util->e, NULL);\n \t\tif (other) {\n \t\t\tif (other->matching >= 0)\n \t\t\t\tBUG(\"already assigned!\");\ndiff --git a/sub-process.c b/sub-process.c\nindex debd86bb68..99fccef592 100644\n--- a/sub-process.c\n+++ b/sub-process.c\n@@ -58,7 +58,7 @@ void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry)\n \tkill(entry->process.pid, SIGTERM);\n \tfinish_command(&entry->process);\n \n-\thashmap_remove(hashmap, entry, NULL);\n+\thashmap_remove(hashmap, &entry->ent, NULL);\n }\n \n static void subprocess_exit_handler(struct child_process *process)\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 58d585cd7d..7486745a6a 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -137,7 +137,7 @@ static void cache_remove_path(struct submodule_cache *cache,\n \tstruct submodule_entry *removed;\n \thashmap_entry_init(&e.ent, hash);\n \te.config = submodule;\n-\tremoved = hashmap_remove(&cache->for_path, &e, NULL);\n+\tremoved = hashmap_remove(&cache->for_path, &e.ent, NULL);\n \tfree(removed);\n }\n \n"},{"id":"382817","messageId":"20190924010324.22619-10-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 09/19] hashmap_put takes \"struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:14Z","receivedAt":"2019-09-24T01:03:50Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is less error-prone than \"void *\" as the compiler now\ndetects invalid types being passed.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n builtin/fast-export.c   | 2 +-\n hashmap.c               | 2 +-\n hashmap.h               | 2 +-\n merge-recursive.c       | 4 ++--\n oidmap.c                | 2 +-\n refs.c                  | 5 ++++-\n remote.c                | 2 +-\n revision.c              | 2 +-\n sequencer.c             | 2 +-\n submodule-config.c      | 2 +-\n t/helper/test-hashmap.c | 2 +-\n 11 files changed, 15 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex c693cf6a8c..192e21dae4 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -160,7 +160,7 @@ static const void *anonymize_mem(struct hashmap *map,\n \t\tret->orig_len = *len;\n \t\tret->anon = generate(orig, len);\n \t\tret->anon_len = *len;\n-\t\thashmap_put(map, ret);\n+\t\thashmap_put(map, &ret->hash);\n \t}\n \n \t*len = ret->anon_len;\ndiff --git a/hashmap.c b/hashmap.c\nindex bdf33e0381..9b83e73d03 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -241,7 +241,7 @@ void *hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n \treturn old;\n }\n \n-void *hashmap_put(struct hashmap *map, void *entry)\n+void *hashmap_put(struct hashmap *map, struct hashmap_entry *entry)\n {\n \tstruct hashmap_entry *old = hashmap_remove(map, entry, NULL);\n \thashmap_add(map, entry);\ndiff --git a/hashmap.h b/hashmap.h\nindex 5e0818c134..cb630447bb 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -340,7 +340,7 @@ void hashmap_add(struct hashmap *map, struct hashmap_entry *entry);\n  * `entry` is the entry to add or replace.\n  * Returns the replaced entry, or NULL if not found (i.e. the entry was added).\n  */\n-void *hashmap_put(struct hashmap *map, void *entry);\n+void *hashmap_put(struct hashmap *map, struct hashmap_entry *entry);\n \n /*\n  * Removes a hashmap entry matching the specified key. If the hashmap contains\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex f60451d396..a685b4fb69 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2229,7 +2229,7 @@ static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs)\n \t\tif (!entry) {\n \t\t\tentry = xmalloc(sizeof(*entry));\n \t\t\tdir_rename_entry_init(entry, old_dir);\n-\t\t\thashmap_put(dir_renames, entry);\n+\t\t\thashmap_put(dir_renames, &entry->ent);\n \t\t} else {\n \t\t\tfree(old_dir);\n \t\t}\n@@ -2360,7 +2360,7 @@ static void compute_collisions(struct hashmap *collisions,\n \t\t\t\t\t\tsizeof(struct collision_entry));\n \t\t\thashmap_entry_init(&collision_ent->ent,\n \t\t\t\t\t\tstrhash(new_path));\n-\t\t\thashmap_put(collisions, collision_ent);\n+\t\t\thashmap_put(collisions, &collision_ent->ent);\n \t\t\tcollision_ent->target_file = new_path;\n \t\t} else {\n \t\t\tfree(new_path);\ndiff --git a/oidmap.c b/oidmap.c\nindex 6d6e840d03..cd22b3a8bf 100644\n--- a/oidmap.c\n+++ b/oidmap.c\n@@ -51,5 +51,5 @@ void *oidmap_put(struct oidmap *map, void *entry)\n \t\toidmap_init(map, 0);\n \n \thashmap_entry_init(&to_put->internal_entry, oidhash(&to_put->oid));\n-\treturn hashmap_put(&map->map, to_put);\n+\treturn hashmap_put(&map->map, &to_put->internal_entry);\n }\ndiff --git a/refs.c b/refs.c\nindex c43ec59c6e..3e55031256 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1863,10 +1863,13 @@ static void register_ref_store_map(struct hashmap *map,\n \t\t\t\t   struct ref_store *refs,\n \t\t\t\t   const char *name)\n {\n+\tstruct ref_store_hash_entry *entry;\n+\n \tif (!map->tablesize)\n \t\thashmap_init(map, ref_store_hash_cmp, NULL, 0);\n \n-\tif (hashmap_put(map, alloc_ref_store_hash_entry(name, refs)))\n+\tentry = alloc_ref_store_hash_entry(name, refs);\n+\tif (hashmap_put(map, &entry->ent))\n \t\tBUG(\"%s ref_store '%s' initialized twice\", type, name);\n }\n \ndiff --git a/remote.c b/remote.c\nindex bd81cb71bc..8ca23d95dc 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -159,7 +159,7 @@ static struct remote *make_remote(const char *name, int len)\n \tremotes[remotes_nr++] = ret;\n \n \thashmap_entry_init(&ret->ent, lookup_entry.hash);\n-\treplaced = hashmap_put(&remotes_hash, ret);\n+\treplaced = hashmap_put(&remotes_hash, &ret->ent);\n \tassert(replaced == NULL);  /* no previous entry overwritten */\n \treturn ret;\n }\ndiff --git a/revision.c b/revision.c\nindex 4336281286..a7e2339064 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -153,7 +153,7 @@ static void paths_and_oids_insert(struct hashmap *map,\n \t\thashmap_entry_init(&entry->ent, hash);\n \t\tentry->path = xstrdup(key.path);\n \t\toidset_init(&entry->trees, 16);\n-\t\thashmap_put(map, entry);\n+\t\thashmap_put(map, &entry->ent);\n \t}\n \n \toidset_insert(&entry->trees, oid);\ndiff --git a/sequencer.c b/sequencer.c\nindex ee11cda7e7..b4ef70e260 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -5254,7 +5254,7 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\t\tentry->i = i;\n \t\t\thashmap_entry_init(&entry->entry,\n \t\t\t\t\tstrhash(entry->subject));\n-\t\t\thashmap_put(&subject2item, entry);\n+\t\t\thashmap_put(&subject2item, &entry->entry);\n \t\t}\n \t}\n \ndiff --git a/submodule-config.c b/submodule-config.c\nindex 7486745a6a..9248c5ea5b 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -125,7 +125,7 @@ static void cache_put_path(struct submodule_cache *cache,\n \tstruct submodule_entry *e = xmalloc(sizeof(*e));\n \thashmap_entry_init(&e->ent, hash);\n \te->config = submodule;\n-\thashmap_put(&cache->for_path, e);\n+\thashmap_put(&cache->for_path, &e->ent);\n }\n \n static void cache_remove_path(struct submodule_cache *cache,\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex 49e715f1cd..de2bd083b9 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -187,7 +187,7 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\tentry = alloc_test_entry(hash, p1, p2);\n \n \t\t\t/* add / replace entry */\n-\t\t\tentry = hashmap_put(&map, entry);\n+\t\t\tentry = hashmap_put(&map, &entry->ent);\n \n \t\t\t/* print and free replaced entry, if any */\n \t\t\tputs(entry ? get_value(entry) : \"NULL\");\n"},{"id":"382818","messageId":"20190924010324.22619-11-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 10/19] introduce container_of macro","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:15Z","receivedAt":"2019-09-24T01:03:52Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This macro is popular within the Linux kernel for supporting\nintrusive data structures such as linked lists, red-black trees,\nand chained hash tables while allowing the compiler to do\ntype checking.\n\nI intend to use this to remove the limitation of \"hashmap_entry\"\nbeing location-dependent and to allow more compile-time type\nchecking.\n\nThis macro already exists in our source as \"list_entry\" in\nlist.h and making \"list_entry\" an alias to \"container_of\"\nas the Linux kernel has done is a possibility.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n git-compat-util.h | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 83be89de0a..4cc2c8283a 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -1312,4 +1312,14 @@ void unleak_memory(const void *ptr, size_t len);\n  */\n #include \"banned.h\"\n \n+/*\n+ * container_of - Get the address of an object containing a field.\n+ *\n+ * @ptr: pointer to the field.\n+ * @type: type of the object.\n+ * @member: name of the field within the object.\n+ */\n+#define container_of(ptr, type, member) \\\n+\t((type *) ((char *)(ptr) - offsetof(type, member)))\n+\n #endif\n"},{"id":"382819","messageId":"20190924010324.22619-12-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 11/19] hashmap_get_next returns \"struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:16Z","receivedAt":"2019-09-24T01:03:55Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is a step towards removing the requirement for\nhashmap_entry being the first field of a struct.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n diff.c                  | 19 ++++++++++++-------\n diffcore-rename.c       | 11 +++++++----\n hashmap.c               |  2 +-\n hashmap.h               | 12 ++++++++----\n name-hash.c             |  8 +++++---\n t/helper/test-hashmap.c | 10 ++++++----\n 6 files changed, 39 insertions(+), 23 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 72d3c6aa19..663b5d01f8 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1035,8 +1035,10 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,\n {\n \tint i;\n \tchar *got_match = xcalloc(1, pmb_nr);\n+\tstruct hashmap_entry *ent = &match->ent;\n \n-\tfor (; match; match = hashmap_get_next(hm, &match->ent)) {\n+\tfor (; ent; ent = hashmap_get_next(hm, ent)) {\n+\t\tmatch = container_of(ent, struct moved_entry, ent);\n \t\tfor (i = 0; i < pmb_nr; i++) {\n \t\t\tstruct moved_entry *prev = pmb[i].match;\n \t\t\tstruct moved_entry *cur = (prev && prev->next_line) ?\n@@ -1135,8 +1137,9 @@ static void mark_color_as_moved(struct diff_options *o,\n \n \tfor (n = 0; n < o->emitted_symbols->nr; n++) {\n \t\tstruct hashmap *hm = NULL;\n+\t\tstruct hashmap_entry *ent = NULL;\n \t\tstruct moved_entry *key;\n-\t\tstruct moved_entry *match = NULL;\n+\t\tstruct moved_entry *match;\n \t\tstruct emitted_diff_symbol *l = &o->emitted_symbols->buf[n];\n \t\tenum diff_symbol last_symbol = 0;\n \n@@ -1144,20 +1147,20 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\tcase DIFF_SYMBOL_PLUS:\n \t\t\thm = del_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tmatch = hashmap_get(hm, &key->ent, NULL);\n+\t\t\tent = hashmap_get(hm, &key->ent, NULL);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tcase DIFF_SYMBOL_MINUS:\n \t\t\thm = add_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tmatch = hashmap_get(hm, &key->ent, NULL);\n+\t\t\tent = hashmap_get(hm, &key->ent, NULL);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tflipped_block = 0;\n \t\t}\n \n-\t\tif (!match) {\n+\t\tif (!ent) {\n \t\t\tint i;\n \n \t\t\tadjust_last_block(o, n, block_length);\n@@ -1169,6 +1172,7 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\t\tlast_symbol = l->s;\n \t\t\tcontinue;\n \t\t}\n+\t\tmatch = container_of(ent, struct moved_entry, ent);\n \n \t\tif (o->color_moved == COLOR_MOVED_PLAIN) {\n \t\t\tlast_symbol = l->s;\n@@ -1189,8 +1193,9 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\t\t * The current line is the start of a new block.\n \t\t\t * Setup the set of potential blocks.\n \t\t\t */\n-\t\t\tfor (; match; match = hashmap_get_next(hm,\n-\t\t\t\t\t\t\t\t&match->ent)) {\n+\t\t\tfor (; ent; ent = hashmap_get_next(hm, ent)) {\n+\t\t\t\tmatch = container_of(ent, struct moved_entry,\n+\t\t\t\t\t\t\tent);\n \t\t\t\tALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);\n \t\t\t\tif (o->color_moved_ws_handling &\n \t\t\t\t    COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 4670a40179..71aa240a68 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -274,7 +274,7 @@ static int find_identical_files(struct hashmap *srcs,\n \t\t\t\tstruct diff_options *options)\n {\n \tint renames = 0;\n-\n+\tstruct hashmap_entry *ent;\n \tstruct diff_filespec *target = rename_dst[dst_index].two;\n \tstruct file_similarity *p, *best = NULL;\n \tint i = 100, best_score = -1;\n@@ -282,12 +282,15 @@ static int find_identical_files(struct hashmap *srcs,\n \t/*\n \t * Find the best source match for specified destination.\n \t */\n-\tp = hashmap_get_from_hash(srcs,\n+\tent = hashmap_get_from_hash(srcs,\n \t\t\t\t  hash_filespec(options->repo, target),\n \t\t\t\t  NULL);\n-\tfor (; p; p = hashmap_get_next(srcs, &p->entry)) {\n+\tfor (; ent; ent = hashmap_get_next(srcs, ent)) {\n \t\tint score;\n-\t\tstruct diff_filespec *source = p->filespec;\n+\t\tstruct diff_filespec *source;\n+\n+\t\tp = container_of(ent, struct file_similarity, entry);\n+\t\tsource = p->filespec;\n \n \t\t/* False hash collision? */\n \t\tif (!oideq(&source->oid, &target->oid))\ndiff --git a/hashmap.c b/hashmap.c\nindex 9b83e73d03..22bc7c5b3b 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -192,7 +192,7 @@ void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n \treturn *find_entry_ptr(map, key, keydata);\n }\n \n-void *hashmap_get_next(const struct hashmap *map,\n+struct hashmap_entry *hashmap_get_next(const struct hashmap *map,\n \t\t\tconst struct hashmap_entry *entry)\n {\n \tstruct hashmap_entry *e = entry->next;\ndiff --git a/hashmap.h b/hashmap.h\nindex cb630447bb..eb38587a63 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -55,15 +55,19 @@\n  *\n  *         if (!strcmp(\"print_all_by_key\", action)) {\n  *             struct long2string k, *e;\n+ *             struct hashmap_entry *ent;\n  *             hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));\n  *             k.key = key;\n  *\n  *             flags &= ~COMPARE_VALUE;\n- *             e = hashmap_get(&map, &k, NULL);\n- *             if (e) {\n+ *             ent = hashmap_get(&map, &k, NULL);\n+ *             if (ent) {\n+ *                 e = container_of(ent, struct long2string, ent);\n  *                 printf(\"first: %ld %s\\n\", e->key, e->value);\n- *                 while ((e = hashmap_get_next(&map, e)))\n+ *                 while ((ent = hashmap_get_next(&map, ent))) {\n+ *                     e = container_of(ent, struct long2string, ent);\n  *                     printf(\"found more: %ld %s\\n\", e->key, e->value);\n+ *                 }\n  *             }\n  *         }\n  *\n@@ -320,7 +324,7 @@ static inline void *hashmap_get_from_hash(const struct hashmap *map,\n  * `entry` is the hashmap_entry to start the search from, obtained via a previous\n  * call to `hashmap_get` or `hashmap_get_next`.\n  */\n-void *hashmap_get_next(const struct hashmap *map,\n+struct hashmap_entry *hashmap_get_next(const struct hashmap *map,\n \t\t\tconst struct hashmap_entry *entry);\n \n /*\ndiff --git a/name-hash.c b/name-hash.c\nindex 44d788f1ce..dbacb34f50 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -702,15 +702,17 @@ void adjust_dirname_case(struct index_state *istate, char *name)\n struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase)\n {\n \tstruct cache_entry *ce;\n+\tstruct hashmap_entry *ent;\n \n \tlazy_init_name_hash(istate);\n \n-\tce = hashmap_get_from_hash(&istate->name_hash,\n+\tent = hashmap_get_from_hash(&istate->name_hash,\n \t\t\t\t   memihash(name, namelen), NULL);\n-\twhile (ce) {\n+\twhile (ent) {\n+\t\tce = container_of(ent, struct cache_entry, ent);\n \t\tif (same_name(ce, name, namelen, icase))\n \t\t\treturn ce;\n-\t\tce = hashmap_get_next(&istate->name_hash, &ce->ent);\n+\t\tent = hashmap_get_next(&istate->name_hash, ent);\n \t}\n \treturn NULL;\n }\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex de2bd083b9..d85b8dc58e 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -194,16 +194,18 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\tfree(entry);\n \n \t\t} else if (!strcmp(\"get\", cmd) && p1) {\n+\t\t\tstruct hashmap_entry *e;\n \n \t\t\t/* lookup entry in hashmap */\n-\t\t\tentry = hashmap_get_from_hash(&map, hash, p1);\n+\t\t\te = hashmap_get_from_hash(&map, hash, p1);\n \n \t\t\t/* print result */\n-\t\t\tif (!entry)\n+\t\t\tif (!e)\n \t\t\t\tputs(\"NULL\");\n-\t\t\twhile (entry) {\n+\t\t\twhile (e) {\n+\t\t\t\tentry = container_of(e, struct test_entry, ent);\n \t\t\t\tputs(get_value(entry));\n-\t\t\t\tentry = hashmap_get_next(&map, &entry->ent);\n+\t\t\t\te = hashmap_get_next(&map, e);\n \t\t\t}\n \n \t\t} else if (!strcmp(\"remove\", cmd) && p1) {\n"},{"id":"382820","messageId":"20190924010324.22619-13-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 12/19] hashmap: use *_entry APIs to wrap container_of","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:17Z","receivedAt":"2019-09-24T01:03:58Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Using `container_of' can be verbose and choosing names for\nintermediate \"struct hashmap_entry\" pointers is a hard problem.\nSo introduce \"*_entry\" APIs inspired by similar linked-list\nAPIs in the Linux kernel.\n\nUnfortunately, `__typeof__' is not portable C, so we need an\nextra parameter to specify the type.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n diff.c                  | 21 +++++++++------------\n diffcore-rename.c       | 14 +++++---------\n git-compat-util.h       | 16 ++++++++++++++++\n hashmap.h               | 40 ++++++++++++++++++++++++++++++++++------\n name-hash.c             | 11 +++++------\n t/helper/test-hashmap.c | 12 +++++-------\n 6 files changed, 74 insertions(+), 40 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 663b5d01f8..66cdf4e9ca 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1035,10 +1035,8 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,\n {\n \tint i;\n \tchar *got_match = xcalloc(1, pmb_nr);\n-\tstruct hashmap_entry *ent = &match->ent;\n \n-\tfor (; ent; ent = hashmap_get_next(hm, ent)) {\n-\t\tmatch = container_of(ent, struct moved_entry, ent);\n+\thashmap_for_each_entry_from(hm, match, struct moved_entry, ent) {\n \t\tfor (i = 0; i < pmb_nr; i++) {\n \t\t\tstruct moved_entry *prev = pmb[i].match;\n \t\t\tstruct moved_entry *cur = (prev && prev->next_line) ?\n@@ -1137,9 +1135,8 @@ static void mark_color_as_moved(struct diff_options *o,\n \n \tfor (n = 0; n < o->emitted_symbols->nr; n++) {\n \t\tstruct hashmap *hm = NULL;\n-\t\tstruct hashmap_entry *ent = NULL;\n \t\tstruct moved_entry *key;\n-\t\tstruct moved_entry *match;\n+\t\tstruct moved_entry *match = NULL;\n \t\tstruct emitted_diff_symbol *l = &o->emitted_symbols->buf[n];\n \t\tenum diff_symbol last_symbol = 0;\n \n@@ -1147,20 +1144,22 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\tcase DIFF_SYMBOL_PLUS:\n \t\t\thm = del_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tent = hashmap_get(hm, &key->ent, NULL);\n+\t\t\tmatch = hashmap_get_entry(hm, key, NULL,\n+\t\t\t\t\t\tstruct moved_entry, ent);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tcase DIFF_SYMBOL_MINUS:\n \t\t\thm = add_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tent = hashmap_get(hm, &key->ent, NULL);\n+\t\t\tmatch = hashmap_get_entry(hm, key, NULL,\n+\t\t\t\t\t\tstruct moved_entry, ent);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tflipped_block = 0;\n \t\t}\n \n-\t\tif (!ent) {\n+\t\tif (!match) {\n \t\t\tint i;\n \n \t\t\tadjust_last_block(o, n, block_length);\n@@ -1172,7 +1171,6 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\t\tlast_symbol = l->s;\n \t\t\tcontinue;\n \t\t}\n-\t\tmatch = container_of(ent, struct moved_entry, ent);\n \n \t\tif (o->color_moved == COLOR_MOVED_PLAIN) {\n \t\t\tlast_symbol = l->s;\n@@ -1193,9 +1191,8 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\t\t * The current line is the start of a new block.\n \t\t\t * Setup the set of potential blocks.\n \t\t\t */\n-\t\t\tfor (; ent; ent = hashmap_get_next(hm, ent)) {\n-\t\t\t\tmatch = container_of(ent, struct moved_entry,\n-\t\t\t\t\t\t\tent);\n+\t\t\thashmap_for_each_entry_from(hm, match,\n+\t\t\t\t\t\tstruct moved_entry, ent) {\n \t\t\t\tALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);\n \t\t\t\tif (o->color_moved_ws_handling &\n \t\t\t\t    COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 71aa240a68..611b08f463 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -274,23 +274,19 @@ static int find_identical_files(struct hashmap *srcs,\n \t\t\t\tstruct diff_options *options)\n {\n \tint renames = 0;\n-\tstruct hashmap_entry *ent;\n \tstruct diff_filespec *target = rename_dst[dst_index].two;\n \tstruct file_similarity *p, *best = NULL;\n \tint i = 100, best_score = -1;\n+\tunsigned int hash = hash_filespec(options->repo, target);\n \n \t/*\n \t * Find the best source match for specified destination.\n \t */\n-\tent = hashmap_get_from_hash(srcs,\n-\t\t\t\t  hash_filespec(options->repo, target),\n-\t\t\t\t  NULL);\n-\tfor (; ent; ent = hashmap_get_next(srcs, ent)) {\n+\tp = hashmap_get_entry_from_hash(srcs, hash, NULL,\n+\t\t\t\t\tstruct file_similarity, entry);\n+\thashmap_for_each_entry_from(srcs, p, struct file_similarity, entry) {\n \t\tint score;\n-\t\tstruct diff_filespec *source;\n-\n-\t\tp = container_of(ent, struct file_similarity, entry);\n-\t\tsource = p->filespec;\n+\t\tstruct diff_filespec *source = p->filespec;\n \n \t\t/* False hash collision? */\n \t\tif (!oideq(&source->oid, &target->oid))\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 4cc2c8283a..e24510452a 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -1322,4 +1322,20 @@ void unleak_memory(const void *ptr, size_t len);\n #define container_of(ptr, type, member) \\\n \t((type *) ((char *)(ptr) - offsetof(type, member)))\n \n+\n+/*\n+ * helper function for `container_of_or_null' to avoid multiple\n+ * evaluation of @ptr\n+ */\n+static inline void *container_of_or_null_offset(void *ptr, size_t offset)\n+{\n+\treturn ptr ? (char *)ptr - offset : NULL;\n+}\n+\n+/*\n+ * like `container_of', but allows returned value to be NULL\n+ */\n+#define container_of_or_null(ptr, type, member) \\\n+\t(type *)container_of_or_null_offset(ptr, offsetof(type, member))\n+\n #endif\ndiff --git a/hashmap.h b/hashmap.h\nindex eb38587a63..6d5f8685a8 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -55,17 +55,15 @@\n  *\n  *         if (!strcmp(\"print_all_by_key\", action)) {\n  *             struct long2string k, *e;\n- *             struct hashmap_entry *ent;\n  *             hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));\n  *             k.key = key;\n  *\n  *             flags &= ~COMPARE_VALUE;\n- *             ent = hashmap_get(&map, &k, NULL);\n- *             if (ent) {\n- *                 e = container_of(ent, struct long2string, ent);\n+ *             e = hashmap_get_entry(&map, &k, NULL, struct long2string, ent);\n+ *             if (e) {\n  *                 printf(\"first: %ld %s\\n\", e->key, e->value);\n- *                 while ((ent = hashmap_get_next(&map, ent))) {\n- *                     e = container_of(ent, struct long2string, ent);\n+ *                 while ((e = hashmap_get_next_entry(&map, e,\n+ *                                              struct long2string, ent))) {\n  *                     printf(\"found more: %ld %s\\n\", e->key, e->value);\n  *                 }\n  *             }\n@@ -387,6 +385,36 @@ static inline void *hashmap_iter_first(struct hashmap *map,\n \treturn hashmap_iter_next(iter);\n }\n \n+/*\n+ * returns a @pointer of @type matching @keyvar, or NULL if nothing found.\n+ * @keyvar is a pointer of @type\n+ * @member is the name of the \"struct hashmap_entry\" field in @type\n+ */\n+#define hashmap_get_entry(map, keyvar, keydata, type, member) \\\n+\tcontainer_of_or_null(hashmap_get(map, &(keyvar)->member, keydata), \\\n+\t\t\t\ttype, member)\n+\n+#define hashmap_get_entry_from_hash(map, hash, keydata, type, member) \\\n+\tcontainer_of_or_null(hashmap_get_from_hash(map, hash, keydata), \\\n+\t\t\t\ttype, member)\n+/*\n+ * returns the next equal @type pointer to @var, or NULL if not found.\n+ * @var is a pointer of @type\n+ * @member is the name of the \"struct hashmap_entry\" field in @type\n+ */\n+#define hashmap_get_next_entry(map, var, type, member) \\\n+\tcontainer_of_or_null(hashmap_get_next(map, &(var)->member), \\\n+\t\t\t\ttype, member)\n+\n+/*\n+ * iterate @map starting from @var, where @var is a pointer of @type\n+ * and @member is the name of the \"struct hashmap_entry\" field in @type\n+ */\n+#define hashmap_for_each_entry_from(map, var, type, member) \\\n+\tfor (; \\\n+\t\tvar; \\\n+\t\tvar = hashmap_get_next_entry(map, var, type, member))\n+\n /*\n  * Disable item counting and automatic rehashing when adding/removing items.\n  *\ndiff --git a/name-hash.c b/name-hash.c\nindex dbacb34f50..73b83adf3d 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -702,17 +702,16 @@ void adjust_dirname_case(struct index_state *istate, char *name)\n struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase)\n {\n \tstruct cache_entry *ce;\n-\tstruct hashmap_entry *ent;\n+\tunsigned int hash = memihash(name, namelen);\n \n \tlazy_init_name_hash(istate);\n \n-\tent = hashmap_get_from_hash(&istate->name_hash,\n-\t\t\t\t   memihash(name, namelen), NULL);\n-\twhile (ent) {\n-\t\tce = container_of(ent, struct cache_entry, ent);\n+\tce = hashmap_get_entry_from_hash(&istate->name_hash, hash, NULL,\n+\t\t\t\t\t struct cache_entry, ent);\n+\thashmap_for_each_entry_from(&istate->name_hash, ce,\n+\t\t\t\t\tstruct cache_entry, ent) {\n \t\tif (same_name(ce, name, namelen, icase))\n \t\t\treturn ce;\n-\t\tent = hashmap_get_next(&istate->name_hash, ent);\n \t}\n \treturn NULL;\n }\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex d85b8dc58e..e82cbfdee2 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -194,18 +194,16 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\tfree(entry);\n \n \t\t} else if (!strcmp(\"get\", cmd) && p1) {\n-\t\t\tstruct hashmap_entry *e;\n-\n \t\t\t/* lookup entry in hashmap */\n-\t\t\te = hashmap_get_from_hash(&map, hash, p1);\n+\t\t\tentry = hashmap_get_entry_from_hash(&map, hash, p1,\n+\t\t\t\t\t\t\tstruct test_entry, ent);\n \n \t\t\t/* print result */\n-\t\t\tif (!e)\n+\t\t\tif (!entry)\n \t\t\t\tputs(\"NULL\");\n-\t\t\twhile (e) {\n-\t\t\t\tentry = container_of(e, struct test_entry, ent);\n+\t\t\thashmap_for_each_entry_from(&map, entry,\n+\t\t\t\t\t\tstruct test_entry, ent) {\n \t\t\t\tputs(get_value(entry));\n-\t\t\t\te = hashmap_get_next(&map, e);\n \t\t\t}\n \n \t\t} else if (!strcmp(\"remove\", cmd) && p1) {\n"},{"id":"382821","messageId":"20190924010324.22619-14-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 13/19] hashmap_get{,_from_hash} return \"struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:18Z","receivedAt":"2019-09-24T01:04:00Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Update callers to use hashmap_get_entry, hashmap_get_entry_from_hash\nor container_of as appropriate.\n\nThis is another step towards eliminating the requirement of\nhashmap_entry being the first field in a struct.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n attr.c                |  2 +-\n blame.c               | 11 ++++++++---\n builtin/describe.c    |  3 ++-\n builtin/difftool.c    |  2 +-\n builtin/fast-export.c |  2 +-\n builtin/fetch.c       | 11 +++++++----\n config.c              |  3 ++-\n hashmap.c             |  5 +++--\n hashmap.h             |  6 ++++--\n merge-recursive.c     |  6 ++++--\n name-hash.c           |  3 ++-\n packfile.c            |  5 +++--\n patch-ids.c           |  3 ++-\n ref-filter.c          | 12 +++++++-----\n refs.c                |  5 ++++-\n remote.c              |  7 ++++---\n revision.c            |  3 ++-\n sequencer.c           |  7 +++++--\n sub-process.c         |  3 ++-\n submodule-config.c    |  6 ++++--\n 20 files changed, 68 insertions(+), 37 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex 9bdef61cc3..4230bee63d 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -101,7 +101,7 @@ static void *attr_hashmap_get(struct attr_hashmap *map,\n \thashmap_entry_init(&k.ent, memhash(key, keylen));\n \tk.key = key;\n \tk.keylen = keylen;\n-\te = hashmap_get(&map->map, &k.ent, NULL);\n+\te = hashmap_get_entry(&map->map, &k, NULL, struct attr_hash_entry, ent);\n \n \treturn e ? e->value : NULL;\n }\ndiff --git a/blame.c b/blame.c\nindex 00f8f3fb0a..aa46c7ec52 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -419,7 +419,8 @@ static void get_fingerprint(struct fingerprint *result,\n \t\t\tcontinue;\n \t\thashmap_entry_init(&entry->entry, hash);\n \n-\t\tfound_entry = hashmap_get(&result->map, &entry->entry, NULL);\n+\t\tfound_entry = hashmap_get_entry(&result->map, entry, NULL,\n+\t\t\t\t\tstruct fingerprint_entry, entry);\n \t\tif (found_entry) {\n \t\t\tfound_entry->count += 1;\n \t\t} else {\n@@ -452,7 +453,9 @@ static int fingerprint_similarity(struct fingerprint *a, struct fingerprint *b)\n \thashmap_iter_init(&b->map, &iter);\n \n \twhile ((entry_b = hashmap_iter_next(&iter))) {\n-\t\tif ((entry_a = hashmap_get(&a->map, &entry_b->entry, NULL))) {\n+\t\tentry_a = hashmap_get_entry(&a->map, entry_b, NULL,\n+\t\t\t\t\tstruct fingerprint_entry, entry);\n+\t\tif (entry_a) {\n \t\t\tintersection += entry_a->count < entry_b->count ?\n \t\t\t\t\tentry_a->count : entry_b->count;\n \t\t}\n@@ -471,7 +474,9 @@ static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b)\n \thashmap_iter_init(&b->map, &iter);\n \n \twhile ((entry_b = hashmap_iter_next(&iter))) {\n-\t\tif ((entry_a = hashmap_get(&a->map, &entry_b->entry, NULL))) {\n+\t\tentry_a = hashmap_get_entry(&a->map, entry_b, NULL,\n+\t\t\t\t\tstruct fingerprint_entry, entry);\n+\t\tif (entry_a) {\n \t\t\tif (entry_a->count <= entry_b->count)\n \t\t\t\thashmap_remove(&a->map, &entry_b->entry, NULL);\n \t\t\telse\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex f5e0a7e033..c6d2386b64 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -76,7 +76,8 @@ static int commit_name_neq(const void *unused_cmp_data,\n \n static inline struct commit_name *find_commit_name(const struct object_id *peeled)\n {\n-\treturn hashmap_get_from_hash(&names, oidhash(peeled), peeled);\n+\treturn hashmap_get_entry_from_hash(&names, oidhash(peeled), peeled,\n+\t\t\t\t\t\tstruct commit_name, entry);\n }\n \n static int replace_name(struct commit_name *e,\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex f41298d199..fa9c862e3a 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -162,7 +162,7 @@ static void add_left_or_right(struct hashmap *map, const char *path,\n \n \tFLEX_ALLOC_STR(e, path, path);\n \thashmap_entry_init(&e->entry, strhash(path));\n-\texisting = hashmap_get(map, &e->entry, NULL);\n+\texisting = hashmap_get_entry(map, e, NULL, struct pair_entry, entry);\n \tif (existing) {\n \t\tfree(e);\n \t\te = existing;\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 192e21dae4..25195badd4 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -151,7 +151,7 @@ static const void *anonymize_mem(struct hashmap *map,\n \thashmap_entry_init(&key.hash, memhash(orig, *len));\n \tkey.orig = orig;\n \tkey.orig_len = *len;\n-\tret = hashmap_get(map, &key.hash, NULL);\n+\tret = hashmap_get_entry(map, &key, NULL, struct anonymized_entry, hash);\n \n \tif (!ret) {\n \t\tret = xmalloc(sizeof(*ret));\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 909dbde909..d06f2b98aa 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -383,8 +383,10 @@ static void find_non_local_tags(const struct ref *refs,\n \tfor_each_string_list_item(remote_ref_item, &remote_refs_list) {\n \t\tconst char *refname = remote_ref_item->string;\n \t\tstruct ref *rm;\n+\t\tunsigned int hash = strhash(refname);\n \n-\t\titem = hashmap_get_from_hash(&remote_refs, strhash(refname), refname);\n+\t\titem = hashmap_get_entry_from_hash(&remote_refs, hash, refname,\n+\t\t\t\t\tstruct refname_hash_entry, ent);\n \t\tif (!item)\n \t\t\tBUG(\"unseen remote ref?\");\n \n@@ -516,10 +518,11 @@ static struct ref *get_ref_map(struct remote *remote,\n \t\tif (rm->peer_ref) {\n \t\t\tconst char *refname = rm->peer_ref->name;\n \t\t\tstruct refname_hash_entry *peer_item;\n+\t\t\tunsigned int hash = strhash(refname);\n \n-\t\t\tpeer_item = hashmap_get_from_hash(&existing_refs,\n-\t\t\t\t\t\t\t  strhash(refname),\n-\t\t\t\t\t\t\t  refname);\n+\t\t\tpeer_item = hashmap_get_entry_from_hash(&existing_refs,\n+\t\t\t\t\t\thash, refname,\n+\t\t\t\t\t\tstruct refname_hash_entry, ent);\n \t\t\tif (peer_item) {\n \t\t\t\tstruct object_id *old_oid = &peer_item->oid;\n \t\t\t\toidcpy(&rm->peer_ref->old_oid, old_oid);\ndiff --git a/config.c b/config.c\nindex 1a1b6675fd..4952d1cc9e 100644\n--- a/config.c\n+++ b/config.c\n@@ -1863,7 +1863,8 @@ static struct config_set_element *configset_find_element(struct config_set *cs,\n \n \thashmap_entry_init(&k.ent, strhash(normalized_key));\n \tk.key = normalized_key;\n-\tfound_entry = hashmap_get(&cs->config_hash, &k.ent, NULL);\n+\tfound_entry = hashmap_get_entry(&cs->config_hash, &k, NULL,\n+\t\t\t\tstruct config_set_element, ent);\n \tfree(normalized_key);\n \treturn found_entry;\n }\ndiff --git a/hashmap.c b/hashmap.c\nindex 22bc7c5b3b..878deb8723 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -186,7 +186,8 @@ void hashmap_free(struct hashmap *map, int free_entries)\n \tmemset(map, 0, sizeof(*map));\n }\n \n-void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n+struct hashmap_entry *\n+hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n \t\tconst void *keydata)\n {\n \treturn *find_entry_ptr(map, key, keydata);\n@@ -298,7 +299,7 @@ const void *memintern(const void *data, size_t len)\n \t/* lookup interned string in pool */\n \thashmap_entry_init(&key.ent, memhash(data, len));\n \tkey.len = len;\n-\te = hashmap_get(&map, &key.ent, data);\n+\te = hashmap_get_entry(&map, &key, data, struct pool_entry, ent);\n \tif (!e) {\n \t\t/* not found: create it */\n \t\tFLEX_ALLOC_MEM(e, data, data, len);\ndiff --git a/hashmap.h b/hashmap.h\nindex 6d5f8685a8..e1e42581ac 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -290,7 +290,8 @@ static inline unsigned int hashmap_get_size(struct hashmap *map)\n  * If an entry with matching hash code is found, `key` and `keydata` are passed\n  * to `hashmap_cmp_fn` to decide whether the entry matches the key.\n  */\n-void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n+struct hashmap_entry *\n+hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n \t\t\t const void *keydata);\n \n /*\n@@ -305,7 +306,8 @@ void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n  * `entry_or_key` parameter of `hashmap_cmp_fn` points to a hashmap_entry\n  * structure that should not be used in the comparison.\n  */\n-static inline void *hashmap_get_from_hash(const struct hashmap *map,\n+static inline struct hashmap_entry *\n+hashmap_get_from_hash(const struct hashmap *map,\n \t\t\t\t\t  unsigned int hash,\n \t\t\t\t\t  const void *keydata)\n {\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex a685b4fb69..8274828c4d 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -63,7 +63,8 @@ static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,\n \t\treturn NULL;\n \thashmap_entry_init(&key.ent, strhash(dir));\n \tkey.dir = dir;\n-\treturn hashmap_get(hashmap, &key.ent, NULL);\n+\treturn hashmap_get_entry(hashmap, &key, NULL,\n+\t\t\t\tstruct dir_rename_entry, ent);\n }\n \n static int dir_rename_cmp(const void *unused_cmp_data,\n@@ -99,7 +100,8 @@ static struct collision_entry *collision_find_entry(struct hashmap *hashmap,\n \n \thashmap_entry_init(&key.ent, strhash(target_file));\n \tkey.target_file = target_file;\n-\treturn hashmap_get(hashmap, &key.ent, NULL);\n+\treturn hashmap_get_entry(hashmap, &key, NULL,\n+\t\t\t\tstruct collision_entry, ent);\n }\n \n static int collision_cmp(void *unused_cmp_data,\ndiff --git a/name-hash.c b/name-hash.c\nindex 73b83adf3d..aa8253ddd5 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -35,7 +35,8 @@ static struct dir_entry *find_dir_entry__hash(struct index_state *istate,\n \tstruct dir_entry key;\n \thashmap_entry_init(&key.ent, hash);\n \tkey.namelen = namelen;\n-\treturn hashmap_get(&istate->dir_hash, &key.ent, name);\n+\treturn hashmap_get_entry(&istate->dir_hash, &key, name,\n+\t\t\t\t\tstruct dir_entry, ent);\n }\n \n static struct dir_entry *find_dir_entry(struct index_state *istate,\ndiff --git a/packfile.c b/packfile.c\nindex 3edd648de0..f2aa34bb49 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1381,7 +1381,7 @@ static unsigned int pack_entry_hash(struct packed_git *p, off_t base_offset)\n static struct delta_base_cache_entry *\n get_delta_base_cache_entry(struct packed_git *p, off_t base_offset)\n {\n-\tstruct hashmap_entry entry;\n+\tstruct hashmap_entry entry, *e;\n \tstruct delta_base_cache_key key;\n \n \tif (!delta_base_cache.cmpfn)\n@@ -1390,7 +1390,8 @@ get_delta_base_cache_entry(struct packed_git *p, off_t base_offset)\n \thashmap_entry_init(&entry, pack_entry_hash(p, base_offset));\n \tkey.p = p;\n \tkey.base_offset = base_offset;\n-\treturn hashmap_get(&delta_base_cache, &entry, &key);\n+\te = hashmap_get(&delta_base_cache, &entry, &key);\n+\treturn e ? container_of(e, struct delta_base_cache_entry, ent) : NULL;\n }\n \n static int delta_base_cache_key_eq(const struct delta_base_cache_key *a,\ndiff --git a/patch-ids.c b/patch-ids.c\nindex 437f29e42c..176c47d967 100644\n--- a/patch-ids.c\n+++ b/patch-ids.c\n@@ -99,7 +99,8 @@ struct patch_id *has_commit_patch_id(struct commit *commit,\n \tif (init_patch_id_entry(&patch, commit, ids))\n \t\treturn NULL;\n \n-\treturn hashmap_get(&ids->patches, &patch.ent, NULL);\n+\treturn hashmap_get_entry(&ids->patches, &patch, NULL,\n+\t\t\t\t\tstruct patch_id, ent);\n }\n \n struct patch_id *add_commit_patch_id(struct commit *commit,\ndiff --git a/ref-filter.c b/ref-filter.c\nindex d939ebc6bb..9999426914 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1585,18 +1585,20 @@ static void lazy_init_worktree_map(void)\n \n static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)\n {\n-\tstruct hashmap_entry entry;\n+\tstruct hashmap_entry entry, *e;\n \tstruct ref_to_worktree_entry *lookup_result;\n \n \tlazy_init_worktree_map();\n \n \thashmap_entry_init(&entry, strhash(ref->refname));\n-\tlookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);\n+\te = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);\n \n-\tif (lookup_result)\n-\t\treturn xstrdup(lookup_result->wt->path);\n-\telse\n+\tif (!e)\n \t\treturn xstrdup(\"\");\n+\n+\tlookup_result = container_of(e, struct ref_to_worktree_entry, ent);\n+\n+\treturn xstrdup(lookup_result->wt->path);\n }\n \n /*\ndiff --git a/refs.c b/refs.c\nindex 3e55031256..43a95105f1 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1815,12 +1815,15 @@ static struct ref_store *lookup_ref_store_map(struct hashmap *map,\n \t\t\t\t\t      const char *name)\n {\n \tstruct ref_store_hash_entry *entry;\n+\tunsigned int hash;\n \n \tif (!map->tablesize)\n \t\t/* It's initialized on demand in register_ref_store(). */\n \t\treturn NULL;\n \n-\tentry = hashmap_get_from_hash(map, strhash(name), name);\n+\thash = strhash(name);\n+\tentry = hashmap_get_entry_from_hash(map, hash, name,\n+\t\t\t\t\tstruct ref_store_hash_entry, ent);\n \treturn entry ? entry->refs : NULL;\n }\n \ndiff --git a/remote.c b/remote.c\nindex 8ca23d95dc..ed95ae6ed6 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -135,7 +135,7 @@ static struct remote *make_remote(const char *name, int len)\n {\n \tstruct remote *ret, *replaced;\n \tstruct remotes_hash_key lookup;\n-\tstruct hashmap_entry lookup_entry;\n+\tstruct hashmap_entry lookup_entry, *e;\n \n \tif (!len)\n \t\tlen = strlen(name);\n@@ -145,8 +145,9 @@ static struct remote *make_remote(const char *name, int len)\n \tlookup.len = len;\n \thashmap_entry_init(&lookup_entry, memhash(name, len));\n \n-\tif ((ret = hashmap_get(&remotes_hash, &lookup_entry, &lookup)) != NULL)\n-\t\treturn ret;\n+\te = hashmap_get(&remotes_hash, &lookup_entry, &lookup);\n+\tif (e)\n+\t\treturn container_of(e, struct remote, ent);\n \n \tret = xcalloc(1, sizeof(struct remote));\n \tret->prune = -1;  /* unspecified */\ndiff --git a/revision.c b/revision.c\nindex a7e2339064..d5f534209d 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -147,7 +147,8 @@ static void paths_and_oids_insert(struct hashmap *map,\n \tkey.path = (char *)path;\n \toidset_init(&key.trees, 0);\n \n-\tentry = hashmap_get(map, &key.ent, NULL);\n+\tentry = hashmap_get_entry(map, &key, NULL,\n+\t\t\t\tstruct path_and_oids_entry, ent);\n \tif (!entry) {\n \t\tentry = xcalloc(1, sizeof(struct path_and_oids_entry));\n \t\thashmap_entry_init(&entry->ent, hash);\ndiff --git a/sequencer.c b/sequencer.c\nindex b4ef70e260..aea2cb12cc 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -5217,8 +5217,11 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\t\t\t\tbreak;\n \t\t\t}\n \n-\t\t\tif ((entry = hashmap_get_from_hash(&subject2item,\n-\t\t\t\t\t\t\t   strhash(p), p)))\n+\t\t\tentry = hashmap_get_entry_from_hash(&subject2item,\n+\t\t\t\t\t\tstrhash(p), p,\n+\t\t\t\t\t\tstruct subject2item_entry,\n+\t\t\t\t\t\tentry);\n+\t\t\tif (entry)\n \t\t\t\t/* found by title */\n \t\t\t\ti2 = entry->i;\n \t\t\telse if (!strchr(p, ' ') &&\ndiff --git a/sub-process.c b/sub-process.c\nindex 99fccef592..f2fcc16c3e 100644\n--- a/sub-process.c\n+++ b/sub-process.c\n@@ -22,7 +22,8 @@ struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const ch\n \n \thashmap_entry_init(&key.ent, strhash(cmd));\n \tkey.cmd = cmd;\n-\treturn hashmap_get(hashmap, &key.ent, NULL);\n+\treturn hashmap_get_entry(hashmap, &key, NULL,\n+\t\t\t\tstruct subprocess_entry, ent);\n }\n \n int subprocess_read_status(int fd, struct strbuf *status)\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 9248c5ea5b..b031884789 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -166,7 +166,8 @@ static const struct submodule *cache_lookup_path(struct submodule_cache *cache,\n \thashmap_entry_init(&key.ent, hash);\n \tkey.config = &key_config;\n \n-\tentry = hashmap_get(&cache->for_path, &key.ent, NULL);\n+\tentry = hashmap_get_entry(&cache->for_path, &key, NULL,\n+\t\t\t\tstruct submodule_entry, ent);\n \tif (entry)\n \t\treturn entry->config;\n \treturn NULL;\n@@ -186,7 +187,8 @@ static struct submodule *cache_lookup_name(struct submodule_cache *cache,\n \thashmap_entry_init(&key.ent, hash);\n \tkey.config = &key_config;\n \n-\tentry = hashmap_get(&cache->for_name, &key.ent, NULL);\n+\tentry = hashmap_get_entry(&cache->for_name, &key, NULL,\n+\t\t\t\tstruct submodule_entry, ent);\n \tif (entry)\n \t\treturn entry->config;\n \treturn NULL;\n"},{"id":"382822","messageId":"20190924010324.22619-15-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 14/19] hashmap_cmp_fn takes hashmap_entry params","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:19Z","receivedAt":"2019-09-24T01:04:05Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Another step in eliminating the requirement of hashmap_entry\nbeing the first member of a struct.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n attr.c                  | 10 ++++++----\n builtin/describe.c      | 10 ++++++----\n builtin/difftool.c      | 31 +++++++++++++++++++------------\n builtin/fast-export.c   |  9 +++++++--\n builtin/fetch.c         |  9 +++++----\n config.c                | 10 ++++++----\n diff.c                  | 12 +++++++-----\n hashmap.c               | 17 +++++++++++------\n hashmap.h               | 13 +++++++++----\n merge-recursive.c       | 33 +++++++++++++++++++++------------\n name-hash.c             | 21 +++++++++++++--------\n oidmap.c                | 14 +++++++++-----\n packfile.c              |  9 +++++++--\n patch-ids.c             | 10 ++++++----\n ref-filter.c            | 11 +++++++----\n refs.c                  | 11 ++++++++---\n remote.c                | 10 ++++++----\n revision.c              | 11 ++++++++---\n sequencer.c             | 24 +++++++++++++++++-------\n sub-process.c           | 10 ++++++----\n sub-process.h           |  4 ++--\n submodule-config.c      | 20 ++++++++++++--------\n t/helper/test-hashmap.c | 10 ++++++----\n 23 files changed, 204 insertions(+), 115 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex 4230bee63d..6053481610 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -70,12 +70,14 @@ struct attr_hash_entry {\n \n /* attr_hashmap comparison function */\n static int attr_hash_entry_cmp(const void *unused_cmp_data,\n-\t\t\t       const void *entry,\n-\t\t\t       const void *entry_or_key,\n+\t\t\t       const struct hashmap_entry *eptr,\n+\t\t\t       const struct hashmap_entry *entry_or_key,\n \t\t\t       const void *unused_keydata)\n {\n-\tconst struct attr_hash_entry *a = entry;\n-\tconst struct attr_hash_entry *b = entry_or_key;\n+\tconst struct attr_hash_entry *a, *b;\n+\n+\ta = container_of(eptr, const struct attr_hash_entry, ent);\n+\tb = container_of(entry_or_key, const struct attr_hash_entry, ent);\n \treturn (a->keylen != b->keylen) || strncmp(a->key, b->key, a->keylen);\n }\n \ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex c6d2386b64..e9267b5c9c 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -64,12 +64,14 @@ static const char *prio_names[] = {\n };\n \n static int commit_name_neq(const void *unused_cmp_data,\n-\t\t\t   const void *entry,\n-\t\t\t   const void *entry_or_key,\n+\t\t\t   const struct hashmap_entry *eptr,\n+\t\t\t   const struct hashmap_entry *entry_or_key,\n \t\t\t   const void *peeled)\n {\n-\tconst struct commit_name *cn1 = entry;\n-\tconst struct commit_name *cn2 = entry_or_key;\n+\tconst struct commit_name *cn1, *cn2;\n+\n+\tcn1 = container_of(eptr, const struct commit_name, entry);\n+\tcn2 = container_of(entry_or_key, const struct commit_name, entry);\n \n \treturn !oideq(&cn1->peeled, peeled ? peeled : &cn2->peeled);\n }\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex fa9c862e3a..4a37b3edee 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -125,12 +125,15 @@ struct working_tree_entry {\n };\n \n static int working_tree_entry_cmp(const void *unused_cmp_data,\n-\t\t\t\t  const void *entry,\n-\t\t\t\t  const void *entry_or_key,\n+\t\t\t\t  const struct hashmap_entry *eptr,\n+\t\t\t\t  const struct hashmap_entry *entry_or_key,\n \t\t\t\t  const void *unused_keydata)\n {\n-\tconst struct working_tree_entry *a = entry;\n-\tconst struct working_tree_entry *b = entry_or_key;\n+\tconst struct working_tree_entry *a, *b;\n+\n+\ta = container_of(eptr, const struct working_tree_entry, entry);\n+\tb = container_of(entry_or_key, const struct working_tree_entry, entry);\n+\n \treturn strcmp(a->path, b->path);\n }\n \n@@ -145,12 +148,14 @@ struct pair_entry {\n };\n \n static int pair_cmp(const void *unused_cmp_data,\n-\t\t    const void *entry,\n-\t\t    const void *entry_or_key,\n+\t\t    const struct hashmap_entry *eptr,\n+\t\t    const struct hashmap_entry *entry_or_key,\n \t\t    const void *unused_keydata)\n {\n-\tconst struct pair_entry *a = entry;\n-\tconst struct pair_entry *b = entry_or_key;\n+\tconst struct pair_entry *a, *b;\n+\n+\ta = container_of(eptr, const struct pair_entry, entry);\n+\tb = container_of(entry_or_key, const struct pair_entry, entry);\n \n \treturn strcmp(a->path, b->path);\n }\n@@ -179,12 +184,14 @@ struct path_entry {\n };\n \n static int path_entry_cmp(const void *unused_cmp_data,\n-\t\t\t  const void *entry,\n-\t\t\t  const void *entry_or_key,\n+\t\t\t  const struct hashmap_entry *eptr,\n+\t\t\t  const struct hashmap_entry *entry_or_key,\n \t\t\t  const void *key)\n {\n-\tconst struct path_entry *a = entry;\n-\tconst struct path_entry *b = entry_or_key;\n+\tconst struct path_entry *a, *b;\n+\n+\ta = container_of(eptr, const struct path_entry, entry);\n+\tb = container_of(entry_or_key, const struct path_entry, entry);\n \n \treturn strcmp(a->path, key ? key : b->path);\n }\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 25195badd4..ef0578bf90 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -126,10 +126,15 @@ struct anonymized_entry {\n };\n \n static int anonymized_entry_cmp(const void *unused_cmp_data,\n-\t\t\t\tconst void *va, const void *vb,\n+\t\t\t\tconst struct hashmap_entry *eptr,\n+\t\t\t\tconst struct hashmap_entry *entry_or_key,\n \t\t\t\tconst void *unused_keydata)\n {\n-\tconst struct anonymized_entry *a = va, *b = vb;\n+\tconst struct anonymized_entry *a, *b;\n+\n+\ta = container_of(eptr, const struct anonymized_entry, hash);\n+\tb = container_of(entry_or_key, const struct anonymized_entry, hash);\n+\n \treturn a->orig_len != b->orig_len ||\n \t\tmemcmp(a->orig, b->orig, a->orig_len);\n }\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex d06f2b98aa..476c2416e3 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -258,13 +258,14 @@ struct refname_hash_entry {\n };\n \n static int refname_hash_entry_cmp(const void *hashmap_cmp_fn_data,\n-\t\t\t\t  const void *e1_,\n-\t\t\t\t  const void *e2_,\n+\t\t\t\t  const struct hashmap_entry *eptr,\n+\t\t\t\t  const struct hashmap_entry *entry_or_key,\n \t\t\t\t  const void *keydata)\n {\n-\tconst struct refname_hash_entry *e1 = e1_;\n-\tconst struct refname_hash_entry *e2 = e2_;\n+\tconst struct refname_hash_entry *e1, *e2;\n \n+\te1 = container_of(eptr, const struct refname_hash_entry, ent);\n+\te2 = container_of(entry_or_key, const struct refname_hash_entry, ent);\n \treturn strcmp(e1->refname, keydata ? keydata : e2->refname);\n }\n \ndiff --git a/config.c b/config.c\nindex 4952d1cc9e..33043ee73c 100644\n--- a/config.c\n+++ b/config.c\n@@ -1914,12 +1914,14 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha\n }\n \n static int config_set_element_cmp(const void *unused_cmp_data,\n-\t\t\t\t  const void *entry,\n-\t\t\t\t  const void *entry_or_key,\n+\t\t\t\t  const struct hashmap_entry *eptr,\n+\t\t\t\t  const struct hashmap_entry *entry_or_key,\n \t\t\t\t  const void *unused_keydata)\n {\n-\tconst struct config_set_element *e1 = entry;\n-\tconst struct config_set_element *e2 = entry_or_key;\n+\tconst struct config_set_element *e1, *e2;\n+\n+\te1 = container_of(eptr, const struct config_set_element, ent);\n+\te2 = container_of(entry_or_key, const struct config_set_element, ent);\n \n \treturn strcmp(e1->key, e2->key);\n }\ndiff --git a/diff.c b/diff.c\nindex 66cdf4e9ca..5eaf689fcc 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -933,16 +933,18 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,\n }\n \n static int moved_entry_cmp(const void *hashmap_cmp_fn_data,\n-\t\t\t   const void *entry,\n-\t\t\t   const void *entry_or_key,\n+\t\t\t   const struct hashmap_entry *eptr,\n+\t\t\t   const struct hashmap_entry *entry_or_key,\n \t\t\t   const void *keydata)\n {\n \tconst struct diff_options *diffopt = hashmap_cmp_fn_data;\n-\tconst struct moved_entry *a = entry;\n-\tconst struct moved_entry *b = entry_or_key;\n+\tconst struct moved_entry *a, *b;\n \tunsigned flags = diffopt->color_moved_ws_handling\n \t\t\t & XDF_WHITESPACE_FLAGS;\n \n+\ta = container_of(eptr, const struct moved_entry, ent);\n+\tb = container_of(entry_or_key, const struct moved_entry, ent);\n+\n \tif (diffopt->color_moved_ws_handling &\n \t    COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE)\n \t\t/*\n@@ -1019,7 +1021,7 @@ static void pmb_advance_or_null(struct diff_options *o,\n \t\tstruct moved_entry *prev = pmb[i].match;\n \t\tstruct moved_entry *cur = (prev && prev->next_line) ?\n \t\t\t\tprev->next_line : NULL;\n-\t\tif (cur && !hm->cmpfn(o, cur, match, NULL)) {\n+\t\tif (cur && !hm->cmpfn(o, &cur->ent, &match->ent, NULL)) {\n \t\t\tpmb[i].match = cur;\n \t\t} else {\n \t\t\tpmb[i].match = NULL;\ndiff --git a/hashmap.c b/hashmap.c\nindex 878deb8723..47934161aa 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -140,8 +140,8 @@ static inline struct hashmap_entry **find_entry_ptr(const struct hashmap *map,\n }\n \n static int always_equal(const void *unused_cmp_data,\n-\t\t\tconst void *unused1,\n-\t\t\tconst void *unused2,\n+\t\t\tconst struct hashmap_entry *unused1,\n+\t\t\tconst struct hashmap_entry *unused2,\n \t\t\tconst void *unused_keydata)\n {\n \treturn 0;\n@@ -279,10 +279,15 @@ struct pool_entry {\n };\n \n static int pool_entry_cmp(const void *unused_cmp_data,\n-\t\t\t  const struct pool_entry *e1,\n-\t\t\t  const struct pool_entry *e2,\n-\t\t\t  const unsigned char *keydata)\n+\t\t\t  const struct hashmap_entry *eptr,\n+\t\t\t  const struct hashmap_entry *entry_or_key,\n+\t\t\t  const void *keydata)\n {\n+\tconst struct pool_entry *e1, *e2;\n+\n+\te1 = container_of(eptr, const struct pool_entry, ent);\n+\te2 = container_of(entry_or_key, const struct pool_entry, ent);\n+\n \treturn e1->data != keydata &&\n \t       (e1->len != e2->len || memcmp(e1->data, keydata, e1->len));\n }\n@@ -294,7 +299,7 @@ const void *memintern(const void *data, size_t len)\n \n \t/* initialize string pool hashmap */\n \tif (!map.tablesize)\n-\t\thashmap_init(&map, (hashmap_cmp_fn) pool_entry_cmp, NULL, 0);\n+\t\thashmap_init(&map, pool_entry_cmp, NULL, 0);\n \n \t/* lookup interned string in pool */\n \thashmap_entry_init(&key.ent, memhash(data, len));\ndiff --git a/hashmap.h b/hashmap.h\nindex e1e42581ac..a657ab0050 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -21,12 +21,16 @@\n  * #define COMPARE_VALUE 1\n  *\n  * static int long2string_cmp(const void *hashmap_cmp_fn_data,\n- *                            const struct long2string *e1,\n- *                            const struct long2string *e2,\n+ *                            const struct hashmap_entry *eptr,\n+ *                            const struct hashmap_entry *entry_or_key,\n  *                            const void *keydata)\n  * {\n  *     const char *string = keydata;\n  *     unsigned flags = *(unsigned *)hashmap_cmp_fn_data;\n+ *     const struct long2string *e1, *e2;\n+ *\n+ *     e1 = container_of(eptr, const struct long2string, ent);\n+ *     e2 = container_of(entry_or_key, const struct long2string, ent);\n  *\n  *     if (flags & COMPARE_VALUE)\n  *         return e1->key != e2->key ||\n@@ -41,7 +45,7 @@\n  *     char value[255], action[32];\n  *     unsigned flags = 0;\n  *\n- *     hashmap_init(&map, (hashmap_cmp_fn) long2string_cmp, &flags, 0);\n+ *     hashmap_init(&map, long2string_cmp, &flags, 0);\n  *\n  *     while (scanf(\"%s %ld %s\", action, &key, value)) {\n  *\n@@ -172,7 +176,8 @@ struct hashmap_entry {\n  * The `hashmap_cmp_fn_data` entry is the pointer given in the init function.\n  */\n typedef int (*hashmap_cmp_fn)(const void *hashmap_cmp_fn_data,\n-\t\t\t      const void *entry, const void *entry_or_key,\n+\t\t\t      const struct hashmap_entry *entry,\n+\t\t\t      const struct hashmap_entry *entry_or_key,\n \t\t\t      const void *keydata);\n \n /*\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 8274828c4d..b06e9f7f0b 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -35,14 +35,16 @@ struct path_hashmap_entry {\n };\n \n static int path_hashmap_cmp(const void *cmp_data,\n-\t\t\t    const void *entry,\n-\t\t\t    const void *entry_or_key,\n+\t\t\t    const struct hashmap_entry *eptr,\n+\t\t\t    const struct hashmap_entry *entry_or_key,\n \t\t\t    const void *keydata)\n {\n-\tconst struct path_hashmap_entry *a = entry;\n-\tconst struct path_hashmap_entry *b = entry_or_key;\n+\tconst struct path_hashmap_entry *a, *b;\n \tconst char *key = keydata;\n \n+\ta = container_of(eptr, const struct path_hashmap_entry, e);\n+\tb = container_of(entry_or_key, const struct path_hashmap_entry, e);\n+\n \tif (ignore_case)\n \t\treturn strcasecmp(a->path, key ? key : b->path);\n \telse\n@@ -68,12 +70,14 @@ static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,\n }\n \n static int dir_rename_cmp(const void *unused_cmp_data,\n-\t\t\t  const void *entry,\n-\t\t\t  const void *entry_or_key,\n+\t\t\t  const struct hashmap_entry *eptr,\n+\t\t\t  const struct hashmap_entry *entry_or_key,\n \t\t\t  const void *unused_keydata)\n {\n-\tconst struct dir_rename_entry *e1 = entry;\n-\tconst struct dir_rename_entry *e2 = entry_or_key;\n+\tconst struct dir_rename_entry *e1, *e2;\n+\n+\te1 = container_of(eptr, const struct dir_rename_entry, ent);\n+\te2 = container_of(entry_or_key, const struct dir_rename_entry, ent);\n \n \treturn strcmp(e1->dir, e2->dir);\n }\n@@ -104,17 +108,22 @@ static struct collision_entry *collision_find_entry(struct hashmap *hashmap,\n \t\t\t\tstruct collision_entry, ent);\n }\n \n-static int collision_cmp(void *unused_cmp_data,\n-\t\t\t const struct collision_entry *e1,\n-\t\t\t const struct collision_entry *e2,\n+static int collision_cmp(const void *unused_cmp_data,\n+\t\t\t const struct hashmap_entry *eptr,\n+\t\t\t const struct hashmap_entry *entry_or_key,\n \t\t\t const void *unused_keydata)\n {\n+\tconst struct collision_entry *e1, *e2;\n+\n+\te1 = container_of(eptr, const struct collision_entry, ent);\n+\te2 = container_of(entry_or_key, const struct collision_entry, ent);\n+\n \treturn strcmp(e1->target_file, e2->target_file);\n }\n \n static void collision_init(struct hashmap *map)\n {\n-\thashmap_init(map, (hashmap_cmp_fn) collision_cmp, NULL, 0);\n+\thashmap_init(map, collision_cmp, NULL, 0);\n }\n \n static void flush_output(struct merge_options *opt)\ndiff --git a/name-hash.c b/name-hash.c\nindex aa8253ddd5..85a1ce982c 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -17,14 +17,16 @@ struct dir_entry {\n };\n \n static int dir_entry_cmp(const void *unused_cmp_data,\n-\t\t\t const void *entry,\n-\t\t\t const void *entry_or_key,\n+\t\t\t const struct hashmap_entry *eptr,\n+\t\t\t const struct hashmap_entry *entry_or_key,\n \t\t\t const void *keydata)\n {\n-\tconst struct dir_entry *e1 = entry;\n-\tconst struct dir_entry *e2 = entry_or_key;\n+\tconst struct dir_entry *e1, *e2;\n \tconst char *name = keydata;\n \n+\te1 = container_of(eptr, const struct dir_entry, ent);\n+\te2 = container_of(entry_or_key, const struct dir_entry, ent);\n+\n \treturn e1->namelen != e2->namelen || strncasecmp(e1->name,\n \t\t\tname ? name : e2->name, e1->namelen);\n }\n@@ -115,12 +117,15 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)\n }\n \n static int cache_entry_cmp(const void *unused_cmp_data,\n-\t\t\t   const void *entry,\n-\t\t\t   const void *entry_or_key,\n+\t\t\t   const struct hashmap_entry *eptr,\n+\t\t\t   const struct hashmap_entry *entry_or_key,\n \t\t\t   const void *remove)\n {\n-\tconst struct cache_entry *ce1 = entry;\n-\tconst struct cache_entry *ce2 = entry_or_key;\n+\tconst struct cache_entry *ce1, *ce2;\n+\n+\tce1 = container_of(eptr, const struct cache_entry, ent);\n+\tce2 = container_of(entry_or_key, const struct cache_entry, ent);\n+\n \t/*\n \t * For remove_name_hash, find the exact entry (pointer equality); for\n \t * index_file_exists, find all entries with matching hash code and\ndiff --git a/oidmap.c b/oidmap.c\nindex cd22b3a8bf..4942599391 100644\n--- a/oidmap.c\n+++ b/oidmap.c\n@@ -2,14 +2,18 @@\n #include \"oidmap.h\"\n \n static int oidmap_neq(const void *hashmap_cmp_fn_data,\n-\t\t      const void *entry, const void *entry_or_key,\n+\t\t      const struct hashmap_entry *e1,\n+\t\t      const struct hashmap_entry *e2,\n \t\t      const void *keydata)\n {\n-\tconst struct oidmap_entry *entry_ = entry;\n+\tconst struct oidmap_entry *a, *b;\n+\n+\ta = container_of(e1, const struct oidmap_entry, internal_entry);\n+\tb = container_of(e2, const struct oidmap_entry, internal_entry);\n+\n \tif (keydata)\n-\t\treturn !oideq(&entry_->oid, (const struct object_id *) keydata);\n-\treturn !oideq(&entry_->oid,\n-\t\t      &((const struct oidmap_entry *) entry_or_key)->oid);\n+\t\treturn !oideq(&a->oid, (const struct object_id *) keydata);\n+\treturn !oideq(&a->oid, &b->oid);\n }\n \n void oidmap_init(struct oidmap *map, size_t initial_size)\ndiff --git a/packfile.c b/packfile.c\nindex f2aa34bb49..675d5f2287 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1401,11 +1401,16 @@ static int delta_base_cache_key_eq(const struct delta_base_cache_key *a,\n }\n \n static int delta_base_cache_hash_cmp(const void *unused_cmp_data,\n-\t\t\t\t     const void *va, const void *vb,\n+\t\t\t\t     const struct hashmap_entry *va,\n+\t\t\t\t     const struct hashmap_entry *vb,\n \t\t\t\t     const void *vkey)\n {\n-\tconst struct delta_base_cache_entry *a = va, *b = vb;\n+\tconst struct delta_base_cache_entry *a, *b;\n \tconst struct delta_base_cache_key *key = vkey;\n+\n+\ta = container_of(va, const struct delta_base_cache_entry, ent);\n+\tb = container_of(vb, const struct delta_base_cache_entry, ent);\n+\n \tif (key)\n \t\treturn !delta_base_cache_key_eq(&a->key, key);\n \telse\ndiff --git a/patch-ids.c b/patch-ids.c\nindex 176c47d967..75f8c9f1a1 100644\n--- a/patch-ids.c\n+++ b/patch-ids.c\n@@ -36,14 +36,16 @@ int commit_patch_id(struct commit *commit, struct diff_options *options,\n  * any significance; only that it is non-zero matters.\n  */\n static int patch_id_neq(const void *cmpfn_data,\n-\t\t\tconst void *entry,\n-\t\t\tconst void *entry_or_key,\n+\t\t\tconst struct hashmap_entry *eptr,\n+\t\t\tconst struct hashmap_entry *entry_or_key,\n \t\t\tconst void *unused_keydata)\n {\n \t/* NEEDSWORK: const correctness? */\n \tstruct diff_options *opt = (void *)cmpfn_data;\n-\tstruct patch_id *a = (void *)entry;\n-\tstruct patch_id *b = (void *)entry_or_key;\n+\tstruct patch_id *a, *b;\n+\n+\ta = container_of(eptr, struct patch_id, ent);\n+\tb = container_of(entry_or_key, struct patch_id, ent);\n \n \tif (is_null_oid(&a->patch_id) &&\n \t    commit_patch_id(a->commit, opt, &a->patch_id, 0, 0))\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 9999426914..4613df8826 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -84,12 +84,15 @@ struct ref_to_worktree_entry {\n };\n \n static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,\n-\t\t\t\t      const void *existing_hashmap_entry_to_test,\n-\t\t\t\t      const void *key,\n+\t\t\t\t      const struct hashmap_entry *eptr,\n+\t\t\t\t      const struct hashmap_entry *kptr,\n \t\t\t\t      const void *keydata_aka_refname)\n {\n-\tconst struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;\n-\tconst struct ref_to_worktree_entry *k = key;\n+\tconst struct ref_to_worktree_entry *e, *k;\n+\n+\te = container_of(eptr, const struct ref_to_worktree_entry, ent);\n+\tk = container_of(kptr, const struct ref_to_worktree_entry, ent);\n+\n \treturn strcmp(e->wt->head_ref,\n \t\tkeydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);\n }\ndiff --git a/refs.c b/refs.c\nindex 43a95105f1..2d3eb40f39 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1781,11 +1781,16 @@ struct ref_store_hash_entry\n };\n \n static int ref_store_hash_cmp(const void *unused_cmp_data,\n-\t\t\t      const void *entry, const void *entry_or_key,\n+\t\t\t      const struct hashmap_entry *eptr,\n+\t\t\t      const struct hashmap_entry *entry_or_key,\n \t\t\t      const void *keydata)\n {\n-\tconst struct ref_store_hash_entry *e1 = entry, *e2 = entry_or_key;\n-\tconst char *name = keydata ? keydata : e2->name;\n+\tconst struct ref_store_hash_entry *e1, *e2;\n+\tconst char *name;\n+\n+\te1 = container_of(eptr, const struct ref_store_hash_entry, ent);\n+\te2 = container_of(entry_or_key, const struct ref_store_hash_entry, ent);\n+\tname = keydata ? keydata : e2->name;\n \n \treturn strcmp(e1->name, name);\n }\ndiff --git a/remote.c b/remote.c\nindex ed95ae6ed6..fa9cadcfbd 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -111,14 +111,16 @@ struct remotes_hash_key {\n };\n \n static int remotes_hash_cmp(const void *unused_cmp_data,\n-\t\t\t    const void *entry,\n-\t\t\t    const void *entry_or_key,\n+\t\t\t    const struct hashmap_entry *eptr,\n+\t\t\t    const struct hashmap_entry *entry_or_key,\n \t\t\t    const void *keydata)\n {\n-\tconst struct remote *a = entry;\n-\tconst struct remote *b = entry_or_key;\n+\tconst struct remote *a, *b;\n \tconst struct remotes_hash_key *key = keydata;\n \n+\ta = container_of(eptr, const struct remote, ent);\n+\tb = container_of(entry_or_key, const struct remote, ent);\n+\n \tif (key)\n \t\treturn strncmp(a->name, key->str, key->len) || a->name[key->len];\n \telse\ndiff --git a/revision.c b/revision.c\nindex d5f534209d..f32fbc5e2e 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -107,16 +107,21 @@ struct path_and_oids_entry {\n };\n \n static int path_and_oids_cmp(const void *hashmap_cmp_fn_data,\n-\t\t\t     const struct path_and_oids_entry *e1,\n-\t\t\t     const struct path_and_oids_entry *e2,\n+\t\t\t     const struct hashmap_entry *eptr,\n+\t\t\t     const struct hashmap_entry *entry_or_key,\n \t\t\t     const void *keydata)\n {\n+\tconst struct path_and_oids_entry *e1, *e2;\n+\n+\te1 = container_of(eptr, const struct path_and_oids_entry, ent);\n+\te2 = container_of(entry_or_key, const struct path_and_oids_entry, ent);\n+\n \treturn strcmp(e1->path, e2->path);\n }\n \n static void paths_and_oids_init(struct hashmap *map)\n {\n-\thashmap_init(map, (hashmap_cmp_fn) path_and_oids_cmp, NULL, 0);\n+\thashmap_init(map, path_and_oids_cmp, NULL, 0);\n }\n \n static void paths_and_oids_clear(struct hashmap *map)\ndiff --git a/sequencer.c b/sequencer.c\nindex aea2cb12cc..b3e7319b55 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4440,9 +4440,14 @@ struct labels_entry {\n \tchar label[FLEX_ARRAY];\n };\n \n-static int labels_cmp(const void *fndata, const struct labels_entry *a,\n-\t\t      const struct labels_entry *b, const void *key)\n+static int labels_cmp(const void *fndata, const struct hashmap_entry *eptr,\n+\t\t      const struct hashmap_entry *entry_or_key, const void *key)\n {\n+\tconst struct labels_entry *a, *b;\n+\n+\ta = container_of(eptr, const struct labels_entry, entry);\n+\tb = container_of(entry_or_key, const struct labels_entry, entry);\n+\n \treturn key ? strcmp(a->label, key) : strcmp(a->label, b->label);\n }\n \n@@ -4573,7 +4578,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,\n \n \toidmap_init(&commit2todo, 0);\n \toidmap_init(&state.commit2label, 0);\n-\thashmap_init(&state.labels, (hashmap_cmp_fn) labels_cmp, NULL, 0);\n+\thashmap_init(&state.labels, labels_cmp, NULL, 0);\n \tstrbuf_init(&state.buf, 32);\n \n \tif (revs->cmdline.nr && (revs->cmdline.rev[0].flags & BOTTOM)) {\n@@ -5138,9 +5143,15 @@ struct subject2item_entry {\n };\n \n static int subject2item_cmp(const void *fndata,\n-\t\t\t    const struct subject2item_entry *a,\n-\t\t\t    const struct subject2item_entry *b, const void *key)\n+\t\t\t    const struct hashmap_entry *eptr,\n+\t\t\t    const struct hashmap_entry *entry_or_key,\n+\t\t\t    const void *key)\n {\n+\tconst struct subject2item_entry *a, *b;\n+\n+\ta = container_of(eptr, const struct subject2item_entry, entry);\n+\tb = container_of(entry_or_key, const struct subject2item_entry, entry);\n+\n \treturn key ? strcmp(a->subject, key) : strcmp(a->subject, b->subject);\n }\n \n@@ -5173,8 +5184,7 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t * In that case, last[i] will indicate the index of the latest item to\n \t * be moved to appear after the i'th.\n \t */\n-\thashmap_init(&subject2item, (hashmap_cmp_fn) subject2item_cmp,\n-\t\t     NULL, todo_list->nr);\n+\thashmap_init(&subject2item, subject2item_cmp, NULL, todo_list->nr);\n \tALLOC_ARRAY(next, todo_list->nr);\n \tALLOC_ARRAY(tail, todo_list->nr);\n \tALLOC_ARRAY(subjects, todo_list->nr);\ndiff --git a/sub-process.c b/sub-process.c\nindex f2fcc16c3e..ad94f72665 100644\n--- a/sub-process.c\n+++ b/sub-process.c\n@@ -6,12 +6,14 @@\n #include \"pkt-line.h\"\n \n int cmd2process_cmp(const void *unused_cmp_data,\n-\t\t    const void *entry,\n-\t\t    const void *entry_or_key,\n+\t\t    const struct hashmap_entry *eptr,\n+\t\t    const struct hashmap_entry *entry_or_key,\n \t\t    const void *unused_keydata)\n {\n-\tconst struct subprocess_entry *e1 = entry;\n-\tconst struct subprocess_entry *e2 = entry_or_key;\n+\tconst struct subprocess_entry *e1, *e2;\n+\n+\te1 = container_of(eptr, const struct subprocess_entry, ent);\n+\te2 = container_of(entry_or_key, const struct subprocess_entry, ent);\n \n \treturn strcmp(e1->cmd, e2->cmd);\n }\ndiff --git a/sub-process.h b/sub-process.h\nindex 5c182fad98..0d12708b8c 100644\n--- a/sub-process.h\n+++ b/sub-process.h\n@@ -43,8 +43,8 @@ struct subprocess_capability {\n \n /* Function to test two subprocess hashmap entries for equality. */\n int cmd2process_cmp(const void *unused_cmp_data,\n-\t\t    const void *e1,\n-\t\t    const void *e2,\n+\t\t    const struct hashmap_entry *e,\n+\t\t    const struct hashmap_entry *entry_or_key,\n \t\t    const void *unused_keydata);\n \n /*\ndiff --git a/submodule-config.c b/submodule-config.c\nindex b031884789..5463729ab8 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -38,24 +38,28 @@ enum lookup_type {\n };\n \n static int config_path_cmp(const void *unused_cmp_data,\n-\t\t\t   const void *entry,\n-\t\t\t   const void *entry_or_key,\n+\t\t\t   const struct hashmap_entry *eptr,\n+\t\t\t   const struct hashmap_entry *entry_or_key,\n \t\t\t   const void *unused_keydata)\n {\n-\tconst struct submodule_entry *a = entry;\n-\tconst struct submodule_entry *b = entry_or_key;\n+\tconst struct submodule_entry *a, *b;\n+\n+\ta = container_of(eptr, const struct submodule_entry, ent);\n+\tb = container_of(entry_or_key, const struct submodule_entry, ent);\n \n \treturn strcmp(a->config->path, b->config->path) ||\n \t       !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);\n }\n \n static int config_name_cmp(const void *unused_cmp_data,\n-\t\t\t   const void *entry,\n-\t\t\t   const void *entry_or_key,\n+\t\t\t   const struct hashmap_entry *eptr,\n+\t\t\t   const struct hashmap_entry *entry_or_key,\n \t\t\t   const void *unused_keydata)\n {\n-\tconst struct submodule_entry *a = entry;\n-\tconst struct submodule_entry *b = entry_or_key;\n+\tconst struct submodule_entry *a, *b;\n+\n+\ta = container_of(eptr, const struct submodule_entry, ent);\n+\tb = container_of(entry_or_key, const struct submodule_entry, ent);\n \n \treturn strcmp(a->config->name, b->config->name) ||\n \t       !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex e82cbfdee2..56846da64c 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -16,15 +16,17 @@ static const char *get_value(const struct test_entry *e)\n }\n \n static int test_entry_cmp(const void *cmp_data,\n-\t\t\t  const void *entry,\n-\t\t\t  const void *entry_or_key,\n+\t\t\t  const struct hashmap_entry *eptr,\n+\t\t\t  const struct hashmap_entry *entry_or_key,\n \t\t\t  const void *keydata)\n {\n \tconst int ignore_case = cmp_data ? *((int *)cmp_data) : 0;\n-\tconst struct test_entry *e1 = entry;\n-\tconst struct test_entry *e2 = entry_or_key;\n+\tconst struct test_entry *e1, *e2;\n \tconst char *key = keydata;\n \n+\te1 = container_of(eptr, const struct test_entry, ent);\n+\te2 = container_of(entry_or_key, const struct test_entry, ent);\n+\n \tif (ignore_case)\n \t\treturn strcasecmp(e1->key, key ? key : e2->key);\n \telse\n"},{"id":"382823","messageId":"20190924010324.22619-16-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 15/19] hashmap: use *_entry APIs for iteration","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:20Z","receivedAt":"2019-09-24T01:04:08Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Inspired by list_for_each_entry in the Linux kernel.\nOnce again, these are somewhat compromised usability-wise\nby compilers lacking __typeof__ support.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n attr.c                              |  5 +++--\n blame.c                             | 10 ++++++----\n builtin/describe.c                  |  4 ++--\n builtin/difftool.c                  |  8 ++++----\n config.c                            |  5 +++--\n hashmap.c                           |  2 +-\n hashmap.h                           | 15 +++++++++++++--\n merge-recursive.c                   | 25 +++++++++++++++----------\n oidmap.h                            |  6 ++++--\n revision.c                          | 10 ++++++----\n submodule-config.c                  |  8 +++++---\n t/helper/test-hashmap.c             |  7 ++++---\n t/helper/test-lazy-init-name-hash.c | 12 ++++--------\n 13 files changed, 70 insertions(+), 47 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex 6053481610..ca8be46e8e 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -163,12 +163,13 @@ static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check)\n \tif (size != check->all_attrs_nr) {\n \t\tstruct attr_hash_entry *e;\n \t\tstruct hashmap_iter iter;\n-\t\thashmap_iter_init(&map->map, &iter);\n \n \t\tREALLOC_ARRAY(check->all_attrs, size);\n \t\tcheck->all_attrs_nr = size;\n \n-\t\twhile ((e = hashmap_iter_next(&iter))) {\n+\t\thashmap_for_each_entry(&map->map, &iter, e,\n+\t\t\t\t\tstruct attr_hash_entry,\n+\t\t\t\t\tent /* member name */) {\n \t\t\tconst struct git_attr *a = e->value;\n \t\t\tcheck->all_attrs[a->attr_nr].attr = a;\n \t\t}\ndiff --git a/blame.c b/blame.c\nindex aa46c7ec52..3d8accf902 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -450,9 +450,9 @@ static int fingerprint_similarity(struct fingerprint *a, struct fingerprint *b)\n \tstruct hashmap_iter iter;\n \tconst struct fingerprint_entry *entry_a, *entry_b;\n \n-\thashmap_iter_init(&b->map, &iter);\n-\n-\twhile ((entry_b = hashmap_iter_next(&iter))) {\n+\thashmap_for_each_entry(&b->map, &iter, entry_b,\n+\t\t\t\tconst struct fingerprint_entry,\n+\t\t\t\tentry /* member name */) {\n \t\tentry_a = hashmap_get_entry(&a->map, entry_b, NULL,\n \t\t\t\t\tstruct fingerprint_entry, entry);\n \t\tif (entry_a) {\n@@ -473,7 +473,9 @@ static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b)\n \n \thashmap_iter_init(&b->map, &iter);\n \n-\twhile ((entry_b = hashmap_iter_next(&iter))) {\n+\thashmap_for_each_entry(&b->map, &iter, entry_b,\n+\t\t\t\tconst struct fingerprint_entry,\n+\t\t\t\tentry /* member name */) {\n \t\tentry_a = hashmap_get_entry(&a->map, entry_b, NULL,\n \t\t\t\t\tstruct fingerprint_entry, entry);\n \t\tif (entry_a) {\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex e9267b5c9c..8cf2cd992d 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -333,8 +333,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)\n \t\tstruct commit_name *n;\n \n \t\tinit_commit_names(&commit_names);\n-\t\tn = hashmap_iter_first(&names, &iter);\n-\t\tfor (; n; n = hashmap_iter_next(&iter)) {\n+\t\thashmap_for_each_entry(&names, &iter, n, struct commit_name,\n+\t\t\t\t\tentry /* member name */) {\n \t\t\tc = lookup_commit_reference_gently(the_repository,\n \t\t\t\t\t\t\t   &n->peeled, 1);\n \t\t\tif (c)\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 4a37b3edee..dd94179b68 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -538,8 +538,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t * temporary file to both the left and right directories to show the\n \t * change in the recorded SHA1 for the submodule.\n \t */\n-\thashmap_iter_init(&submodules, &iter);\n-\twhile ((entry = hashmap_iter_next(&iter))) {\n+\thashmap_for_each_entry(&submodules, &iter, entry,\n+\t\t\t\tstruct pair_entry, entry /* member name */) {\n \t\tif (*entry->left) {\n \t\t\tadd_path(&ldir, ldir_len, entry->path);\n \t\t\tensure_leading_directories(ldir.buf);\n@@ -557,8 +557,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t * shows only the link itself, not the contents of the link target.\n \t * This loop replicates that behavior.\n \t */\n-\thashmap_iter_init(&symlinks2, &iter);\n-\twhile ((entry = hashmap_iter_next(&iter))) {\n+\thashmap_for_each_entry(&symlinks2, &iter, entry,\n+\t\t\t\tstruct pair_entry, entry /* member name */) {\n \t\tif (*entry->left) {\n \t\t\tadd_path(&ldir, ldir_len, entry->path);\n \t\t\tensure_leading_directories(ldir.buf);\ndiff --git a/config.c b/config.c\nindex 33043ee73c..8433f74371 100644\n--- a/config.c\n+++ b/config.c\n@@ -1942,8 +1942,9 @@ void git_configset_clear(struct config_set *cs)\n \tif (!cs->hash_initialized)\n \t\treturn;\n \n-\thashmap_iter_init(&cs->config_hash, &iter);\n-\twhile ((entry = hashmap_iter_next(&iter))) {\n+\thashmap_for_each_entry(&cs->config_hash, &iter, entry,\n+\t\t\t\tstruct config_set_element,\n+\t\t\t\tent /* member name */) {\n \t\tfree(entry->key);\n \t\tstring_list_clear(&entry->value_list, 1);\n \t}\ndiff --git a/hashmap.c b/hashmap.c\nindex 47934161aa..fd81a389dd 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -256,7 +256,7 @@ void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter)\n \titer->next = NULL;\n }\n \n-void *hashmap_iter_next(struct hashmap_iter *iter)\n+struct hashmap_entry *hashmap_iter_next(struct hashmap_iter *iter)\n {\n \tstruct hashmap_entry *current = iter->next;\n \tfor (;;) {\ndiff --git a/hashmap.h b/hashmap.h\nindex a657ab0050..46837ba436 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -382,16 +382,27 @@ struct hashmap_iter {\n void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter);\n \n /* Returns the next hashmap_entry, or NULL if there are no more entries. */\n-void *hashmap_iter_next(struct hashmap_iter *iter);\n+struct hashmap_entry *hashmap_iter_next(struct hashmap_iter *iter);\n \n /* Initializes the iterator and returns the first entry, if any. */\n-static inline void *hashmap_iter_first(struct hashmap *map,\n+static inline struct hashmap_entry *hashmap_iter_first(struct hashmap *map,\n \t\tstruct hashmap_iter *iter)\n {\n \thashmap_iter_init(map, iter);\n \treturn hashmap_iter_next(iter);\n }\n \n+#define hashmap_iter_next_entry(iter, type, member) \\\n+\tcontainer_of_or_null(hashmap_iter_next(iter), type, member)\n+\n+#define hashmap_iter_first_entry(map, iter, type, member) \\\n+\tcontainer_of_or_null(hashmap_iter_first(map, iter), type, member)\n+\n+#define hashmap_for_each_entry(map, iter, var, type, member) \\\n+\tfor (var = hashmap_iter_first_entry(map, iter, type, member); \\\n+\t\tvar; \\\n+\t\tvar = hashmap_iter_next_entry(iter, type, member))\n+\n /*\n  * returns a @pointer of @type matching @keyvar, or NULL if nothing found.\n  * @keyvar is a pointer of @type\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex b06e9f7f0b..73c7750448 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2135,8 +2135,9 @@ static void handle_directory_level_conflicts(struct merge_options *opt,\n \tstruct string_list remove_from_head = STRING_LIST_INIT_NODUP;\n \tstruct string_list remove_from_merge = STRING_LIST_INIT_NODUP;\n \n-\thashmap_iter_init(dir_re_head, &iter);\n-\twhile ((head_ent = hashmap_iter_next(&iter))) {\n+\thashmap_for_each_entry(dir_re_head, &iter, head_ent,\n+\t\t\t\tstruct dir_rename_entry,\n+\t\t\t\tent /* member name */) {\n \t\tmerge_ent = dir_rename_find_entry(dir_re_merge, head_ent->dir);\n \t\tif (merge_ent &&\n \t\t    !head_ent->non_unique_new_dir &&\n@@ -2160,8 +2161,9 @@ static void handle_directory_level_conflicts(struct merge_options *opt,\n \tremove_hashmap_entries(dir_re_head, &remove_from_head);\n \tremove_hashmap_entries(dir_re_merge, &remove_from_merge);\n \n-\thashmap_iter_init(dir_re_merge, &iter);\n-\twhile ((merge_ent = hashmap_iter_next(&iter))) {\n+\thashmap_for_each_entry(dir_re_merge, &iter, merge_ent,\n+\t\t\t\tstruct dir_rename_entry,\n+\t\t\t\tent /* member name */) {\n \t\thead_ent = dir_rename_find_entry(dir_re_head, merge_ent->dir);\n \t\tif (tree_has_path(opt->repo, merge, merge_ent->dir)) {\n \t\t\t/* 2. This wasn't a directory rename after all */\n@@ -2265,8 +2267,9 @@ static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs)\n \t * we set non_unique_new_dir.  Once we've determined the winner (or\n \t * that there is no winner), we no longer need possible_new_dirs.\n \t */\n-\thashmap_iter_init(dir_renames, &iter);\n-\twhile ((entry = hashmap_iter_next(&iter))) {\n+\thashmap_for_each_entry(dir_renames, &iter, entry,\n+\t\t\t\tstruct dir_rename_entry,\n+\t\t\t\tent /* member name */) {\n \t\tint max = 0;\n \t\tint bad_max = 0;\n \t\tchar *best = NULL;\n@@ -2624,8 +2627,9 @@ static struct string_list *get_renames(struct merge_options *opt,\n \t\t\t\t\t\t\t     entries);\n \t}\n \n-\thashmap_iter_init(&collisions, &iter);\n-\twhile ((e = hashmap_iter_next(&iter))) {\n+\thashmap_for_each_entry(&collisions, &iter, e,\n+\t\t\t\tstruct collision_entry,\n+\t\t\t\tent /* member name */) {\n \t\tfree(e->target_file);\n \t\tstring_list_clear(&e->source_files, 0);\n \t}\n@@ -2842,8 +2846,9 @@ static void initial_cleanup_rename(struct diff_queue_struct *pairs,\n \tstruct hashmap_iter iter;\n \tstruct dir_rename_entry *e;\n \n-\thashmap_iter_init(dir_renames, &iter);\n-\twhile ((e = hashmap_iter_next(&iter))) {\n+\thashmap_for_each_entry(dir_renames, &iter, e,\n+\t\t\t\tstruct dir_rename_entry,\n+\t\t\t\tent /* member name */) {\n \t\tfree(e->dir);\n \t\tstrbuf_release(&e->new_dir);\n \t\t/* possible_new_dirs already cleared in get_directory_renames */\ndiff --git a/oidmap.h b/oidmap.h\nindex 7a939461ff..c66a83ab1d 100644\n--- a/oidmap.h\n+++ b/oidmap.h\n@@ -78,14 +78,16 @@ static inline void oidmap_iter_init(struct oidmap *map, struct oidmap_iter *iter\n \n static inline void *oidmap_iter_next(struct oidmap_iter *iter)\n {\n-\treturn hashmap_iter_next(&iter->h_iter);\n+\t/* TODO: this API could be reworked to do compile-time type checks */\n+\treturn (void *)hashmap_iter_next(&iter->h_iter);\n }\n \n static inline void *oidmap_iter_first(struct oidmap *map,\n \t\t\t\t      struct oidmap_iter *iter)\n {\n \toidmap_iter_init(map, iter);\n-\treturn oidmap_iter_next(iter);\n+\t/* TODO: this API could be reworked to do compile-time type checks */\n+\treturn (void *)oidmap_iter_next(iter);\n }\n \n #endif\ndiff --git a/revision.c b/revision.c\nindex f32fbc5e2e..f28cbe5de8 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -128,9 +128,10 @@ static void paths_and_oids_clear(struct hashmap *map)\n {\n \tstruct hashmap_iter iter;\n \tstruct path_and_oids_entry *entry;\n-\thashmap_iter_init(map, &iter);\n \n-\twhile ((entry = (struct path_and_oids_entry *)hashmap_iter_next(&iter))) {\n+\thashmap_for_each_entry(map, &iter, entry,\n+\t\t\t\tstruct path_and_oids_entry,\n+\t\t\t\tent /* member name */) {\n \t\toidset_clear(&entry->trees);\n \t\tfree(entry->path);\n \t}\n@@ -242,8 +243,9 @@ void mark_trees_uninteresting_sparse(struct repository *r,\n \t\tadd_children_by_path(r, tree, &map);\n \t}\n \n-\thashmap_iter_init(&map, &map_iter);\n-\twhile ((entry = hashmap_iter_next(&map_iter)))\n+\thashmap_for_each_entry(&map, &map_iter, entry,\n+\t\t\t\tstruct path_and_oids_entry,\n+\t\t\t\tent /* member name */)\n \t\tmark_trees_uninteresting_sparse(r, &entry->trees);\n \n \tpaths_and_oids_clear(&map);\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 5463729ab8..5319933e1d 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -99,8 +99,8 @@ static void submodule_cache_clear(struct submodule_cache *cache)\n \t * allocation of struct submodule entries. Each is allocated by\n \t * their .gitmodules blob sha1 and submodule name.\n \t */\n-\thashmap_iter_init(&cache->for_name, &iter);\n-\twhile ((entry = hashmap_iter_next(&iter)))\n+\thashmap_for_each_entry(&cache->for_name, &iter, entry,\n+\t\t\t\tstruct submodule_entry, ent /* member name */)\n \t\tfree_one_config(entry);\n \n \thashmap_free(&cache->for_path, 1);\n@@ -556,7 +556,9 @@ static const struct submodule *config_from(struct submodule_cache *cache,\n \t\tstruct hashmap_iter iter;\n \t\tstruct submodule_entry *entry;\n \n-\t\tentry = hashmap_iter_first(&cache->for_name, &iter);\n+\t\tentry = hashmap_iter_first_entry(&cache->for_name, &iter,\n+\t\t\t\t\t\tstruct submodule_entry,\n+\t\t\t\t\t\tent /* member name */);\n \t\tif (!entry)\n \t\t\treturn NULL;\n \t\treturn entry->config;\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex 56846da64c..4ec5e11556 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -222,10 +222,11 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\tfree(entry);\n \n \t\t} else if (!strcmp(\"iterate\", cmd)) {\n-\n \t\t\tstruct hashmap_iter iter;\n-\t\t\thashmap_iter_init(&map, &iter);\n-\t\t\twhile ((entry = hashmap_iter_next(&iter)))\n+\n+\t\t\thashmap_for_each_entry(&map, &iter, entry,\n+\t\t\t\t\t\tstruct test_entry,\n+\t\t\t\t\t\tent /* member name */)\n \t\t\t\tprintf(\"%s %s\\n\", entry->key, get_value(entry));\n \n \t\t} else if (!strcmp(\"size\", cmd)) {\ndiff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c\nindex b99a37080d..9d4664d6a4 100644\n--- a/t/helper/test-lazy-init-name-hash.c\n+++ b/t/helper/test-lazy-init-name-hash.c\n@@ -41,17 +41,13 @@ static void dump_run(void)\n \t\t\tdie(\"non-threaded code path used\");\n \t}\n \n-\tdir = hashmap_iter_first(&the_index.dir_hash, &iter_dir);\n-\twhile (dir) {\n+\thashmap_for_each_entry(&the_index.dir_hash, &iter_dir, dir,\n+\t\t\t\tstruct dir_entry, ent /* member name */)\n \t\tprintf(\"dir %08x %7d %s\\n\", dir->ent.hash, dir->nr, dir->name);\n-\t\tdir = hashmap_iter_next(&iter_dir);\n-\t}\n \n-\tce = hashmap_iter_first(&the_index.name_hash, &iter_cache);\n-\twhile (ce) {\n+\thashmap_for_each_entry(&the_index.name_hash, &iter_cache, ce,\n+\t\t\t\tstruct cache_entry, ent /* member name */)\n \t\tprintf(\"name %08x %s\\n\", ce->ent.hash, ce->name);\n-\t\tce = hashmap_iter_next(&iter_cache);\n-\t}\n \n \tdiscard_cache();\n }\n"},{"id":"382824","messageId":"20190924010324.22619-17-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 16/19] hashmap: hashmap_{put,remove} return hashmap_entry *","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:21Z","receivedAt":"2019-09-24T01:04:10Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"And add *_entry variants to perform container_of as necessary\nto simplify most callers.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n hashmap.c               |  6 ++++--\n hashmap.h               | 13 +++++++++++--\n range-diff.c            |  4 +++-\n remote.c                |  3 ++-\n submodule-config.c      |  4 +++-\n t/helper/test-hashmap.c |  9 +++++++--\n 6 files changed, 30 insertions(+), 9 deletions(-)\n\ndiff --git a/hashmap.c b/hashmap.c\nindex fd81a389dd..75ad053de1 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -219,7 +219,8 @@ void hashmap_add(struct hashmap *map, struct hashmap_entry *entry)\n \t}\n }\n \n-void *hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n+struct hashmap_entry *\n+hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n \t\tconst void *keydata)\n {\n \tstruct hashmap_entry *old;\n@@ -242,7 +243,8 @@ void *hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n \treturn old;\n }\n \n-void *hashmap_put(struct hashmap *map, struct hashmap_entry *entry)\n+struct hashmap_entry *\n+hashmap_put(struct hashmap *map, struct hashmap_entry *entry)\n {\n \tstruct hashmap_entry *old = hashmap_remove(map, entry, NULL);\n \thashmap_add(map, entry);\ndiff --git a/hashmap.h b/hashmap.h\nindex 46837ba436..e4078135dd 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -349,7 +349,11 @@ void hashmap_add(struct hashmap *map, struct hashmap_entry *entry);\n  * `entry` is the entry to add or replace.\n  * Returns the replaced entry, or NULL if not found (i.e. the entry was added).\n  */\n-void *hashmap_put(struct hashmap *map, struct hashmap_entry *entry);\n+struct hashmap_entry *\n+hashmap_put(struct hashmap *map, struct hashmap_entry *entry);\n+\n+#define hashmap_put_entry(map, keyvar, type, member) \\\n+\tcontainer_of_or_null(hashmap_put(map, &(keyvar)->member), type, member)\n \n /*\n  * Removes a hashmap entry matching the specified key. If the hashmap contains\n@@ -358,9 +362,14 @@ void *hashmap_put(struct hashmap *map, struct hashmap_entry *entry);\n  *\n  * Argument explanation is the same as in `hashmap_get`.\n  */\n-void *hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n+struct hashmap_entry *\n+hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n \t\tconst void *keydata);\n \n+#define hashmap_remove_entry(map, keyvar, keydata, type, member) \\\n+\tcontainer_of_or_null(hashmap_remove(map, &(keyvar)->member, keydata), \\\n+\t\t\t\ttype, member)\n+\n /*\n  * Returns the `bucket` an entry is stored in.\n  * Useful for multithreaded read access.\ndiff --git a/range-diff.c b/range-diff.c\nindex c51cfd5556..e5e7820bfe 100644\n--- a/range-diff.c\n+++ b/range-diff.c\n@@ -229,7 +229,9 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n \t\tutil->patch = b->items[i].string;\n \t\tutil->diff = util->patch + util->diff_offset;\n \t\thashmap_entry_init(&util->e, strhash(util->diff));\n-\t\tother = hashmap_remove(&map, &util->e, NULL);\n+\t\tother = hashmap_remove_entry(&map, util, NULL,\n+\t\t\t\t\tstruct patch_util,\n+\t\t\t\t\te /* member name */);\n \t\tif (other) {\n \t\t\tif (other->matching >= 0)\n \t\t\t\tBUG(\"already assigned!\");\ndiff --git a/remote.c b/remote.c\nindex fa9cadcfbd..5fcddcd88d 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -162,7 +162,8 @@ static struct remote *make_remote(const char *name, int len)\n \tremotes[remotes_nr++] = ret;\n \n \thashmap_entry_init(&ret->ent, lookup_entry.hash);\n-\treplaced = hashmap_put(&remotes_hash, &ret->ent);\n+\treplaced = hashmap_put_entry(&remotes_hash, ret, struct remote,\n+\t\t\t\t\tent /* member name */);\n \tassert(replaced == NULL);  /* no previous entry overwritten */\n \treturn ret;\n }\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 5319933e1d..a289d195f6 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -141,7 +141,9 @@ static void cache_remove_path(struct submodule_cache *cache,\n \tstruct submodule_entry *removed;\n \thashmap_entry_init(&e.ent, hash);\n \te.config = submodule;\n-\tremoved = hashmap_remove(&cache->for_path, &e.ent, NULL);\n+\tremoved = hashmap_remove_entry(&cache->for_path, &e, NULL,\n+\t\t\t\t\tstruct submodule_entry,\n+\t\t\t\t\tent /* member name */);\n \tfree(removed);\n }\n \ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex 4ec5e11556..07a93a2aec 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -189,7 +189,9 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\tentry = alloc_test_entry(hash, p1, p2);\n \n \t\t\t/* add / replace entry */\n-\t\t\tentry = hashmap_put(&map, &entry->ent);\n+\t\t\tentry = hashmap_put_entry(&map, entry,\n+\t\t\t\t\t\tstruct test_entry,\n+\t\t\t\t\t\tent /* member name */);\n \n \t\t\t/* print and free replaced entry, if any */\n \t\t\tputs(entry ? get_value(entry) : \"NULL\");\n@@ -212,10 +214,13 @@ int cmd__hashmap(int argc, const char **argv)\n \n \t\t\t/* setup static key */\n \t\t\tstruct hashmap_entry key;\n+\t\t\tstruct hashmap_entry *rm;\n \t\t\thashmap_entry_init(&key, hash);\n \n \t\t\t/* remove entry from hashmap */\n-\t\t\tentry = hashmap_remove(&map, &key, p1);\n+\t\t\trm = hashmap_remove(&map, &key, p1);\n+\t\t\tentry = rm ? container_of(rm, struct test_entry, ent)\n+\t\t\t\t\t: NULL;\n \n \t\t\t/* print result and free entry*/\n \t\t\tputs(entry ? get_value(entry) : \"NULL\");\n"},{"id":"382825","messageId":"20190924010324.22619-18-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 17/19] hashmap: introduce hashmap_free_entries","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:22Z","receivedAt":"2019-09-24T01:04:13Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"`hashmap_free_entries' behaves like `container_of' and passes\nthe offset of the hashmap_entry struct to the internal\n`hashmap_free_' function, allowing the function to free any\nstruct pointer regardless of where the hashmap_entry field\nis located.\n\n`hashmap_free' no longer takes any arguments aside from\nthe hashmap itself.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n blame.c                 |  2 +-\n builtin/fetch.c         |  6 +++---\n config.c                |  2 +-\n diff.c                  |  6 ++++--\n diffcore-rename.c       |  2 +-\n hashmap.c               | 11 ++++++++---\n hashmap.h               | 19 +++++++++++++------\n merge-recursive.c       |  7 ++++---\n name-hash.c             |  4 ++--\n oidmap.c                |  4 +++-\n patch-ids.c             |  2 +-\n range-diff.c            |  2 +-\n ref-filter.c            |  3 ++-\n revision.c              |  2 +-\n sequencer.c             |  4 ++--\n submodule-config.c      |  4 ++--\n t/helper/test-hashmap.c |  6 +++---\n 17 files changed, 52 insertions(+), 34 deletions(-)\n\ndiff --git a/blame.c b/blame.c\nindex 3d8accf902..f33af0da9f 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -433,7 +433,7 @@ static void get_fingerprint(struct fingerprint *result,\n \n static void free_fingerprint(struct fingerprint *f)\n {\n-\thashmap_free(&f->map, 0);\n+\thashmap_free(&f->map);\n \tfree(f->entries);\n }\n \ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 476c2416e3..09f7170616 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -366,7 +366,7 @@ static void find_non_local_tags(const struct ref *refs,\n \t\titem = refname_hash_add(&remote_refs, ref->name, &ref->old_oid);\n \t\tstring_list_insert(&remote_refs_list, ref->name);\n \t}\n-\thashmap_free(&existing_refs, 1);\n+\thashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);\n \n \t/*\n \t * We may have a final lightweight tag that needs to be\n@@ -401,7 +401,7 @@ static void find_non_local_tags(const struct ref *refs,\n \t\t**tail = rm;\n \t\t*tail = &rm->next;\n \t}\n-\thashmap_free(&remote_refs, 1);\n+\thashmap_free_entries(&remote_refs, struct refname_hash_entry, ent);\n \tstring_list_clear(&remote_refs_list, 0);\n }\n \n@@ -530,7 +530,7 @@ static struct ref *get_ref_map(struct remote *remote,\n \t\t\t}\n \t\t}\n \t}\n-\thashmap_free(&existing_refs, 1);\n+\thashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);\n \n \treturn ref_map;\n }\ndiff --git a/config.c b/config.c\nindex 8433f74371..4d05dbc15a 100644\n--- a/config.c\n+++ b/config.c\n@@ -1948,7 +1948,7 @@ void git_configset_clear(struct config_set *cs)\n \t\tfree(entry->key);\n \t\tstring_list_clear(&entry->value_list, 1);\n \t}\n-\thashmap_free(&cs->config_hash, 1);\n+\thashmap_free_entries(&cs->config_hash, struct config_set_element, ent);\n \tcs->hash_initialized = 0;\n \tfree(cs->list.items);\n \tcs->list.nr = 0;\ndiff --git a/diff.c b/diff.c\nindex 5eaf689fcc..f94d9f96af 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -6236,8 +6236,10 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)\n \t\t\tif (o->color_moved == COLOR_MOVED_ZEBRA_DIM)\n \t\t\t\tdim_moved_lines(o);\n \n-\t\t\thashmap_free(&add_lines, 1);\n-\t\t\thashmap_free(&del_lines, 1);\n+\t\t\thashmap_free_entries(&add_lines, struct moved_entry,\n+\t\t\t\t\t\tent);\n+\t\t\thashmap_free_entries(&del_lines, struct moved_entry,\n+\t\t\t\t\t\tent);\n \t\t}\n \n \t\tfor (i = 0; i < esm.nr; i++)\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 611b08f463..994609ed58 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -358,7 +358,7 @@ static int find_exact_renames(struct diff_options *options)\n \t\trenames += find_identical_files(&file_table, i, options);\n \n \t/* Free the hash data structure and entries */\n-\thashmap_free(&file_table, 1);\n+\thashmap_free_entries(&file_table, struct file_similarity, entry);\n \n \treturn renames;\n }\ndiff --git a/hashmap.c b/hashmap.c\nindex 75ad053de1..1efd5e431b 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -171,16 +171,21 @@ void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function,\n \tmap->do_count_items = 1;\n }\n \n-void hashmap_free(struct hashmap *map, int free_entries)\n+void hashmap_free_(struct hashmap *map, ssize_t entry_offset)\n {\n \tif (!map || !map->table)\n \t\treturn;\n-\tif (free_entries) {\n+\tif (entry_offset >= 0) { /* called by hashmap_free_entries */\n \t\tstruct hashmap_iter iter;\n \t\tstruct hashmap_entry *e;\n+\n \t\thashmap_iter_init(map, &iter);\n \t\twhile ((e = hashmap_iter_next(&iter)))\n-\t\t\tfree(e);\n+\t\t\t/*\n+\t\t\t * like container_of, but using caller-calculated\n+\t\t\t * offset (caller being hashmap_free_entries)\n+\t\t\t */\n+\t\t\tfree((char *)e - entry_offset);\n \t}\n \tfree(map->table);\n \tmemset(map, 0, sizeof(*map));\ndiff --git a/hashmap.h b/hashmap.h\nindex e4078135dd..7c7a54d15e 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -96,7 +96,7 @@\n  *         }\n  *\n  *         if (!strcmp(\"end\", action)) {\n- *             hashmap_free(&map, 1);\n+ *             hashmap_free_entries(&map, struct long2string, ent);\n  *             break;\n  *         }\n  *     }\n@@ -232,13 +232,20 @@ void hashmap_init(struct hashmap *map,\n \t\t\t const void *equals_function_data,\n \t\t\t size_t initial_size);\n \n+/* internal function for freeing hashmap */\n+void hashmap_free_(struct hashmap *map, ssize_t offset);\n+\n /*\n- * Frees a hashmap structure and allocated memory.\n- *\n- * If `free_entries` is true, each hashmap_entry in the map is freed as well\n- * using stdlibs free().\n+ * Frees a hashmap structure and allocated memory, leaves entries undisturbed\n+ */\n+#define hashmap_free(map) hashmap_free_(map, -1)\n+\n+/*\n+ * Frees @map and all entries.  @type is the struct type of the entry\n+ * where @member is the hashmap_entry struct used to associate with @map\n  */\n-void hashmap_free(struct hashmap *map, int free_entries);\n+#define hashmap_free_entries(map, type, member) \\\n+\thashmap_free_(map, offsetof(type, member));\n \n /* hashmap_entry functions */\n \ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 73c7750448..34b3d54154 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2633,7 +2633,7 @@ static struct string_list *get_renames(struct merge_options *opt,\n \t\tfree(e->target_file);\n \t\tstring_list_clear(&e->source_files, 0);\n \t}\n-\thashmap_free(&collisions, 1);\n+\thashmap_free_entries(&collisions, struct collision_entry, ent);\n \treturn renames;\n }\n \n@@ -2853,7 +2853,7 @@ static void initial_cleanup_rename(struct diff_queue_struct *pairs,\n \t\tstrbuf_release(&e->new_dir);\n \t\t/* possible_new_dirs already cleared in get_directory_renames */\n \t}\n-\thashmap_free(dir_renames, 1);\n+\thashmap_free_entries(dir_renames, struct dir_rename_entry, ent);\n \tfree(dir_renames);\n \n \tfree(pairs->queue);\n@@ -3482,7 +3482,8 @@ int merge_trees(struct merge_options *opt,\n \t\tstring_list_clear(entries, 1);\n \t\tfree(entries);\n \n-\t\thashmap_free(&opt->current_file_dir_set, 1);\n+\t\thashmap_free_entries(&opt->current_file_dir_set,\n+\t\t\t\t\tstruct path_hashmap_entry, e);\n \n \t\tif (clean < 0) {\n \t\t\tunpack_trees_finish(opt);\ndiff --git a/name-hash.c b/name-hash.c\nindex 85a1ce982c..c86fe0f1df 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -728,6 +728,6 @@ void free_name_hash(struct index_state *istate)\n \t\treturn;\n \tistate->name_hash_initialized = 0;\n \n-\thashmap_free(&istate->name_hash, 0);\n-\thashmap_free(&istate->dir_hash, 1);\n+\thashmap_free(&istate->name_hash);\n+\thashmap_free_entries(&istate->dir_hash, struct dir_entry, ent);\n }\ndiff --git a/oidmap.c b/oidmap.c\nindex 4942599391..423aa014a3 100644\n--- a/oidmap.c\n+++ b/oidmap.c\n@@ -25,7 +25,9 @@ void oidmap_free(struct oidmap *map, int free_entries)\n {\n \tif (!map)\n \t\treturn;\n-\thashmap_free(&map->map, free_entries);\n+\n+\t/* TODO: make oidmap itself not depend on struct layouts */\n+\thashmap_free_(&map->map, free_entries ? 0 : -1);\n }\n \n void *oidmap_get(const struct oidmap *map, const struct object_id *key)\ndiff --git a/patch-ids.c b/patch-ids.c\nindex 75f8c9f1a1..af17828e33 100644\n--- a/patch-ids.c\n+++ b/patch-ids.c\n@@ -71,7 +71,7 @@ int init_patch_ids(struct repository *r, struct patch_ids *ids)\n \n int free_patch_ids(struct patch_ids *ids)\n {\n-\thashmap_free(&ids->patches, 1);\n+\thashmap_free_entries(&ids->patches, struct patch_id, ent);\n \treturn 0;\n }\n \ndiff --git a/range-diff.c b/range-diff.c\nindex e5e7820bfe..9df53569bb 100644\n--- a/range-diff.c\n+++ b/range-diff.c\n@@ -241,7 +241,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n \t\t}\n \t}\n \n-\thashmap_free(&map, 0);\n+\thashmap_free(&map);\n }\n \n static void diffsize_consume(void *data, char *line, unsigned long len)\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 4613df8826..0950b789e3 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -2172,7 +2172,8 @@ void ref_array_clear(struct ref_array *array)\n \tused_atom_cnt = 0;\n \n \tif (ref_to_worktree_map.worktrees) {\n-\t\thashmap_free(&(ref_to_worktree_map.map), 1);\n+\t\thashmap_free_entries(&(ref_to_worktree_map.map),\n+\t\t\t\t\tstruct ref_to_worktree_entry, ent);\n \t\tfree_worktrees(ref_to_worktree_map.worktrees);\n \t\tref_to_worktree_map.worktrees = NULL;\n \t}\ndiff --git a/revision.c b/revision.c\nindex f28cbe5de8..8a5f866ae6 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -136,7 +136,7 @@ static void paths_and_oids_clear(struct hashmap *map)\n \t\tfree(entry->path);\n \t}\n \n-\thashmap_free(map, 1);\n+\thashmap_free_entries(map, struct path_and_oids_entry, ent);\n }\n \n static void paths_and_oids_insert(struct hashmap *map,\ndiff --git a/sequencer.c b/sequencer.c\nindex b3e7319b55..694b463518 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4772,7 +4772,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,\n \n \toidmap_free(&commit2todo, 1);\n \toidmap_free(&state.commit2label, 1);\n-\thashmap_free(&state.labels, 1);\n+\thashmap_free_entries(&state.labels, struct labels_entry, entry);\n \tstrbuf_release(&state.buf);\n \n \treturn 0;\n@@ -5301,7 +5301,7 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \tfor (i = 0; i < todo_list->nr; i++)\n \t\tfree(subjects[i]);\n \tfree(subjects);\n-\thashmap_free(&subject2item, 1);\n+\thashmap_free_entries(&subject2item, struct subject2item_entry, entry);\n \n \tclear_commit_todo_item(&commit_todo);\n \ndiff --git a/submodule-config.c b/submodule-config.c\nindex a289d195f6..5462acc8ec 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -103,8 +103,8 @@ static void submodule_cache_clear(struct submodule_cache *cache)\n \t\t\t\tstruct submodule_entry, ent /* member name */)\n \t\tfree_one_config(entry);\n \n-\thashmap_free(&cache->for_path, 1);\n-\thashmap_free(&cache->for_name, 1);\n+\thashmap_free_entries(&cache->for_path, struct submodule_entry, ent);\n+\thashmap_free_entries(&cache->for_name, struct submodule_entry, ent);\n \tcache->initialized = 0;\n \tcache->gitmodules_read = 0;\n }\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex 07a93a2aec..6f2530dcc8 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -109,7 +109,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)\n \t\t\t\thashmap_add(&map, &entries[i]->ent);\n \t\t\t}\n \n-\t\t\thashmap_free(&map, 0);\n+\t\t\thashmap_free(&map);\n \t\t}\n \t} else {\n \t\t/* test map lookups */\n@@ -129,7 +129,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)\n \t\t\t}\n \t\t}\n \n-\t\thashmap_free(&map, 0);\n+\t\thashmap_free(&map);\n \t}\n }\n \n@@ -266,6 +266,6 @@ int cmd__hashmap(int argc, const char **argv)\n \t}\n \n \tstrbuf_release(&line);\n-\thashmap_free(&map, 1);\n+\thashmap_free_entries(&map, struct test_entry, ent);\n \treturn 0;\n }\n"},{"id":"382826","messageId":"20190924010324.22619-19-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 18/19] OFFSETOF_VAR macro to simplify hashmap iterators","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:23Z","receivedAt":"2019-09-24T01:04:17Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"While we cannot rely on a `__typeof__' operator being portable\nto use with `offsetof'; we can calculate the pointer offset\nusing an existing pointer and the address of a member using\npointer arithmetic.\n\nThis allows us to simplify usage of hashmap iterator macros\nby not having to specify a type when a pointer of that type\nis already given.\n\nIn the future, list iterator macros (e.g. list_for_each_entry)\nmay also be implemented using OFFSETOF_VAR to save hackers the\ntrouble of using container_of/list_entry macros and without\nrelying on non-portable `__typeof__'.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n attr.c                              |  1 -\n blame.c                             |  2 --\n builtin/describe.c                  |  2 +-\n builtin/difftool.c                  |  4 +--\n config.c                            |  1 -\n diff.c                              |  5 ++--\n diffcore-rename.c                   |  2 +-\n git-compat-util.h                   |  7 +++++\n hashmap.h                           | 44 ++++++++++++++++++++---------\n merge-recursive.c                   |  5 ----\n name-hash.c                         |  3 +-\n revision.c                          |  8 ++----\n submodule-config.c                  |  2 +-\n t/helper/test-hashmap.c             |  5 +---\n t/helper/test-lazy-init-name-hash.c |  4 +--\n 15 files changed, 50 insertions(+), 45 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex ca8be46e8e..9849106627 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -168,7 +168,6 @@ static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check)\n \t\tcheck->all_attrs_nr = size;\n \n \t\thashmap_for_each_entry(&map->map, &iter, e,\n-\t\t\t\t\tstruct attr_hash_entry,\n \t\t\t\t\tent /* member name */) {\n \t\t\tconst struct git_attr *a = e->value;\n \t\t\tcheck->all_attrs[a->attr_nr].attr = a;\ndiff --git a/blame.c b/blame.c\nindex f33af0da9f..90b247abf9 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -451,7 +451,6 @@ static int fingerprint_similarity(struct fingerprint *a, struct fingerprint *b)\n \tconst struct fingerprint_entry *entry_a, *entry_b;\n \n \thashmap_for_each_entry(&b->map, &iter, entry_b,\n-\t\t\t\tconst struct fingerprint_entry,\n \t\t\t\tentry /* member name */) {\n \t\tentry_a = hashmap_get_entry(&a->map, entry_b, NULL,\n \t\t\t\t\tstruct fingerprint_entry, entry);\n@@ -474,7 +473,6 @@ static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b)\n \thashmap_iter_init(&b->map, &iter);\n \n \thashmap_for_each_entry(&b->map, &iter, entry_b,\n-\t\t\t\tconst struct fingerprint_entry,\n \t\t\t\tentry /* member name */) {\n \t\tentry_a = hashmap_get_entry(&a->map, entry_b, NULL,\n \t\t\t\t\tstruct fingerprint_entry, entry);\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 8cf2cd992d..1caf98f716 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -333,7 +333,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)\n \t\tstruct commit_name *n;\n \n \t\tinit_commit_names(&commit_names);\n-\t\thashmap_for_each_entry(&names, &iter, n, struct commit_name,\n+\t\thashmap_for_each_entry(&names, &iter, n,\n \t\t\t\t\tentry /* member name */) {\n \t\t\tc = lookup_commit_reference_gently(the_repository,\n \t\t\t\t\t\t\t   &n->peeled, 1);\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex dd94179b68..f2d4d1e0f8 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -539,7 +539,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t * change in the recorded SHA1 for the submodule.\n \t */\n \thashmap_for_each_entry(&submodules, &iter, entry,\n-\t\t\t\tstruct pair_entry, entry /* member name */) {\n+\t\t\t\tentry /* member name */) {\n \t\tif (*entry->left) {\n \t\t\tadd_path(&ldir, ldir_len, entry->path);\n \t\t\tensure_leading_directories(ldir.buf);\n@@ -558,7 +558,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t * This loop replicates that behavior.\n \t */\n \thashmap_for_each_entry(&symlinks2, &iter, entry,\n-\t\t\t\tstruct pair_entry, entry /* member name */) {\n+\t\t\t\tentry /* member name */) {\n \t\tif (*entry->left) {\n \t\t\tadd_path(&ldir, ldir_len, entry->path);\n \t\t\tensure_leading_directories(ldir.buf);\ndiff --git a/config.c b/config.c\nindex 4d05dbc15a..77ed00bfbf 100644\n--- a/config.c\n+++ b/config.c\n@@ -1943,7 +1943,6 @@ void git_configset_clear(struct config_set *cs)\n \t\treturn;\n \n \thashmap_for_each_entry(&cs->config_hash, &iter, entry,\n-\t\t\t\tstruct config_set_element,\n \t\t\t\tent /* member name */) {\n \t\tfree(entry->key);\n \t\tstring_list_clear(&entry->value_list, 1);\ndiff --git a/diff.c b/diff.c\nindex f94d9f96af..051de9832d 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1038,7 +1038,7 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,\n \tint i;\n \tchar *got_match = xcalloc(1, pmb_nr);\n \n-\thashmap_for_each_entry_from(hm, match, struct moved_entry, ent) {\n+\thashmap_for_each_entry_from(hm, match, ent) {\n \t\tfor (i = 0; i < pmb_nr; i++) {\n \t\t\tstruct moved_entry *prev = pmb[i].match;\n \t\t\tstruct moved_entry *cur = (prev && prev->next_line) ?\n@@ -1193,8 +1193,7 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\t\t * The current line is the start of a new block.\n \t\t\t * Setup the set of potential blocks.\n \t\t\t */\n-\t\t\thashmap_for_each_entry_from(hm, match,\n-\t\t\t\t\t\tstruct moved_entry, ent) {\n+\t\t\thashmap_for_each_entry_from(hm, match, ent) {\n \t\t\t\tALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);\n \t\t\t\tif (o->color_moved_ws_handling &\n \t\t\t\t    COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 994609ed58..9ad4dc395a 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -284,7 +284,7 @@ static int find_identical_files(struct hashmap *srcs,\n \t */\n \tp = hashmap_get_entry_from_hash(srcs, hash, NULL,\n \t\t\t\t\tstruct file_similarity, entry);\n-\thashmap_for_each_entry_from(srcs, p, struct file_similarity, entry) {\n+\thashmap_for_each_entry_from(srcs, p, entry) {\n \t\tint score;\n \t\tstruct diff_filespec *source = p->filespec;\n \ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex e24510452a..b3dbb5a3c9 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -1338,4 +1338,11 @@ static inline void *container_of_or_null_offset(void *ptr, size_t offset)\n #define container_of_or_null(ptr, type, member) \\\n \t(type *)container_of_or_null_offset(ptr, offsetof(type, member))\n \n+/*\n+ * like offsetof(), but takes a pointer to type instead of the type\n+ * @ptr is subject to multiple evaluation since we can't rely on TYPEOF()\n+ */\n+#define OFFSETOF_VAR(ptr, member) \\\n+\t((uintptr_t)&(ptr)->member - (uintptr_t)(ptr))\n+\n #endif\ndiff --git a/hashmap.h b/hashmap.h\nindex 7c7a54d15e..519213a812 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -408,16 +408,32 @@ static inline struct hashmap_entry *hashmap_iter_first(struct hashmap *map,\n \treturn hashmap_iter_next(iter);\n }\n \n-#define hashmap_iter_next_entry(iter, type, member) \\\n-\tcontainer_of_or_null(hashmap_iter_next(iter), type, member)\n-\n+/*\n+ * returns the first entry in @map using @iter, where the entry is of\n+ * @type (e.g. \"struct foo\") and @member is the name of the\n+ * \"struct hashmap_entry\" in @type\n+ */\n #define hashmap_iter_first_entry(map, iter, type, member) \\\n \tcontainer_of_or_null(hashmap_iter_first(map, iter), type, member)\n \n-#define hashmap_for_each_entry(map, iter, var, type, member) \\\n-\tfor (var = hashmap_iter_first_entry(map, iter, type, member); \\\n+/* internal macro for hashmap_for_each_entry */\n+#define hashmap_iter_next_entry_offset(iter, offset) \\\n+\tcontainer_of_or_null_offset(hashmap_iter_next(iter), offset)\n+\n+/* internal macro for hashmap_for_each_entry */\n+#define hashmap_iter_first_entry_offset(map, iter, offset) \\\n+\tcontainer_of_or_null_offset(hashmap_iter_first(map, iter), offset)\n+\n+/*\n+ * iterate through @map using @iter, @var is a pointer to a type\n+ * containing a @member which is a \"struct hashmap_entry\"\n+ */\n+#define hashmap_for_each_entry(map, iter, var, member) \\\n+\tfor (var = hashmap_iter_first_entry_offset(map, iter, \\\n+\t\t\t\t\t\tOFFSETOF_VAR(var, member)); \\\n \t\tvar; \\\n-\t\tvar = hashmap_iter_next_entry(iter, type, member))\n+\t\tvar = hashmap_iter_next_entry_offset(iter, \\\n+\t\t\t\t\t\tOFFSETOF_VAR(var, member)))\n \n /*\n  * returns a @pointer of @type matching @keyvar, or NULL if nothing found.\n@@ -432,22 +448,22 @@ static inline struct hashmap_entry *hashmap_iter_first(struct hashmap *map,\n \tcontainer_of_or_null(hashmap_get_from_hash(map, hash, keydata), \\\n \t\t\t\ttype, member)\n /*\n- * returns the next equal @type pointer to @var, or NULL if not found.\n- * @var is a pointer of @type\n- * @member is the name of the \"struct hashmap_entry\" field in @type\n+ * returns the next equal pointer to @var, or NULL if not found.\n+ * @var is a pointer of any type containing \"struct hashmap_entry\"\n+ * @member is the name of the \"struct hashmap_entry\" field\n  */\n-#define hashmap_get_next_entry(map, var, type, member) \\\n-\tcontainer_of_or_null(hashmap_get_next(map, &(var)->member), \\\n-\t\t\t\ttype, member)\n+#define hashmap_get_next_entry(map, var, member) \\\n+\tcontainer_of_or_null_offset(hashmap_get_next(map, &(var)->member), \\\n+\t\t\t\tOFFSETOF_VAR(var, member))\n \n /*\n  * iterate @map starting from @var, where @var is a pointer of @type\n  * and @member is the name of the \"struct hashmap_entry\" field in @type\n  */\n-#define hashmap_for_each_entry_from(map, var, type, member) \\\n+#define hashmap_for_each_entry_from(map, var, member) \\\n \tfor (; \\\n \t\tvar; \\\n-\t\tvar = hashmap_get_next_entry(map, var, type, member))\n+\t\tvar = hashmap_get_next_entry(map, var, member))\n \n /*\n  * Disable item counting and automatic rehashing when adding/removing items.\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 34b3d54154..3abba3a618 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2136,7 +2136,6 @@ static void handle_directory_level_conflicts(struct merge_options *opt,\n \tstruct string_list remove_from_merge = STRING_LIST_INIT_NODUP;\n \n \thashmap_for_each_entry(dir_re_head, &iter, head_ent,\n-\t\t\t\tstruct dir_rename_entry,\n \t\t\t\tent /* member name */) {\n \t\tmerge_ent = dir_rename_find_entry(dir_re_merge, head_ent->dir);\n \t\tif (merge_ent &&\n@@ -2162,7 +2161,6 @@ static void handle_directory_level_conflicts(struct merge_options *opt,\n \tremove_hashmap_entries(dir_re_merge, &remove_from_merge);\n \n \thashmap_for_each_entry(dir_re_merge, &iter, merge_ent,\n-\t\t\t\tstruct dir_rename_entry,\n \t\t\t\tent /* member name */) {\n \t\thead_ent = dir_rename_find_entry(dir_re_head, merge_ent->dir);\n \t\tif (tree_has_path(opt->repo, merge, merge_ent->dir)) {\n@@ -2268,7 +2266,6 @@ static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs)\n \t * that there is no winner), we no longer need possible_new_dirs.\n \t */\n \thashmap_for_each_entry(dir_renames, &iter, entry,\n-\t\t\t\tstruct dir_rename_entry,\n \t\t\t\tent /* member name */) {\n \t\tint max = 0;\n \t\tint bad_max = 0;\n@@ -2628,7 +2625,6 @@ static struct string_list *get_renames(struct merge_options *opt,\n \t}\n \n \thashmap_for_each_entry(&collisions, &iter, e,\n-\t\t\t\tstruct collision_entry,\n \t\t\t\tent /* member name */) {\n \t\tfree(e->target_file);\n \t\tstring_list_clear(&e->source_files, 0);\n@@ -2847,7 +2843,6 @@ static void initial_cleanup_rename(struct diff_queue_struct *pairs,\n \tstruct dir_rename_entry *e;\n \n \thashmap_for_each_entry(dir_renames, &iter, e,\n-\t\t\t\tstruct dir_rename_entry,\n \t\t\t\tent /* member name */) {\n \t\tfree(e->dir);\n \t\tstrbuf_release(&e->new_dir);\ndiff --git a/name-hash.c b/name-hash.c\nindex c86fe0f1df..3cda22b657 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -714,8 +714,7 @@ struct cache_entry *index_file_exists(struct index_state *istate, const char *na\n \n \tce = hashmap_get_entry_from_hash(&istate->name_hash, hash, NULL,\n \t\t\t\t\t struct cache_entry, ent);\n-\thashmap_for_each_entry_from(&istate->name_hash, ce,\n-\t\t\t\t\tstruct cache_entry, ent) {\n+\thashmap_for_each_entry_from(&istate->name_hash, ce, ent) {\n \t\tif (same_name(ce, name, namelen, icase))\n \t\t\treturn ce;\n \t}\ndiff --git a/revision.c b/revision.c\nindex 8a5f866ae6..5abd4a1fe7 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -129,9 +129,7 @@ static void paths_and_oids_clear(struct hashmap *map)\n \tstruct hashmap_iter iter;\n \tstruct path_and_oids_entry *entry;\n \n-\thashmap_for_each_entry(map, &iter, entry,\n-\t\t\t\tstruct path_and_oids_entry,\n-\t\t\t\tent /* member name */) {\n+\thashmap_for_each_entry(map, &iter, entry, ent /* member name */) {\n \t\toidset_clear(&entry->trees);\n \t\tfree(entry->path);\n \t}\n@@ -243,9 +241,7 @@ void mark_trees_uninteresting_sparse(struct repository *r,\n \t\tadd_children_by_path(r, tree, &map);\n \t}\n \n-\thashmap_for_each_entry(&map, &map_iter, entry,\n-\t\t\t\tstruct path_and_oids_entry,\n-\t\t\t\tent /* member name */)\n+\thashmap_for_each_entry(&map, &map_iter, entry, ent /* member name */)\n \t\tmark_trees_uninteresting_sparse(r, &entry->trees);\n \n \tpaths_and_oids_clear(&map);\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 5462acc8ec..c22855cd38 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -100,7 +100,7 @@ static void submodule_cache_clear(struct submodule_cache *cache)\n \t * their .gitmodules blob sha1 and submodule name.\n \t */\n \thashmap_for_each_entry(&cache->for_name, &iter, entry,\n-\t\t\t\tstruct submodule_entry, ent /* member name */)\n+\t\t\t\tent /* member name */)\n \t\tfree_one_config(entry);\n \n \thashmap_free_entries(&cache->for_path, struct submodule_entry, ent);\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex 6f2530dcc8..f89d1194ef 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -205,10 +205,8 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\t/* print result */\n \t\t\tif (!entry)\n \t\t\t\tputs(\"NULL\");\n-\t\t\thashmap_for_each_entry_from(&map, entry,\n-\t\t\t\t\t\tstruct test_entry, ent) {\n+\t\t\thashmap_for_each_entry_from(&map, entry, ent)\n \t\t\t\tputs(get_value(entry));\n-\t\t\t}\n \n \t\t} else if (!strcmp(\"remove\", cmd) && p1) {\n \n@@ -230,7 +228,6 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\tstruct hashmap_iter iter;\n \n \t\t\thashmap_for_each_entry(&map, &iter, entry,\n-\t\t\t\t\t\tstruct test_entry,\n \t\t\t\t\t\tent /* member name */)\n \t\t\t\tprintf(\"%s %s\\n\", entry->key, get_value(entry));\n \ndiff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c\nindex 9d4664d6a4..cd1b4c9736 100644\n--- a/t/helper/test-lazy-init-name-hash.c\n+++ b/t/helper/test-lazy-init-name-hash.c\n@@ -42,11 +42,11 @@ static void dump_run(void)\n \t}\n \n \thashmap_for_each_entry(&the_index.dir_hash, &iter_dir, dir,\n-\t\t\t\tstruct dir_entry, ent /* member name */)\n+\t\t\t\tent /* member name */)\n \t\tprintf(\"dir %08x %7d %s\\n\", dir->ent.hash, dir->nr, dir->name);\n \n \thashmap_for_each_entry(&the_index.name_hash, &iter_cache, ce,\n-\t\t\t\tstruct cache_entry, ent /* member name */)\n+\t\t\t\tent /* member name */)\n \t\tprintf(\"name %08x %s\\n\", ce->ent.hash, ce->name);\n \n \tdiscard_cache();\n"},{"id":"382827","messageId":"20190924010324.22619-20-e@80x24.org","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"[PATCH v2 19/19] hashmap: remove type arg from hashmap_{get,put,remove}_entry","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-24T01:03:24Z","receivedAt":"2019-09-24T01:04:20Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Since these macros already take a `keyvar' pointer of a known type,\nwe can rely on OFFSETOF_VAR to get the correct offset without\nrelying on non-portable `__typeof__' and `offsetof'.\n\nArgument order is also rearranged, so `keyvar' and `member' are\nsequential as they are used as: `keyvar->member'\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n attr.c                  |  2 +-\n blame.c                 | 10 ++++-----\n builtin/difftool.c      |  2 +-\n builtin/fast-export.c   |  2 +-\n config.c                |  3 +--\n diff.c                  |  6 ++----\n hashmap.c               |  2 +-\n hashmap.h               | 45 ++++++++++++++++++++++++++++++-----------\n merge-recursive.c       |  6 ++----\n name-hash.c             |  3 +--\n patch-ids.c             |  3 +--\n range-diff.c            |  4 +---\n remote.c                |  3 +--\n revision.c              |  3 +--\n sub-process.c           |  3 +--\n submodule-config.c      | 10 +++------\n t/helper/test-hashmap.c |  4 +---\n 17 files changed, 56 insertions(+), 55 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex 9849106627..15f0efdf60 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -103,7 +103,7 @@ static void *attr_hashmap_get(struct attr_hashmap *map,\n \thashmap_entry_init(&k.ent, memhash(key, keylen));\n \tk.key = key;\n \tk.keylen = keylen;\n-\te = hashmap_get_entry(&map->map, &k, NULL, struct attr_hash_entry, ent);\n+\te = hashmap_get_entry(&map->map, &k, ent, NULL);\n \n \treturn e ? e->value : NULL;\n }\ndiff --git a/blame.c b/blame.c\nindex 90b247abf9..6384f48133 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -419,8 +419,8 @@ static void get_fingerprint(struct fingerprint *result,\n \t\t\tcontinue;\n \t\thashmap_entry_init(&entry->entry, hash);\n \n-\t\tfound_entry = hashmap_get_entry(&result->map, entry, NULL,\n-\t\t\t\t\tstruct fingerprint_entry, entry);\n+\t\tfound_entry = hashmap_get_entry(&result->map, entry,\n+\t\t\t\t\t\t/* member name */ entry, NULL);\n \t\tif (found_entry) {\n \t\t\tfound_entry->count += 1;\n \t\t} else {\n@@ -452,8 +452,7 @@ static int fingerprint_similarity(struct fingerprint *a, struct fingerprint *b)\n \n \thashmap_for_each_entry(&b->map, &iter, entry_b,\n \t\t\t\tentry /* member name */) {\n-\t\tentry_a = hashmap_get_entry(&a->map, entry_b, NULL,\n-\t\t\t\t\tstruct fingerprint_entry, entry);\n+\t\tentry_a = hashmap_get_entry(&a->map, entry_b, entry, NULL);\n \t\tif (entry_a) {\n \t\t\tintersection += entry_a->count < entry_b->count ?\n \t\t\t\t\tentry_a->count : entry_b->count;\n@@ -474,8 +473,7 @@ static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b)\n \n \thashmap_for_each_entry(&b->map, &iter, entry_b,\n \t\t\t\tentry /* member name */) {\n-\t\tentry_a = hashmap_get_entry(&a->map, entry_b, NULL,\n-\t\t\t\t\tstruct fingerprint_entry, entry);\n+\t\tentry_a = hashmap_get_entry(&a->map, entry_b, entry, NULL);\n \t\tif (entry_a) {\n \t\t\tif (entry_a->count <= entry_b->count)\n \t\t\t\thashmap_remove(&a->map, &entry_b->entry, NULL);\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex f2d4d1e0f8..c280e682b2 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -167,7 +167,7 @@ static void add_left_or_right(struct hashmap *map, const char *path,\n \n \tFLEX_ALLOC_STR(e, path, path);\n \thashmap_entry_init(&e->entry, strhash(path));\n-\texisting = hashmap_get_entry(map, e, NULL, struct pair_entry, entry);\n+\texisting = hashmap_get_entry(map, e, entry, NULL);\n \tif (existing) {\n \t\tfree(e);\n \t\te = existing;\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex ef0578bf90..e3de403efd 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -156,7 +156,7 @@ static const void *anonymize_mem(struct hashmap *map,\n \thashmap_entry_init(&key.hash, memhash(orig, *len));\n \tkey.orig = orig;\n \tkey.orig_len = *len;\n-\tret = hashmap_get_entry(map, &key, NULL, struct anonymized_entry, hash);\n+\tret = hashmap_get_entry(map, &key, hash, NULL);\n \n \tif (!ret) {\n \t\tret = xmalloc(sizeof(*ret));\ndiff --git a/config.c b/config.c\nindex 77ed00bfbf..a4fa464ed2 100644\n--- a/config.c\n+++ b/config.c\n@@ -1863,8 +1863,7 @@ static struct config_set_element *configset_find_element(struct config_set *cs,\n \n \thashmap_entry_init(&k.ent, strhash(normalized_key));\n \tk.key = normalized_key;\n-\tfound_entry = hashmap_get_entry(&cs->config_hash, &k, NULL,\n-\t\t\t\tstruct config_set_element, ent);\n+\tfound_entry = hashmap_get_entry(&cs->config_hash, &k, ent, NULL);\n \tfree(normalized_key);\n \treturn found_entry;\n }\ndiff --git a/diff.c b/diff.c\nindex 051de9832d..a9ecb93af3 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1146,15 +1146,13 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\tcase DIFF_SYMBOL_PLUS:\n \t\t\thm = del_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tmatch = hashmap_get_entry(hm, key, NULL,\n-\t\t\t\t\t\tstruct moved_entry, ent);\n+\t\t\tmatch = hashmap_get_entry(hm, key, ent, NULL);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tcase DIFF_SYMBOL_MINUS:\n \t\t\thm = add_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tmatch = hashmap_get_entry(hm, key, NULL,\n-\t\t\t\t\t\tstruct moved_entry, ent);\n+\t\t\tmatch = hashmap_get_entry(hm, key, ent, NULL);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tdefault:\ndiff --git a/hashmap.c b/hashmap.c\nindex 1efd5e431b..83358226c0 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -311,7 +311,7 @@ const void *memintern(const void *data, size_t len)\n \t/* lookup interned string in pool */\n \thashmap_entry_init(&key.ent, memhash(data, len));\n \tkey.len = len;\n-\te = hashmap_get_entry(&map, &key, data, struct pool_entry, ent);\n+\te = hashmap_get_entry(&map, &key, ent, data);\n \tif (!e) {\n \t\t/* not found: create it */\n \t\tFLEX_ALLOC_MEM(e, data, data, len);\ndiff --git a/hashmap.h b/hashmap.h\nindex 519213a812..407bc10913 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -63,7 +63,7 @@\n  *             k.key = key;\n  *\n  *             flags &= ~COMPARE_VALUE;\n- *             e = hashmap_get_entry(&map, &k, NULL, struct long2string, ent);\n+ *             e = hashmap_get_entry(&map, &k, ent, NULL);\n  *             if (e) {\n  *                 printf(\"first: %ld %s\\n\", e->key, e->value);\n  *                 while ((e = hashmap_get_next_entry(&map, e,\n@@ -359,8 +359,17 @@ void hashmap_add(struct hashmap *map, struct hashmap_entry *entry);\n struct hashmap_entry *\n hashmap_put(struct hashmap *map, struct hashmap_entry *entry);\n \n-#define hashmap_put_entry(map, keyvar, type, member) \\\n-\tcontainer_of_or_null(hashmap_put(map, &(keyvar)->member), type, member)\n+/*\n+ * Adds or replaces a hashmap entry contained within @keyvar,\n+ * where @keyvar is a pointer to a struct containing a\n+ * \"struct hashmap_entry\" @member.\n+ *\n+ * Returns the replaced pointer which is of the same type as @keyvar,\n+ * or NULL if not found.\n+ */\n+#define hashmap_put_entry(map, keyvar, member) \\\n+\tcontainer_of_or_null_offset(hashmap_put(map, &(keyvar)->member), \\\n+\t\t\t\tOFFSETOF_VAR(keyvar, member))\n \n /*\n  * Removes a hashmap entry matching the specified key. If the hashmap contains\n@@ -373,9 +382,20 @@ struct hashmap_entry *\n hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n \t\tconst void *keydata);\n \n-#define hashmap_remove_entry(map, keyvar, keydata, type, member) \\\n-\tcontainer_of_or_null(hashmap_remove(map, &(keyvar)->member, keydata), \\\n-\t\t\t\ttype, member)\n+/*\n+ * Removes a hashmap entry contained within @keyvar,\n+ * where @keyvar is a pointer to a struct containing a\n+ * \"struct hashmap_entry\" @member.\n+ *\n+ * See `hashmap_get` for an explanation of @keydata\n+ *\n+ * Returns the replaced pointer which is of the same type as @keyvar,\n+ * or NULL if not found.\n+ */\n+#define hashmap_remove_entry(map, keyvar, member, keydata) \\\n+\tcontainer_of_or_null_offset( \\\n+\t\t\thashmap_remove(map, &(keyvar)->member, keydata), \\\n+\t\t\tOFFSETOF_VAR(keyvar, member))\n \n /*\n  * Returns the `bucket` an entry is stored in.\n@@ -436,13 +456,14 @@ static inline struct hashmap_entry *hashmap_iter_first(struct hashmap *map,\n \t\t\t\t\t\tOFFSETOF_VAR(var, member)))\n \n /*\n- * returns a @pointer of @type matching @keyvar, or NULL if nothing found.\n- * @keyvar is a pointer of @type\n- * @member is the name of the \"struct hashmap_entry\" field in @type\n+ * returns a pointer of type matching @keyvar, or NULL if nothing found.\n+ * @keyvar is a pointer to a struct containing a\n+ * \"struct hashmap_entry\" @member.\n  */\n-#define hashmap_get_entry(map, keyvar, keydata, type, member) \\\n-\tcontainer_of_or_null(hashmap_get(map, &(keyvar)->member, keydata), \\\n-\t\t\t\ttype, member)\n+#define hashmap_get_entry(map, keyvar, member, keydata) \\\n+\tcontainer_of_or_null_offset( \\\n+\t\t\t\thashmap_get(map, &(keyvar)->member, keydata), \\\n+\t\t\t\tOFFSETOF_VAR(keyvar, member))\n \n #define hashmap_get_entry_from_hash(map, hash, keydata, type, member) \\\n \tcontainer_of_or_null(hashmap_get_from_hash(map, hash, keydata), \\\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 3abba3a618..8787a40b0c 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -65,8 +65,7 @@ static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,\n \t\treturn NULL;\n \thashmap_entry_init(&key.ent, strhash(dir));\n \tkey.dir = dir;\n-\treturn hashmap_get_entry(hashmap, &key, NULL,\n-\t\t\t\tstruct dir_rename_entry, ent);\n+\treturn hashmap_get_entry(hashmap, &key, ent, NULL);\n }\n \n static int dir_rename_cmp(const void *unused_cmp_data,\n@@ -104,8 +103,7 @@ static struct collision_entry *collision_find_entry(struct hashmap *hashmap,\n \n \thashmap_entry_init(&key.ent, strhash(target_file));\n \tkey.target_file = target_file;\n-\treturn hashmap_get_entry(hashmap, &key, NULL,\n-\t\t\t\tstruct collision_entry, ent);\n+\treturn hashmap_get_entry(hashmap, &key, ent, NULL);\n }\n \n static int collision_cmp(const void *unused_cmp_data,\ndiff --git a/name-hash.c b/name-hash.c\nindex 3cda22b657..ceb1d7bd6f 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -37,8 +37,7 @@ static struct dir_entry *find_dir_entry__hash(struct index_state *istate,\n \tstruct dir_entry key;\n \thashmap_entry_init(&key.ent, hash);\n \tkey.namelen = namelen;\n-\treturn hashmap_get_entry(&istate->dir_hash, &key, name,\n-\t\t\t\t\tstruct dir_entry, ent);\n+\treturn hashmap_get_entry(&istate->dir_hash, &key, ent, name);\n }\n \n static struct dir_entry *find_dir_entry(struct index_state *istate,\ndiff --git a/patch-ids.c b/patch-ids.c\nindex af17828e33..12aa6d494b 100644\n--- a/patch-ids.c\n+++ b/patch-ids.c\n@@ -101,8 +101,7 @@ struct patch_id *has_commit_patch_id(struct commit *commit,\n \tif (init_patch_id_entry(&patch, commit, ids))\n \t\treturn NULL;\n \n-\treturn hashmap_get_entry(&ids->patches, &patch, NULL,\n-\t\t\t\t\tstruct patch_id, ent);\n+\treturn hashmap_get_entry(&ids->patches, &patch, ent, NULL);\n }\n \n struct patch_id *add_commit_patch_id(struct commit *commit,\ndiff --git a/range-diff.c b/range-diff.c\nindex 9df53569bb..22ad959cee 100644\n--- a/range-diff.c\n+++ b/range-diff.c\n@@ -229,9 +229,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)\n \t\tutil->patch = b->items[i].string;\n \t\tutil->diff = util->patch + util->diff_offset;\n \t\thashmap_entry_init(&util->e, strhash(util->diff));\n-\t\tother = hashmap_remove_entry(&map, util, NULL,\n-\t\t\t\t\tstruct patch_util,\n-\t\t\t\t\te /* member name */);\n+\t\tother = hashmap_remove_entry(&map, util, e, NULL);\n \t\tif (other) {\n \t\t\tif (other->matching >= 0)\n \t\t\t\tBUG(\"already assigned!\");\ndiff --git a/remote.c b/remote.c\nindex 5fcddcd88d..5c4666b53a 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -162,8 +162,7 @@ static struct remote *make_remote(const char *name, int len)\n \tremotes[remotes_nr++] = ret;\n \n \thashmap_entry_init(&ret->ent, lookup_entry.hash);\n-\treplaced = hashmap_put_entry(&remotes_hash, ret, struct remote,\n-\t\t\t\t\tent /* member name */);\n+\treplaced = hashmap_put_entry(&remotes_hash, ret, ent);\n \tassert(replaced == NULL);  /* no previous entry overwritten */\n \treturn ret;\n }\ndiff --git a/revision.c b/revision.c\nindex 5abd4a1fe7..6688f89d0d 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -151,8 +151,7 @@ static void paths_and_oids_insert(struct hashmap *map,\n \tkey.path = (char *)path;\n \toidset_init(&key.trees, 0);\n \n-\tentry = hashmap_get_entry(map, &key, NULL,\n-\t\t\t\tstruct path_and_oids_entry, ent);\n+\tentry = hashmap_get_entry(map, &key, ent, NULL);\n \tif (!entry) {\n \t\tentry = xcalloc(1, sizeof(struct path_and_oids_entry));\n \t\thashmap_entry_init(&entry->ent, hash);\ndiff --git a/sub-process.c b/sub-process.c\nindex ad94f72665..1b1af9dcbd 100644\n--- a/sub-process.c\n+++ b/sub-process.c\n@@ -24,8 +24,7 @@ struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const ch\n \n \thashmap_entry_init(&key.ent, strhash(cmd));\n \tkey.cmd = cmd;\n-\treturn hashmap_get_entry(hashmap, &key, NULL,\n-\t\t\t\tstruct subprocess_entry, ent);\n+\treturn hashmap_get_entry(hashmap, &key, ent, NULL);\n }\n \n int subprocess_read_status(int fd, struct strbuf *status)\ndiff --git a/submodule-config.c b/submodule-config.c\nindex c22855cd38..401a9b2382 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -141,9 +141,7 @@ static void cache_remove_path(struct submodule_cache *cache,\n \tstruct submodule_entry *removed;\n \thashmap_entry_init(&e.ent, hash);\n \te.config = submodule;\n-\tremoved = hashmap_remove_entry(&cache->for_path, &e, NULL,\n-\t\t\t\t\tstruct submodule_entry,\n-\t\t\t\t\tent /* member name */);\n+\tremoved = hashmap_remove_entry(&cache->for_path, &e, ent, NULL);\n \tfree(removed);\n }\n \n@@ -172,8 +170,7 @@ static const struct submodule *cache_lookup_path(struct submodule_cache *cache,\n \thashmap_entry_init(&key.ent, hash);\n \tkey.config = &key_config;\n \n-\tentry = hashmap_get_entry(&cache->for_path, &key, NULL,\n-\t\t\t\tstruct submodule_entry, ent);\n+\tentry = hashmap_get_entry(&cache->for_path, &key, ent, NULL);\n \tif (entry)\n \t\treturn entry->config;\n \treturn NULL;\n@@ -193,8 +190,7 @@ static struct submodule *cache_lookup_name(struct submodule_cache *cache,\n \thashmap_entry_init(&key.ent, hash);\n \tkey.config = &key_config;\n \n-\tentry = hashmap_get_entry(&cache->for_name, &key, NULL,\n-\t\t\t\tstruct submodule_entry, ent);\n+\tentry = hashmap_get_entry(&cache->for_name, &key, ent, NULL);\n \tif (entry)\n \t\treturn entry->config;\n \treturn NULL;\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex f89d1194ef..cc577c8956 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -189,9 +189,7 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\tentry = alloc_test_entry(hash, p1, p2);\n \n \t\t\t/* add / replace entry */\n-\t\t\tentry = hashmap_put_entry(&map, entry,\n-\t\t\t\t\t\tstruct test_entry,\n-\t\t\t\t\t\tent /* member name */);\n+\t\t\tentry = hashmap_put_entry(&map, entry, ent);\n \n \t\t\t/* print and free replaced entry, if any */\n \t\t\tputs(entry ? get_value(entry) : \"NULL\");\n"},{"id":"382914","messageId":"20c83a67-09c4-5c88-e937-7307541e4bf5@gmail.com","threadId":"51736","inReplyTo":"20190924010324.22619-20-e@80x24.org","subject":"Re: [PATCH v2 19/19] hashmap: remove type arg from hashmap_{get,put,remove}_entry","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-09-25T12:42:54Z","receivedAt":"2019-09-25T12:42:59Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/23/2019 9:03 PM, Eric Wong wrote:\n> Since these macros already take a `keyvar' pointer of a known type,\n> we can rely on OFFSETOF_VAR to get the correct offset without\n> relying on non-portable `__typeof__' and `offsetof'.\n> \n> Argument order is also rearranged, so `keyvar' and `member' are\n> sequential as they are used as: `keyvar->member'\n> \n> Signed-off-by: Eric Wong <e@80x24.org>\n> ---\n>  attr.c                  |  2 +-\n>  blame.c                 | 10 ++++-----\n>  builtin/difftool.c      |  2 +-\n>  builtin/fast-export.c   |  2 +-\n>  config.c                |  3 +--\n>  diff.c                  |  6 ++----\n>  hashmap.c               |  2 +-\n>  hashmap.h               | 45 ++++++++++++++++++++++++++++++-----------\n>  merge-recursive.c       |  6 ++----\n>  name-hash.c             |  3 +--\n>  patch-ids.c             |  3 +--\n>  range-diff.c            |  4 +---\n>  remote.c                |  3 +--\n>  revision.c              |  3 +--\n>  sub-process.c           |  3 +--\n>  submodule-config.c      | 10 +++------\n>  t/helper/test-hashmap.c |  4 +---\n>  17 files changed, 56 insertions(+), 55 deletions(-)\n> \n> diff --git a/attr.c b/attr.c\n> index 9849106627..15f0efdf60 100644\n> --- a/attr.c\n> +++ b/attr.c\n> @@ -103,7 +103,7 @@ static void *attr_hashmap_get(struct attr_hashmap *map,\n>  \thashmap_entry_init(&k.ent, memhash(key, keylen));\n>  \tk.key = key;\n>  \tk.keylen = keylen;\n> -\te = hashmap_get_entry(&map->map, &k, NULL, struct attr_hash_entry, ent);\n> +\te = hashmap_get_entry(&map->map, &k, ent, NULL);\n>  \n>  \treturn e ? e->value : NULL;\n>  }\n> diff --git a/blame.c b/blame.c\n> index 90b247abf9..6384f48133 100644\n> --- a/blame.c\n> +++ b/blame.c\n> @@ -419,8 +419,8 @@ static void get_fingerprint(struct fingerprint *result,\n>  \t\t\tcontinue;\n>  \t\thashmap_entry_init(&entry->entry, hash);\n>  \n> -\t\tfound_entry = hashmap_get_entry(&result->map, entry, NULL,\n> -\t\t\t\t\tstruct fingerprint_entry, entry);\n> +\t\tfound_entry = hashmap_get_entry(&result->map, entry,\n> +\t\t\t\t\t\t/* member name */ entry, NULL);\n\nIn case I forget to point this out during the rest of my review: this\nuse of \"/* member name */\" to distinguish between the two \"entry\"\nstrings is very helpful for review. Likely, it will help future code\nauthors.\n\nI looked at PATCHes 18 & 19 to see the end-result before going through\nthe rest. These are nice mechanical changes that present a cleaner API.\nA worthy goal.\n\nThanks,\n-Stolee\n"},{"id":"382915","messageId":"fe53e15f-d78a-5b94-9745-43a521cb0f80@gmail.com","threadId":"51736","inReplyTo":"20190924010324.22619-3-e@80x24.org","subject":"Re: [PATCH v2 02/19] coccicheck: detect hashmap_entry.hash assignment","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-09-25T12:44:56Z","receivedAt":"2019-09-25T12:45:03Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/23/2019 9:03 PM, Eric Wong wrote:\n> Assigning hashmap_entry.hash manually leaves hashmap_entry.next\n> uninitialized, which can be dangerous once the hashmap_entry is\n> inserted into a hashmap.   Detect those assignments and use\n> hashmap_entry_init, instead.\n\nI appreciate this future-proofing! Thanks.\n\n> \n> Signed-off-by: Eric Wong <e@80x24.org>\n> ---\n>  contrib/coccinelle/hashmap.cocci | 16 ++++++++++++++++\n>  1 file changed, 16 insertions(+)\n>  create mode 100644 contrib/coccinelle/hashmap.cocci\n> \n> diff --git a/contrib/coccinelle/hashmap.cocci b/contrib/coccinelle/hashmap.cocci\n> new file mode 100644\n> index 0000000000..d69e120ccf\n> --- /dev/null\n> +++ b/contrib/coccinelle/hashmap.cocci\n> @@ -0,0 +1,16 @@\n> +@ hashmap_entry_init_usage @\n> +expression E;\n> +struct hashmap_entry HME;\n> +@@\n> +- HME.hash = E;\n> ++ hashmap_entry_init(&HME, E);\n> +\n> +@@\n> +identifier f !~ \"^hashmap_entry_init$\";\n> +expression E;\n> +struct hashmap_entry *HMEP;\n> +@@\n> +  f(...) {<...\n> +- HMEP->hash = E;\n> ++ hashmap_entry_init(HMEP, E);\n> +  ...>}\n> \n\n"},{"id":"382918","messageId":"d0f08de3-3fa8-1e76-0b57-425eb96aefcf@gmail.com","threadId":"51736","inReplyTo":"20190924010324.22619-5-e@80x24.org","subject":"Re: [PATCH v2 04/19] hashmap_entry_init takes \"struct hashmap_entry *\"","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-09-25T12:48:08Z","receivedAt":"2019-09-25T12:48:12Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/23/2019 9:03 PM, Eric Wong wrote:\n> C compilers do type checking to make life easier for us.  So\n> rely on that and update all hashmap_entry_init callers to take\n> \"struct hashmap_entry *\" to avoid future bugs while improving\n> safety and readability.\n[snip]\n> @@ -244,9 +244,9 @@ void hashmap_free(struct hashmap *map, int free_entries);\n>   * your structure was allocated with xmalloc(), you can just free(3) it,\n>   * and if it is on stack, you can just let it go out of scope).\n>   */\n> -static inline void hashmap_entry_init(void *entry, unsigned int hash)\n> +static inline void\n> +hashmap_entry_init(struct hashmap_entry *e, unsigned int hash)\n>  {\n\nI think the preferred line break here would be something like:\n\nstatic inline void hashmap_entry_init(struct hashmap_entry *e,\n\t\t\t\t      unsigned int hash)\n\nThe rest of this patch is very mechanical and easy to check\nfor correctness.\n\nThanks,\n-Stolee\n\n"},{"id":"382919","messageId":"9dc71ed0-617c-84e8-b7fc-0766f4d83695@gmail.com","threadId":"51736","inReplyTo":"20190924010324.22619-8-e@80x24.org","subject":"Re: [PATCH v2 07/19] hashmap_get takes \"const struct hashmap_entry *\"","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-09-25T12:52:05Z","receivedAt":"2019-09-25T12:52:09Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/23/2019 9:03 PM, Eric Wong wrote:\n> This is less error-prone than \"const void *\" as the compiler\n> now detects invalid types being passed.\n[snip]\n> diff --git a/hashmap.h b/hashmap.h\n> index 40bcc64289..2a4b4a3954 100644\n> --- a/hashmap.h\n> +++ b/hashmap.h\n> @@ -74,7 +74,8 @@\n>   *             e->key = key;\n>   *\n>   *             flags |= COMPARE_VALUE;\n> - *             printf(\"%sfound\\n\", hashmap_get(&map, e, NULL) ? \"\" : \"not \");\n> + *             printf(\"%sfound\\n\",\n> + *                    hashmap_get(&map, &e->ent, NULL) ? \"\" : \"not \");\n>   *             free(e);\n>   *         }\n>   *\n> @@ -84,7 +85,8 @@\n>   *             k.key = key;\n>   *\n>   *             flags |= COMPARE_VALUE;\n> - *             printf(\"%sfound\\n\", hashmap_get(&map, &k, value) ? \"\" : \"not \");\n> + *             printf(\"%sfound\\n\",\n> + *                    hashmap_get(&map, &k->ent, value) ? \"\" : \"not \");\n>   *         }\n>   *\n>   *         if (!strcmp(\"end\", action)) {\n> @@ -286,7 +288,7 @@ static inline unsigned int hashmap_get_size(struct hashmap *map)\n>   * If an entry with matching hash code is found, `key` and `keydata` are passed\n>   * to `hashmap_cmp_fn` to decide whether the entry matches the key.\n>   */\n> -void *hashmap_get(const struct hashmap *map, const void *key,\n> +void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n>  \t\t\t const void *keydata);\n\nsuper-nit: the whitespace before the second line is \"\\t\\t\\t \" but should be\n\"\\t\\t  \".\n\n(I'm really struggling to find things wrong with this series. Am I not\nreading it correctly, or is it just that good?)\n\nThanks,\n-Stolee\n"},{"id":"382920","messageId":"d80f2000-3788-f422-e51a-9e3f6fff9f41@gmail.com","threadId":"51736","inReplyTo":"20190924010324.22619-9-e@80x24.org","subject":"Re: [PATCH v2 08/19] hashmap_remove takes \"const struct hashmap_entry *\"","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-09-25T12:54:31Z","receivedAt":"2019-09-25T12:54:40Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/23/2019 9:03 PM, Eric Wong wrote:\n> This is less error-prone than \"const void *\" as the compiler\n> now detects invalid types being passed.\n[snip]\n> diff --git a/hashmap.c b/hashmap.c\n> index 092236c09a..bdf33e0381 100644\n> --- a/hashmap.c\n> +++ b/hashmap.c\n> @@ -218,7 +218,8 @@ void hashmap_add(struct hashmap *map, struct hashmap_entry *entry)\n>  \t}\n>  }\n>  \n> -void *hashmap_remove(struct hashmap *map, const void *key, const void *keydata)\n> +void *hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n> +\t\tconst void *keydata)\n>  {\n>  \tstruct hashmap_entry *old;\n>  \tstruct hashmap_entry **e = find_entry_ptr(map, key, keydata);\n> diff --git a/hashmap.h b/hashmap.h\n> index 2a4b4a3954..5e0818c134 100644\n> --- a/hashmap.h\n> +++ b/hashmap.h\n> @@ -349,7 +349,7 @@ void *hashmap_put(struct hashmap *map, void *entry);\n>   *\n>   * Argument explanation is the same as in `hashmap_get`.\n>   */\n> -void *hashmap_remove(struct hashmap *map, const void *key,\n> +void *hashmap_remove(struct hashmap *map, const struct hashmap_entry *key,\n>  \t\tconst void *keydata);\n\nIn my effort to continue being detail-oriented, I'll point out whitespace\nalignment again here. But then I'll stop mentioning it for hashmap.[c|h]\nand leave it to you for a potential v3.\n\nThanks,\n-Stolee\n\n"},{"id":"382921","messageId":"02e90301-9d50-4105-5988-853d1018ba30@gmail.com","threadId":"51736","inReplyTo":"20190924010324.22619-12-e@80x24.org","subject":"Re: [PATCH v2 11/19] hashmap_get_next returns \"struct hashmap_entry *\"","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-09-25T13:05:12Z","receivedAt":"2019-09-25T13:05:17Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/23/2019 9:03 PM, Eric Wong wrote:\n> This is a step towards removing the requirement for\n> hashmap_entry being the first field of a struct.\n> \n> Signed-off-by: Eric Wong <e@80x24.org>\n> ---\n>  diff.c                  | 19 ++++++++++++-------\n>  diffcore-rename.c       | 11 +++++++----\n>  hashmap.c               |  2 +-\n>  hashmap.h               | 12 ++++++++----\n>  name-hash.c             |  8 +++++---\n>  t/helper/test-hashmap.c | 10 ++++++----\n>  6 files changed, 39 insertions(+), 23 deletions(-)\n> \n> diff --git a/diff.c b/diff.c\n> index 72d3c6aa19..663b5d01f8 100644\n> --- a/diff.c\n> +++ b/diff.c\n> @@ -1035,8 +1035,10 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,\n>  {\n>  \tint i;\n>  \tchar *got_match = xcalloc(1, pmb_nr);\n> +\tstruct hashmap_entry *ent = &match->ent;\n>  \n> -\tfor (; match; match = hashmap_get_next(hm, &match->ent)) {\n> +\tfor (; ent; ent = hashmap_get_next(hm, ent)) {\n\nI suppose that the old code had a blank first entry in the for(;;),\nbut we could move our `ent = &match->ent` into the initializer, right?\nThat would make the loop look a little better, maybe. This happens\nagain below.\n\nThanks,\n-Stolee\n\n> @@ -1189,8 +1193,9 @@ static void mark_color_as_moved(struct diff_options *o,\n>  \t\t\t * The current line is the start of a new block.\n>  \t\t\t * Setup the set of potential blocks.\n>  \t\t\t */\n> -\t\t\tfor (; match; match = hashmap_get_next(hm,\n> -\t\t\t\t\t\t\t\t&match->ent)) {\n> +\t\t\tfor (; ent; ent = hashmap_get_next(hm, ent)) {\n> +\t\t\t\tmatch = container_of(ent, struct moved_entry,\n> +\t\t\t\t\t\t\tent);\n"},{"id":"382922","messageId":"059c05bb-685a-7933-55ff-f18ed271ac3a@gmail.com","threadId":"51736","inReplyTo":"20190924010324.22619-11-e@80x24.org","subject":"Re: [PATCH v2 10/19] introduce container_of macro","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-09-25T13:12:12Z","receivedAt":"2019-09-25T13:12:16Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/23/2019 9:03 PM, Eric Wong wrote:\n> This macro is popular within the Linux kernel for supporting\n> intrusive data structures such as linked lists, red-black trees,\n> and chained hash tables while allowing the compiler to do\n> type checking.\n> \n> I intend to use this to remove the limitation of \"hashmap_entry\"\n> being location-dependent and to allow more compile-time type\n> checking.\n\nnit: I don't know why the first-person singular language caused\nme to stumble during this message. Perhaps the following rewrite\nwould convey the same information:\n\n  Later patches will use container_of() to remove the limitation\n  of \"hashmap_entry\" being location-dependent. This will complete\n  the transition to compile-time type checking for the hashmap API.\n\n> This macro already exists in our source as \"list_entry\" in\n> list.h and making \"list_entry\" an alias to \"container_of\"\n> as the Linux kernel has done is a possibility.\n\nIf it is the same code, then I would prefer you do this conversion\nnow so we can see that equivalence in the patch AND we know that\nexisting code will test it.\n\nThanks,\n-Stolee\n\n> \n> Signed-off-by: Eric Wong <e@80x24.org>\n> ---\n>  git-compat-util.h | 10 ++++++++++\n>  1 file changed, 10 insertions(+)\n> \n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index 83be89de0a..4cc2c8283a 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -1312,4 +1312,14 @@ void unleak_memory(const void *ptr, size_t len);\n>   */\n>  #include \"banned.h\"\n>  \n> +/*\n> + * container_of - Get the address of an object containing a field.\n> + *\n> + * @ptr: pointer to the field.\n> + * @type: type of the object.\n> + * @member: name of the field within the object.\n> + */\n> +#define container_of(ptr, type, member) \\\n> +\t((type *) ((char *)(ptr) - offsetof(type, member)))\n> +\n>  #endif\n> \n\n"},{"id":"382923","messageId":"610f3f40-ebff-c2e5-a210-ef3628193e81@gmail.com","threadId":"51736","inReplyTo":"20190924010324.22619-13-e@80x24.org","subject":"Re: [PATCH v2 12/19] hashmap: use *_entry APIs to wrap container_of","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-09-25T13:15:28Z","receivedAt":"2019-09-25T13:15:33Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/23/2019 9:03 PM, Eric Wong wrote:\n> Using `container_of' can be verbose and choosing names for\n> intermediate \"struct hashmap_entry\" pointers is a hard problem.\n> So introduce \"*_entry\" APIs inspired by similar linked-list\n> APIs in the Linux kernel.\n> \n> Unfortunately, `__typeof__' is not portable C, so we need an\n> extra parameter to specify the type.\n> \n> Signed-off-by: Eric Wong <e@80x24.org>\n> ---\n>  diff.c                  | 21 +++++++++------------\n>  diffcore-rename.c       | 14 +++++---------\n>  git-compat-util.h       | 16 ++++++++++++++++\n>  hashmap.h               | 40 ++++++++++++++++++++++++++++++++++------\n>  name-hash.c             | 11 +++++------\n>  t/helper/test-hashmap.c | 12 +++++-------\n>  6 files changed, 74 insertions(+), 40 deletions(-)\n> \n> diff --git a/diff.c b/diff.c\n> index 663b5d01f8..66cdf4e9ca 100644\n> --- a/diff.c\n> +++ b/diff.c\n> @@ -1035,10 +1035,8 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,\n>  {\n>  \tint i;\n>  \tchar *got_match = xcalloc(1, pmb_nr);\n> -\tstruct hashmap_entry *ent = &match->ent;\n>  \n> -\tfor (; ent; ent = hashmap_get_next(hm, ent)) {\n> -\t\tmatch = container_of(ent, struct moved_entry, ent);\n> +\thashmap_for_each_entry_from(hm, match, struct moved_entry, ent) {\n\nOf course, my recommendation for using the initializer in the for(;;)\nis undone here, anyway.\n\nHowever, how does this work? Let's investigate the macro.\n\n> +/*\n> + * iterate @map starting from @var, where @var is a pointer of @type\n> + * and @member is the name of the \"struct hashmap_entry\" field in @type\n> + */\n> +#define hashmap_for_each_entry_from(map, var, type, member) \\\n> +\tfor (; \\\n> +\t\tvar; \\\n> +\t\tvar = hashmap_get_next_entry(map, var, type, member))\n> +\n\nWhen reading this patch immediately after the previous change to use \"ent\"\nas the iteration variable, I was confused as to which entry was used for \"var\".\nThe expansion of this macro more closely resembles the code without the\nprevious patch.\n\nIn fact, after pulling your code, I think the diff for PATCHes 10 & 11\ntogether is cleaner than looking at the two together. I include that\ndiff below.\n\nThanks,\n-Stolee\n\n---\ndiff --git a/diff.c b/diff.c\nindex 72d3c6aa19..66cdf4e9ca 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1036,7 +1036,7 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,\n \tint i;\n \tchar *got_match = xcalloc(1, pmb_nr);\n \n-\tfor (; match; match = hashmap_get_next(hm, &match->ent)) {\n+\thashmap_for_each_entry_from(hm, match, struct moved_entry, ent) {\n \t\tfor (i = 0; i < pmb_nr; i++) {\n \t\t\tstruct moved_entry *prev = pmb[i].match;\n \t\t\tstruct moved_entry *cur = (prev && prev->next_line) ?\n@@ -1144,13 +1144,15 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\tcase DIFF_SYMBOL_PLUS:\n \t\t\thm = del_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tmatch = hashmap_get(hm, &key->ent, NULL);\n+\t\t\tmatch = hashmap_get_entry(hm, key, NULL,\n+\t\t\t\t\t\tstruct moved_entry, ent);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tcase DIFF_SYMBOL_MINUS:\n \t\t\thm = add_lines;\n \t\t\tkey = prepare_entry(o, n);\n-\t\t\tmatch = hashmap_get(hm, &key->ent, NULL);\n+\t\t\tmatch = hashmap_get_entry(hm, key, NULL,\n+\t\t\t\t\t\tstruct moved_entry, ent);\n \t\t\tfree(key);\n \t\t\tbreak;\n \t\tdefault:\n@@ -1189,8 +1191,8 @@ static void mark_color_as_moved(struct diff_options *o,\n \t\t\t * The current line is the start of a new block.\n \t\t\t * Setup the set of potential blocks.\n \t\t\t */\n-\t\t\tfor (; match; match = hashmap_get_next(hm,\n-\t\t\t\t\t\t\t\t&match->ent)) {\n+\t\t\thashmap_for_each_entry_from(hm, match,\n+\t\t\t\t\t\tstruct moved_entry, ent) {\n \t\t\t\tALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);\n \t\t\t\tif (o->color_moved_ws_handling &\n \t\t\t\t    COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex 4670a40179..611b08f463 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -274,18 +274,17 @@ static int find_identical_files(struct hashmap *srcs,\n \t\t\t\tstruct diff_options *options)\n {\n \tint renames = 0;\n-\n \tstruct diff_filespec *target = rename_dst[dst_index].two;\n \tstruct file_similarity *p, *best = NULL;\n \tint i = 100, best_score = -1;\n+\tunsigned int hash = hash_filespec(options->repo, target);\n \n \t/*\n \t * Find the best source match for specified destination.\n \t */\n-\tp = hashmap_get_from_hash(srcs,\n-\t\t\t\t  hash_filespec(options->repo, target),\n-\t\t\t\t  NULL);\n-\tfor (; p; p = hashmap_get_next(srcs, &p->entry)) {\n+\tp = hashmap_get_entry_from_hash(srcs, hash, NULL,\n+\t\t\t\t\tstruct file_similarity, entry);\n+\thashmap_for_each_entry_from(srcs, p, struct file_similarity, entry) {\n \t\tint score;\n \t\tstruct diff_filespec *source = p->filespec;\n \ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 4cc2c8283a..e24510452a 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -1322,4 +1322,20 @@ void unleak_memory(const void *ptr, size_t len);\n #define container_of(ptr, type, member) \\\n \t((type *) ((char *)(ptr) - offsetof(type, member)))\n \n+\n+/*\n+ * helper function for `container_of_or_null' to avoid multiple\n+ * evaluation of @ptr\n+ */\n+static inline void *container_of_or_null_offset(void *ptr, size_t offset)\n+{\n+\treturn ptr ? (char *)ptr - offset : NULL;\n+}\n+\n+/*\n+ * like `container_of', but allows returned value to be NULL\n+ */\n+#define container_of_or_null(ptr, type, member) \\\n+\t(type *)container_of_or_null_offset(ptr, offsetof(type, member))\n+\n #endif\ndiff --git a/hashmap.c b/hashmap.c\nindex 9b83e73d03..22bc7c5b3b 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -192,7 +192,7 @@ void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n \treturn *find_entry_ptr(map, key, keydata);\n }\n \n-void *hashmap_get_next(const struct hashmap *map,\n+struct hashmap_entry *hashmap_get_next(const struct hashmap *map,\n \t\t\tconst struct hashmap_entry *entry)\n {\n \tstruct hashmap_entry *e = entry->next;\ndiff --git a/hashmap.h b/hashmap.h\nindex cb630447bb..6d5f8685a8 100644\n--- a/hashmap.h\n+++ b/hashmap.h\n@@ -59,11 +59,13 @@\n  *             k.key = key;\n  *\n  *             flags &= ~COMPARE_VALUE;\n- *             e = hashmap_get(&map, &k, NULL);\n+ *             e = hashmap_get_entry(&map, &k, NULL, struct long2string, ent);\n  *             if (e) {\n  *                 printf(\"first: %ld %s\\n\", e->key, e->value);\n- *                 while ((e = hashmap_get_next(&map, e)))\n+ *                 while ((e = hashmap_get_next_entry(&map, e,\n+ *                                              struct long2string, ent))) {\n  *                     printf(\"found more: %ld %s\\n\", e->key, e->value);\n+ *                 }\n  *             }\n  *         }\n  *\n@@ -320,7 +322,7 @@ static inline void *hashmap_get_from_hash(const struct hashmap *map,\n  * `entry` is the hashmap_entry to start the search from, obtained via a previous\n  * call to `hashmap_get` or `hashmap_get_next`.\n  */\n-void *hashmap_get_next(const struct hashmap *map,\n+struct hashmap_entry *hashmap_get_next(const struct hashmap *map,\n \t\t\tconst struct hashmap_entry *entry);\n \n /*\n@@ -383,6 +385,36 @@ static inline void *hashmap_iter_first(struct hashmap *map,\n \treturn hashmap_iter_next(iter);\n }\n \n+/*\n+ * returns a @pointer of @type matching @keyvar, or NULL if nothing found.\n+ * @keyvar is a pointer of @type\n+ * @member is the name of the \"struct hashmap_entry\" field in @type\n+ */\n+#define hashmap_get_entry(map, keyvar, keydata, type, member) \\\n+\tcontainer_of_or_null(hashmap_get(map, &(keyvar)->member, keydata), \\\n+\t\t\t\ttype, member)\n+\n+#define hashmap_get_entry_from_hash(map, hash, keydata, type, member) \\\n+\tcontainer_of_or_null(hashmap_get_from_hash(map, hash, keydata), \\\n+\t\t\t\ttype, member)\n+/*\n+ * returns the next equal @type pointer to @var, or NULL if not found.\n+ * @var is a pointer of @type\n+ * @member is the name of the \"struct hashmap_entry\" field in @type\n+ */\n+#define hashmap_get_next_entry(map, var, type, member) \\\n+\tcontainer_of_or_null(hashmap_get_next(map, &(var)->member), \\\n+\t\t\t\ttype, member)\n+\n+/*\n+ * iterate @map starting from @var, where @var is a pointer of @type\n+ * and @member is the name of the \"struct hashmap_entry\" field in @type\n+ */\n+#define hashmap_for_each_entry_from(map, var, type, member) \\\n+\tfor (; \\\n+\t\tvar; \\\n+\t\tvar = hashmap_get_next_entry(map, var, type, member))\n+\n /*\n  * Disable item counting and automatic rehashing when adding/removing items.\n  *\ndiff --git a/name-hash.c b/name-hash.c\nindex 44d788f1ce..73b83adf3d 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -702,15 +702,16 @@ void adjust_dirname_case(struct index_state *istate, char *name)\n struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase)\n {\n \tstruct cache_entry *ce;\n+\tunsigned int hash = memihash(name, namelen);\n \n \tlazy_init_name_hash(istate);\n \n-\tce = hashmap_get_from_hash(&istate->name_hash,\n-\t\t\t\t   memihash(name, namelen), NULL);\n-\twhile (ce) {\n+\tce = hashmap_get_entry_from_hash(&istate->name_hash, hash, NULL,\n+\t\t\t\t\t struct cache_entry, ent);\n+\thashmap_for_each_entry_from(&istate->name_hash, ce,\n+\t\t\t\t\tstruct cache_entry, ent) {\n \t\tif (same_name(ce, name, namelen, icase))\n \t\t\treturn ce;\n-\t\tce = hashmap_get_next(&istate->name_hash, &ce->ent);\n \t}\n \treturn NULL;\n }\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex de2bd083b9..e82cbfdee2 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -194,16 +194,16 @@ int cmd__hashmap(int argc, const char **argv)\n \t\t\tfree(entry);\n \n \t\t} else if (!strcmp(\"get\", cmd) && p1) {\n-\n \t\t\t/* lookup entry in hashmap */\n-\t\t\tentry = hashmap_get_from_hash(&map, hash, p1);\n+\t\t\tentry = hashmap_get_entry_from_hash(&map, hash, p1,\n+\t\t\t\t\t\t\tstruct test_entry, ent);\n \n \t\t\t/* print result */\n \t\t\tif (!entry)\n \t\t\t\tputs(\"NULL\");\n-\t\t\twhile (entry) {\n+\t\t\thashmap_for_each_entry_from(&map, entry,\n+\t\t\t\t\t\tstruct test_entry, ent) {\n \t\t\t\tputs(get_value(entry));\n-\t\t\t\tentry = hashmap_get_next(&map, &entry->ent);\n \t\t\t}\n \n \t\t} else if (!strcmp(\"remove\", cmd) && p1) {\n\n"},{"id":"382924","messageId":"d16b22c9-c437-0947-fb5a-9421f987a1f1@gmail.com","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"Re: [PATCH v2 00/19] hashmap bug/safety/ease-of-use fixes","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2019-09-25T13:30:14Z","receivedAt":"2019-09-25T13:30:18Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/23/2019 9:03 PM, Eric Wong wrote:\n> Patches 1-11 are largely unchanged from the original series with the\n> exception of 2, which is new and posted at:\n> \n> \thttps://public-inbox.org/git/20190908074953.kux7zz4y7iolqko4@whir/\n> \n> 12-17 take further steps to get us away from hashmap_entry being\n> the first element, but they're also a bit ugly because __typeof__\n> isn't portable\n> \n> 18-19 finally brings me to the APIs I want to expose without\n> relying on __typeof :)\n\nI like this series a lot. The goal is very noble. As one who\nrecently interacted with the hashmap API for the first time,\nI would have preferred working with the new API.\n\nI do wonder about it conflicting with my sparse-checkout changes,\nwhich create a lot of new callers to the API. I suspect that your\nchange will be easier to merge quickly and I will want to rebase\non top. Perhaps Junio could chime in with his preferred integration\nplan?\n\nAs for review, I have mostly minor comments. There appears to be\nconsistent whitespace issues in hashmap.c and hashmap.h, but maybe\nI'm reading them incorrectly.\n\nAlso, consider merging patches 10 & 11 as 11 seems to undo the work\nin patch 10.\n\nThanks,\n-Stolee\n\n"},{"id":"382972","messageId":"nycvar.QRO.7.76.6.1909261032520.15067@tvgsbejvaqbjf.bet","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"Re: [PATCH v2 00/19] hashmap bug/safety/ease-of-use fixes","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-09-26T08:39:43Z","receivedAt":"2019-09-26T08:40:15Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Eric,\n\nOn Tue, 24 Sep 2019, Eric Wong wrote:\n\n> Patches 1-11 are largely unchanged from the original series with the\n> exception of 2, which is new and posted at:\n>\n> \thttps://public-inbox.org/git/20190908074953.kux7zz4y7iolqko4@whir/\n>\n> 12-17 take further steps to get us away from hashmap_entry being\n> the first element, but they're also a bit ugly because __typeof__\n> isn't portable\n>\n> 18-19 finally brings me to the APIs I want to expose without\n> relying on __typeof :)\n\nI won't have time to review this patch series, but I wanted to throw out\nthe idea of storing the offset in `struct hashmap`, i.e. the offset of\nthe `struct hashmap_entry` in the actual entry struct?\n\nExample:\n\n\tstruct erics_entry {\n\t\tconst char *i_want_this_to_be_the_first_field;\n\t\tstruct hashmap_entry e;\n\t\t[...]\n\t};\n\n\t[...]\n\n\tstruct erics_entry *dummy = NULL;\n\tsize_t offset = ((char *)dummy->e) - ((char *)dummy);\n\t[... store that offset in the hashmap and subtract it from the\n\tstored pointers before returning an entry...]\n\nIOW rather than assuming that it is the first field, we could allow an\noffset other than 0. I'm just not sure how to implement this elegantly,\nbut it should be much easier to do this portably than the `typeof()`\napproach.\n\nCiao,\nDscho\n\n>\n> Apologies for the delays, been busy with other stuff...\n>\n> Previous discussion starts at:\n>\n> \thttps://public-inbox.org/git/20190826024332.3403-1-e@80x24.org/\n>\n> The following changes since commit 745f6812895b31c02b29bdfe4ae8e5498f776c26:\n>\n>   First batch after Git 2.23 (2019-08-22 12:41:04 -0700)\n>\n> are available in the Git repository at:\n>\n>   https://80x24.org/git-svn.git hashmap-wip-v2\n>\n> for you to fetch changes up to 212a596edd99169b284912b7b70b6280e2fb90e6:\n>\n>   hashmap: remove type arg from hashmap_{get,put,remove}_entry (2019-09-24 00:42:22 +0000)\n>\n> ----------------------------------------------------------------\n> Eric Wong (19):\n>       diff: use hashmap_entry_init on moved_entry.ent\n>       coccicheck: detect hashmap_entry.hash assignment\n>       packfile: use hashmap_entry in delta_base_cache_entry\n>       hashmap_entry_init takes \"struct hashmap_entry *\"\n>       hashmap_get_next takes \"const struct hashmap_entry *\"\n>       hashmap_add takes \"struct hashmap_entry *\"\n>       hashmap_get takes \"const struct hashmap_entry *\"\n>       hashmap_remove takes \"const struct hashmap_entry *\"\n>       hashmap_put takes \"struct hashmap_entry *\"\n>       introduce container_of macro\n>       hashmap_get_next returns \"struct hashmap_entry *\"\n>       hashmap: use *_entry APIs to wrap container_of\n>       hashmap_get{,_from_hash} return \"struct hashmap_entry *\"\n>       hashmap_cmp_fn takes hashmap_entry params\n>       hashmap: use *_entry APIs for iteration\n>       hashmap: hashmap_{put,remove} return hashmap_entry *\n>       hashmap: introduce hashmap_free_entries\n>       OFFSETOF_VAR macro to simplify hashmap iterators\n>       hashmap: remove type arg from hashmap_{get,put,remove}_entry\n>\n>  attr.c                              |  22 ++---\n>  blame.c                             |  25 +++---\n>  builtin/describe.c                  |  21 +++--\n>  builtin/difftool.c                  |  56 ++++++------\n>  builtin/fast-export.c               |  15 ++--\n>  builtin/fetch.c                     |  30 ++++---\n>  config.c                            |  24 +++---\n>  contrib/coccinelle/hashmap.cocci    |  16 ++++\n>  diff.c                              |  31 ++++---\n>  diffcore-rename.c                   |  15 ++--\n>  git-compat-util.h                   |  33 ++++++++\n>  hashmap.c                           |  58 ++++++++-----\n>  hashmap.h                           | 164 +++++++++++++++++++++++++++++-------\n>  merge-recursive.c                   |  87 ++++++++++---------\n>  name-hash.c                         |  57 +++++++------\n>  oidmap.c                            |  20 +++--\n>  oidmap.h                            |   6 +-\n>  packfile.c                          |  22 +++--\n>  patch-ids.c                         |  18 ++--\n>  range-diff.c                        |  10 +--\n>  ref-filter.c                        |  31 ++++---\n>  refs.c                              |  23 +++--\n>  remote.c                            |  21 +++--\n>  revision.c                          |  28 +++---\n>  sequencer.c                         |  44 ++++++----\n>  sub-process.c                       |  20 +++--\n>  sub-process.h                       |   4 +-\n>  submodule-config.c                  |  52 +++++++-----\n>  t/helper/test-hashmap.c             |  49 ++++++-----\n>  t/helper/test-lazy-init-name-hash.c |  12 +--\n>  30 files changed, 647 insertions(+), 367 deletions(-)\n>  create mode 100644 contrib/coccinelle/hashmap.cocci\n>\n> Eric Wong (19):\n>   diff: use hashmap_entry_init on moved_entry.ent\n>   coccicheck: detect hashmap_entry.hash assignment\n>   packfile: use hashmap_entry in delta_base_cache_entry\n>   hashmap_entry_init takes \"struct hashmap_entry *\"\n>   hashmap_get_next takes \"const struct hashmap_entry *\"\n>   hashmap_add takes \"struct hashmap_entry *\"\n>   hashmap_get takes \"const struct hashmap_entry *\"\n>   hashmap_remove takes \"const struct hashmap_entry *\"\n>   hashmap_put takes \"struct hashmap_entry *\"\n>   introduce container_of macro\n>   hashmap_get_next returns \"struct hashmap_entry *\"\n>   hashmap: use *_entry APIs to wrap container_of\n>   hashmap_get{,_from_hash} return \"struct hashmap_entry *\"\n>   hashmap_cmp_fn takes hashmap_entry params\n>   hashmap: use *_entry APIs for iteration\n>   hashmap: hashmap_{put,remove} return hashmap_entry *\n>   hashmap: introduce hashmap_free_entries\n>   OFFSETOF_VAR macro to simplify hashmap iterators\n>   hashmap: remove type arg from hashmap_{get,put,remove}_entry\n>\n>  attr.c                              |  22 ++--\n>  blame.c                             |  25 +++--\n>  builtin/describe.c                  |  21 ++--\n>  builtin/difftool.c                  |  56 ++++++----\n>  builtin/fast-export.c               |  15 ++-\n>  builtin/fetch.c                     |  30 ++---\n>  config.c                            |  24 ++--\n>  contrib/coccinelle/hashmap.cocci    |  16 +++\n>  diff.c                              |  31 +++---\n>  diffcore-rename.c                   |  15 ++-\n>  git-compat-util.h                   |  33 ++++++\n>  hashmap.c                           |  58 ++++++----\n>  hashmap.h                           | 164 +++++++++++++++++++++++-----\n>  merge-recursive.c                   |  87 ++++++++-------\n>  name-hash.c                         |  57 +++++-----\n>  oidmap.c                            |  20 ++--\n>  oidmap.h                            |   6 +-\n>  packfile.c                          |  22 ++--\n>  patch-ids.c                         |  18 +--\n>  range-diff.c                        |  10 +-\n>  ref-filter.c                        |  31 ++++--\n>  refs.c                              |  23 +++-\n>  remote.c                            |  21 ++--\n>  revision.c                          |  28 +++--\n>  sequencer.c                         |  44 +++++---\n>  sub-process.c                       |  20 ++--\n>  sub-process.h                       |   4 +-\n>  submodule-config.c                  |  52 +++++----\n>  t/helper/test-hashmap.c             |  49 +++++----\n>  t/helper/test-lazy-init-name-hash.c |  12 +-\n>  30 files changed, 647 insertions(+), 367 deletions(-)\n>  create mode 100644 contrib/coccinelle/hashmap.cocci\n>\n>\n> base-commit: 745f6812895b31c02b29bdfe4ae8e5498f776c26\n>\n"},{"id":"382989","messageId":"935a9ad6-2dfb-3073-9f62-4e0f7bf7a170@gmail.com","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"Re: [PATCH v2 00/19] hashmap bug/safety/ease-of-use fixes","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-09-26T13:48:24Z","receivedAt":"2019-09-26T13:48:31Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Eric\n\nOn 24/09/2019 02:03, Eric Wong wrote:\n> Patches 1-11 are largely unchanged from the original series with the\n> exception of 2, which is new and posted at:\n> \n> \thttps://public-inbox.org/git/20190908074953.kux7zz4y7iolqko4@whir/\n> \n> 12-17 take further steps to get us away from hashmap_entry being\n> the first element, but they're also a bit ugly because __typeof__\n> isn't portable\n> \n> 18-19 finally brings me to the APIs I want to expose without\n> relying on __typeof :)\n\nLooking at the overall diff for this series looks a lot nicer with the \nextra patches that eliminate most of the explicit calls to \ncontainer_of(). Thanks for the improved api and the cocci-check patch as \nwell.\n\nI've only had time for a quick look through but the patches seem well \nordered and easy to follow. I think there are some line folding issues \nwhere you have wrapped a line when you added the type parameter and then \nremoved it in a later path without re-flowing the line. Apart from that \nthe only thing I noticed is that hashmap.h still starts with\n\n   * struct long2string {\n   *     struct hashmap_entry ent; // must be the first member!\n\nIs that still the case now that hashmap_{get,put,remove}_entry() use \ncontainer_of() and hashmap_init() takes a struct hashmap_entry? That \ncomment is in a lot of our structure definitions as well.\n\nBest Wishes\n\nPhillip\n\n> Apologies for the delays, been busy with other stuff...\n> \n> Previous discussion starts at:\n> \n> \thttps://public-inbox.org/git/20190826024332.3403-1-e@80x24.org/\n> \n> The following changes since commit 745f6812895b31c02b29bdfe4ae8e5498f776c26:\n> \n>    First batch after Git 2.23 (2019-08-22 12:41:04 -0700)\n> \n> are available in the Git repository at:\n> \n>    https://80x24.org/git-svn.git hashmap-wip-v2\n> \n> for you to fetch changes up to 212a596edd99169b284912b7b70b6280e2fb90e6:\n> \n>    hashmap: remove type arg from hashmap_{get,put,remove}_entry (2019-09-24 00:42:22 +0000)\n> \n> ----------------------------------------------------------------\n> Eric Wong (19):\n>        diff: use hashmap_entry_init on moved_entry.ent\n>        coccicheck: detect hashmap_entry.hash assignment\n>        packfile: use hashmap_entry in delta_base_cache_entry\n>        hashmap_entry_init takes \"struct hashmap_entry *\"\n>        hashmap_get_next takes \"const struct hashmap_entry *\"\n>        hashmap_add takes \"struct hashmap_entry *\"\n>        hashmap_get takes \"const struct hashmap_entry *\"\n>        hashmap_remove takes \"const struct hashmap_entry *\"\n>        hashmap_put takes \"struct hashmap_entry *\"\n>        introduce container_of macro\n>        hashmap_get_next returns \"struct hashmap_entry *\"\n>        hashmap: use *_entry APIs to wrap container_of\n>        hashmap_get{,_from_hash} return \"struct hashmap_entry *\"\n>        hashmap_cmp_fn takes hashmap_entry params\n>        hashmap: use *_entry APIs for iteration\n>        hashmap: hashmap_{put,remove} return hashmap_entry *\n>        hashmap: introduce hashmap_free_entries\n>        OFFSETOF_VAR macro to simplify hashmap iterators\n>        hashmap: remove type arg from hashmap_{get,put,remove}_entry\n> \n>   attr.c                              |  22 ++---\n>   blame.c                             |  25 +++---\n>   builtin/describe.c                  |  21 +++--\n>   builtin/difftool.c                  |  56 ++++++------\n>   builtin/fast-export.c               |  15 ++--\n>   builtin/fetch.c                     |  30 ++++---\n>   config.c                            |  24 +++---\n>   contrib/coccinelle/hashmap.cocci    |  16 ++++\n>   diff.c                              |  31 ++++---\n>   diffcore-rename.c                   |  15 ++--\n>   git-compat-util.h                   |  33 ++++++++\n>   hashmap.c                           |  58 ++++++++-----\n>   hashmap.h                           | 164 +++++++++++++++++++++++++++++-------\n>   merge-recursive.c                   |  87 ++++++++++---------\n>   name-hash.c                         |  57 +++++++------\n>   oidmap.c                            |  20 +++--\n>   oidmap.h                            |   6 +-\n>   packfile.c                          |  22 +++--\n>   patch-ids.c                         |  18 ++--\n>   range-diff.c                        |  10 +--\n>   ref-filter.c                        |  31 ++++---\n>   refs.c                              |  23 +++--\n>   remote.c                            |  21 +++--\n>   revision.c                          |  28 +++---\n>   sequencer.c                         |  44 ++++++----\n>   sub-process.c                       |  20 +++--\n>   sub-process.h                       |   4 +-\n>   submodule-config.c                  |  52 +++++++-----\n>   t/helper/test-hashmap.c             |  49 ++++++-----\n>   t/helper/test-lazy-init-name-hash.c |  12 +--\n>   30 files changed, 647 insertions(+), 367 deletions(-)\n>   create mode 100644 contrib/coccinelle/hashmap.cocci\n> \n> Eric Wong (19):\n>    diff: use hashmap_entry_init on moved_entry.ent\n>    coccicheck: detect hashmap_entry.hash assignment\n>    packfile: use hashmap_entry in delta_base_cache_entry\n>    hashmap_entry_init takes \"struct hashmap_entry *\"\n>    hashmap_get_next takes \"const struct hashmap_entry *\"\n>    hashmap_add takes \"struct hashmap_entry *\"\n>    hashmap_get takes \"const struct hashmap_entry *\"\n>    hashmap_remove takes \"const struct hashmap_entry *\"\n>    hashmap_put takes \"struct hashmap_entry *\"\n>    introduce container_of macro\n>    hashmap_get_next returns \"struct hashmap_entry *\"\n>    hashmap: use *_entry APIs to wrap container_of\n>    hashmap_get{,_from_hash} return \"struct hashmap_entry *\"\n>    hashmap_cmp_fn takes hashmap_entry params\n>    hashmap: use *_entry APIs for iteration\n>    hashmap: hashmap_{put,remove} return hashmap_entry *\n>    hashmap: introduce hashmap_free_entries\n>    OFFSETOF_VAR macro to simplify hashmap iterators\n>    hashmap: remove type arg from hashmap_{get,put,remove}_entry\n> \n>   attr.c                              |  22 ++--\n>   blame.c                             |  25 +++--\n>   builtin/describe.c                  |  21 ++--\n>   builtin/difftool.c                  |  56 ++++++----\n>   builtin/fast-export.c               |  15 ++-\n>   builtin/fetch.c                     |  30 ++---\n>   config.c                            |  24 ++--\n>   contrib/coccinelle/hashmap.cocci    |  16 +++\n>   diff.c                              |  31 +++---\n>   diffcore-rename.c                   |  15 ++-\n>   git-compat-util.h                   |  33 ++++++\n>   hashmap.c                           |  58 ++++++----\n>   hashmap.h                           | 164 +++++++++++++++++++++++-----\n>   merge-recursive.c                   |  87 ++++++++-------\n>   name-hash.c                         |  57 +++++-----\n>   oidmap.c                            |  20 ++--\n>   oidmap.h                            |   6 +-\n>   packfile.c                          |  22 ++--\n>   patch-ids.c                         |  18 +--\n>   range-diff.c                        |  10 +-\n>   ref-filter.c                        |  31 ++++--\n>   refs.c                              |  23 +++-\n>   remote.c                            |  21 ++--\n>   revision.c                          |  28 +++--\n>   sequencer.c                         |  44 +++++---\n>   sub-process.c                       |  20 ++--\n>   sub-process.h                       |   4 +-\n>   submodule-config.c                  |  52 +++++----\n>   t/helper/test-hashmap.c             |  49 +++++----\n>   t/helper/test-lazy-init-name-hash.c |  12 +-\n>   30 files changed, 647 insertions(+), 367 deletions(-)\n>   create mode 100644 contrib/coccinelle/hashmap.cocci\n> \n> \n> base-commit: 745f6812895b31c02b29bdfe4ae8e5498f776c26\n> \n"},{"id":"383097","messageId":"xmqqy2y7ihih.fsf@gitster-ct.c.googlers.com","threadId":"51736","inReplyTo":"20190924010324.22619-1-e@80x24.org","subject":"Re: [PATCH v2 00/19] hashmap bug/safety/ease-of-use fixes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-09-29T09:22:30Z","receivedAt":"2019-09-29T09:22:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Wong <e@80x24.org> writes:\n\n> Patches 1-11 are largely unchanged from the original series with the\n> exception of 2, which is new and posted at:\n>\n> \thttps://public-inbox.org/git/20190908074953.kux7zz4y7iolqko4@whir/\n>\n> 12-17 take further steps to get us away from hashmap_entry being\n> the first element, but they're also a bit ugly because __typeof__\n> isn't portable\n>\n> 18-19 finally brings me to the APIs I want to expose without\n> relying on __typeof :)\n>\n> Apologies for the delays, been busy with other stuff...\n\nThanks.  clang version 6.0.1-10 (which is the version I happen to\nhave installed locally) seems to throw a lot of errors like these:\n\n -- -- --\n\n$ make CC=clang config.o\n    CC config.o\nconfig.c:1944:50: error: variable 'entry' is uninitialized when used here [-Werror,-Wuninitialized]\n        hashmap_for_each_entry(&cs->config_hash, &iter, entry,\n                                                        ^~~~~\n./hashmap.h:453:20: note: expanded from macro 'hashmap_for_each_entry'\n                                                OFFSETOF_VAR(var, member)); \\\n                                                             ^~~\n./git-compat-util.h:1346:16: note: expanded from macro 'OFFSETOF_VAR'\n        ((uintptr_t)&(ptr)->member - (uintptr_t)(ptr))\n                      ^~~\n./hashmap.h:445:61: note: expanded from macro 'hashmap_iter_first_entry_offset'\n        container_of_or_null_offset(hashmap_iter_first(map, iter), offset)\n                                                                   ^~~~~~\nconfig.c:1939:34: note: initialize the variable 'entry' to silence this warning\n        struct config_set_element *entry;\n                                        ^\n                                         = NULL\n1 error generated.\nmake: *** [Makefile:2365: config.o] Error 1\n\n -- -- --\n\neven though gcc seems to be happy with the source.\n\n"},{"id":"383151","messageId":"20190930095749.GA24511@dcvr","threadId":"51736","inReplyTo":"9dc71ed0-617c-84e8-b7fc-0766f4d83695@gmail.com","subject":"Re: [PATCH v2 07/19] hashmap_get takes \"const struct hashmap_entry *\"","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-30T09:57:49Z","receivedAt":"2019-09-30T09:57:50Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Derrick Stolee <stolee@gmail.com> wrote:\n> On 9/23/2019 9:03 PM, Eric Wong wrote:\n> > This is less error-prone than \"const void *\" as the compiler\n> > now detects invalid types being passed.\n> [snip]\n> > diff --git a/hashmap.h b/hashmap.h\n> > index 40bcc64289..2a4b4a3954 100644\n> > --- a/hashmap.h\n> > +++ b/hashmap.h\n> > @@ -74,7 +74,8 @@\n> >   *             e->key = key;\n> >   *\n> >   *             flags |= COMPARE_VALUE;\n> > - *             printf(\"%sfound\\n\", hashmap_get(&map, e, NULL) ? \"\" : \"not \");\n> > + *             printf(\"%sfound\\n\",\n> > + *                    hashmap_get(&map, &e->ent, NULL) ? \"\" : \"not \");\n> >   *             free(e);\n> >   *         }\n> >   *\n> > @@ -84,7 +85,8 @@\n> >   *             k.key = key;\n> >   *\n> >   *             flags |= COMPARE_VALUE;\n> > - *             printf(\"%sfound\\n\", hashmap_get(&map, &k, value) ? \"\" : \"not \");\n> > + *             printf(\"%sfound\\n\",\n> > + *                    hashmap_get(&map, &k->ent, value) ? \"\" : \"not \");\n> >   *         }\n> >   *\n> >   *         if (!strcmp(\"end\", action)) {\n> > @@ -286,7 +288,7 @@ static inline unsigned int hashmap_get_size(struct hashmap *map)\n> >   * If an entry with matching hash code is found, `key` and `keydata` are passed\n> >   * to `hashmap_cmp_fn` to decide whether the entry matches the key.\n> >   */\n> > -void *hashmap_get(const struct hashmap *map, const void *key,\n> > +void *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key,\n> >  \t\t\t const void *keydata);\n> \n> super-nit: the whitespace before the second line is \"\\t\\t\\t \" but should be\n> \"\\t\\t  \".\n\nHuh?  Do you mean the \"const void *keydata);\" line?\nThat's context and unchanged from before.  Thanks.\n"},{"id":"383152","messageId":"20190930100137.GB24511@dcvr","threadId":"51736","inReplyTo":"nycvar.QRO.7.76.6.1909261032520.15067@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v2 00/19] hashmap bug/safety/ease-of-use fixes","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-30T10:01:38Z","receivedAt":"2019-09-30T10:01:39Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> Hi Eric,\n> \n> On Tue, 24 Sep 2019, Eric Wong wrote:\n> \n> > Patches 1-11 are largely unchanged from the original series with the\n> > exception of 2, which is new and posted at:\n> >\n> > \thttps://public-inbox.org/git/20190908074953.kux7zz4y7iolqko4@whir/\n> >\n> > 12-17 take further steps to get us away from hashmap_entry being\n> > the first element, but they're also a bit ugly because __typeof__\n> > isn't portable\n> >\n> > 18-19 finally brings me to the APIs I want to expose without\n> > relying on __typeof :)\n> \n> I won't have time to review this patch series, but I wanted to throw out\n> the idea of storing the offset in `struct hashmap`, i.e. the offset of\n> the `struct hashmap_entry` in the actual entry struct?\n> \n> Example:\n> \n> \tstruct erics_entry {\n> \t\tconst char *i_want_this_to_be_the_first_field;\n> \t\tstruct hashmap_entry e;\n> \t\t[...]\n> \t};\n> \n> \t[...]\n> \n> \tstruct erics_entry *dummy = NULL;\n> \tsize_t offset = ((char *)dummy->e) - ((char *)dummy);\n> \t[... store that offset in the hashmap and subtract it from the\n> \tstored pointers before returning an entry...]\n> \n> IOW rather than assuming that it is the first field, we could allow an\n> offset other than 0. I'm just not sure how to implement this elegantly,\n> but it should be much easier to do this portably than the `typeof()`\n> approach.\n\nYeah, that needs to be &dummy->e, but that's the OFFSETOF_VAR\nmacro in patch 18.  I think it's quite elegant, but I need to\nfix a clang warning for it...\n"},{"id":"383154","messageId":"20190930103948.GA29474@dcvr","threadId":"51736","inReplyTo":"059c05bb-685a-7933-55ff-f18ed271ac3a@gmail.com","subject":"Re: [PATCH v2 10/19] introduce container_of macro","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-09-30T10:39:48Z","receivedAt":"2019-09-30T10:39:50Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Derrick Stolee <stolee@gmail.com> wrote:\n> On 9/23/2019 9:03 PM, Eric Wong wrote:\n> > This macro is popular within the Linux kernel for supporting\n> > intrusive data structures such as linked lists, red-black trees,\n> > and chained hash tables while allowing the compiler to do\n> > type checking.\n> > \n> > I intend to use this to remove the limitation of \"hashmap_entry\"\n> > being location-dependent and to allow more compile-time type\n> > checking.\n> \n> nit: I don't know why the first-person singular language caused\n> me to stumble during this message. Perhaps the following rewrite\n> would convey the same information:\n> \n>   Later patches will use container_of() to remove the limitation\n>   of \"hashmap_entry\" being location-dependent. This will complete\n>   the transition to compile-time type checking for the hashmap API.\n\nAgreed.  Thanks.\n\n> > This macro already exists in our source as \"list_entry\" in\n> > list.h and making \"list_entry\" an alias to \"container_of\"\n> > as the Linux kernel has done is a possibility.\n> \n> If it is the same code, then I would prefer you do this conversion\n> now so we can see that equivalence in the patch AND we know that\n> existing code will test it.\n\nOne problem is I'm not sure if list.h should have an\n#include for git-compat-util.h, since list.h comes from an\noutside source....\n"},{"id":"383161","messageId":"xmqqy2y5hgau.fsf@gitster-ct.c.googlers.com","threadId":"51736","inReplyTo":"20190924010324.22619-19-e@80x24.org","subject":"Re: [PATCH v2 18/19] OFFSETOF_VAR macro to simplify hashmap iterators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-09-30T16:58:33Z","receivedAt":"2019-09-30T16:58:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Wong <e@80x24.org> writes:\n\n> While we cannot rely on a `__typeof__' operator being portable\n> to use with `offsetof'; we can calculate the pointer offset\n> using an existing pointer and the address of a member using\n> pointer arithmetic.\n\n> +/*\n> + * like offsetof(), but takes a pointer to type instead of the type\n\nIt actually takes \"a pointer to a variable of the type\".  I had to\nread the above twice to guess what is going on.\n\n> + * @ptr is subject to multiple evaluation since we can't rely on TYPEOF()\n> + */\n> +#define OFFSETOF_VAR(ptr, member) \\\n> +\t((uintptr_t)&(ptr)->member - (uintptr_t)(ptr))\n> +\n\nThis unfortunately has funny interactions with using uninitialized\nvariables.  \"make CC=clang config.o\" gives something like this:\n\nconfig.c:1944:50: error: variable 'entry' is uninitialized when used here\n      [-Werror,-Wuninitialized]\n        hashmap_for_each_entry(&cs->config_hash, &iter, entry,\n                                                        ^~~~~\n./hashmap.h:453:20: note: expanded from macro 'hashmap_for_each_entry'\n                                                OFFSETOF_VAR(var, member)); \\\n                                                             ^~~\n./git-compat-util.h:1346:16: note: expanded from macro 'OFFSETOF_VAR'\n        ((uintptr_t)&(ptr)->member - (uintptr_t)(ptr))\n                      ^~~\n./hashmap.h:445:61: note: expanded from macro 'hashmap_iter_first_entry_offset'\n        container_of_or_null_offset(hashmap_iter_first(map, iter), offset)\n                                                                   ^~~~~~\nconfig.c:1939:34: note: initialize the variable 'entry' to silence this warning\n        struct config_set_element *entry;\n                                        ^\n                                         = NULL\n\nPersonally, I feel the workaround suggested by the compiler is just\nas bogus as the warning itself X-<.  Casting NULL as if it were a\npointer to an object of type typeof(*ptr), treating it as if it is a\nvalid address, and doing raw address arith is just as bogus as doing\nthe same raw address arith on an uninitialized ptr, isn't it?\n\nAnyway...\n"},{"id":"383393","messageId":"xmqqr23t8g0t.fsf@gitster-ct.c.googlers.com","threadId":"51736","inReplyTo":"20190924010324.22619-19-e@80x24.org","subject":"Re: [PATCH v2 18/19] OFFSETOF_VAR macro to simplify hashmap iterators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-10-04T01:18:26Z","receivedAt":"2019-10-04T01:20:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Wong <e@80x24.org> writes:\n\n> In the future, list iterator macros (e.g. list_for_each_entry)\n> may also be implemented using OFFSETOF_VAR to save hackers the\n> trouble of using container_of/list_entry macros and without\n> relying on non-portable `__typeof__'.\n\nCan we add something like this as a preliminary preparation step\nbefore the series?\n\nSubject: [PATCH] treewide: initialize pointers to hashmap entries\n\nThere are not strictly necessary, but some compilers (e.g. clang\n6.0.1) apparently have trouble in construct we will use in the\nOFFSETOF_VAR() macro, i.e.\n\n    ((uintptr_t)&(ptr)->member - (uintptr_t)(ptr))\n\nwhen the ptr is uninitialized.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n attr.c                              | 2 +-\n blame.c                             | 4 ++--\n builtin/describe.c                  | 2 +-\n builtin/difftool.c                  | 2 +-\n config.c                            | 2 +-\n merge-recursive.c                   | 6 +++---\n revision.c                          | 4 ++--\n submodule-config.c                  | 2 +-\n t/helper/test-hashmap.c             | 2 +-\n t/helper/test-lazy-init-name-hash.c | 4 ++--\n 10 files changed, 15 insertions(+), 15 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex 15f0efdf60..0c367fb84a 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -161,7 +161,7 @@ static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check)\n \t * field and fill each entry with its corresponding git_attr.\n \t */\n \tif (size != check->all_attrs_nr) {\n-\t\tstruct attr_hash_entry *e;\n+\t\tstruct attr_hash_entry *e = NULL;\n \t\tstruct hashmap_iter iter;\n \n \t\tREALLOC_ARRAY(check->all_attrs, size);\ndiff --git a/blame.c b/blame.c\nindex 6384f48133..a5f8672419 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -448,7 +448,7 @@ static int fingerprint_similarity(struct fingerprint *a, struct fingerprint *b)\n {\n \tint intersection = 0;\n \tstruct hashmap_iter iter;\n-\tconst struct fingerprint_entry *entry_a, *entry_b;\n+\tconst struct fingerprint_entry *entry_a, *entry_b = NULL;\n \n \thashmap_for_each_entry(&b->map, &iter, entry_b,\n \t\t\t\tentry /* member name */) {\n@@ -467,7 +467,7 @@ static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b)\n {\n \tstruct hashmap_iter iter;\n \tstruct fingerprint_entry *entry_a;\n-\tconst struct fingerprint_entry *entry_b;\n+\tconst struct fingerprint_entry *entry_b = NULL;\n \n \thashmap_iter_init(&b->map, &iter);\n \ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 1caf98f716..42e6cc3a4f 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -330,7 +330,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)\n \tif (!have_util) {\n \t\tstruct hashmap_iter iter;\n \t\tstruct commit *c;\n-\t\tstruct commit_name *n;\n+\t\tstruct commit_name *n = NULL;\n \n \t\tinit_commit_names(&commit_names);\n \t\thashmap_for_each_entry(&names, &iter, n,\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex c280e682b2..30f3bd6219 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -344,7 +344,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \tFILE *fp;\n \tstruct hashmap working_tree_dups, submodules, symlinks2;\n \tstruct hashmap_iter iter;\n-\tstruct pair_entry *entry;\n+\tstruct pair_entry *entry = NULL;\n \tstruct index_state wtindex;\n \tstruct checkout lstate, rstate;\n \tint rc, flags = RUN_GIT_CMD, err = 0;\ndiff --git a/config.c b/config.c\nindex a4fa464ed2..6ceefb7cff 100644\n--- a/config.c\n+++ b/config.c\n@@ -1936,7 +1936,7 @@ void git_configset_init(struct config_set *cs)\n \n void git_configset_clear(struct config_set *cs)\n {\n-\tstruct config_set_element *entry;\n+\tstruct config_set_element *entry = NULL;\n \tstruct hashmap_iter iter;\n \tif (!cs->hash_initialized)\n \t\treturn;\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 8787a40b0c..bc826fb7ac 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2127,7 +2127,7 @@ static void handle_directory_level_conflicts(struct merge_options *opt,\n \t\t\t\t\t     struct tree *merge)\n {\n \tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *head_ent;\n+\tstruct dir_rename_entry *head_ent = NULL;\n \tstruct dir_rename_entry *merge_ent;\n \n \tstruct string_list remove_from_head = STRING_LIST_INIT_NODUP;\n@@ -2566,7 +2566,7 @@ static struct string_list *get_renames(struct merge_options *opt,\n \tint i;\n \tstruct hashmap collisions;\n \tstruct hashmap_iter iter;\n-\tstruct collision_entry *e;\n+\tstruct collision_entry *e = NULL;\n \tstruct string_list *renames;\n \n \tcompute_collisions(&collisions, dir_renames, pairs);\n@@ -2838,7 +2838,7 @@ static void initial_cleanup_rename(struct diff_queue_struct *pairs,\n \t\t\t\t   struct hashmap *dir_renames)\n {\n \tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *e;\n+\tstruct dir_rename_entry *e = NULL;\n \n \thashmap_for_each_entry(dir_renames, &iter, e,\n \t\t\t\tent /* member name */) {\ndiff --git a/revision.c b/revision.c\nindex 6688f89d0d..70f478666b 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -127,7 +127,7 @@ static void paths_and_oids_init(struct hashmap *map)\n static void paths_and_oids_clear(struct hashmap *map)\n {\n \tstruct hashmap_iter iter;\n-\tstruct path_and_oids_entry *entry;\n+\tstruct path_and_oids_entry *entry = NULL;\n \n \thashmap_for_each_entry(map, &iter, entry, ent /* member name */) {\n \t\toidset_clear(&entry->trees);\n@@ -210,7 +210,7 @@ void mark_trees_uninteresting_sparse(struct repository *r,\n \tunsigned has_interesting = 0, has_uninteresting = 0;\n \tstruct hashmap map;\n \tstruct hashmap_iter map_iter;\n-\tstruct path_and_oids_entry *entry;\n+\tstruct path_and_oids_entry *entry = NULL;\n \tstruct object_id *oid;\n \tstruct oidset_iter iter;\n \ndiff --git a/submodule-config.c b/submodule-config.c\nindex 401a9b2382..4d4d3b7dd7 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -89,7 +89,7 @@ static void free_one_config(struct submodule_entry *entry)\n static void submodule_cache_clear(struct submodule_cache *cache)\n {\n \tstruct hashmap_iter iter;\n-\tstruct submodule_entry *entry;\n+\tstruct submodule_entry *entry = NULL;\n \n \tif (!cache->initialized)\n \t\treturn;\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex cc577c8956..a3bed8cc70 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -161,7 +161,7 @@ int cmd__hashmap(int argc, const char **argv)\n \twhile (strbuf_getline(&line, stdin) != EOF) {\n \t\tchar *cmd, *p1 = NULL, *p2 = NULL;\n \t\tunsigned int hash = 0;\n-\t\tstruct test_entry *entry;\n+\t\tstruct test_entry *entry = NULL;\n \n \t\t/* break line into command and up to two parameters */\n \t\tcmd = strtok(line.buf, DELIM);\ndiff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c\nindex cd1b4c9736..2cb1fa3d8c 100644\n--- a/t/helper/test-lazy-init-name-hash.c\n+++ b/t/helper/test-lazy-init-name-hash.c\n@@ -29,8 +29,8 @@ static void dump_run(void)\n \t\tchar name[FLEX_ARRAY];\n \t};\n \n-\tstruct dir_entry *dir;\n-\tstruct cache_entry *ce;\n+\tstruct dir_entry *dir = NULL;\n+\tstruct cache_entry *ce = NULL;\n \n \tread_cache();\n \tif (single) {\n-- \n2.23.0-680-gad10c89764\n\n"},{"id":"383394","messageId":"20191004025115.GA26605@dcvr","threadId":"51736","inReplyTo":"xmqqr23t8g0t.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 18/19] OFFSETOF_VAR macro to simplify hashmap iterators","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-10-04T02:51:15Z","receivedAt":"2019-10-04T02:51:16Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n> Eric Wong <e@80x24.org> writes:\n> \n> > In the future, list iterator macros (e.g. list_for_each_entry)\n> > may also be implemented using OFFSETOF_VAR to save hackers the\n> > trouble of using container_of/list_entry macros and without\n> > relying on non-portable `__typeof__'.\n> \n> Can we add something like this as a preliminary preparation step\n> before the series?\n> \n> Subject: [PATCH] treewide: initialize pointers to hashmap entries\n> \n> There are not strictly necessary, but some compilers (e.g. clang\n> 6.0.1) apparently have trouble in construct we will use in the\n> OFFSETOF_VAR() macro, i.e.\n> \n>     ((uintptr_t)&(ptr)->member - (uintptr_t)(ptr))\n> \n> when the ptr is uninitialized.\n> \n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  attr.c                              | 2 +-\n>  blame.c                             | 4 ++--\n>  builtin/describe.c                  | 2 +-\n>  builtin/difftool.c                  | 2 +-\n>  config.c                            | 2 +-\n>  merge-recursive.c                   | 6 +++---\n>  revision.c                          | 4 ++--\n>  submodule-config.c                  | 2 +-\n>  t/helper/test-hashmap.c             | 2 +-\n>  t/helper/test-lazy-init-name-hash.c | 4 ++--\n>  10 files changed, 15 insertions(+), 15 deletions(-)\n\nThat seems too tedious.  I'm learning towards just initializing\nvar = NULL in the start of the for-loop:\n\n@@ -449,7 +449,8 @@ static inline struct hashmap_entry *hashmap_iter_first(struct hashmap *map,\n  * containing a @member which is a \"struct hashmap_entry\"\n  */\n #define hashmap_for_each_entry(map, iter, var, member) \\\n-\tfor (var = hashmap_iter_first_entry_offset(map, iter, \\\n+\tfor (var = NULL /* squelch uninitialized warnings for OFFSETOF_VAR */, \\\n+\t\tvar = hashmap_iter_first_entry_offset(map, iter, \\\n \t\t\t\t\t\tOFFSETOF_VAR(var, member)); \\\n \t\tvar; \\\n \t\tvar = hashmap_iter_next_entry_offset(iter, \\\n\n\n(But I'm running on fumes all week, so not sure I trust it)\n"},{"id":"383395","messageId":"xmqqk19l89xt.fsf@gitster-ct.c.googlers.com","threadId":"51736","inReplyTo":"20191004025115.GA26605@dcvr","subject":"Re: [PATCH v2 18/19] OFFSETOF_VAR macro to simplify hashmap iterators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-10-04T03:29:50Z","receivedAt":"2019-10-04T03:29:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Wong <e@80x24.org> writes:\n\n> That seems too tedious.  I'm learning towards just initializing\n> var = NULL in the start of the for-loop:\n>\n> @@ -449,7 +449,8 @@ static inline struct hashmap_entry *hashmap_iter_first(struct hashmap *map,\n>   * containing a @member which is a \"struct hashmap_entry\"\n>   */\n>  #define hashmap_for_each_entry(map, iter, var, member) \\\n> -\tfor (var = hashmap_iter_first_entry_offset(map, iter, \\\n> +\tfor (var = NULL /* squelch uninitialized warnings for OFFSETOF_VAR */, \\\n> +\t\tvar = hashmap_iter_first_entry_offset(map, iter, \\\n>  \t\t\t\t\t\tOFFSETOF_VAR(var, member)); \\\n\nThat looks a bit too ugly for my taste.  I've added an updated\nversion (see below) and then rebased the whole thing on top of it.\n\n\"hashmap: use *_entry APIs for iteration\" needs a trivial textual\nconflict resolved, but otherwise the result looked OK.\n\n-- >8 --\nFrom: Junio C Hamano <gitster@pobox.com>\nDate: Fri, 4 Oct 2019 10:12:25 +0900\nSubject: [PATCH] treewide: initialize pointers to hashmap entries\n\nThere are not strictly necessary to avoid use of uninitialized\nvariables, but some compilers (e.g. clang 6.0.1) apparently have\ntrouble in construct we will use in the OFFSETOF_VAR() macro, i.e.\n\n    ((uintptr_t)&(ptr)->member - (uintptr_t)(ptr))\n\nwhen the ptr is uninitialized, treating such a \"ptr\" as \"used\".\n\nIt is just as bogus to subtract NULL from the address of the\n\"member\" field pretending the structure sits at NULL address\nas doing so with a structure that sits at a random address, but\napparently clang issues a warning with an advice to initialize the\npointer to NULL, so let's do that.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n attr.c                              | 2 +-\n blame.c                             | 4 ++--\n builtin/describe.c                  | 2 +-\n builtin/difftool.c                  | 2 +-\n config.c                            | 2 +-\n merge-recursive.c                   | 6 +++---\n revision.c                          | 4 ++--\n submodule-config.c                  | 2 +-\n t/helper/test-hashmap.c             | 2 +-\n t/helper/test-lazy-init-name-hash.c | 4 ++--\n 10 files changed, 15 insertions(+), 15 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex 93dc16b59c..cb85303a06 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -159,7 +159,7 @@ static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check)\n \t * field and fill each entry with its corresponding git_attr.\n \t */\n \tif (size != check->all_attrs_nr) {\n-\t\tstruct attr_hash_entry *e;\n+\t\tstruct attr_hash_entry *e = NULL;\n \t\tstruct hashmap_iter iter;\n \t\thashmap_iter_init(&map->map, &iter);\n \ndiff --git a/blame.c b/blame.c\nindex 36a2e7ef11..9b912867f7 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -447,7 +447,7 @@ static int fingerprint_similarity(struct fingerprint *a, struct fingerprint *b)\n {\n \tint intersection = 0;\n \tstruct hashmap_iter iter;\n-\tconst struct fingerprint_entry *entry_a, *entry_b;\n+\tconst struct fingerprint_entry *entry_a, *entry_b = NULL;\n \n \thashmap_iter_init(&b->map, &iter);\n \n@@ -466,7 +466,7 @@ static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b)\n {\n \tstruct hashmap_iter iter;\n \tstruct fingerprint_entry *entry_a;\n-\tconst struct fingerprint_entry *entry_b;\n+\tconst struct fingerprint_entry *entry_b = NULL;\n \n \thashmap_iter_init(&b->map, &iter);\n \ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 200154297d..0369ed66ce 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -327,7 +327,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)\n \tif (!have_util) {\n \t\tstruct hashmap_iter iter;\n \t\tstruct commit *c;\n-\t\tstruct commit_name *n;\n+\t\tstruct commit_name *n = NULL;\n \n \t\tinit_commit_names(&commit_names);\n \t\tn = hashmap_iter_first(&names, &iter);\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 16eb8b70ea..fbb4c87a86 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -337,7 +337,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \tFILE *fp;\n \tstruct hashmap working_tree_dups, submodules, symlinks2;\n \tstruct hashmap_iter iter;\n-\tstruct pair_entry *entry;\n+\tstruct pair_entry *entry = NULL;\n \tstruct index_state wtindex;\n \tstruct checkout lstate, rstate;\n \tint rc, flags = RUN_GIT_CMD, err = 0;\ndiff --git a/config.c b/config.c\nindex 3900e4947b..6c92d2825d 100644\n--- a/config.c\n+++ b/config.c\n@@ -1934,7 +1934,7 @@ void git_configset_init(struct config_set *cs)\n \n void git_configset_clear(struct config_set *cs)\n {\n-\tstruct config_set_element *entry;\n+\tstruct config_set_element *entry = NULL;\n \tstruct hashmap_iter iter;\n \tif (!cs->hash_initialized)\n \t\treturn;\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 6b812d67e3..ea17d9c30f 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2118,7 +2118,7 @@ static void handle_directory_level_conflicts(struct merge_options *opt,\n \t\t\t\t\t     struct tree *merge)\n {\n \tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *head_ent;\n+\tstruct dir_rename_entry *head_ent = NULL;\n \tstruct dir_rename_entry *merge_ent;\n \n \tstruct string_list remove_from_head = STRING_LIST_INIT_NODUP;\n@@ -2556,7 +2556,7 @@ static struct string_list *get_renames(struct merge_options *opt,\n \tint i;\n \tstruct hashmap collisions;\n \tstruct hashmap_iter iter;\n-\tstruct collision_entry *e;\n+\tstruct collision_entry *e = NULL;\n \tstruct string_list *renames;\n \n \tcompute_collisions(&collisions, dir_renames, pairs);\n@@ -2828,7 +2828,7 @@ static void initial_cleanup_rename(struct diff_queue_struct *pairs,\n \t\t\t\t   struct hashmap *dir_renames)\n {\n \tstruct hashmap_iter iter;\n-\tstruct dir_rename_entry *e;\n+\tstruct dir_rename_entry *e = NULL;\n \n \thashmap_iter_init(dir_renames, &iter);\n \twhile ((e = hashmap_iter_next(&iter))) {\ndiff --git a/revision.c b/revision.c\nindex 07412297f0..b9b538c4d2 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -122,7 +122,7 @@ static void paths_and_oids_init(struct hashmap *map)\n static void paths_and_oids_clear(struct hashmap *map)\n {\n \tstruct hashmap_iter iter;\n-\tstruct path_and_oids_entry *entry;\n+\tstruct path_and_oids_entry *entry = NULL;\n \thashmap_iter_init(map, &iter);\n \n \twhile ((entry = (struct path_and_oids_entry *)hashmap_iter_next(&iter))) {\n@@ -205,7 +205,7 @@ void mark_trees_uninteresting_sparse(struct repository *r,\n \tunsigned has_interesting = 0, has_uninteresting = 0;\n \tstruct hashmap map;\n \tstruct hashmap_iter map_iter;\n-\tstruct path_and_oids_entry *entry;\n+\tstruct path_and_oids_entry *entry = NULL;\n \tstruct object_id *oid;\n \tstruct oidset_iter iter;\n \ndiff --git a/submodule-config.c b/submodule-config.c\nindex 4264ee216f..af86fe9ac1 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -85,7 +85,7 @@ static void free_one_config(struct submodule_entry *entry)\n static void submodule_cache_clear(struct submodule_cache *cache)\n {\n \tstruct hashmap_iter iter;\n-\tstruct submodule_entry *entry;\n+\tstruct submodule_entry *entry = NULL;\n \n \tif (!cache->initialized)\n \t\treturn;\ndiff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c\nindex aaf17b0ddf..6407e0b426 100644\n--- a/t/helper/test-hashmap.c\n+++ b/t/helper/test-hashmap.c\n@@ -159,7 +159,7 @@ int cmd__hashmap(int argc, const char **argv)\n \twhile (strbuf_getline(&line, stdin) != EOF) {\n \t\tchar *cmd, *p1 = NULL, *p2 = NULL;\n \t\tunsigned int hash = 0;\n-\t\tstruct test_entry *entry;\n+\t\tstruct test_entry *entry = NULL;\n \n \t\t/* break line into command and up to two parameters */\n \t\tcmd = strtok(line.buf, DELIM);\ndiff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c\nindex b99a37080d..95ab81ee7a 100644\n--- a/t/helper/test-lazy-init-name-hash.c\n+++ b/t/helper/test-lazy-init-name-hash.c\n@@ -29,8 +29,8 @@ static void dump_run(void)\n \t\tchar name[FLEX_ARRAY];\n \t};\n \n-\tstruct dir_entry *dir;\n-\tstruct cache_entry *ce;\n+\tstruct dir_entry *dir = NULL;\n+\tstruct cache_entry *ce = NULL;\n \n \tread_cache();\n \tif (single) {\n-- \n2.23.0-681-g60d083e3f0\n\n"},{"id":"383438","messageId":"20191004172603.GA7215@dcvr","threadId":"51736","inReplyTo":"xmqqk19l89xt.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 18/19] OFFSETOF_VAR macro to simplify hashmap iterators","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2019-10-04T17:26:03Z","receivedAt":"2019-10-04T17:26:04Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n> Eric Wong <e@80x24.org> writes:\n> \n> > That seems too tedious.  I'm learning towards just initializing\n> > var = NULL in the start of the for-loop:\n> >\n> > @@ -449,7 +449,8 @@ static inline struct hashmap_entry *hashmap_iter_first(struct hashmap *map,\n> >   * containing a @member which is a \"struct hashmap_entry\"\n> >   */\n> >  #define hashmap_for_each_entry(map, iter, var, member) \\\n> > -\tfor (var = hashmap_iter_first_entry_offset(map, iter, \\\n> > +\tfor (var = NULL /* squelch uninitialized warnings for OFFSETOF_VAR */, \\\n> > +\t\tvar = hashmap_iter_first_entry_offset(map, iter, \\\n> >  \t\t\t\t\t\tOFFSETOF_VAR(var, member)); \\\n> \n> That looks a bit too ugly for my taste.  I've added an updated\n> version (see below) and then rebased the whole thing on top of it.\n\nI prefer to minimize the amount of stuff we do to work around\nbuggy compilers (in case they get fixed and old versions are\nobsoleted).\n\nIf it's just clang with this problem, we know clang sets\n__GNUC__, so we can use __typeof__ directly (bypassing extra\nparentheses in our TYPEOF macro) to get around the warning:\n\n#if defined(__GNUC__) /* clang sets this, too */\n#define OFFSETOF_VAR(ptr, member) offsetof(__typeof__(*ptr), member)\n#else /* !__GNUC__ */\n...\n\n\nThat said, there could be other compilers which don't set\n__GNUC__ and have the same problem as clang.  But maybe those\ncompilers are too buggy and we already ignore invalid warnings\non those compilers.\n"},{"id":"383504","messageId":"xmqqmuee68p6.fsf@gitster-ct.c.googlers.com","threadId":"51736","inReplyTo":"20191004172603.GA7215@dcvr","subject":"Re: [PATCH v2 18/19] OFFSETOF_VAR macro to simplify hashmap iterators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-10-06T00:04:05Z","receivedAt":"2019-10-06T00:04:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Wong <e@80x24.org> writes:\n\n> That said, there could be other compilers which don't set\n> __GNUC__ and have the same problem as clang.  But maybe those\n> compilers are too buggy and we already ignore invalid warnings\n> on those compilers.\n\nPerhaps.\n"}]}