From d22245a2e360d2e708ca37169be8eb5a5899b98d Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:27 +0000 Subject: hashmap_entry_init takes "struct hashmap_entry *" C compilers do type checking to make life easier for us. So rely on that and update all hashmap_entry_init callers to take "struct hashmap_entry *" to avoid future bugs while improving safety and readability. Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'config.c') diff --git a/config.c b/config.c index 3900e4947b..08d866e7de 100644 --- a/config.c +++ b/config.c @@ -1861,7 +1861,7 @@ static struct config_set_element *configset_find_element(struct config_set *cs, if (git_config_parse_key(key, &normalized_key, NULL)) return NULL; - hashmap_entry_init(&k, strhash(normalized_key)); + hashmap_entry_init(&k.ent, strhash(normalized_key)); k.key = normalized_key; found_entry = hashmap_get(&cs->config_hash, &k, NULL); free(normalized_key); @@ -1882,7 +1882,7 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha */ if (!e) { e = xmalloc(sizeof(*e)); - hashmap_entry_init(e, strhash(key)); + hashmap_entry_init(&e->ent, strhash(key)); e->key = xstrdup(key); string_list_init(&e->value_list, 1); hashmap_add(&cs->config_hash, e); -- cgit v1.2.3 From b94e5c1df674eb4ec8fdeaaae1ad8df552cb5d70 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:29 +0000 Subject: hashmap_add takes "struct hashmap_entry *" This is less error-prone than "void *" as the compiler now detects invalid types being passed. Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config.c') diff --git a/config.c b/config.c index 08d866e7de..2243d7c3d6 100644 --- a/config.c +++ b/config.c @@ -1885,7 +1885,7 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha hashmap_entry_init(&e->ent, strhash(key)); e->key = xstrdup(key); string_list_init(&e->value_list, 1); - hashmap_add(&cs->config_hash, e); + hashmap_add(&cs->config_hash, &e->ent); } si = string_list_append_nodup(&e->value_list, xstrdup_or_null(value)); -- cgit v1.2.3 From b6c5241606e67b57470e86ccf547d4ab90008a1d Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:30 +0000 Subject: hashmap_get takes "const struct hashmap_entry *" This is less error-prone than "const void *" as the compiler now detects invalid types being passed. Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config.c') diff --git a/config.c b/config.c index 2243d7c3d6..1a1b6675fd 100644 --- a/config.c +++ b/config.c @@ -1863,7 +1863,7 @@ static struct config_set_element *configset_find_element(struct config_set *cs, hashmap_entry_init(&k.ent, strhash(normalized_key)); k.key = normalized_key; - found_entry = hashmap_get(&cs->config_hash, &k, NULL); + found_entry = hashmap_get(&cs->config_hash, &k.ent, NULL); free(normalized_key); return found_entry; } -- cgit v1.2.3 From f23a465132a22860684ac66052cf9a954a18e27d Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:36 +0000 Subject: hashmap_get{,_from_hash} return "struct hashmap_entry *" Update callers to use hashmap_get_entry, hashmap_get_entry_from_hash or container_of as appropriate. This is another step towards eliminating the requirement of hashmap_entry being the first field in a struct. Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- config.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'config.c') diff --git a/config.c b/config.c index 1a1b6675fd..4952d1cc9e 100644 --- a/config.c +++ b/config.c @@ -1863,7 +1863,8 @@ static struct config_set_element *configset_find_element(struct config_set *cs, hashmap_entry_init(&k.ent, strhash(normalized_key)); k.key = normalized_key; - found_entry = hashmap_get(&cs->config_hash, &k.ent, NULL); + found_entry = hashmap_get_entry(&cs->config_hash, &k, NULL, + struct config_set_element, ent); free(normalized_key); return found_entry; } -- cgit v1.2.3 From 939af16eac1608766273d3971598dbcc4fe09928 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:37 +0000 Subject: hashmap_cmp_fn takes hashmap_entry params Another step in eliminating the requirement of hashmap_entry being the first member of a struct. Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- config.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'config.c') diff --git a/config.c b/config.c index 4952d1cc9e..33043ee73c 100644 --- a/config.c +++ b/config.c @@ -1914,12 +1914,14 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha } static int config_set_element_cmp(const void *unused_cmp_data, - const void *entry, - const void *entry_or_key, + const struct hashmap_entry *eptr, + const struct hashmap_entry *entry_or_key, const void *unused_keydata) { - const struct config_set_element *e1 = entry; - const struct config_set_element *e2 = entry_or_key; + const struct config_set_element *e1, *e2; + + e1 = container_of(eptr, const struct config_set_element, ent); + e2 = container_of(entry_or_key, const struct config_set_element, ent); return strcmp(e1->key, e2->key); } -- cgit v1.2.3 From 87571c3f71ba41d89eef5202f8589daa26f984ca Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:38 +0000 Subject: hashmap: use *_entry APIs for iteration Inspired by list_for_each_entry in the Linux kernel. Once again, these are somewhat compromised usability-wise by compilers lacking __typeof__ support. Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- config.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'config.c') diff --git a/config.c b/config.c index 33043ee73c..8433f74371 100644 --- a/config.c +++ b/config.c @@ -1942,8 +1942,9 @@ void git_configset_clear(struct config_set *cs) if (!cs->hash_initialized) return; - hashmap_iter_init(&cs->config_hash, &iter); - while ((entry = hashmap_iter_next(&iter))) { + hashmap_for_each_entry(&cs->config_hash, &iter, entry, + struct config_set_element, + ent /* member name */) { free(entry->key); string_list_clear(&entry->value_list, 1); } -- cgit v1.2.3 From c8e424c9c94d97b18cd335be17f32a8ce94a5b7f Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:40 +0000 Subject: hashmap: introduce hashmap_free_entries `hashmap_free_entries' behaves like `container_of' and passes the offset of the hashmap_entry struct to the internal `hashmap_free_' function, allowing the function to free any struct pointer regardless of where the hashmap_entry field is located. `hashmap_free' no longer takes any arguments aside from the hashmap itself. Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config.c') diff --git a/config.c b/config.c index 8433f74371..4d05dbc15a 100644 --- a/config.c +++ b/config.c @@ -1948,7 +1948,7 @@ void git_configset_clear(struct config_set *cs) free(entry->key); string_list_clear(&entry->value_list, 1); } - hashmap_free(&cs->config_hash, 1); + hashmap_free_entries(&cs->config_hash, struct config_set_element, ent); cs->hash_initialized = 0; free(cs->list.items); cs->list.nr = 0; -- cgit v1.2.3 From 23dee69f53cf5024ca79e0b707dcb03c63f33bef Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:41 +0000 Subject: OFFSETOF_VAR macro to simplify hashmap iterators While we cannot rely on a `__typeof__' operator being portable to use with `offsetof'; we can calculate the pointer offset using an existing pointer and the address of a member using pointer arithmetic for compilers without `__typeof__'. This allows us to simplify usage of hashmap iterator macros by not having to specify a type when a pointer of that type is already given. In the future, list iterator macros (e.g. list_for_each_entry) may also be implemented using OFFSETOF_VAR to save hackers the trouble of using container_of/list_entry macros and without relying on non-portable `__typeof__'. v3: use `__typeof__' to avoid clang warnings Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- config.c | 1 - 1 file changed, 1 deletion(-) (limited to 'config.c') diff --git a/config.c b/config.c index 4d05dbc15a..77ed00bfbf 100644 --- a/config.c +++ b/config.c @@ -1943,7 +1943,6 @@ void git_configset_clear(struct config_set *cs) return; hashmap_for_each_entry(&cs->config_hash, &iter, entry, - struct config_set_element, ent /* member name */) { free(entry->key); string_list_clear(&entry->value_list, 1); -- cgit v1.2.3 From 404ab78e39fc74c4eb604b6003642ed264f687a6 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Oct 2019 23:30:42 +0000 Subject: hashmap: remove type arg from hashmap_{get,put,remove}_entry Since these macros already take a `keyvar' pointer of a known type, we can rely on OFFSETOF_VAR to get the correct offset without relying on non-portable `__typeof__' and `offsetof'. Argument order is also rearranged, so `keyvar' and `member' are sequential as they are used as: `keyvar->member' Signed-off-by: Eric Wong Reviewed-by: Derrick Stolee Signed-off-by: Junio C Hamano --- config.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'config.c') diff --git a/config.c b/config.c index 77ed00bfbf..a4fa464ed2 100644 --- a/config.c +++ b/config.c @@ -1863,8 +1863,7 @@ static struct config_set_element *configset_find_element(struct config_set *cs, hashmap_entry_init(&k.ent, strhash(normalized_key)); k.key = normalized_key; - found_entry = hashmap_get_entry(&cs->config_hash, &k, NULL, - struct config_set_element, ent); + found_entry = hashmap_get_entry(&cs->config_hash, &k, ent, NULL); free(normalized_key); return found_entry; } -- cgit v1.2.3