]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
basic/hashmap: add hashops variant that does strdup/freeing on its own
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 11 Apr 2019 16:08:57 +0000 (18:08 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 19 Jul 2019 14:50:36 +0000 (16:50 +0200)
So far, we'd use hashmap_free_free to free both keys and values along with
the hashmap. I think it's better to make this more encapsulated: in this variant
the way contents are freed can be decided when the hashmap is created, and
users of the hashmap can always use hashmap_free.

src/basic/hash-funcs.c
src/basic/hash-funcs.h
src/basic/hashmap.c
src/basic/hashmap.h
src/test/test-hashmap-plain.c

index 1be43d41a93ff7ae1a78e0df57ea52f9247285b7..11cd371fad4217bdabb545dfe779bfdbca539435 100644 (file)
@@ -10,6 +10,9 @@ void string_hash_func(const char *p, struct siphash *state) {
 }
 
 DEFINE_HASH_OPS(string_hash_ops, char, string_hash_func, string_compare_func);
+DEFINE_HASH_OPS_FULL(string_hash_ops_free_free,
+                     char, string_hash_func, string_compare_func, free,
+                     char, free);
 
 void path_hash_func(const char *q, struct siphash *state) {
         size_t n;
index 3d2ae4b55ee99bef7337981c5d681c0c65100c6a..0d2d42838930a64cc4f9539c55714cd98da74249 100644 (file)
@@ -76,6 +76,7 @@ struct hash_ops {
 void string_hash_func(const char *p, struct siphash *state);
 #define string_compare_func strcmp
 extern const struct hash_ops string_hash_ops;
+extern const struct hash_ops string_hash_ops_free_free;
 
 void path_hash_func(const char *p, struct siphash *state);
 int path_compare_func(const char *a, const char *b) _pure_;
index f244d767da72a8b0c5f1d3f796b38d5f4a65912c..c33e00fc598050e1c26024af2771f0ed2e3e1e88 100644 (file)
@@ -1768,6 +1768,32 @@ int set_consume(Set *s, void *value) {
         return r;
 }
 
+int hashmap_put_strdup(Hashmap **h, const char *k, const char *v) {
+        int r;
+
+        r = hashmap_ensure_allocated(h, &string_hash_ops_free_free);
+        if (r < 0)
+                return r;
+
+        _cleanup_free_ char *kdup = NULL, *vdup = NULL;
+        kdup = strdup(k);
+        vdup = strdup(v);
+        if (!kdup || !vdup)
+                return -ENOMEM;
+
+        r = hashmap_put(*h, kdup, vdup);
+        if (r < 0) {
+                if (r == -EEXIST && streq(v, hashmap_get(*h, kdup)))
+                        return 0;
+                return r;
+        }
+
+        assert(r > 0); /* 0 would mean vdup is already in the hashmap, which cannot be */
+        kdup = vdup = NULL;
+
+        return 0;
+}
+
 int set_put_strdup(Set *s, const char *p) {
         char *c;
 
index 1b071c230e77201d82d397f251fb640d1a8d6f07..65adc92513d737854607a406ad15e0a13e0ef111 100644 (file)
@@ -147,6 +147,8 @@ static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *
         return hashmap_put(PLAIN_HASHMAP(h), key, value);
 }
 
+int hashmap_put_strdup(Hashmap **h, const char *k, const char *v);
+
 int hashmap_update(Hashmap *h, const void *key, void *value);
 static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) {
         return hashmap_update(PLAIN_HASHMAP(h), key, value);
index fdb0c7e87ffd5c879e32a68edfe2450ebeef40f8..02cc396cf75bb12edd1dfad24b9948ba53ae7ecb 100644 (file)
@@ -978,6 +978,33 @@ static void test_hashmap_reserve(void) {
         assert_se(hashmap_reserve(m, UINT_MAX - 1) == -ENOMEM);
 }
 
+static void test_string_strv_hashmap(void) {
+        _cleanup_hashmap_free_ Hashmap *m = NULL;
+        char **s;
+
+        log_info("/* %s */", __func__);
+
+        assert_se(string_strv_hashmap_put(&m, "foo", "bar") == 1);
+        assert_se(string_strv_hashmap_put(&m, "foo", "bar") == 0);
+        assert_se(string_strv_hashmap_put(&m, "foo", "BAR") == 1);
+        assert_se(string_strv_hashmap_put(&m, "foo", "BAR") == 0);
+        assert_se(string_strv_hashmap_put(&m, "foo", "bar") == 0);
+        assert_se(hashmap_contains(m, "foo"));
+
+        s = hashmap_get(m, "foo");
+        assert_se(strv_equal(s, STRV_MAKE("bar", "BAR")));
+
+        assert_se(string_strv_hashmap_put(&m, "xxx", "bar") == 1);
+        assert_se(string_strv_hashmap_put(&m, "xxx", "bar") == 0);
+        assert_se(string_strv_hashmap_put(&m, "xxx", "BAR") == 1);
+        assert_se(string_strv_hashmap_put(&m, "xxx", "BAR") == 0);
+        assert_se(string_strv_hashmap_put(&m, "xxx", "bar") == 0);
+        assert_se(hashmap_contains(m, "xxx"));
+
+        s = hashmap_get(m, "xxx");
+        assert_se(strv_equal(s, STRV_MAKE("bar", "BAR")));
+}
+
 void test_hashmap_funcs(void) {
         log_parse_environment();
         log_open();
@@ -1012,4 +1039,5 @@ void test_hashmap_funcs(void) {
         test_hashmap_clear_free_free();
         test_hashmap_clear_free_with_destructor();
         test_hashmap_reserve();
+        test_string_strv_hashmap();
 }