hashmap: add simplified hashmap_get_from_hash() API

Hashmap entries are typically looked up by just a key. The hashmap_get() API expects an initialized entry structure instead, to support compound keys. This flexibility is currently only needed by find_dir_entry() in name-hash.c (and compat/win32/fscache.c in the msysgit fork). All other (currently five) call sites of hashmap_get() have to set up a near emtpy entry structure, resulting in duplicate code like this: struct hashmap_entry keyentry; hashmap_entry_init(&keyentry, hash(key)); return hashmap_get(map, &keyentry, key); Add a hashmap_get_from_hash() API that allows hashmap lookups by just specifying the key and its hash code, i.e.: return hashmap_get_from_hash(map, hash(key), key); Signed-off-by: Karsten Blees <blees@dcon.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Karsten Blees committed Jul 3, 2014 at 00:22 UTC ab73a9d119240b0b908ccb9edd19b8e536ce29b9
6 files changed +31 -18
Documentation/technical/api-hashmap.txt
+14
@@ -118,6 +118,20 @@ hashmap_entry) that has at least been initialized with the proper hash code
118 If an entry with matching hash code is found, `key` and `keydata` are passed
119 to `hashmap_cmp_fn` to decide whether the entry matches the key.
120
121 +`void *hashmap_get_from_hash(const struct hashmap *map, unsigned int hash, const void *keydata)`::
122 +
123 + Returns the hashmap entry for the specified hash code and key data,
124 + or NULL if not found.
125 ++
126 +`map` is the hashmap structure.
127 ++
128 +`hash` is the hash code of the entry to look up.
129 ++
130 +If an entry with matching hash code is found, `keydata` is passed to
131 +`hashmap_cmp_fn` to decide whether the entry matches the key. The
132 +`entry_or_key` parameter points to a bogus hashmap_entry structure that
133 +should not be used in the comparison.
134 +
135 `void *hashmap_get_next(const struct hashmap *map, const void *entry)`::
136
137 Returns the next equal hashmap entry, or NULL if not found. This can be
builtin/describe.c
+1 -3
@@ -58,9 +58,7 @@ static int commit_name_cmp(const struct commit_name *cn1,
58
59 static inline struct commit_name *find_commit_name(const unsigned char *peeled)
60 {
61 - struct commit_name key;
62 - hashmap_entry_init(&key, sha1hash(peeled));
63 - return hashmap_get(&names, &key, peeled);
61 + return hashmap_get_from_hash(&names, sha1hash(peeled), peeled);
62 }
63
64 static int replace_name(struct commit_name *e,
diffcore-rename.c
+3 -4
@@ -257,15 +257,14 @@ static int find_identical_files(struct hashmap *srcs,
257 int renames = 0;
258
259 struct diff_filespec *target = rename_dst[dst_index].two;
260 - struct file_similarity *p, *best, dst;
260 + struct file_similarity *p, *best = NULL;
261 int i = 100, best_score = -1;
262
263 /*
264 * Find the best source match for specified destination.
265 */
266 - best = NULL;
267 - hashmap_entry_init(&dst, hash_filespec(target));
268 - for (p = hashmap_get(srcs, &dst, NULL); p; p = hashmap_get_next(srcs, p)) {
266 + p = hashmap_get_from_hash(srcs, hash_filespec(target), NULL);
267 + for (; p; p = hashmap_get_next(srcs, p)) {
268 int score;
269 struct diff_filespec *source = p->filespec;
270
hashmap.h
+8
@@ -68,6 +68,14 @@ extern void *hashmap_put(struct hashmap *map, void *entry);
68 extern void *hashmap_remove(struct hashmap *map, const void *key,
69 const void *keydata);
70
71 +static inline void *hashmap_get_from_hash(const struct hashmap *map,
72 + unsigned int hash, const void *keydata)
73 +{
74 + struct hashmap_entry key;
75 + hashmap_entry_init(&key, hash);
76 + return hashmap_get(map, &key, keydata);
77 +}
78 +
79 /* hashmap_iter functions */
80
81 extern void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter);
name-hash.c
+2 -3
@@ -213,12 +213,11 @@ struct cache_entry *index_dir_exists(struct index_state *istate, const char *nam
213 struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase)
214 {
215 struct cache_entry *ce;
216 - struct hashmap_entry key;
216
217 lazy_init_name_hash(istate);
218
220 - hashmap_entry_init(&key, memihash(name, namelen));
221 - ce = hashmap_get(&istate->name_hash, &key, NULL);
219 + ce = hashmap_get_from_hash(&istate->name_hash,
220 + memihash(name, namelen), NULL);
221 while (ce) {
222 if (same_name(ce, name, namelen, icase))
223 return ce;
test-hashmap.c
+3 -8
@@ -115,9 +115,8 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
115
116 for (j = 0; j < rounds; j++) {
117 for (i = 0; i < TEST_SIZE; i++) {
118 - struct hashmap_entry key;
119 - hashmap_entry_init(&key, hashes[i]);
120 - hashmap_get(&map, &key, entries[i]->key);
118 + hashmap_get_from_hash(&map, hashes[i],
119 + entries[i]->key);
120 }
121 }
122
@@ -199,12 +198,8 @@ int main(int argc, char *argv[])
198
199 } else if (!strcmp("get", cmd) && l1) {
200
202 - /* setup static key */
203 - struct hashmap_entry key;
204 - hashmap_entry_init(&key, hash);
205 -
201 /* lookup entry in hashmap */
207 - entry = hashmap_get(&map, &key, p1);
202 + entry = hashmap_get_from_hash(&map, hash, p1);
203
204 /* print result */
205 if (!entry)