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:
commit
5efabc7ed9
24
attr.c
24
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;
|
||||
}
|
||||
|
25
blame.c
25
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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
24
config.c
24
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;
|
||||
|
16
contrib/coccinelle/hashmap.cocci
Normal file
16
contrib/coccinelle/hashmap.cocci
Normal 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
31
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++)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
58
hashmap.c
58
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;
|
||||
}
|
||||
|
176
hashmap.h
176
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,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.
|
||||
*
|
||||
|
@ -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);
|
||||
|
57
name-hash.c
57
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);
|
||||
}
|
||||
|
20
oidmap.c
20
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);
|
||||
}
|
||||
|
6
oidmap.h
6
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
|
||||
|
22
packfile.c
22
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,
|
||||
|
18
patch-ids.c
18
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;
|
||||
}
|
||||
|
10
range-diff.c
10
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)
|
||||
|
33
ref-filter.c
33
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;
|
||||
}
|
||||
|
25
refs.c
25
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);
|
||||
}
|
||||
|
||||
|
21
remote.c
21
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;
|
||||
}
|
||||
|
2
remote.h
2
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;
|
||||
|
28
revision.c
28
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);
|
||||
|
44
sequencer.c
44
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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user