hashmap: Add helper to dump sorted keys
authorAdrian Vovk <adrianvovk@gmail.com>
Fri, 19 Jan 2024 01:48:24 +0000 (20:48 -0500)
committerLennart Poettering <lennart@poettering.net>
Wed, 14 Feb 2024 08:35:36 +0000 (09:35 +0100)
Currently, hashmap_dump_sorted sorts by key and then returns the values
in order sorted by key. This commit adds another helper that does the
same but returns the sorted keys instead

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

index 894760ca6098df22a83f898fce06d2c7207e2e44..a9fd7620295f0034321f914e4314f8a1b8e0849d 100644 (file)
@@ -2120,24 +2120,27 @@ static int hashmap_entry_compare(
         return compare((*a)->key, (*b)->key);
 }
 
-int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
-        _cleanup_free_ struct hashmap_base_entry **entries = NULL;
+static int _hashmap_dump_entries_sorted(
+                HashmapBase *h,
+                void ***ret,
+                size_t *ret_n) {
+        _cleanup_free_ void **entries = NULL;
         Iterator iter;
         unsigned idx;
         size_t n = 0;
 
         assert(ret);
+        assert(ret_n);
 
         if (_hashmap_size(h) == 0) {
                 *ret = NULL;
-                if (ret_n)
-                        *ret_n = 0;
+                *ret_n = 0;
                 return 0;
         }
 
         /* We append one more element than needed so that the resulting array can be used as a strv. We
          * don't count this entry in the returned size. */
-        entries = new(struct hashmap_base_entry*, _hashmap_size(h) + 1);
+        entries = new(void*, _hashmap_size(h) + 1);
         if (!entries)
                 return -ENOMEM;
 
@@ -2147,13 +2150,47 @@ int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
         assert(n == _hashmap_size(h));
         entries[n] = NULL;
 
-        typesafe_qsort_r(entries, n, hashmap_entry_compare, h->hash_ops->compare);
+        typesafe_qsort_r((struct hashmap_base_entry**) entries, n,
+                         hashmap_entry_compare, h->hash_ops->compare);
+
+        *ret = TAKE_PTR(entries);
+        *ret_n = n;
+        return 0;
+}
+
+int _hashmap_dump_keys_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
+        _cleanup_free_ void **entries = NULL;
+        size_t n;
+        int r;
+
+        r = _hashmap_dump_entries_sorted(h, &entries, &n);
+        if (r < 0)
+                return r;
+
+        /* Reuse the array. */
+        FOREACH_ARRAY(e, entries, n)
+                *e = (void*) (*(struct hashmap_base_entry**) e)->key;
+
+        *ret = TAKE_PTR(entries);
+        if (ret_n)
+                *ret_n = n;
+        return 0;
+}
+
+int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
+        _cleanup_free_ void **entries = NULL;
+        size_t n;
+        int r;
+
+        r = _hashmap_dump_entries_sorted(h, &entries, &n);
+        if (r < 0)
+                return r;
 
         /* Reuse the array. */
         FOREACH_ARRAY(e, entries, n)
-                *e = entry_value(h, *e);
+                *e = entry_value(h, *(struct hashmap_base_entry**) e);
 
-        *ret = (void**) TAKE_PTR(entries);
+        *ret = TAKE_PTR(entries);
         if (ret_n)
                 *ret_n = n;
         return 0;
index 233f1d7a1ee2dd7902e700a38ce68affcef2590b..28929843c89a3604293c0b60556c8fe713b44674 100644 (file)
@@ -409,6 +409,14 @@ static inline int set_dump_sorted(Set *h, void ***ret, size_t *ret_n) {
         return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n);
 }
 
+int _hashmap_dump_keys_sorted(HashmapBase *h, void ***ret, size_t *ret_n);
+static inline int hashmap_dump_keys_sorted(Hashmap *h, void ***ret, size_t *ret_n) {
+        return _hashmap_dump_keys_sorted(HASHMAP_BASE(h), ret, ret_n);
+}
+static inline int ordered_hashmap_dump_keys_sorted(OrderedHashmap *h, void ***ret, size_t *ret_n) {
+        return _hashmap_dump_keys_sorted(HASHMAP_BASE(h), ret, ret_n);
+}
+
 /*
  * Hashmaps are iterated in unpredictable order.
  * OrderedHashmaps are an exception to this. They are iterated in the order
index 152b1c03e6def40b1ca3a13dd66094b778bd1ee8..0d1f84579442f060e3dae5c71f173a1fed2e3a5f 100644 (file)
@@ -965,6 +965,8 @@ TEST(string_strv_hashmap) {
 
 TEST(hashmap_dump_sorted) {
         static void * const expected[] = { UINT_TO_PTR(123U), UINT_TO_PTR(12U), UINT_TO_PTR(345U), };
+        static const char *expected_keys[] = { "key 0", "key 1", "key 2", };
+        static void * const expected_keys2[] = { UINT_TO_PTR(111U), UINT_TO_PTR(222U), UINT_TO_PTR(333U), };
         _cleanup_hashmap_free_ Hashmap *m = NULL;
         _cleanup_free_ void **vals = NULL;
         size_t n;
@@ -983,6 +985,13 @@ TEST(hashmap_dump_sorted) {
         assert_se(n == ELEMENTSOF(expected));
         assert_se(memcmp(vals, expected, n * sizeof(void*)) == 0);
 
+        vals = mfree(vals);
+
+        assert_se(hashmap_dump_keys_sorted(m, &vals, &n) >= 0);
+        assert_se(n == ELEMENTSOF(expected_keys));
+        for (size_t i = 0; i < n; i++)
+                assert_se(streq(vals[i], expected_keys[i]));
+
         vals = mfree(vals);
         m = hashmap_free(m);
 
@@ -999,6 +1008,12 @@ TEST(hashmap_dump_sorted) {
         assert_se(hashmap_dump_sorted(m, &vals, &n) >= 0);
         assert_se(n == ELEMENTSOF(expected));
         assert_se(memcmp(vals, expected, n * sizeof(void*)) == 0);
+
+        vals = mfree(vals);
+
+        assert_se(hashmap_dump_keys_sorted(m, &vals, &n) >= 0);
+        assert_se(n == ELEMENTSOF(expected_keys2));
+        assert_se(memcmp(vals, expected_keys2, n * sizeof(void*)) == 0);
 }
 
 /* Signal to test-hashmap.c that tests from this compilation unit were run. */