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
This commit is contained in:
Junio C Hamano 2019-10-15 13:48:01 +09:00
commit 5efabc7ed9
31 changed files with 667 additions and 381 deletions

24
attr.c
View File

@ -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;
}

25
blame.c
View File

@ -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;
}

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
...>}

31
diff.c
View File

@ -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++)

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

176
hashmap.h
View File

@ -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,16 +418,74 @@ 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);
return hashmap_iter_next(iter);
}
/*
* 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.
*

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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,

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}

25
refs.c
View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
/*

View File

@ -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;

View File

@ -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;
}

View File

@ -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();
}