summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar Junio C Hamano <gitster@pobox.com>2019-10-15 13:48:01 +0900
committerLibravatar Junio C Hamano <gitster@pobox.com>2019-10-15 13:48:02 +0900
commit5efabc7ed9e57bb73159d1ad7739c508167ef24a (patch)
tree9e7de3dfe38dcb92614d11613976d32151925ea2
parentMerge branch 'js/trace2-cap-max-output-files' (diff)
parenthashmap_entry: remove first member requirement from docs (diff)
downloadtgif-5efabc7ed9e57bb73159d1ad7739c508167ef24a.tar.xz
Merge branch 'ew/hashmap'
Code clean-up of the hashmap API, both users and implementation. * ew/hashmap: hashmap_entry: remove first member requirement from docs hashmap: remove type arg from hashmap_{get,put,remove}_entry OFFSETOF_VAR macro to simplify hashmap iterators hashmap: introduce hashmap_free_entries hashmap: hashmap_{put,remove} return hashmap_entry * hashmap: use *_entry APIs for iteration hashmap_cmp_fn takes hashmap_entry params hashmap_get{,_from_hash} return "struct hashmap_entry *" hashmap: use *_entry APIs to wrap container_of hashmap_get_next returns "struct hashmap_entry *" introduce container_of macro hashmap_put takes "struct hashmap_entry *" hashmap_remove takes "const struct hashmap_entry *" hashmap_get takes "const struct hashmap_entry *" hashmap_add takes "struct hashmap_entry *" hashmap_get_next takes "const struct hashmap_entry *" hashmap_entry_init takes "struct hashmap_entry *" packfile: use hashmap_entry in delta_base_cache_entry coccicheck: detect hashmap_entry.hash assignment diff: use hashmap_entry_init on moved_entry.ent
-rw-r--r--attr.c24
-rw-r--r--blame.c25
-rw-r--r--builtin/describe.c21
-rw-r--r--builtin/difftool.c56
-rw-r--r--builtin/fast-export.c15
-rw-r--r--builtin/fetch.c32
-rw-r--r--config.c24
-rw-r--r--contrib/coccinelle/hashmap.cocci16
-rw-r--r--diff.c31
-rw-r--r--diffcore-rename.c15
-rw-r--r--git-compat-util.h38
-rw-r--r--hashmap.c58
-rw-r--r--hashmap.h176
-rw-r--r--merge-recursive.c91
-rw-r--r--name-hash.c57
-rw-r--r--oidmap.c20
-rw-r--r--oidmap.h6
-rw-r--r--packfile.c22
-rw-r--r--patch-ids.c18
-rw-r--r--range-diff.c10
-rw-r--r--ref-filter.c33
-rw-r--r--refs.c25
-rw-r--r--remote.c21
-rw-r--r--remote.h2
-rw-r--r--revision.c28
-rw-r--r--sequencer.c44
-rw-r--r--sub-process.c20
-rw-r--r--sub-process.h6
-rw-r--r--submodule-config.c52
-rw-r--r--t/helper/test-hashmap.c50
-rw-r--r--t/helper/test-lazy-init-name-hash.c12
31 files changed, 667 insertions, 381 deletions
diff --git a/attr.c b/attr.c
index d02d081e28..11f19b541c 100644
--- a/attr.c
+++ b/attr.c
@@ -62,7 +62,7 @@ static struct attr_hashmap g_attr_hashmap;
/* The container for objects stored in "struct attr_hashmap" */
struct attr_hash_entry {
- struct hashmap_entry ent; /* must be the first member! */
+ struct hashmap_entry ent;
const char *key; /* the key; memory should be owned by value */
size_t keylen; /* length of the key */
void *value; /* the stored value */
@@ -70,12 +70,14 @@ struct attr_hash_entry {
/* attr_hashmap comparison function */
static int attr_hash_entry_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 attr_hash_entry *a = entry;
- const struct attr_hash_entry *b = entry_or_key;
+ const struct attr_hash_entry *a, *b;
+
+ a = container_of(eptr, const struct attr_hash_entry, ent);
+ b = container_of(entry_or_key, const struct attr_hash_entry, ent);
return (a->keylen != b->keylen) || strncmp(a->key, b->key, a->keylen);
}
@@ -98,10 +100,10 @@ static void *attr_hashmap_get(struct attr_hashmap *map,
if (!map->map.tablesize)
attr_hashmap_init(map);
- hashmap_entry_init(&k, memhash(key, keylen));
+ hashmap_entry_init(&k.ent, memhash(key, keylen));
k.key = key;
k.keylen = keylen;
- e = hashmap_get(&map->map, &k, NULL);
+ e = hashmap_get_entry(&map->map, &k, ent, NULL);
return e ? e->value : NULL;
}
@@ -117,12 +119,12 @@ static void attr_hashmap_add(struct attr_hashmap *map,
attr_hashmap_init(map);
e = xmalloc(sizeof(struct attr_hash_entry));
- hashmap_entry_init(e, memhash(key, keylen));
+ hashmap_entry_init(&e->ent, memhash(key, keylen));
e->key = key;
e->keylen = keylen;
e->value = value;
- hashmap_add(&map->map, e);
+ hashmap_add(&map->map, &e->ent);
}
struct all_attrs_item {
@@ -161,12 +163,12 @@ static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check)
if (size != check->all_attrs_nr) {
struct attr_hash_entry *e;
struct hashmap_iter iter;
- hashmap_iter_init(&map->map, &iter);
REALLOC_ARRAY(check->all_attrs, size);
check->all_attrs_nr = size;
- while ((e = hashmap_iter_next(&iter))) {
+ hashmap_for_each_entry(&map->map, &iter, e,
+ ent /* member name */) {
const struct git_attr *a = e->value;
check->all_attrs[a->attr_nr].attr = a;
}
diff --git a/blame.c b/blame.c
index 6596d8de88..29770e5c81 100644
--- a/blame.c
+++ b/blame.c
@@ -417,14 +417,15 @@ static void get_fingerprint(struct fingerprint *result,
/* Ignore whitespace pairs */
if (hash == 0)
continue;
- hashmap_entry_init(entry, hash);
+ hashmap_entry_init(&entry->entry, hash);
- found_entry = hashmap_get(&result->map, entry, NULL);
+ found_entry = hashmap_get_entry(&result->map, entry,
+ /* member name */ entry, NULL);
if (found_entry) {
found_entry->count += 1;
} else {
entry->count = 1;
- hashmap_add(&result->map, entry);
+ hashmap_add(&result->map, &entry->entry);
++entry;
}
}
@@ -432,7 +433,7 @@ static void get_fingerprint(struct fingerprint *result,
static void free_fingerprint(struct fingerprint *f)
{
- hashmap_free(&f->map, 0);
+ hashmap_free(&f->map);
free(f->entries);
}
@@ -449,10 +450,10 @@ static int fingerprint_similarity(struct fingerprint *a, struct fingerprint *b)
struct hashmap_iter iter;
const struct fingerprint_entry *entry_a, *entry_b;
- hashmap_iter_init(&b->map, &iter);
-
- while ((entry_b = hashmap_iter_next(&iter))) {
- if ((entry_a = hashmap_get(&a->map, entry_b, NULL))) {
+ hashmap_for_each_entry(&b->map, &iter, entry_b,
+ entry /* member name */) {
+ entry_a = hashmap_get_entry(&a->map, entry_b, entry, NULL);
+ if (entry_a) {
intersection += entry_a->count < entry_b->count ?
entry_a->count : entry_b->count;
}
@@ -470,10 +471,12 @@ static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b)
hashmap_iter_init(&b->map, &iter);
- while ((entry_b = hashmap_iter_next(&iter))) {
- if ((entry_a = hashmap_get(&a->map, entry_b, NULL))) {
+ hashmap_for_each_entry(&b->map, &iter, entry_b,
+ entry /* member name */) {
+ entry_a = hashmap_get_entry(&a->map, entry_b, entry, NULL);
+ if (entry_a) {
if (entry_a->count <= entry_b->count)
- hashmap_remove(&a->map, entry_b, NULL);
+ hashmap_remove(&a->map, &entry_b->entry, NULL);
else
entry_a->count -= entry_b->count;
}
diff --git a/builtin/describe.c b/builtin/describe.c
index 90feab1120..b6df81d8d0 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -63,19 +63,22 @@ static const char *prio_names[] = {
};
static int commit_name_neq(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 *peeled)
{
- const struct commit_name *cn1 = entry;
- const struct commit_name *cn2 = entry_or_key;
+ const struct commit_name *cn1, *cn2;
+
+ cn1 = container_of(eptr, const struct commit_name, entry);
+ cn2 = container_of(entry_or_key, const struct commit_name, entry);
return !oideq(&cn1->peeled, peeled ? peeled : &cn2->peeled);
}
static inline struct commit_name *find_commit_name(const struct object_id *peeled)
{
- return hashmap_get_from_hash(&names, oidhash(peeled), peeled);
+ return hashmap_get_entry_from_hash(&names, oidhash(peeled), peeled,
+ struct commit_name, entry);
}
static int replace_name(struct commit_name *e,
@@ -122,8 +125,8 @@ static void add_to_known_names(const char *path,
if (!e) {
e = xmalloc(sizeof(struct commit_name));
oidcpy(&e->peeled, peeled);
- hashmap_entry_init(e, oidhash(peeled));
- hashmap_add(&names, e);
+ hashmap_entry_init(&e->entry, oidhash(peeled));
+ hashmap_add(&names, &e->entry);
e->path = NULL;
}
e->tag = tag;
@@ -329,8 +332,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
struct commit_name *n;
init_commit_names(&commit_names);
- n = hashmap_iter_first(&names, &iter);
- for (; n; n = hashmap_iter_next(&iter)) {
+ hashmap_for_each_entry(&names, &iter, n,
+ entry /* member name */) {
c = lookup_commit_reference_gently(the_repository,
&n->peeled, 1);
if (c)
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 16eb8b70ea..c280e682b2 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -125,12 +125,15 @@ struct working_tree_entry {
};
static int working_tree_entry_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 working_tree_entry *a = entry;
- const struct working_tree_entry *b = entry_or_key;
+ const struct working_tree_entry *a, *b;
+
+ a = container_of(eptr, const struct working_tree_entry, entry);
+ b = container_of(entry_or_key, const struct working_tree_entry, entry);
+
return strcmp(a->path, b->path);
}
@@ -145,12 +148,14 @@ struct pair_entry {
};
static int pair_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 pair_entry *a = entry;
- const struct pair_entry *b = entry_or_key;
+ const struct pair_entry *a, *b;
+
+ a = container_of(eptr, const struct pair_entry, entry);
+ b = container_of(entry_or_key, const struct pair_entry, entry);
return strcmp(a->path, b->path);
}
@@ -161,14 +166,14 @@ static void add_left_or_right(struct hashmap *map, const char *path,
struct pair_entry *e, *existing;
FLEX_ALLOC_STR(e, path, path);
- hashmap_entry_init(e, strhash(path));
- existing = hashmap_get(map, e, NULL);
+ hashmap_entry_init(&e->entry, strhash(path));
+ existing = hashmap_get_entry(map, e, entry, NULL);
if (existing) {
free(e);
e = existing;
} else {
e->left[0] = e->right[0] = '\0';
- hashmap_add(map, e);
+ hashmap_add(map, &e->entry);
}
strlcpy(is_right ? e->right : e->left, content, PATH_MAX);
}
@@ -179,12 +184,14 @@ struct path_entry {
};
static int path_entry_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 *key)
{
- const struct path_entry *a = entry;
- const struct path_entry *b = entry_or_key;
+ const struct path_entry *a, *b;
+
+ a = container_of(eptr, const struct path_entry, entry);
+ b = container_of(entry_or_key, const struct path_entry, entry);
return strcmp(a->path, key ? key : b->path);
}
@@ -234,8 +241,8 @@ static void changed_files(struct hashmap *result, const char *index_path,
while (!strbuf_getline_nul(&buf, fp)) {
struct path_entry *entry;
FLEX_ALLOC_STR(entry, path, buf.buf);
- hashmap_entry_init(entry, strhash(buf.buf));
- hashmap_add(result, entry);
+ hashmap_entry_init(&entry->entry, strhash(buf.buf));
+ hashmap_add(result, &entry->entry);
}
fclose(fp);
if (finish_command(&diff_files))
@@ -461,12 +468,13 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
/* Avoid duplicate working_tree entries */
FLEX_ALLOC_STR(entry, path, dst_path);
- hashmap_entry_init(entry, strhash(dst_path));
- if (hashmap_get(&working_tree_dups, entry, NULL)) {
+ hashmap_entry_init(&entry->entry, strhash(dst_path));
+ if (hashmap_get(&working_tree_dups, &entry->entry,
+ NULL)) {
free(entry);
continue;
}
- hashmap_add(&working_tree_dups, entry);
+ hashmap_add(&working_tree_dups, &entry->entry);
if (!use_wt_file(workdir, dst_path, &roid)) {
if (checkout_path(rmode, &roid, dst_path,
@@ -530,8 +538,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
* temporary file to both the left and right directories to show the
* change in the recorded SHA1 for the submodule.
*/
- hashmap_iter_init(&submodules, &iter);
- while ((entry = hashmap_iter_next(&iter))) {
+ hashmap_for_each_entry(&submodules, &iter, entry,
+ entry /* member name */) {
if (*entry->left) {
add_path(&ldir, ldir_len, entry->path);
ensure_leading_directories(ldir.buf);
@@ -549,8 +557,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
* shows only the link itself, not the contents of the link target.
* This loop replicates that behavior.
*/
- hashmap_iter_init(&symlinks2, &iter);
- while ((entry = hashmap_iter_next(&iter))) {
+ hashmap_for_each_entry(&symlinks2, &iter, entry,
+ entry /* member name */) {
if (*entry->left) {
add_path(&ldir, ldir_len, entry->path);
ensure_leading_directories(ldir.buf);
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 58a74de42a..dbec4df92b 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -127,10 +127,15 @@ struct anonymized_entry {
};
static int anonymized_entry_cmp(const void *unused_cmp_data,
- const void *va, const void *vb,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
const void *unused_keydata)
{
- const struct anonymized_entry *a = va, *b = vb;
+ const struct anonymized_entry *a, *b;
+
+ a = container_of(eptr, const struct anonymized_entry, hash);
+ b = container_of(entry_or_key, const struct anonymized_entry, hash);
+
return a->orig_len != b->orig_len ||
memcmp(a->orig, b->orig, a->orig_len);
}
@@ -149,10 +154,10 @@ static const void *anonymize_mem(struct hashmap *map,
if (!map->cmpfn)
hashmap_init(map, anonymized_entry_cmp, NULL, 0);
- hashmap_entry_init(&key, memhash(orig, *len));
+ hashmap_entry_init(&key.hash, memhash(orig, *len));
key.orig = orig;
key.orig_len = *len;
- ret = hashmap_get(map, &key, NULL);
+ ret = hashmap_get_entry(map, &key, hash, NULL);
if (!ret) {
ret = xmalloc(sizeof(*ret));
@@ -161,7 +166,7 @@ static const void *anonymize_mem(struct hashmap *map,
ret->orig_len = *len;
ret->anon = generate(orig, len);
ret->anon_len = *len;
- hashmap_put(map, ret);
+ hashmap_put(map, &ret->hash);
}
*len = ret->anon_len;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index b0f9473489..ef731631c2 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -264,20 +264,21 @@ static void create_fetch_oidset(struct ref **head, struct oidset *out)
}
struct refname_hash_entry {
- struct hashmap_entry ent; /* must be the first member */
+ struct hashmap_entry ent;
struct object_id oid;
int ignore;
char refname[FLEX_ARRAY];
};
static int refname_hash_entry_cmp(const void *hashmap_cmp_fn_data,
- const void *e1_,
- const void *e2_,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
const void *keydata)
{
- const struct refname_hash_entry *e1 = e1_;
- const struct refname_hash_entry *e2 = e2_;
+ const struct refname_hash_entry *e1, *e2;
+ e1 = container_of(eptr, const struct refname_hash_entry, ent);
+ e2 = container_of(entry_or_key, const struct refname_hash_entry, ent);
return strcmp(e1->refname, keydata ? keydata : e2->refname);
}
@@ -289,9 +290,9 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map,
size_t len = strlen(refname);
FLEX_ALLOC_MEM(ent, refname, refname, len);
- hashmap_entry_init(ent, strhash(refname));
+ hashmap_entry_init(&ent->ent, strhash(refname));
oidcpy(&ent->oid, oid);
- hashmap_add(map, ent);
+ hashmap_add(map, &ent->ent);
return ent;
}
@@ -380,7 +381,7 @@ static void find_non_local_tags(const struct ref *refs,
item = refname_hash_add(&remote_refs, ref->name, &ref->old_oid);
string_list_insert(&remote_refs_list, ref->name);
}
- hashmap_free(&existing_refs, 1);
+ hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
/*
* We may have a final lightweight tag that needs to be
@@ -398,8 +399,10 @@ static void find_non_local_tags(const struct ref *refs,
for_each_string_list_item(remote_ref_item, &remote_refs_list) {
const char *refname = remote_ref_item->string;
struct ref *rm;
+ unsigned int hash = strhash(refname);
- item = hashmap_get_from_hash(&remote_refs, strhash(refname), refname);
+ item = hashmap_get_entry_from_hash(&remote_refs, hash, refname,
+ struct refname_hash_entry, ent);
if (!item)
BUG("unseen remote ref?");
@@ -413,7 +416,7 @@ static void find_non_local_tags(const struct ref *refs,
**tail = rm;
*tail = &rm->next;
}
- hashmap_free(&remote_refs, 1);
+ hashmap_free_entries(&remote_refs, struct refname_hash_entry, ent);
string_list_clear(&remote_refs_list, 0);
oidset_clear(&fetch_oids);
}
@@ -532,17 +535,18 @@ static struct ref *get_ref_map(struct remote *remote,
if (rm->peer_ref) {
const char *refname = rm->peer_ref->name;
struct refname_hash_entry *peer_item;
+ unsigned int hash = strhash(refname);
- peer_item = hashmap_get_from_hash(&existing_refs,
- strhash(refname),
- refname);
+ peer_item = hashmap_get_entry_from_hash(&existing_refs,
+ hash, refname,
+ struct refname_hash_entry, ent);
if (peer_item) {
struct object_id *old_oid = &peer_item->oid;
oidcpy(&rm->peer_ref->old_oid, old_oid);
}
}
}
- hashmap_free(&existing_refs, 1);
+ hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
return ref_map;
}
diff --git a/config.c b/config.c
index eef4f4f1bb..e7052b3977 100644
--- a/config.c
+++ b/config.c
@@ -1856,9 +1856,9 @@ 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);
+ found_entry = hashmap_get_entry(&cs->config_hash, &k, ent, NULL);
free(normalized_key);
return found_entry;
}
@@ -1877,10 +1877,10 @@ 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);
+ hashmap_add(&cs->config_hash, &e->ent);
}
si = string_list_append_nodup(&e->value_list, xstrdup_or_null(value));
@@ -1908,12 +1908,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);
}
@@ -1934,12 +1936,12 @@ 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,
+ ent /* member name */) {
free(entry->key);
string_list_clear(&entry->value_list, 1);
}
- hashmap_free(&cs->config_hash, 1);
+ hashmap_free_entries(&cs->config_hash, struct config_set_element, ent);
cs->hash_initialized = 0;
free(cs->list.items);
cs->list.nr = 0;
diff --git a/contrib/coccinelle/hashmap.cocci b/contrib/coccinelle/hashmap.cocci
new file mode 100644
index 0000000000..d69e120ccf
--- /dev/null
+++ b/contrib/coccinelle/hashmap.cocci
@@ -0,0 +1,16 @@
+@ hashmap_entry_init_usage @
+expression E;
+struct hashmap_entry HME;
+@@
+- HME.hash = E;
++ hashmap_entry_init(&HME, E);
+
+@@
+identifier f !~ "^hashmap_entry_init$";
+expression E;
+struct hashmap_entry *HMEP;
+@@
+ f(...) {<...
+- HMEP->hash = E;
++ hashmap_entry_init(HMEP, E);
+ ...>}
diff --git a/diff.c b/diff.c
index 8fb57b73ef..afe4400a60 100644
--- a/diff.c
+++ b/diff.c
@@ -933,16 +933,18 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,
}
static int moved_entry_cmp(const void *hashmap_cmp_fn_data,
- const void *entry,
- const void *entry_or_key,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
const void *keydata)
{
const struct diff_options *diffopt = hashmap_cmp_fn_data;
- const struct moved_entry *a = entry;
- const struct moved_entry *b = entry_or_key;
+ const struct moved_entry *a, *b;
unsigned flags = diffopt->color_moved_ws_handling
& XDF_WHITESPACE_FLAGS;
+ a = container_of(eptr, const struct moved_entry, ent);
+ b = container_of(entry_or_key, const struct moved_entry, ent);
+
if (diffopt->color_moved_ws_handling &
COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE)
/*
@@ -964,8 +966,9 @@ static struct moved_entry *prepare_entry(struct diff_options *o,
struct moved_entry *ret = xmalloc(sizeof(*ret));
struct emitted_diff_symbol *l = &o->emitted_symbols->buf[line_no];
unsigned flags = o->color_moved_ws_handling & XDF_WHITESPACE_FLAGS;
+ unsigned int hash = xdiff_hash_string(l->line, l->len, flags);
- ret->ent.hash = xdiff_hash_string(l->line, l->len, flags);
+ hashmap_entry_init(&ret->ent, hash);
ret->es = l;
ret->next_line = NULL;
@@ -1002,7 +1005,7 @@ static void add_lines_to_move_detection(struct diff_options *o,
if (prev_line && prev_line->es->s == o->emitted_symbols->buf[n].s)
prev_line->next_line = key;
- hashmap_add(hm, key);
+ hashmap_add(hm, &key->ent);
prev_line = key;
}
}
@@ -1018,7 +1021,7 @@ static void pmb_advance_or_null(struct diff_options *o,
struct moved_entry *prev = pmb[i].match;
struct moved_entry *cur = (prev && prev->next_line) ?
prev->next_line : NULL;
- if (cur && !hm->cmpfn(o, cur, match, NULL)) {
+ if (cur && !hm->cmpfn(o, &cur->ent, &match->ent, NULL)) {
pmb[i].match = cur;
} else {
pmb[i].match = NULL;
@@ -1035,7 +1038,7 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,
int i;
char *got_match = xcalloc(1, pmb_nr);
- for (; match; match = hashmap_get_next(hm, match)) {
+ hashmap_for_each_entry_from(hm, match, ent) {
for (i = 0; i < pmb_nr; i++) {
struct moved_entry *prev = pmb[i].match;
struct moved_entry *cur = (prev && prev->next_line) ?
@@ -1143,13 +1146,13 @@ static void mark_color_as_moved(struct diff_options *o,
case DIFF_SYMBOL_PLUS:
hm = del_lines;
key = prepare_entry(o, n);
- match = hashmap_get(hm, key, NULL);
+ match = hashmap_get_entry(hm, key, ent, NULL);
free(key);
break;
case DIFF_SYMBOL_MINUS:
hm = add_lines;
key = prepare_entry(o, n);
- match = hashmap_get(hm, key, NULL);
+ match = hashmap_get_entry(hm, key, ent, NULL);
free(key);
break;
default:
@@ -1188,7 +1191,7 @@ static void mark_color_as_moved(struct diff_options *o,
* The current line is the start of a new block.
* Setup the set of potential blocks.
*/
- for (; match; match = hashmap_get_next(hm, match)) {
+ hashmap_for_each_entry_from(hm, match, ent) {
ALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);
if (o->color_moved_ws_handling &
COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {
@@ -6230,8 +6233,10 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)
if (o->color_moved == COLOR_MOVED_ZEBRA_DIM)
dim_moved_lines(o);
- hashmap_free(&add_lines, 1);
- hashmap_free(&del_lines, 1);
+ hashmap_free_entries(&add_lines, struct moved_entry,
+ ent);
+ hashmap_free_entries(&del_lines, struct moved_entry,
+ ent);
}
for (i = 0; i < esm.nr; i++)
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 9042936aba..531d7adeaf 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -274,18 +274,17 @@ static int find_identical_files(struct hashmap *srcs,
struct diff_options *options)
{
int renames = 0;
-
struct diff_filespec *target = rename_dst[dst_index].two;
struct file_similarity *p, *best = NULL;
int i = 100, best_score = -1;
+ unsigned int hash = hash_filespec(options->repo, target);
/*
* Find the best source match for specified destination.
*/
- p = hashmap_get_from_hash(srcs,
- hash_filespec(options->repo, target),
- NULL);
- for (; p; p = hashmap_get_next(srcs, p)) {
+ p = hashmap_get_entry_from_hash(srcs, hash, NULL,
+ struct file_similarity, entry);
+ hashmap_for_each_entry_from(srcs, p, entry) {
int score;
struct diff_filespec *source = p->filespec;
@@ -329,8 +328,8 @@ static void insert_file_table(struct repository *r,
entry->index = index;
entry->filespec = filespec;
- hashmap_entry_init(entry, hash_filespec(r, filespec));
- hashmap_add(table, entry);
+ hashmap_entry_init(&entry->entry, hash_filespec(r, filespec));
+ hashmap_add(table, &entry->entry);
}
/*
@@ -359,7 +358,7 @@ static int find_exact_renames(struct diff_options *options)
renames += find_identical_files(&file_table, i, options);
/* Free the hash data structure and entries */
- hashmap_free(&file_table, 1);
+ hashmap_free_entries(&file_table, struct file_similarity, entry);
return renames;
}
diff --git a/git-compat-util.h b/git-compat-util.h
index a8b5854e27..8b8b29a867 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -1313,4 +1313,42 @@ void unleak_memory(const void *ptr, size_t len);
*/
#include "banned.h"
+/*
+ * container_of - Get the address of an object containing a field.
+ *
+ * @ptr: pointer to the field.
+ * @type: type of the object.
+ * @member: name of the field within the object.
+ */
+#define container_of(ptr, type, member) \
+ ((type *) ((char *)(ptr) - offsetof(type, member)))
+
+/*
+ * helper function for `container_of_or_null' to avoid multiple
+ * evaluation of @ptr
+ */
+static inline void *container_of_or_null_offset(void *ptr, size_t offset)
+{
+ return ptr ? (char *)ptr - offset : NULL;
+}
+
+/*
+ * like `container_of', but allows returned value to be NULL
+ */
+#define container_of_or_null(ptr, type, member) \
+ (type *)container_of_or_null_offset(ptr, offsetof(type, member))
+
+/*
+ * like offsetof(), but takes a pointer to a a variable of type which
+ * contains @member, instead of a specified type.
+ * @ptr is subject to multiple evaluation since we can't rely on __typeof__
+ * everywhere.
+ */
+#if defined(__GNUC__) /* clang sets this, too */
+#define OFFSETOF_VAR(ptr, member) offsetof(__typeof__(*ptr), member)
+#else /* !__GNUC__ */
+#define OFFSETOF_VAR(ptr, member) \
+ ((uintptr_t)&(ptr)->member - (uintptr_t)(ptr))
+#endif /* !__GNUC__ */
+
#endif
diff --git a/hashmap.c b/hashmap.c
index d42f01ff5a..39c13110bc 100644
--- a/hashmap.c
+++ b/hashmap.c
@@ -140,8 +140,8 @@ static inline struct hashmap_entry **find_entry_ptr(const struct hashmap *map,
}
static int always_equal(const void *unused_cmp_data,
- const void *unused1,
- const void *unused2,
+ const struct hashmap_entry *unused1,
+ const struct hashmap_entry *unused2,
const void *unused_keydata)
{
return 0;
@@ -171,41 +171,49 @@ void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function,
map->do_count_items = 1;
}
-void hashmap_free(struct hashmap *map, int free_entries)
+void hashmap_free_(struct hashmap *map, ssize_t entry_offset)
{
if (!map || !map->table)
return;
- if (free_entries) {
+ if (entry_offset >= 0) { /* called by hashmap_free_entries */
struct hashmap_iter iter;
struct hashmap_entry *e;
+
hashmap_iter_init(map, &iter);
while ((e = hashmap_iter_next(&iter)))
- free(e);
+ /*
+ * like container_of, but using caller-calculated
+ * offset (caller being hashmap_free_entries)
+ */
+ free((char *)e - entry_offset);
}
free(map->table);
memset(map, 0, sizeof(*map));
}
-void *hashmap_get(const struct hashmap *map, const void *key, const void *keydata)
+struct hashmap_entry *hashmap_get(const struct hashmap *map,
+ const struct hashmap_entry *key,
+ const void *keydata)
{
return *find_entry_ptr(map, key, keydata);
}
-void *hashmap_get_next(const struct hashmap *map, const void *entry)
+struct hashmap_entry *hashmap_get_next(const struct hashmap *map,
+ const struct hashmap_entry *entry)
{
- struct hashmap_entry *e = ((struct hashmap_entry *) entry)->next;
+ struct hashmap_entry *e = entry->next;
for (; e; e = e->next)
if (entry_equals(map, entry, e, NULL))
return e;
return NULL;
}
-void hashmap_add(struct hashmap *map, void *entry)
+void hashmap_add(struct hashmap *map, struct hashmap_entry *entry)
{
unsigned int b = bucket(map, entry);
/* add entry */
- ((struct hashmap_entry *) entry)->next = map->table[b];
+ entry->next = map->table[b];
map->table[b] = entry;
/* fix size and rehash if appropriate */
@@ -216,7 +224,9 @@ void hashmap_add(struct hashmap *map, void *entry)
}
}
-void *hashmap_remove(struct hashmap *map, const void *key, const void *keydata)
+struct hashmap_entry *hashmap_remove(struct hashmap *map,
+ const struct hashmap_entry *key,
+ const void *keydata)
{
struct hashmap_entry *old;
struct hashmap_entry **e = find_entry_ptr(map, key, keydata);
@@ -238,7 +248,8 @@ void *hashmap_remove(struct hashmap *map, const void *key, const void *keydata)
return old;
}
-void *hashmap_put(struct hashmap *map, void *entry)
+struct hashmap_entry *hashmap_put(struct hashmap *map,
+ struct hashmap_entry *entry)
{
struct hashmap_entry *old = hashmap_remove(map, entry, NULL);
hashmap_add(map, entry);
@@ -252,7 +263,7 @@ void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter)
iter->next = NULL;
}
-void *hashmap_iter_next(struct hashmap_iter *iter)
+struct hashmap_entry *hashmap_iter_next(struct hashmap_iter *iter)
{
struct hashmap_entry *current = iter->next;
for (;;) {
@@ -275,10 +286,15 @@ struct pool_entry {
};
static int pool_entry_cmp(const void *unused_cmp_data,
- const struct pool_entry *e1,
- const struct pool_entry *e2,
- const unsigned char *keydata)
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
+ const void *keydata)
{
+ const struct pool_entry *e1, *e2;
+
+ e1 = container_of(eptr, const struct pool_entry, ent);
+ e2 = container_of(entry_or_key, const struct pool_entry, ent);
+
return e1->data != keydata &&
(e1->len != e2->len || memcmp(e1->data, keydata, e1->len));
}
@@ -290,18 +306,18 @@ const void *memintern(const void *data, size_t len)
/* initialize string pool hashmap */
if (!map.tablesize)
- hashmap_init(&map, (hashmap_cmp_fn) pool_entry_cmp, NULL, 0);
+ hashmap_init(&map, pool_entry_cmp, NULL, 0);
/* lookup interned string in pool */
- hashmap_entry_init(&key, memhash(data, len));
+ hashmap_entry_init(&key.ent, memhash(data, len));
key.len = len;
- e = hashmap_get(&map, &key, data);
+ e = hashmap_get_entry(&map, &key, ent, data);
if (!e) {
/* not found: create it */
FLEX_ALLOC_MEM(e, data, data, len);
- hashmap_entry_init(e, key.ent.hash);
+ hashmap_entry_init(&e->ent, key.ent.hash);
e->len = len;
- hashmap_add(&map, e);
+ hashmap_add(&map, &e->ent);
}
return e->data;
}
diff --git a/hashmap.h b/hashmap.h
index 8424911566..bd2701549f 100644
--- a/hashmap.h
+++ b/hashmap.h
@@ -13,7 +13,7 @@
*
* struct hashmap map;
* struct long2string {
- * struct hashmap_entry ent; // must be the first member!
+ * struct hashmap_entry ent;
* long key;
* char value[FLEX_ARRAY]; // be careful with allocating on stack!
* };
@@ -21,12 +21,16 @@
* #define COMPARE_VALUE 1
*
* static int long2string_cmp(const void *hashmap_cmp_fn_data,
- * const struct long2string *e1,
- * const struct long2string *e2,
+ * const struct hashmap_entry *eptr,
+ * const struct hashmap_entry *entry_or_key,
* const void *keydata)
* {
* const char *string = keydata;
* unsigned flags = *(unsigned *)hashmap_cmp_fn_data;
+ * const struct long2string *e1, *e2;
+ *
+ * e1 = container_of(eptr, const struct long2string, ent);
+ * e2 = container_of(entry_or_key, const struct long2string, ent);
*
* if (flags & COMPARE_VALUE)
* return e1->key != e2->key ||
@@ -41,54 +45,58 @@
* char value[255], action[32];
* unsigned flags = 0;
*
- * hashmap_init(&map, (hashmap_cmp_fn) long2string_cmp, &flags, 0);
+ * hashmap_init(&map, long2string_cmp, &flags, 0);
*
* while (scanf("%s %ld %s", action, &key, value)) {
*
* if (!strcmp("add", action)) {
* struct long2string *e;
* FLEX_ALLOC_STR(e, value, value);
- * hashmap_entry_init(e, memhash(&key, sizeof(long)));
+ * hashmap_entry_init(&e->ent, memhash(&key, sizeof(long)));
* e->key = key;
- * hashmap_add(&map, e);
+ * hashmap_add(&map, &e->ent);
* }
*
* if (!strcmp("print_all_by_key", action)) {
* struct long2string k, *e;
- * hashmap_entry_init(&k, memhash(&key, sizeof(long)));
+ * hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));
* k.key = key;
*
* flags &= ~COMPARE_VALUE;
- * e = hashmap_get(&map, &k, NULL);
+ * e = hashmap_get_entry(&map, &k, ent, NULL);
* if (e) {
* printf("first: %ld %s\n", e->key, e->value);
- * while ((e = hashmap_get_next(&map, e)))
+ * while ((e = hashmap_get_next_entry(&map, e,
+ * struct long2string, ent))) {
* printf("found more: %ld %s\n", e->key, e->value);
+ * }
* }
* }
*
* if (!strcmp("has_exact_match", action)) {
* struct long2string *e;
* FLEX_ALLOC_STR(e, value, value);
- * hashmap_entry_init(e, memhash(&key, sizeof(long)));
+ * hashmap_entry_init(&e->ent, memhash(&key, sizeof(long)));
* e->key = key;
*
* flags |= COMPARE_VALUE;
- * printf("%sfound\n", hashmap_get(&map, e, NULL) ? "" : "not ");
+ * printf("%sfound\n",
+ * hashmap_get(&map, &e->ent, NULL) ? "" : "not ");
* free(e);
* }
*
* if (!strcmp("has_exact_match_no_heap_alloc", action)) {
* struct long2string k;
- * hashmap_entry_init(&k, memhash(&key, sizeof(long)));
+ * hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));
* k.key = key;
*
* flags |= COMPARE_VALUE;
- * printf("%sfound\n", hashmap_get(&map, &k, value) ? "" : "not ");
+ * printf("%sfound\n",
+ * hashmap_get(&map, &k->ent, value) ? "" : "not ");
* }
*
* if (!strcmp("end", action)) {
- * hashmap_free(&map, 1);
+ * hashmap_free_entries(&map, struct long2string, ent);
* break;
* }
* }
@@ -133,7 +141,7 @@ static inline unsigned int oidhash(const struct object_id *oid)
/*
* struct hashmap_entry is an opaque structure representing an entry in the
- * hash table, which must be used as first member of user data structures.
+ * hash table.
* Ideally it should be followed by an int-sized member to prevent unused
* memory on 64-bit systems due to alignment.
*/
@@ -168,7 +176,8 @@ struct hashmap_entry {
* The `hashmap_cmp_fn_data` entry is the pointer given in the init function.
*/
typedef int (*hashmap_cmp_fn)(const void *hashmap_cmp_fn_data,
- const void *entry, const void *entry_or_key,
+ const struct hashmap_entry *entry,
+ const struct hashmap_entry *entry_or_key,
const void *keydata);
/*
@@ -223,13 +232,20 @@ void hashmap_init(struct hashmap *map,
const void *equals_function_data,
size_t initial_size);
+/* internal function for freeing hashmap */
+void hashmap_free_(struct hashmap *map, ssize_t offset);
+
/*
- * Frees a hashmap structure and allocated memory.
- *
- * If `free_entries` is true, each hashmap_entry in the map is freed as well
- * using stdlibs free().
+ * Frees a hashmap structure and allocated memory, leaves entries undisturbed
*/
-void hashmap_free(struct hashmap *map, int free_entries);
+#define hashmap_free(map) hashmap_free_(map, -1)
+
+/*
+ * Frees @map and all entries. @type is the struct type of the entry
+ * where @member is the hashmap_entry struct used to associate with @map
+ */
+#define hashmap_free_entries(map, type, member) \
+ hashmap_free_(map, offsetof(type, member));
/* hashmap_entry functions */
@@ -244,9 +260,9 @@ void hashmap_free(struct hashmap *map, int free_entries);
* your structure was allocated with xmalloc(), you can just free(3) it,
* and if it is on stack, you can just let it go out of scope).
*/
-static inline void hashmap_entry_init(void *entry, unsigned int hash)
+static inline void hashmap_entry_init(struct hashmap_entry *e,
+ unsigned int hash)
{
- struct hashmap_entry *e = entry;
e->hash = hash;
e->next = NULL;
}
@@ -286,8 +302,9 @@ static inline unsigned int hashmap_get_size(struct hashmap *map)
* If an entry with matching hash code is found, `key` and `keydata` are passed
* to `hashmap_cmp_fn` to decide whether the entry matches the key.
*/
-void *hashmap_get(const struct hashmap *map, const void *key,
- const void *keydata);
+struct hashmap_entry *hashmap_get(const struct hashmap *map,
+ const struct hashmap_entry *key,
+ const void *keydata);
/*
* Returns the hashmap entry for the specified hash code and key data,
@@ -301,9 +318,10 @@ void *hashmap_get(const struct hashmap *map, const void *key,
* `entry_or_key` parameter of `hashmap_cmp_fn` points to a hashmap_entry
* structure that should not be used in the comparison.
*/
-static inline void *hashmap_get_from_hash(const struct hashmap *map,
- unsigned int hash,
- const void *keydata)
+static inline struct hashmap_entry *hashmap_get_from_hash(
+ const struct hashmap *map,
+ unsigned int hash,
+ const void *keydata)
{
struct hashmap_entry key;
hashmap_entry_init(&key, hash);
@@ -318,7 +336,8 @@ static inline void *hashmap_get_from_hash(const struct hashmap *map,
* `entry` is the hashmap_entry to start the search from, obtained via a previous
* call to `hashmap_get` or `hashmap_get_next`.
*/
-void *hashmap_get_next(const struct hashmap *map, const void *entry);
+struct hashmap_entry *hashmap_get_next(const struct hashmap *map,
+ const struct hashmap_entry *entry);
/*
* Adds a hashmap entry. This allows to add duplicate entries (i.e.
@@ -327,7 +346,7 @@ void *hashmap_get_next(const struct hashmap *map, const void *entry);
* `map` is the hashmap structure.
* `entry` is the entry to add.
*/
-void hashmap_add(struct hashmap *map, void *entry);
+void hashmap_add(struct hashmap *map, struct hashmap_entry *entry);
/*
* Adds or replaces a hashmap entry. If the hashmap contains duplicate
@@ -337,7 +356,20 @@ void hashmap_add(struct hashmap *map, void *entry);
* `entry` is the entry to add or replace.
* Returns the replaced entry, or NULL if not found (i.e. the entry was added).
*/
-void *hashmap_put(struct hashmap *map, void *entry);
+struct hashmap_entry *hashmap_put(struct hashmap *map,
+ struct hashmap_entry *entry);
+
+/*
+ * Adds or replaces a hashmap entry contained within @keyvar,
+ * where @keyvar is a pointer to a struct containing a
+ * "struct hashmap_entry" @member.
+ *
+ * Returns the replaced pointer which is of the same type as @keyvar,
+ * or NULL if not found.
+ */
+#define hashmap_put_entry(map, keyvar, member) \
+ container_of_or_null_offset(hashmap_put(map, &(keyvar)->member), \
+ OFFSETOF_VAR(keyvar, member))
/*
* Removes a hashmap entry matching the specified key. If the hashmap contains
@@ -346,8 +378,24 @@ void *hashmap_put(struct hashmap *map, void *entry);
*
* Argument explanation is the same as in `hashmap_get`.
*/
-void *hashmap_remove(struct hashmap *map, const void *key,
- const void *keydata);
+struct hashmap_entry *hashmap_remove(struct hashmap *map,
+ const struct hashmap_entry *key,
+ const void *keydata);
+
+/*
+ * Removes a hashmap entry contained within @keyvar,
+ * where @keyvar is a pointer to a struct containing a
+ * "struct hashmap_entry" @member.
+ *
+ * See `hashmap_get` for an explanation of @keydata
+ *
+ * Returns the replaced pointer which is of the same type as @keyvar,
+ * or NULL if not found.
+ */
+#define hashmap_remove_entry(map, keyvar, member, keydata) \
+ container_of_or_null_offset( \
+ hashmap_remove(map, &(keyvar)->member, keydata), \
+ OFFSETOF_VAR(keyvar, member))
/*
* Returns the `bucket` an entry is stored in.
@@ -370,10 +418,10 @@ struct hashmap_iter {
void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter);
/* Returns the next hashmap_entry, or NULL if there are no more entries. */
-void *hashmap_iter_next(struct hashmap_iter *iter);
+struct hashmap_entry *hashmap_iter_next(struct hashmap_iter *iter);
/* Initializes the iterator and returns the first entry, if any. */
-static inline void *hashmap_iter_first(struct hashmap *map,
+static inline struct hashmap_entry *hashmap_iter_first(struct hashmap *map,
struct hashmap_iter *iter)
{
hashmap_iter_init(map, iter);
@@ -381,6 +429,64 @@ static inline void *hashmap_iter_first(struct hashmap *map,
}
/*
+ * returns the first entry in @map using @iter, where the entry is of
+ * @type (e.g. "struct foo") and @member is the name of the
+ * "struct hashmap_entry" in @type
+ */
+#define hashmap_iter_first_entry(map, iter, type, member) \
+ container_of_or_null(hashmap_iter_first(map, iter), type, member)
+
+/* internal macro for hashmap_for_each_entry */
+#define hashmap_iter_next_entry_offset(iter, offset) \
+ container_of_or_null_offset(hashmap_iter_next(iter), offset)
+
+/* internal macro for hashmap_for_each_entry */
+#define hashmap_iter_first_entry_offset(map, iter, offset) \
+ container_of_or_null_offset(hashmap_iter_first(map, iter), offset)
+
+/*
+ * iterate through @map using @iter, @var is a pointer to a type
+ * containing a @member which is a "struct hashmap_entry"
+ */
+#define hashmap_for_each_entry(map, iter, var, member) \
+ for (var = hashmap_iter_first_entry_offset(map, iter, \
+ OFFSETOF_VAR(var, member)); \
+ var; \
+ var = hashmap_iter_next_entry_offset(iter, \
+ OFFSETOF_VAR(var, member)))
+
+/*
+ * returns a pointer of type matching @keyvar, or NULL if nothing found.
+ * @keyvar is a pointer to a struct containing a
+ * "struct hashmap_entry" @member.
+ */
+#define hashmap_get_entry(map, keyvar, member, keydata) \
+ container_of_or_null_offset( \
+ hashmap_get(map, &(keyvar)->member, keydata), \
+ OFFSETOF_VAR(keyvar, member))
+
+#define hashmap_get_entry_from_hash(map, hash, keydata, type, member) \
+ container_of_or_null(hashmap_get_from_hash(map, hash, keydata), \
+ type, member)
+/*
+ * returns the next equal pointer to @var, or NULL if not found.
+ * @var is a pointer of any type containing "struct hashmap_entry"
+ * @member is the name of the "struct hashmap_entry" field
+ */
+#define hashmap_get_next_entry(map, var, member) \
+ container_of_or_null_offset(hashmap_get_next(map, &(var)->member), \
+ OFFSETOF_VAR(var, member))
+
+/*
+ * iterate @map starting from @var, where @var is a pointer of @type
+ * and @member is the name of the "struct hashmap_entry" field in @type
+ */
+#define hashmap_for_each_entry_from(map, var, member) \
+ for (; \
+ var; \
+ var = hashmap_get_next_entry(map, var, member))
+
+/*
* Disable item counting and automatic rehashing when adding/removing items.
*
* Normally, the hashmap keeps track of the number of items in the map
diff --git a/merge-recursive.c b/merge-recursive.c
index e86571c91b..42be7c9960 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -45,14 +45,16 @@ struct path_hashmap_entry {
};
static int path_hashmap_cmp(const void *cmp_data,
- const void *entry,
- const void *entry_or_key,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
const void *keydata)
{
- const struct path_hashmap_entry *a = entry;
- const struct path_hashmap_entry *b = entry_or_key;
+ const struct path_hashmap_entry *a, *b;
const char *key = keydata;
+ a = container_of(eptr, const struct path_hashmap_entry, e);
+ b = container_of(entry_or_key, const struct path_hashmap_entry, e);
+
if (ignore_case)
return strcasecmp(a->path, key ? key : b->path);
else
@@ -75,7 +77,7 @@ static unsigned int path_hash(const char *path)
* in get_directory_renames() for details
*/
struct dir_rename_entry {
- struct hashmap_entry ent; /* must be the first member! */
+ struct hashmap_entry ent;
char *dir;
unsigned non_unique_new_dir:1;
struct strbuf new_dir;
@@ -89,18 +91,20 @@ static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,
if (dir == NULL)
return NULL;
- hashmap_entry_init(&key, strhash(dir));
+ hashmap_entry_init(&key.ent, strhash(dir));
key.dir = dir;
- return hashmap_get(hashmap, &key, NULL);
+ return hashmap_get_entry(hashmap, &key, ent, NULL);
}
static int dir_rename_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 dir_rename_entry *e1 = entry;
- const struct dir_rename_entry *e2 = entry_or_key;
+ const struct dir_rename_entry *e1, *e2;
+
+ e1 = container_of(eptr, const struct dir_rename_entry, ent);
+ e2 = container_of(entry_or_key, const struct dir_rename_entry, ent);
return strcmp(e1->dir, e2->dir);
}
@@ -113,7 +117,7 @@ static void dir_rename_init(struct hashmap *map)
static void dir_rename_entry_init(struct dir_rename_entry *entry,
char *directory)
{
- hashmap_entry_init(entry, strhash(directory));
+ hashmap_entry_init(&entry->ent, strhash(directory));
entry->dir = directory;
entry->non_unique_new_dir = 0;
strbuf_init(&entry->new_dir, 0);
@@ -121,7 +125,7 @@ static void dir_rename_entry_init(struct dir_rename_entry *entry,
}
struct collision_entry {
- struct hashmap_entry ent; /* must be the first member! */
+ struct hashmap_entry ent;
char *target_file;
struct string_list source_files;
unsigned reported_already:1;
@@ -132,22 +136,27 @@ static struct collision_entry *collision_find_entry(struct hashmap *hashmap,
{
struct collision_entry key;
- hashmap_entry_init(&key, strhash(target_file));
+ hashmap_entry_init(&key.ent, strhash(target_file));
key.target_file = target_file;
- return hashmap_get(hashmap, &key, NULL);
+ return hashmap_get_entry(hashmap, &key, ent, NULL);
}
-static int collision_cmp(void *unused_cmp_data,
- const struct collision_entry *e1,
- const struct collision_entry *e2,
+static int collision_cmp(const void *unused_cmp_data,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
const void *unused_keydata)
{
+ const struct collision_entry *e1, *e2;
+
+ e1 = container_of(eptr, const struct collision_entry, ent);
+ e2 = container_of(entry_or_key, const struct collision_entry, ent);
+
return strcmp(e1->target_file, e2->target_file);
}
static void collision_init(struct hashmap *map)
{
- hashmap_init(map, (hashmap_cmp_fn) collision_cmp, NULL, 0);
+ hashmap_init(map, collision_cmp, NULL, 0);
}
static void flush_output(struct merge_options *opt)
@@ -464,8 +473,8 @@ static int save_files_dirs(const struct object_id *oid,
strbuf_addstr(base, path);
FLEX_ALLOC_MEM(entry, path, base->buf, base->len);
- hashmap_entry_init(entry, path_hash(entry->path));
- hashmap_add(&opt->priv->current_file_dir_set, entry);
+ hashmap_entry_init(&entry->e, path_hash(entry->path));
+ hashmap_add(&opt->priv->current_file_dir_set, &entry->e);
strbuf_setlen(base, baselen);
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
@@ -743,8 +752,8 @@ static char *unique_path(struct merge_options *opt,
}
FLEX_ALLOC_MEM(entry, path, newpath.buf, newpath.len);
- hashmap_entry_init(entry, path_hash(entry->path));
- hashmap_add(&opt->priv->current_file_dir_set, entry);
+ hashmap_entry_init(&entry->e, path_hash(entry->path));
+ hashmap_add(&opt->priv->current_file_dir_set, &entry->e);
return strbuf_detach(&newpath, NULL);
}
@@ -2013,7 +2022,7 @@ static void remove_hashmap_entries(struct hashmap *dir_renames,
for (i = 0; i < items_to_remove->nr; i++) {
entry = items_to_remove->items[i].util;
- hashmap_remove(dir_renames, entry, NULL);
+ hashmap_remove(dir_renames, &entry->ent, NULL);
}
string_list_clear(items_to_remove, 0);
}
@@ -2136,8 +2145,8 @@ static void handle_directory_level_conflicts(struct merge_options *opt,
struct string_list remove_from_head = STRING_LIST_INIT_NODUP;
struct string_list remove_from_merge = STRING_LIST_INIT_NODUP;
- hashmap_iter_init(dir_re_head, &iter);
- while ((head_ent = hashmap_iter_next(&iter))) {
+ hashmap_for_each_entry(dir_re_head, &iter, head_ent,
+ ent /* member name */) {
merge_ent = dir_rename_find_entry(dir_re_merge, head_ent->dir);
if (merge_ent &&
!head_ent->non_unique_new_dir &&
@@ -2161,8 +2170,8 @@ static void handle_directory_level_conflicts(struct merge_options *opt,
remove_hashmap_entries(dir_re_head, &remove_from_head);
remove_hashmap_entries(dir_re_merge, &remove_from_merge);
- hashmap_iter_init(dir_re_merge, &iter);
- while ((merge_ent = hashmap_iter_next(&iter))) {
+ hashmap_for_each_entry(dir_re_merge, &iter, merge_ent,
+ ent /* member name */) {
head_ent = dir_rename_find_entry(dir_re_head, merge_ent->dir);
if (tree_has_path(opt->repo, merge, merge_ent->dir)) {
/* 2. This wasn't a directory rename after all */
@@ -2241,7 +2250,7 @@ static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs)
if (!entry) {
entry = xmalloc(sizeof(*entry));
dir_rename_entry_init(entry, old_dir);
- hashmap_put(dir_renames, entry);
+ hashmap_put(dir_renames, &entry->ent);
} else {
free(old_dir);
}
@@ -2266,8 +2275,8 @@ static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs)
* we set non_unique_new_dir. Once we've determined the winner (or
* that there is no winner), we no longer need possible_new_dirs.
*/
- hashmap_iter_init(dir_renames, &iter);
- while ((entry = hashmap_iter_next(&iter))) {
+ hashmap_for_each_entry(dir_renames, &iter, entry,
+ ent /* member name */) {
int max = 0;
int bad_max = 0;
char *best = NULL;
@@ -2370,8 +2379,9 @@ static void compute_collisions(struct hashmap *collisions,
if (!collision_ent) {
collision_ent = xcalloc(1,
sizeof(struct collision_entry));
- hashmap_entry_init(collision_ent, strhash(new_path));
- hashmap_put(collisions, collision_ent);
+ hashmap_entry_init(&collision_ent->ent,
+ strhash(new_path));
+ hashmap_put(collisions, &collision_ent->ent);
collision_ent->target_file = new_path;
} else {
free(new_path);
@@ -2624,12 +2634,12 @@ static struct string_list *get_renames(struct merge_options *opt,
entries);
}
- hashmap_iter_init(&collisions, &iter);
- while ((e = hashmap_iter_next(&iter))) {
+ hashmap_for_each_entry(&collisions, &iter, e,
+ ent /* member name */) {
free(e->target_file);
string_list_clear(&e->source_files, 0);
}
- hashmap_free(&collisions, 1);
+ hashmap_free_entries(&collisions, struct collision_entry, ent);
return renames;
}
@@ -2842,13 +2852,13 @@ static void initial_cleanup_rename(struct diff_queue_struct *pairs,
struct hashmap_iter iter;
struct dir_rename_entry *e;
- hashmap_iter_init(dir_renames, &iter);
- while ((e = hashmap_iter_next(&iter))) {
+ hashmap_for_each_entry(dir_renames, &iter, e,
+ ent /* member name */) {
free(e->dir);
strbuf_release(&e->new_dir);
/* possible_new_dirs already cleared in get_directory_renames */
}
- hashmap_free(dir_renames, 1);
+ hashmap_free_entries(dir_renames, struct dir_rename_entry, ent);
free(dir_renames);
free(pairs->queue);
@@ -3475,7 +3485,8 @@ static int merge_trees_internal(struct merge_options *opt,
string_list_clear(entries, 1);
free(entries);
- hashmap_free(&opt->priv->current_file_dir_set, 1);
+ hashmap_free_entries(&opt->priv->current_file_dir_set,
+ struct path_hashmap_entry, e);
if (clean < 0) {
unpack_trees_finish(opt);
diff --git a/name-hash.c b/name-hash.c
index 695908609f..ceb1d7bd6f 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -17,14 +17,16 @@ struct dir_entry {
};
static int dir_entry_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 *keydata)
{
- const struct dir_entry *e1 = entry;
- const struct dir_entry *e2 = entry_or_key;
+ const struct dir_entry *e1, *e2;
const char *name = keydata;
+ e1 = container_of(eptr, const struct dir_entry, ent);
+ e2 = container_of(entry_or_key, const struct dir_entry, ent);
+
return e1->namelen != e2->namelen || strncasecmp(e1->name,
name ? name : e2->name, e1->namelen);
}
@@ -33,9 +35,9 @@ static struct dir_entry *find_dir_entry__hash(struct index_state *istate,
const char *name, unsigned int namelen, unsigned int hash)
{
struct dir_entry key;
- hashmap_entry_init(&key, hash);
+ hashmap_entry_init(&key.ent, hash);
key.namelen = namelen;
- return hashmap_get(&istate->dir_hash, &key, name);
+ return hashmap_get_entry(&istate->dir_hash, &key, ent, name);
}
static struct dir_entry *find_dir_entry(struct index_state *istate,
@@ -68,9 +70,9 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,
if (!dir) {
/* not found, create it and add to hash table */
FLEX_ALLOC_MEM(dir, name, ce->name, namelen);
- hashmap_entry_init(dir, memihash(ce->name, namelen));
+ hashmap_entry_init(&dir->ent, memihash(ce->name, namelen));
dir->namelen = namelen;
- hashmap_add(&istate->dir_hash, dir);
+ hashmap_add(&istate->dir_hash, &dir->ent);
/* recursively add missing parent directories */
dir->parent = hash_dir_entry(istate, ce, namelen);
@@ -95,7 +97,7 @@ static void remove_dir_entry(struct index_state *istate, struct cache_entry *ce)
struct dir_entry *dir = hash_dir_entry(istate, ce, ce_namelen(ce));
while (dir && !(--dir->nr)) {
struct dir_entry *parent = dir->parent;
- hashmap_remove(&istate->dir_hash, dir, NULL);
+ hashmap_remove(&istate->dir_hash, &dir->ent, NULL);
free(dir);
dir = parent;
}
@@ -106,20 +108,23 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)
if (ce->ce_flags & CE_HASHED)
return;
ce->ce_flags |= CE_HASHED;
- hashmap_entry_init(ce, memihash(ce->name, ce_namelen(ce)));
- hashmap_add(&istate->name_hash, ce);
+ hashmap_entry_init(&ce->ent, memihash(ce->name, ce_namelen(ce)));
+ hashmap_add(&istate->name_hash, &ce->ent);
if (ignore_case)
add_dir_entry(istate, ce);
}
static int cache_entry_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 *remove)
{
- const struct cache_entry *ce1 = entry;
- const struct cache_entry *ce2 = entry_or_key;
+ const struct cache_entry *ce1, *ce2;
+
+ ce1 = container_of(eptr, const struct cache_entry, ent);
+ ce2 = container_of(entry_or_key, const struct cache_entry, ent);
+
/*
* For remove_name_hash, find the exact entry (pointer equality); for
* index_file_exists, find all entries with matching hash code and
@@ -280,10 +285,10 @@ static struct dir_entry *hash_dir_entry_with_parent_and_prefix(
dir = find_dir_entry__hash(istate, prefix->buf, prefix->len, hash);
if (!dir) {
FLEX_ALLOC_MEM(dir, name, prefix->buf, prefix->len);
- hashmap_entry_init(dir, hash);
+ hashmap_entry_init(&dir->ent, hash);
dir->namelen = prefix->len;
dir->parent = parent;
- hashmap_add(&istate->dir_hash, dir);
+ hashmap_add(&istate->dir_hash, &dir->ent);
if (parent) {
unlock_dir_mutex(lock_nr);
@@ -472,8 +477,8 @@ static void *lazy_name_thread_proc(void *_data)
for (k = 0; k < d->istate->cache_nr; k++) {
struct cache_entry *ce_k = d->istate->cache[k];
ce_k->ce_flags |= CE_HASHED;
- hashmap_entry_init(ce_k, d->lazy_entries[k].hash_name);
- hashmap_add(&d->istate->name_hash, ce_k);
+ hashmap_entry_init(&ce_k->ent, d->lazy_entries[k].hash_name);
+ hashmap_add(&d->istate->name_hash, &ce_k->ent);
}
return NULL;
@@ -625,7 +630,7 @@ void remove_name_hash(struct index_state *istate, struct cache_entry *ce)
if (!istate->name_hash_initialized || !(ce->ce_flags & CE_HASHED))
return;
ce->ce_flags &= ~CE_HASHED;
- hashmap_remove(&istate->name_hash, ce, ce);
+ hashmap_remove(&istate->name_hash, &ce->ent, ce);
if (ignore_case)
remove_dir_entry(istate, ce);
@@ -702,15 +707,15 @@ void adjust_dirname_case(struct index_state *istate, char *name)
struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase)
{
struct cache_entry *ce;
+ unsigned int hash = memihash(name, namelen);
lazy_init_name_hash(istate);
- ce = hashmap_get_from_hash(&istate->name_hash,
- memihash(name, namelen), NULL);
- while (ce) {
+ ce = hashmap_get_entry_from_hash(&istate->name_hash, hash, NULL,
+ struct cache_entry, ent);
+ hashmap_for_each_entry_from(&istate->name_hash, ce, ent) {
if (same_name(ce, name, namelen, icase))
return ce;
- ce = hashmap_get_next(&istate->name_hash, ce);
}
return NULL;
}
@@ -721,6 +726,6 @@ void free_name_hash(struct index_state *istate)
return;
istate->name_hash_initialized = 0;
- hashmap_free(&istate->name_hash, 0);
- hashmap_free(&istate->dir_hash, 1);
+ hashmap_free(&istate->name_hash);
+ hashmap_free_entries(&istate->dir_hash, struct dir_entry, ent);
}
diff --git a/oidmap.c b/oidmap.c
index 6d6e840d03..423aa014a3 100644
--- a/oidmap.c
+++ b/oidmap.c
@@ -2,14 +2,18 @@
#include "oidmap.h"
static int oidmap_neq(const void *hashmap_cmp_fn_data,
- const void *entry, const void *entry_or_key,
+ const struct hashmap_entry *e1,
+ const struct hashmap_entry *e2,
const void *keydata)
{
- const struct oidmap_entry *entry_ = entry;
+ const struct oidmap_entry *a, *b;
+
+ a = container_of(e1, const struct oidmap_entry, internal_entry);
+ b = container_of(e2, const struct oidmap_entry, internal_entry);
+
if (keydata)
- return !oideq(&entry_->oid, (const struct object_id *) keydata);
- return !oideq(&entry_->oid,
- &((const struct oidmap_entry *) entry_or_key)->oid);
+ return !oideq(&a->oid, (const struct object_id *) keydata);
+ return !oideq(&a->oid, &b->oid);
}
void oidmap_init(struct oidmap *map, size_t initial_size)
@@ -21,7 +25,9 @@ void oidmap_free(struct oidmap *map, int free_entries)
{
if (!map)
return;
- hashmap_free(&map->map, free_entries);
+
+ /* TODO: make oidmap itself not depend on struct layouts */
+ hashmap_free_(&map->map, free_entries ? 0 : -1);
}
void *oidmap_get(const struct oidmap *map, const struct object_id *key)
@@ -51,5 +57,5 @@ void *oidmap_put(struct oidmap *map, void *entry)
oidmap_init(map, 0);
hashmap_entry_init(&to_put->internal_entry, oidhash(&to_put->oid));
- return hashmap_put(&map->map, to_put);
+ return hashmap_put(&map->map, &to_put->internal_entry);
}
diff --git a/oidmap.h b/oidmap.h
index 7a939461ff..c66a83ab1d 100644
--- a/oidmap.h
+++ b/oidmap.h
@@ -78,14 +78,16 @@ static inline void oidmap_iter_init(struct oidmap *map, struct oidmap_iter *iter
static inline void *oidmap_iter_next(struct oidmap_iter *iter)
{
- return hashmap_iter_next(&iter->h_iter);
+ /* TODO: this API could be reworked to do compile-time type checks */
+ return (void *)hashmap_iter_next(&iter->h_iter);
}
static inline void *oidmap_iter_first(struct oidmap *map,
struct oidmap_iter *iter)
{
oidmap_iter_init(map, iter);
- return oidmap_iter_next(iter);
+ /* TODO: this API could be reworked to do compile-time type checks */
+ return (void *)oidmap_iter_next(iter);
}
#endif
diff --git a/packfile.c b/packfile.c
index b4c218d78e..355066de17 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1343,7 +1343,7 @@ struct delta_base_cache_key {
};
struct delta_base_cache_entry {
- struct hashmap hash;
+ struct hashmap_entry ent;
struct delta_base_cache_key key;
struct list_head lru;
void *data;
@@ -1363,7 +1363,7 @@ static unsigned int pack_entry_hash(struct packed_git *p, off_t base_offset)
static struct delta_base_cache_entry *
get_delta_base_cache_entry(struct packed_git *p, off_t base_offset)
{
- struct hashmap_entry entry;
+ struct hashmap_entry entry, *e;
struct delta_base_cache_key key;
if (!delta_base_cache.cmpfn)
@@ -1372,7 +1372,8 @@ get_delta_base_cache_entry(struct packed_git *p, off_t base_offset)
hashmap_entry_init(&entry, pack_entry_hash(p, base_offset));
key.p = p;
key.base_offset = base_offset;
- return hashmap_get(&delta_base_cache, &entry, &key);
+ e = hashmap_get(&delta_base_cache, &entry, &key);
+ return e ? container_of(e, struct delta_base_cache_entry, ent) : NULL;
}
static int delta_base_cache_key_eq(const struct delta_base_cache_key *a,
@@ -1382,11 +1383,16 @@ static int delta_base_cache_key_eq(const struct delta_base_cache_key *a,
}
static int delta_base_cache_hash_cmp(const void *unused_cmp_data,
- const void *va, const void *vb,
+ const struct hashmap_entry *va,
+ const struct hashmap_entry *vb,
const void *vkey)
{
- const struct delta_base_cache_entry *a = va, *b = vb;
+ const struct delta_base_cache_entry *a, *b;
const struct delta_base_cache_key *key = vkey;
+
+ a = container_of(va, const struct delta_base_cache_entry, ent);
+ b = container_of(vb, const struct delta_base_cache_entry, ent);
+
if (key)
return !delta_base_cache_key_eq(&a->key, key);
else
@@ -1405,7 +1411,7 @@ static int in_delta_base_cache(struct packed_git *p, off_t base_offset)
*/
static void detach_delta_base_cache_entry(struct delta_base_cache_entry *ent)
{
- hashmap_remove(&delta_base_cache, ent, &ent->key);
+ hashmap_remove(&delta_base_cache, &ent->ent, &ent->key);
list_del(&ent->lru);
delta_base_cached -= ent->size;
free(ent);
@@ -1469,8 +1475,8 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
if (!delta_base_cache.cmpfn)
hashmap_init(&delta_base_cache, delta_base_cache_hash_cmp, NULL, 0);
- hashmap_entry_init(ent, pack_entry_hash(p, base_offset));
- hashmap_add(&delta_base_cache, ent);
+ hashmap_entry_init(&ent->ent, pack_entry_hash(p, base_offset));
+ hashmap_add(&delta_base_cache, &ent->ent);
}
int packed_object_info(struct repository *r, struct packed_git *p,
diff --git a/patch-ids.c b/patch-ids.c
index e8c150d0c9..12aa6d494b 100644
--- a/patch-ids.c
+++ b/patch-ids.c
@@ -36,14 +36,16 @@ int commit_patch_id(struct commit *commit, struct diff_options *options,
* any significance; only that it is non-zero matters.
*/
static int patch_id_neq(const void *cmpfn_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)
{
/* NEEDSWORK: const correctness? */
struct diff_options *opt = (void *)cmpfn_data;
- struct patch_id *a = (void *)entry;
- struct patch_id *b = (void *)entry_or_key;
+ struct patch_id *a, *b;
+
+ a = container_of(eptr, struct patch_id, ent);
+ b = container_of(entry_or_key, struct patch_id, ent);
if (is_null_oid(&a->patch_id) &&
commit_patch_id(a->commit, opt, &a->patch_id, 0, 0))
@@ -69,7 +71,7 @@ int init_patch_ids(struct repository *r, struct patch_ids *ids)
int free_patch_ids(struct patch_ids *ids)
{
- hashmap_free(&ids->patches, 1);
+ hashmap_free_entries(&ids->patches, struct patch_id, ent);
return 0;
}
@@ -83,7 +85,7 @@ static int init_patch_id_entry(struct patch_id *patch,
if (commit_patch_id(commit, &ids->diffopts, &header_only_patch_id, 1, 0))
return -1;
- hashmap_entry_init(patch, oidhash(&header_only_patch_id));
+ hashmap_entry_init(&patch->ent, oidhash(&header_only_patch_id));
return 0;
}
@@ -99,7 +101,7 @@ struct patch_id *has_commit_patch_id(struct commit *commit,
if (init_patch_id_entry(&patch, commit, ids))
return NULL;
- return hashmap_get(&ids->patches, &patch, NULL);
+ return hashmap_get_entry(&ids->patches, &patch, ent, NULL);
}
struct patch_id *add_commit_patch_id(struct commit *commit,
@@ -116,6 +118,6 @@ struct patch_id *add_commit_patch_id(struct commit *commit,
return NULL;
}
- hashmap_add(&ids->patches, key);
+ hashmap_add(&ids->patches, &key->ent);
return key;
}
diff --git a/range-diff.c b/range-diff.c
index f2fc1e02c2..7fed5a3b4b 100644
--- a/range-diff.c
+++ b/range-diff.c
@@ -218,8 +218,8 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)
util->i = i;
util->patch = a->items[i].string;
util->diff = util->patch + util->diff_offset;
- hashmap_entry_init(util, strhash(util->diff));
- hashmap_add(&map, util);
+ hashmap_entry_init(&util->e, strhash(util->diff));
+ hashmap_add(&map, &util->e);
}
/* Now try to find exact matches in b */
@@ -229,8 +229,8 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)
util->i = i;
util->patch = b->items[i].string;
util->diff = util->patch + util->diff_offset;
- hashmap_entry_init(util, strhash(util->diff));
- other = hashmap_remove(&map, util, NULL);
+ hashmap_entry_init(&util->e, strhash(util->diff));
+ other = hashmap_remove_entry(&map, util, e, NULL);
if (other) {
if (other->matching >= 0)
BUG("already assigned!");
@@ -240,7 +240,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)
}
}
- hashmap_free(&map, 0);
+ hashmap_free(&map);
}
static void diffsize_consume(void *data, char *line, unsigned long len)
diff --git a/ref-filter.c b/ref-filter.c
index 220e9bd74a..6867e33648 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -79,17 +79,20 @@ static struct expand_data {
} oi, oi_deref;
struct ref_to_worktree_entry {
- struct hashmap_entry ent; /* must be the first member! */
+ struct hashmap_entry ent;
struct worktree *wt; /* key is wt->head_ref */
};
static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,
- const void *existing_hashmap_entry_to_test,
- const void *key,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *kptr,
const void *keydata_aka_refname)
{
- const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
- const struct ref_to_worktree_entry *k = key;
+ const struct ref_to_worktree_entry *e, *k;
+
+ e = container_of(eptr, const struct ref_to_worktree_entry, ent);
+ k = container_of(kptr, const struct ref_to_worktree_entry, ent);
+
return strcmp(e->wt->head_ref,
keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);
}
@@ -1565,9 +1568,10 @@ static void populate_worktree_map(struct hashmap *map, struct worktree **worktre
struct ref_to_worktree_entry *entry;
entry = xmalloc(sizeof(*entry));
entry->wt = worktrees[i];
- hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
+ hashmap_entry_init(&entry->ent,
+ strhash(worktrees[i]->head_ref));
- hashmap_add(map, entry);
+ hashmap_add(map, &entry->ent);
}
}
}
@@ -1584,18 +1588,20 @@ static void lazy_init_worktree_map(void)
static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
{
- struct hashmap_entry entry;
+ struct hashmap_entry entry, *e;
struct ref_to_worktree_entry *lookup_result;
lazy_init_worktree_map();
hashmap_entry_init(&entry, strhash(ref->refname));
- lookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);
+ e = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);
- if (lookup_result)
- return xstrdup(lookup_result->wt->path);
- else
+ if (!e)
return xstrdup("");
+
+ lookup_result = container_of(e, struct ref_to_worktree_entry, ent);
+
+ return xstrdup(lookup_result->wt->path);
}
/*
@@ -2166,7 +2172,8 @@ void ref_array_clear(struct ref_array *array)
used_atom_cnt = 0;
if (ref_to_worktree_map.worktrees) {
- hashmap_free(&(ref_to_worktree_map.map), 1);
+ hashmap_free_entries(&(ref_to_worktree_map.map),
+ struct ref_to_worktree_entry, ent);
free_worktrees(ref_to_worktree_map.worktrees);
ref_to_worktree_map.worktrees = NULL;
}
diff --git a/refs.c b/refs.c
index cd297ee4bd..1ab0bb54d3 100644
--- a/refs.c
+++ b/refs.c
@@ -1772,7 +1772,7 @@ int resolve_gitlink_ref(const char *submodule, const char *refname,
struct ref_store_hash_entry
{
- struct hashmap_entry ent; /* must be the first member! */
+ struct hashmap_entry ent;
struct ref_store *refs;
@@ -1781,11 +1781,16 @@ struct ref_store_hash_entry
};
static int ref_store_hash_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 *keydata)
{
- const struct ref_store_hash_entry *e1 = entry, *e2 = entry_or_key;
- const char *name = keydata ? keydata : e2->name;
+ const struct ref_store_hash_entry *e1, *e2;
+ const char *name;
+
+ e1 = container_of(eptr, const struct ref_store_hash_entry, ent);
+ e2 = container_of(entry_or_key, const struct ref_store_hash_entry, ent);
+ name = keydata ? keydata : e2->name;
return strcmp(e1->name, name);
}
@@ -1796,7 +1801,7 @@ static struct ref_store_hash_entry *alloc_ref_store_hash_entry(
struct ref_store_hash_entry *entry;
FLEX_ALLOC_STR(entry, name, name);
- hashmap_entry_init(entry, strhash(name));
+ hashmap_entry_init(&entry->ent, strhash(name));
entry->refs = refs;
return entry;
}
@@ -1815,12 +1820,15 @@ static struct ref_store *lookup_ref_store_map(struct hashmap *map,
const char *name)
{
struct ref_store_hash_entry *entry;
+ unsigned int hash;
if (!map->tablesize)
/* It's initialized on demand in register_ref_store(). */
return NULL;
- entry = hashmap_get_from_hash(map, strhash(name), name);
+ hash = strhash(name);
+ entry = hashmap_get_entry_from_hash(map, hash, name,
+ struct ref_store_hash_entry, ent);
return entry ? entry->refs : NULL;
}
@@ -1863,10 +1871,13 @@ static void register_ref_store_map(struct hashmap *map,
struct ref_store *refs,
const char *name)
{
+ struct ref_store_hash_entry *entry;
+
if (!map->tablesize)
hashmap_init(map, ref_store_hash_cmp, NULL, 0);
- if (hashmap_put(map, alloc_ref_store_hash_entry(name, refs)))
+ entry = alloc_ref_store_hash_entry(name, refs);
+ if (hashmap_put(map, &entry->ent))
BUG("%s ref_store '%s' initialized twice", type, name);
}
diff --git a/remote.c b/remote.c
index e50f7602ed..5c4666b53a 100644
--- a/remote.c
+++ b/remote.c
@@ -111,14 +111,16 @@ struct remotes_hash_key {
};
static int remotes_hash_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 *keydata)
{
- const struct remote *a = entry;
- const struct remote *b = entry_or_key;
+ const struct remote *a, *b;
const struct remotes_hash_key *key = keydata;
+ a = container_of(eptr, const struct remote, ent);
+ b = container_of(entry_or_key, const struct remote, ent);
+
if (key)
return strncmp(a->name, key->str, key->len) || a->name[key->len];
else
@@ -135,7 +137,7 @@ static struct remote *make_remote(const char *name, int len)
{
struct remote *ret, *replaced;
struct remotes_hash_key lookup;
- struct hashmap_entry lookup_entry;
+ struct hashmap_entry lookup_entry, *e;
if (!len)
len = strlen(name);
@@ -145,8 +147,9 @@ static struct remote *make_remote(const char *name, int len)
lookup.len = len;
hashmap_entry_init(&lookup_entry, memhash(name, len));
- if ((ret = hashmap_get(&remotes_hash, &lookup_entry, &lookup)) != NULL)
- return ret;
+ e = hashmap_get(&remotes_hash, &lookup_entry, &lookup);
+ if (e)
+ return container_of(e, struct remote, ent);
ret = xcalloc(1, sizeof(struct remote));
ret->prune = -1; /* unspecified */
@@ -158,8 +161,8 @@ static struct remote *make_remote(const char *name, int len)
ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
remotes[remotes_nr++] = ret;
- hashmap_entry_init(ret, lookup_entry.hash);
- replaced = hashmap_put(&remotes_hash, ret);
+ hashmap_entry_init(&ret->ent, lookup_entry.hash);
+ replaced = hashmap_put_entry(&remotes_hash, ret, ent);
assert(replaced == NULL); /* no previous entry overwritten */
return ret;
}
diff --git a/remote.h b/remote.h
index 83e885672b..0e1d2b245b 100644
--- a/remote.h
+++ b/remote.h
@@ -14,7 +14,7 @@ enum {
};
struct remote {
- struct hashmap_entry ent; /* must be first */
+ struct hashmap_entry ent;
const char *name;
int origin, configured_in_repo;
diff --git a/revision.c b/revision.c
index 0fc0b425f6..0e39b2b8a5 100644
--- a/revision.c
+++ b/revision.c
@@ -108,30 +108,34 @@ struct path_and_oids_entry {
};
static int path_and_oids_cmp(const void *hashmap_cmp_fn_data,
- const struct path_and_oids_entry *e1,
- const struct path_and_oids_entry *e2,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
const void *keydata)
{
+ const struct path_and_oids_entry *e1, *e2;
+
+ e1 = container_of(eptr, const struct path_and_oids_entry, ent);
+ e2 = container_of(entry_or_key, const struct path_and_oids_entry, ent);
+
return strcmp(e1->path, e2->path);
}
static void paths_and_oids_init(struct hashmap *map)
{
- hashmap_init(map, (hashmap_cmp_fn) path_and_oids_cmp, NULL, 0);
+ hashmap_init(map, path_and_oids_cmp, NULL, 0);
}
static void paths_and_oids_clear(struct hashmap *map)
{
struct hashmap_iter iter;
struct path_and_oids_entry *entry;
- hashmap_iter_init(map, &iter);
- while ((entry = (struct path_and_oids_entry *)hashmap_iter_next(&iter))) {
+ hashmap_for_each_entry(map, &iter, entry, ent /* member name */) {
oidset_clear(&entry->trees);
free(entry->path);
}
- hashmap_free(map, 1);
+ hashmap_free_entries(map, struct path_and_oids_entry, ent);
}
static void paths_and_oids_insert(struct hashmap *map,
@@ -142,18 +146,19 @@ static void paths_and_oids_insert(struct hashmap *map,
struct path_and_oids_entry key;
struct path_and_oids_entry *entry;
- hashmap_entry_init(&key, hash);
+ hashmap_entry_init(&key.ent, hash);
/* use a shallow copy for the lookup */
key.path = (char *)path;
oidset_init(&key.trees, 0);
- if (!(entry = (struct path_and_oids_entry *)hashmap_get(map, &key, NULL))) {
+ entry = hashmap_get_entry(map, &key, ent, NULL);
+ if (!entry) {
entry = xcalloc(1, sizeof(struct path_and_oids_entry));
- hashmap_entry_init(entry, hash);
+ hashmap_entry_init(&entry->ent, hash);
entry->path = xstrdup(key.path);
oidset_init(&entry->trees, 16);
- hashmap_put(map, entry);
+ hashmap_put(map, &entry->ent);
}
oidset_insert(&entry->trees, oid);
@@ -236,8 +241,7 @@ void mark_trees_uninteresting_sparse(struct repository *r,
add_children_by_path(r, tree, &map);
}
- hashmap_iter_init(&map, &map_iter);
- while ((entry = hashmap_iter_next(&map_iter)))
+ hashmap_for_each_entry(&map, &map_iter, entry, ent /* member name */)
mark_trees_uninteresting_sparse(r, &entry->trees);
paths_and_oids_clear(&map);
diff --git a/sequencer.c b/sequencer.c
index 5670bd7e7a..9d5964fd81 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -4397,9 +4397,14 @@ struct labels_entry {
char label[FLEX_ARRAY];
};
-static int labels_cmp(const void *fndata, const struct labels_entry *a,
- const struct labels_entry *b, const void *key)
+static int labels_cmp(const void *fndata, const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key, const void *key)
{
+ const struct labels_entry *a, *b;
+
+ a = container_of(eptr, const struct labels_entry, entry);
+ b = container_of(entry_or_key, const struct labels_entry, entry);
+
return key ? strcmp(a->label, key) : strcmp(a->label, b->label);
}
@@ -4495,8 +4500,8 @@ static const char *label_oid(struct object_id *oid, const char *label,
}
FLEX_ALLOC_STR(labels_entry, label, label);
- hashmap_entry_init(labels_entry, strihash(label));
- hashmap_add(&state->labels, labels_entry);
+ hashmap_entry_init(&labels_entry->entry, strihash(label));
+ hashmap_add(&state->labels, &labels_entry->entry);
FLEX_ALLOC_STR(string_entry, string, label);
oidcpy(&string_entry->entry.oid, oid);
@@ -4531,7 +4536,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
oidmap_init(&commit2todo, 0);
oidmap_init(&state.commit2label, 0);
- hashmap_init(&state.labels, (hashmap_cmp_fn) labels_cmp, NULL, 0);
+ hashmap_init(&state.labels, labels_cmp, NULL, 0);
strbuf_init(&state.buf, 32);
if (revs->cmdline.nr && (revs->cmdline.rev[0].flags & BOTTOM)) {
@@ -4726,7 +4731,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
oidmap_free(&commit2todo, 1);
oidmap_free(&state.commit2label, 1);
- hashmap_free(&state.labels, 1);
+ hashmap_free_entries(&state.labels, struct labels_entry, entry);
strbuf_release(&state.buf);
return 0;
@@ -5097,9 +5102,15 @@ struct subject2item_entry {
};
static int subject2item_cmp(const void *fndata,
- const struct subject2item_entry *a,
- const struct subject2item_entry *b, const void *key)
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
+ const void *key)
{
+ const struct subject2item_entry *a, *b;
+
+ a = container_of(eptr, const struct subject2item_entry, entry);
+ b = container_of(entry_or_key, const struct subject2item_entry, entry);
+
return key ? strcmp(a->subject, key) : strcmp(a->subject, b->subject);
}
@@ -5132,8 +5143,7 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
* In that case, last[i] will indicate the index of the latest item to
* be moved to appear after the i'th.
*/
- hashmap_init(&subject2item, (hashmap_cmp_fn) subject2item_cmp,
- NULL, todo_list->nr);
+ hashmap_init(&subject2item, subject2item_cmp, NULL, todo_list->nr);
ALLOC_ARRAY(next, todo_list->nr);
ALLOC_ARRAY(tail, todo_list->nr);
ALLOC_ARRAY(subjects, todo_list->nr);
@@ -5176,8 +5186,11 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
break;
}
- if ((entry = hashmap_get_from_hash(&subject2item,
- strhash(p), p)))
+ entry = hashmap_get_entry_from_hash(&subject2item,
+ strhash(p), p,
+ struct subject2item_entry,
+ entry);
+ if (entry)
/* found by title */
i2 = entry->i;
else if (!strchr(p, ' ') &&
@@ -5211,8 +5224,9 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
strhash(subject), subject)) {
FLEX_ALLOC_MEM(entry, subject, subject, subject_len);
entry->i = i;
- hashmap_entry_init(entry, strhash(entry->subject));
- hashmap_put(&subject2item, entry);
+ hashmap_entry_init(&entry->entry,
+ strhash(entry->subject));
+ hashmap_put(&subject2item, &entry->entry);
}
}
@@ -5246,7 +5260,7 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
for (i = 0; i < todo_list->nr; i++)
free(subjects[i]);
free(subjects);
- hashmap_free(&subject2item, 1);
+ hashmap_free_entries(&subject2item, struct subject2item_entry, entry);
clear_commit_todo_item(&commit_todo);
diff --git a/sub-process.c b/sub-process.c
index 3f4af93555..1b1af9dcbd 100644
--- a/sub-process.c
+++ b/sub-process.c
@@ -6,12 +6,14 @@
#include "pkt-line.h"
int cmd2process_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 subprocess_entry *e1 = entry;
- const struct subprocess_entry *e2 = entry_or_key;
+ const struct subprocess_entry *e1, *e2;
+
+ e1 = container_of(eptr, const struct subprocess_entry, ent);
+ e2 = container_of(entry_or_key, const struct subprocess_entry, ent);
return strcmp(e1->cmd, e2->cmd);
}
@@ -20,9 +22,9 @@ struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const ch
{
struct subprocess_entry key;
- hashmap_entry_init(&key, strhash(cmd));
+ hashmap_entry_init(&key.ent, strhash(cmd));
key.cmd = cmd;
- return hashmap_get(hashmap, &key, NULL);
+ return hashmap_get_entry(hashmap, &key, ent, NULL);
}
int subprocess_read_status(int fd, struct strbuf *status)
@@ -58,7 +60,7 @@ void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry)
kill(entry->process.pid, SIGTERM);
finish_command(&entry->process);
- hashmap_remove(hashmap, entry, NULL);
+ hashmap_remove(hashmap, &entry->ent, NULL);
}
static void subprocess_exit_handler(struct child_process *process)
@@ -96,7 +98,7 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co
return err;
}
- hashmap_entry_init(entry, strhash(cmd));
+ hashmap_entry_init(&entry->ent, strhash(cmd));
err = startfn(entry);
if (err) {
@@ -105,7 +107,7 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co
return err;
}
- hashmap_add(hashmap, entry);
+ hashmap_add(hashmap, &entry->ent);
return 0;
}
diff --git a/sub-process.h b/sub-process.h
index 5c182fad98..e85f21fa1a 100644
--- a/sub-process.h
+++ b/sub-process.h
@@ -24,7 +24,7 @@
/* Members should not be accessed directly. */
struct subprocess_entry {
- struct hashmap_entry ent; /* must be the first member! */
+ struct hashmap_entry ent;
const char *cmd;
struct child_process process;
};
@@ -43,8 +43,8 @@ struct subprocess_capability {
/* Function to test two subprocess hashmap entries for equality. */
int cmd2process_cmp(const void *unused_cmp_data,
- const void *e1,
- const void *e2,
+ const struct hashmap_entry *e,
+ const struct hashmap_entry *entry_or_key,
const void *unused_keydata);
/*
diff --git a/submodule-config.c b/submodule-config.c
index 4264ee216f..401a9b2382 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -38,24 +38,28 @@ enum lookup_type {
};
static int config_path_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 submodule_entry *a = entry;
- const struct submodule_entry *b = entry_or_key;
+ const struct submodule_entry *a, *b;
+
+ a = container_of(eptr, const struct submodule_entry, ent);
+ b = container_of(entry_or_key, const struct submodule_entry, ent);
return strcmp(a->config->path, b->config->path) ||
!oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
}
static int config_name_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 submodule_entry *a = entry;
- const struct submodule_entry *b = entry_or_key;
+ const struct submodule_entry *a, *b;
+
+ a = container_of(eptr, const struct submodule_entry, ent);
+ b = container_of(entry_or_key, const struct submodule_entry, ent);
return strcmp(a->config->name, b->config->name) ||
!oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
@@ -95,12 +99,12 @@ static void submodule_cache_clear(struct submodule_cache *cache)
* allocation of struct submodule entries. Each is allocated by
* their .gitmodules blob sha1 and submodule name.
*/
- hashmap_iter_init(&cache->for_name, &iter);
- while ((entry = hashmap_iter_next(&iter)))
+ hashmap_for_each_entry(&cache->for_name, &iter, entry,
+ ent /* member name */)
free_one_config(entry);
- hashmap_free(&cache->for_path, 1);
- hashmap_free(&cache->for_name, 1);
+ hashmap_free_entries(&cache->for_path, struct submodule_entry, ent);
+ hashmap_free_entries(&cache->for_name, struct submodule_entry, ent);
cache->initialized = 0;
cache->gitmodules_read = 0;
}
@@ -123,9 +127,9 @@ static void cache_put_path(struct submodule_cache *cache,
unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
submodule->path);
struct submodule_entry *e = xmalloc(sizeof(*e));
- hashmap_entry_init(e, hash);
+ hashmap_entry_init(&e->ent, hash);
e->config = submodule;
- hashmap_put(&cache->for_path, e);
+ hashmap_put(&cache->for_path, &e->ent);
}
static void cache_remove_path(struct submodule_cache *cache,
@@ -135,9 +139,9 @@ static void cache_remove_path(struct submodule_cache *cache,
submodule->path);
struct submodule_entry e;
struct submodule_entry *removed;
- hashmap_entry_init(&e, hash);
+ hashmap_entry_init(&e.ent, hash);
e.config = submodule;
- removed = hashmap_remove(&cache->for_path, &e, NULL);
+ removed = hashmap_remove_entry(&cache->for_path, &e, ent, NULL);
free(removed);
}
@@ -147,9 +151,9 @@ static void cache_add(struct submodule_cache *cache,
unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
submodule->name);
struct submodule_entry *e = xmalloc(sizeof(*e));
- hashmap_entry_init(e, hash);
+ hashmap_entry_init(&e->ent, hash);
e->config = submodule;
- hashmap_add(&cache->for_name, e);
+ hashmap_add(&cache->for_name, &e->ent);
}
static const struct submodule *cache_lookup_path(struct submodule_cache *cache,
@@ -163,10 +167,10 @@ static const struct submodule *cache_lookup_path(struct submodule_cache *cache,
oidcpy(&key_config.gitmodules_oid, gitmodules_oid);
key_config.path = path;
- hashmap_entry_init(&key, hash);
+ hashmap_entry_init(&key.ent, hash);
key.config = &key_config;
- entry = hashmap_get(&cache->for_path, &key, NULL);
+ entry = hashmap_get_entry(&cache->for_path, &key, ent, NULL);
if (entry)
return entry->config;
return NULL;
@@ -183,10 +187,10 @@ static struct submodule *cache_lookup_name(struct submodule_cache *cache,
oidcpy(&key_config.gitmodules_oid, gitmodules_oid);
key_config.name = name;
- hashmap_entry_init(&key, hash);
+ hashmap_entry_init(&key.ent, hash);
key.config = &key_config;
- entry = hashmap_get(&cache->for_name, &key, NULL);
+ entry = hashmap_get_entry(&cache->for_name, &key, ent, NULL);
if (entry)
return entry->config;
return NULL;
@@ -550,7 +554,9 @@ static const struct submodule *config_from(struct submodule_cache *cache,
struct hashmap_iter iter;
struct submodule_entry *entry;
- entry = hashmap_iter_first(&cache->for_name, &iter);
+ entry = hashmap_iter_first_entry(&cache->for_name, &iter,
+ struct submodule_entry,
+ ent /* member name */);
if (!entry)
return NULL;
return entry->config;
diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c
index aaf17b0ddf..f38706216f 100644
--- a/t/helper/test-hashmap.c
+++ b/t/helper/test-hashmap.c
@@ -5,6 +5,7 @@
struct test_entry
{
+ int padding; /* hashmap entry no longer needs to be the first member */
struct hashmap_entry ent;
/* key and value as two \0-terminated strings */
char key[FLEX_ARRAY];
@@ -16,15 +17,17 @@ static const char *get_value(const struct test_entry *e)
}
static int test_entry_cmp(const void *cmp_data,
- const void *entry,
- const void *entry_or_key,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
const void *keydata)
{
const int ignore_case = cmp_data ? *((int *)cmp_data) : 0;
- const struct test_entry *e1 = entry;
- const struct test_entry *e2 = entry_or_key;
+ const struct test_entry *e1, *e2;
const char *key = keydata;
+ e1 = container_of(eptr, const struct test_entry, ent);
+ e2 = container_of(entry_or_key, const struct test_entry, ent);
+
if (ignore_case)
return strcasecmp(e1->key, key ? key : e2->key);
else
@@ -37,7 +40,7 @@ static struct test_entry *alloc_test_entry(unsigned int hash,
size_t klen = strlen(key);
size_t vlen = strlen(value);
struct test_entry *entry = xmalloc(st_add4(sizeof(*entry), klen, vlen, 2));
- hashmap_entry_init(entry, hash);
+ hashmap_entry_init(&entry->ent, hash);
memcpy(entry->key, key, klen + 1);
memcpy(entry->key + klen + 1, value, vlen + 1);
return entry;
@@ -103,11 +106,11 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
/* add entries */
for (i = 0; i < TEST_SIZE; i++) {
- hashmap_entry_init(entries[i], hashes[i]);
- hashmap_add(&map, entries[i]);
+ hashmap_entry_init(&entries[i]->ent, hashes[i]);
+ hashmap_add(&map, &entries[i]->ent);
}
- hashmap_free(&map, 0);
+ hashmap_free(&map);
}
} else {
/* test map lookups */
@@ -116,8 +119,8 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
/* fill the map (sparsely if specified) */
j = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE;
for (i = 0; i < j; i++) {
- hashmap_entry_init(entries[i], hashes[i]);
- hashmap_add(&map, entries[i]);
+ hashmap_entry_init(&entries[i]->ent, hashes[i]);
+ hashmap_add(&map, &entries[i]->ent);
}
for (j = 0; j < rounds; j++) {
@@ -127,7 +130,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
}
}
- hashmap_free(&map, 0);
+ hashmap_free(&map);
}
}
@@ -179,7 +182,7 @@ int cmd__hashmap(int argc, const char **argv)
entry = alloc_test_entry(hash, p1, p2);
/* add to hashmap */
- hashmap_add(&map, entry);
+ hashmap_add(&map, &entry->ent);
} else if (!strcmp("put", cmd) && p1 && p2) {
@@ -187,43 +190,44 @@ int cmd__hashmap(int argc, const char **argv)
entry = alloc_test_entry(hash, p1, p2);
/* add / replace entry */
- entry = hashmap_put(&map, entry);
+ entry = hashmap_put_entry(&map, entry, ent);
/* print and free replaced entry, if any */
puts(entry ? get_value(entry) : "NULL");
free(entry);
} else if (!strcmp("get", cmd) && p1) {
-
/* lookup entry in hashmap */
- entry = hashmap_get_from_hash(&map, hash, p1);
+ entry = hashmap_get_entry_from_hash(&map, hash, p1,
+ struct test_entry, ent);
/* print result */
if (!entry)
puts("NULL");
- while (entry) {
+ hashmap_for_each_entry_from(&map, entry, ent)
puts(get_value(entry));
- entry = hashmap_get_next(&map, entry);
- }
} else if (!strcmp("remove", cmd) && p1) {
/* setup static key */
struct hashmap_entry key;
+ struct hashmap_entry *rm;
hashmap_entry_init(&key, hash);
/* remove entry from hashmap */
- entry = hashmap_remove(&map, &key, p1);
+ rm = hashmap_remove(&map, &key, p1);
+ entry = rm ? container_of(rm, struct test_entry, ent)
+ : NULL;
/* print result and free entry*/
puts(entry ? get_value(entry) : "NULL");
free(entry);
} else if (!strcmp("iterate", cmd)) {
-
struct hashmap_iter iter;
- hashmap_iter_init(&map, &iter);
- while ((entry = hashmap_iter_next(&iter)))
+
+ hashmap_for_each_entry(&map, &iter, entry,
+ ent /* member name */)
printf("%s %s\n", entry->key, get_value(entry));
} else if (!strcmp("size", cmd)) {
@@ -258,6 +262,6 @@ int cmd__hashmap(int argc, const char **argv)
}
strbuf_release(&line);
- hashmap_free(&map, 1);
+ hashmap_free_entries(&map, struct test_entry, ent);
return 0;
}
diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c
index b99a37080d..cd1b4c9736 100644
--- a/t/helper/test-lazy-init-name-hash.c
+++ b/t/helper/test-lazy-init-name-hash.c
@@ -41,17 +41,13 @@ static void dump_run(void)
die("non-threaded code path used");
}
- dir = hashmap_iter_first(&the_index.dir_hash, &iter_dir);
- while (dir) {
+ hashmap_for_each_entry(&the_index.dir_hash, &iter_dir, dir,
+ ent /* member name */)
printf("dir %08x %7d %s\n", dir->ent.hash, dir->nr, dir->name);
- dir = hashmap_iter_next(&iter_dir);
- }
- ce = hashmap_iter_first(&the_index.name_hash, &iter_cache);
- while (ce) {
+ hashmap_for_each_entry(&the_index.name_hash, &iter_cache, ce,
+ ent /* member name */)
printf("name %08x %s\n", ce->ent.hash, ce->name);
- ce = hashmap_iter_next(&iter_cache);
- }
discard_cache();
}