From: Adrian Vovk Date: Fri, 19 Jan 2024 01:48:24 +0000 (-0500) Subject: hashmap: Add helper to dump sorted keys X-Git-Tag: v256-rc1~870 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c425c8854f52b099e0166aae4a8ea358d827848f;p=thirdparty%2Fsystemd.git hashmap: Add helper to dump sorted keys 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 --- diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 894760ca609..a9fd7620295 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -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; diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index 233f1d7a1ee..28929843c89 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -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 diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c index 152b1c03e6d..0d1f8457944 100644 --- a/src/test/test-hashmap-plain.c +++ b/src/test/test-hashmap-plain.c @@ -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. */