Skip to content

Commit ae20bf1

Browse files
newrengitster
authored andcommitted
strmap: new utility functions
Add strmap as a new struct and associated utility functions, specifically for hashmaps that map strings to some value. The API is taken directly from Peff's proposal at https://lore.kernel.org/git/[email protected]/ Note that similar string-list, I have a strdup_strings setting. However, unlike string-list, strmap_init() does not take a parameter for this setting and instead automatically sets it to 1; callers who want to control this detail need to instead call strmap_init_with_options(). (Future patches will add additional parameters to strmap_init_with_options()). Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6da1a25 commit ae20bf1

File tree

3 files changed

+165
-0
lines changed

3 files changed

+165
-0
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,7 @@ LIB_OBJS += stable-qsort.o
10001000
LIB_OBJS += strbuf.o
10011001
LIB_OBJS += streaming.o
10021002
LIB_OBJS += string-list.o
1003+
LIB_OBJS += strmap.o
10031004
LIB_OBJS += strvec.o
10041005
LIB_OBJS += sub-process.o
10051006
LIB_OBJS += submodule-config.o

strmap.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#include "git-compat-util.h"
2+
#include "strmap.h"
3+
4+
int cmp_strmap_entry(const void *hashmap_cmp_fn_data,
5+
const struct hashmap_entry *entry1,
6+
const struct hashmap_entry *entry2,
7+
const void *keydata)
8+
{
9+
const struct strmap_entry *e1, *e2;
10+
11+
e1 = container_of(entry1, const struct strmap_entry, ent);
12+
e2 = container_of(entry2, const struct strmap_entry, ent);
13+
return strcmp(e1->key, e2->key);
14+
}
15+
16+
static struct strmap_entry *find_strmap_entry(struct strmap *map,
17+
const char *str)
18+
{
19+
struct strmap_entry entry;
20+
hashmap_entry_init(&entry.ent, strhash(str));
21+
entry.key = str;
22+
return hashmap_get_entry(&map->map, &entry, ent, NULL);
23+
}
24+
25+
void strmap_init(struct strmap *map)
26+
{
27+
strmap_init_with_options(map, 1);
28+
}
29+
30+
void strmap_init_with_options(struct strmap *map,
31+
int strdup_strings)
32+
{
33+
hashmap_init(&map->map, cmp_strmap_entry, NULL, 0);
34+
map->strdup_strings = strdup_strings;
35+
}
36+
37+
static void strmap_free_entries_(struct strmap *map, int free_values)
38+
{
39+
struct hashmap_iter iter;
40+
struct strmap_entry *e;
41+
42+
if (!map)
43+
return;
44+
45+
/*
46+
* We need to iterate over the hashmap entries and free
47+
* e->key and e->value ourselves; hashmap has no API to
48+
* take care of that for us. Since we're already iterating over
49+
* the hashmap, though, might as well free e too and avoid the need
50+
* to make some call into the hashmap API to do that.
51+
*/
52+
hashmap_for_each_entry(&map->map, &iter, e, ent) {
53+
if (free_values)
54+
free(e->value);
55+
if (map->strdup_strings)
56+
free((char*)e->key);
57+
free(e);
58+
}
59+
}
60+
61+
void strmap_clear(struct strmap *map, int free_values)
62+
{
63+
strmap_free_entries_(map, free_values);
64+
hashmap_clear(&map->map);
65+
}
66+
67+
void *strmap_put(struct strmap *map, const char *str, void *data)
68+
{
69+
struct strmap_entry *entry = find_strmap_entry(map, str);
70+
void *old = NULL;
71+
72+
if (entry) {
73+
old = entry->value;
74+
entry->value = data;
75+
} else {
76+
const char *key = str;
77+
78+
entry = xmalloc(sizeof(*entry));
79+
hashmap_entry_init(&entry->ent, strhash(str));
80+
81+
if (map->strdup_strings)
82+
key = xstrdup(str);
83+
entry->key = key;
84+
entry->value = data;
85+
hashmap_add(&map->map, &entry->ent);
86+
}
87+
return old;
88+
}
89+
90+
void *strmap_get(struct strmap *map, const char *str)
91+
{
92+
struct strmap_entry *entry = find_strmap_entry(map, str);
93+
return entry ? entry->value : NULL;
94+
}
95+
96+
int strmap_contains(struct strmap *map, const char *str)
97+
{
98+
return find_strmap_entry(map, str) != NULL;
99+
}

strmap.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#ifndef STRMAP_H
2+
#define STRMAP_H
3+
4+
#include "hashmap.h"
5+
6+
struct strmap {
7+
struct hashmap map;
8+
unsigned int strdup_strings:1;
9+
};
10+
11+
struct strmap_entry {
12+
struct hashmap_entry ent;
13+
const char *key;
14+
void *value;
15+
};
16+
17+
int cmp_strmap_entry(const void *hashmap_cmp_fn_data,
18+
const struct hashmap_entry *entry1,
19+
const struct hashmap_entry *entry2,
20+
const void *keydata);
21+
22+
#define STRMAP_INIT { \
23+
.map = HASHMAP_INIT(cmp_strmap_entry, NULL), \
24+
.strdup_strings = 1, \
25+
}
26+
27+
/*
28+
* Initialize the members of the strmap. Any keys added to the strmap will
29+
* be strdup'ed with their memory managed by the strmap.
30+
*/
31+
void strmap_init(struct strmap *map);
32+
33+
/*
34+
* Same as strmap_init, but for those who want to control the memory management
35+
* carefully instead of using the default of strdup_strings=1.
36+
*/
37+
void strmap_init_with_options(struct strmap *map,
38+
int strdup_strings);
39+
40+
/*
41+
* Remove all entries from the map, releasing any allocated resources.
42+
*/
43+
void strmap_clear(struct strmap *map, int free_values);
44+
45+
/*
46+
* Insert "str" into the map, pointing to "data".
47+
*
48+
* If an entry for "str" already exists, its data pointer is overwritten, and
49+
* the original data pointer returned. Otherwise, returns NULL.
50+
*/
51+
void *strmap_put(struct strmap *map, const char *str, void *data);
52+
53+
/*
54+
* Return the data pointer mapped by "str", or NULL if the entry does not
55+
* exist.
56+
*/
57+
void *strmap_get(struct strmap *map, const char *str);
58+
59+
/*
60+
* Return non-zero iff "str" is present in the map. This differs from
61+
* strmap_get() in that it can distinguish entries with a NULL data pointer.
62+
*/
63+
int strmap_contains(struct strmap *map, const char *str);
64+
65+
#endif /* STRMAP_H */

0 commit comments

Comments
 (0)