hashmap: introduce hashmap_dump_sorted() and friends

This commit is contained in:
Yu Watanabe
2023-07-13 17:06:47 +09:00
parent ddd6875d19
commit c619033f09
3 changed files with 98 additions and 0 deletions
+49
View File
@@ -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;
}
+11
View File
@@ -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
+38
View File
@@ -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) {