From: Yu Watanabe Date: Thu, 13 Jul 2023 05:43:45 +0000 (+0900) Subject: hashmap: introduce hashmap_dump_sorted() and friends X-Git-Tag: v254-rc2~23^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c619033f09eb4fed750bb144071aab9c1634f1f8;p=thirdparty%2Fsystemd.git hashmap: introduce hashmap_dump_sorted() and friends --- diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 30931567480..ac1c7329788 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -21,6 +21,7 @@ #include "random-util.h" #include "set.h" #include "siphash24.h" +#include "sort-util.h" #include "string-util.h" #include "strv.h" @@ -2106,3 +2107,51 @@ bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needl return set_fnmatch_one(include_patterns, needle); } + +static int hashmap_entry_compare( + struct hashmap_base_entry * const *a, + struct hashmap_base_entry * const *b, + compare_func_t compare) { + + assert(a && *a); + assert(b && *b); + assert(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; + Iterator iter; + unsigned idx; + size_t n = 0; + + assert(ret); + + if (_hashmap_size(h) == 0) { + *ret = NULL; + if (ret_n) + *ret_n = 0; + return 0; + } + + entries = new(struct hashmap_base_entry*, _hashmap_size(h)); + if (!entries) + return -ENOMEM; + + HASHMAP_FOREACH_IDX(idx, h, iter) + entries[n++] = bucket_at(h, idx); + + assert(n == _hashmap_size(h)); + + typesafe_qsort_r(entries, n, hashmap_entry_compare, h->hash_ops->compare); + + /* Reuse the array. */ + FOREACH_ARRAY(e, entries, n) + *e = entry_value(h, *e); + + *ret = (void**) TAKE_PTR(entries); + if (ret_n) + *ret_n = n; + return 0; +} diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index 68d9b81cf20..ad85093d69a 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -398,6 +398,17 @@ static inline char** ordered_hashmap_get_strv(OrderedHashmap *h) { return _hashmap_get_strv(HASHMAP_BASE(h)); } +int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n); +static inline int hashmap_dump_sorted(Hashmap *h, void ***ret, size_t *ret_n) { + return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n); +} +static inline int ordered_hashmap_dump_sorted(OrderedHashmap *h, void ***ret, size_t *ret_n) { + return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n); +} +static inline int set_dump_sorted(Set *h, void ***ret, size_t *ret_n) { + return _hashmap_dump_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 560a64b959f..a821d412b7e 100644 --- a/src/test/test-hashmap-plain.c +++ b/src/test/test-hashmap-plain.c @@ -963,6 +963,44 @@ TEST(string_strv_hashmap) { assert_se(strv_equal(s, STRV_MAKE("bar", "BAR"))); } +TEST(hashmap_dump_sorted) { + static void * const expected[] = { UINT_TO_PTR(123U), UINT_TO_PTR(12U), UINT_TO_PTR(345U), }; + _cleanup_hashmap_free_ Hashmap *m = NULL; + _cleanup_free_ void **vals = NULL; + size_t n; + + assert_se(m = hashmap_new(&string_hash_ops)); + + assert_se(hashmap_dump_sorted(m, &vals, &n) >= 0); + assert_se(n == 0); + assert_se(!vals); + + assert_se(hashmap_put(m, "key 0", expected[0]) == 1); + assert_se(hashmap_put(m, "key 1", expected[1]) == 1); + assert_se(hashmap_put(m, "key 2", expected[2]) == 1); + + 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); + m = hashmap_free(m); + + assert_se(m = hashmap_new(NULL)); + + assert_se(hashmap_dump_sorted(m, &vals, &n) >= 0); + assert_se(n == 0); + assert_se(!vals); + + assert_se(hashmap_put(m, UINT_TO_PTR(333U), expected[2]) == 1); + assert_se(hashmap_put(m, UINT_TO_PTR(222U), expected[1]) == 1); + assert_se(hashmap_put(m, UINT_TO_PTR(111U), expected[0]) == 1); + + assert_se(hashmap_dump_sorted(m, &vals, &n) >= 0); + assert_se(n == ELEMENTSOF(expected)); + assert_se(memcmp(vals, expected, n * sizeof(void*)) == 0); +} + /* Signal to test-hashmap.c that tests from this compilation unit were run. */ extern int n_extern_tests_run; TEST(ensure_extern_hashmap_tests) {