util/ht: add key-value pair iterator support (#6483)

---------

Co-authored-by: Rot127 <45763064+Rot127@users.noreply.github.com>
This commit is contained in:
Thiago Mucci 2026-08-05 16:33:05 -04:00 committed by GitHub
parent 6f264e7019
commit e33674578c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 90 additions and 0 deletions

View file

@ -304,7 +304,9 @@ RZ_API void Ht_(free_iter_state)(RZ_NULLABLE HT_(IterState) *state);
RZ_API RZ_BORROW VALUE_TYPE *Ht_(iter_next_mut)(RzIterator *it); RZ_API RZ_BORROW VALUE_TYPE *Ht_(iter_next_mut)(RzIterator *it);
RZ_API const VALUE_TYPE *Ht_(iter_next)(RzIterator *it); RZ_API const VALUE_TYPE *Ht_(iter_next)(RzIterator *it);
RZ_API const KEY_TYPE *Ht_(iter_next_key)(RzIterator *it); RZ_API const KEY_TYPE *Ht_(iter_next_key)(RzIterator *it);
RZ_API const HT_(Kv) *Ht_(iter_next_kv)(RzIterator *it);
RZ_API RZ_OWN RzIterator /* <HtName_(Ht)> */ *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht); RZ_API RZ_OWN RzIterator /* <HtName_(Ht)> */ *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht);
RZ_API RZ_OWN RzIterator /* <HtName_(Ht)> */ *Ht_(as_iter)(const RZ_NONNULL HtName_(Ht) *ht); RZ_API RZ_OWN RzIterator /* <HtName_(Ht)> */ *Ht_(as_iter)(const RZ_NONNULL HtName_(Ht) *ht);
RZ_API RZ_OWN RzIterator /* <HtName_(Ht)> */ *Ht_(as_iter_keys)(const RZ_NONNULL HtName_(Ht) *ht); RZ_API RZ_OWN RzIterator /* <HtName_(Ht)> */ *Ht_(as_iter_keys)(const RZ_NONNULL HtName_(Ht) *ht);
RZ_API RZ_OWN RzIterator /* <const HtName_(Ht)> */ *Ht_(as_iter_kv)(const RZ_NONNULL HtName_(Ht) *ht);

View file

@ -1029,6 +1029,29 @@ RZ_API const KEY_TYPE *Ht_(iter_next_key)(RzIterator *it) {
return NULL; return NULL;
} }
/**
* \brief Advances the iterator \p it and yields the next immutable key-value pair.
*
* \param it The iterator instance.
*/
RZ_API const HT_(Kv) *Ht_(iter_next_kv)(RzIterator *it) {
rz_return_val_if_fail(it, NULL);
HT_(IterState) *state = it->u;
// Iterate over tables until a table with an element is found.
for (; state->ti < state->ht->capacity; state->ti++) {
if (H2_IS_EMPTY_OR_DELETED(state->ht->ctrl[state->ti])) {
continue;
}
state->kv = HT_SLOT_AT(state->ht, state->ti);
state->ti++;
return state->kv;
}
// Iteration is done. No elements left to select.
return NULL;
}
RZ_API RZ_OWN HT_(IterMutState) *Ht_(new_iter_mut_state)(RZ_NONNULL HtName_(Ht) *ht) { RZ_API RZ_OWN HT_(IterMutState) *Ht_(new_iter_mut_state)(RZ_NONNULL HtName_(Ht) *ht) {
rz_return_val_if_fail(ht, NULL); rz_return_val_if_fail(ht, NULL);
HT_(IterMutState) *state = RZ_NEW0(HT_(IterMutState)); HT_(IterMutState) *state = RZ_NEW0(HT_(IterMutState));
@ -1112,3 +1135,22 @@ RZ_API RZ_OWN RzIterator /* <HtName_(Ht)> */ *Ht_(as_iter_keys)(const RZ_NONNULL
} }
return iter; return iter;
} }
/**
* \brief Returns an iterator over the hash table \p ht. The iterator yields immutable key-value pairs.
*
* \param ht The hash table to create the iterator for.
*
* \return The iterator over the hash table key-value pairs or NULL in case of failure.
*/
RZ_API RZ_OWN RzIterator /* <const HtName_(Ht)> */ *Ht_(as_iter_kv)(const RZ_NONNULL HtName_(Ht) *ht) {
rz_return_val_if_fail(ht, NULL);
HT_(IterState) *state = Ht_(new_iter_state)(ht);
rz_return_val_if_fail(state, NULL);
RzIterator *iter = rz_iterator_new((rz_iterator_next_cb)Ht_(iter_next_kv), NULL, (rz_iterator_free_cb)Ht_(free_iter_state), state);
if (!iter) {
Ht_(free_iter_state)(state);
}
return iter;
}

View file

@ -766,6 +766,51 @@ bool test_ht_uu_iter(void) {
mu_end; mu_end;
} }
bool test_ht_uu_iter_kv(void) {
HtUU *ht = ht_uu_new();
ut32 icnt = 0;
const HtUUKv *kv;
RzIterator *it = ht_uu_as_iter_kv(ht);
rz_iterator_foreach(it, kv) {
icnt++;
}
rz_iterator_free(it);
mu_assert_eq(icnt, 0, "Wrong number of iterations");
ht_uu_insert(ht, 0x11, 0x1111);
ht_uu_insert(ht, 0x22, 0x2222);
ht_uu_insert(ht, 0x33, 0x3333);
bool found_1 = false;
bool found_2 = false;
bool found_3 = false;
icnt = 0;
it = ht_uu_as_iter_kv(ht);
rz_iterator_foreach(it, kv) {
icnt++;
if (kv->key == 0x11 && kv->value == 0x1111) {
found_1 = true;
}
if (kv->key == 0x22 && kv->value == 0x2222) {
found_2 = true;
}
if (kv->key == 0x33 && kv->value == 0x3333) {
found_3 = true;
}
}
rz_iterator_free(it);
mu_assert_eq(icnt, 3, "Wrong number of iterations");
mu_assert_true(found_1, "key not found");
mu_assert_true(found_2, "key not found");
mu_assert_true(found_3, "key not found");
ht_uu_free(ht);
mu_end;
}
bool test_ht_ss_iter(void) { bool test_ht_ss_iter(void) {
HtSS *ht = ht_ss_new(HT_STR_CONST, HT_STR_CONST); HtSS *ht = ht_ss_new(HT_STR_CONST, HT_STR_CONST);
ut32 icnt = 0; ut32 icnt = 0;
@ -992,6 +1037,7 @@ int all_tests() {
mu_run_test(test_insert_update_ex); mu_run_test(test_insert_update_ex);
mu_run_test(test_ht_size); mu_run_test(test_ht_size);
mu_run_test(test_ht_uu_iter); mu_run_test(test_ht_uu_iter);
mu_run_test(test_ht_uu_iter_kv);
mu_run_test(test_ht_ss_iter); mu_run_test(test_ht_ss_iter);
mu_run_test(test_set_u); mu_run_test(test_set_u);
mu_run_test(test_set_s); mu_run_test(test_set_s);