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/20180906191203.GA26184@sigill.intra.peff.net/ 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 <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Elijah Newren committed
Nov 2, 2020 at 18:55 UTC
ae20bf1ad98bdc716879a8da99e7f329e3cc2730
3 files changed
+165
Makefile
+1
@@ -1000,6 +1000,7 @@ LIB_OBJS += stable-qsort.o
1000
LIB_OBJS += strbuf.o
1001
LIB_OBJS += streaming.o
1002
LIB_OBJS += string-list.o
1003
+LIB_OBJS += strmap.o
1004
LIB_OBJS += strvec.o
1005
LIB_OBJS += sub-process.o
1006
LIB_OBJS += submodule-config.o
strmap.c
new
+99
@@ -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
new
+65
@@ -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 */