From 84008127d0fb91c9bccbba8f3c83f405a81e6ad6 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 18 Sep 2024 03:33:53 -0500 Subject: [PATCH 01/10] Implement iterators for hash tables. --- librz/include/rz_util/ht_inc.h | 30 +++++ librz/include/rz_util/rz_set.h | 4 + librz/util/ht/ht_inc.c | 142 +++++++++++++++++++++++ test/unit/{test_sdb_hash.c => test_ht.c} | 137 ++++++++++++++++++++++ 4 files changed, 313 insertions(+) rename test/unit/{test_sdb_hash.c => test_ht.c} (81%) diff --git a/librz/include/rz_util/ht_inc.h b/librz/include/rz_util/ht_inc.h index 9fc4024f8a0..fb87fb2af46 100644 --- a/librz/include/rz_util/ht_inc.h +++ b/librz/include/rz_util/ht_inc.h @@ -4,6 +4,8 @@ // SPDX-FileCopyrightText: 2024 pelijah // SPDX-License-Identifier: BSD-3-Clause +#include + #ifndef HT_TYPE #error HT_TYPE should be defined before including this header #endif @@ -166,6 +168,22 @@ typedef struct Ht_(t) { } HtName_(Ht); +typedef struct Ht_(iter_mut_t) { + HtName_(Ht) *ht; ///< The hash table to iterate over. + ut32 ti; ///< Table index + ut32 bi; ///< Bucket index + HT_(Kv) *kv; ///< Current Key-Value-pair. +} +HT_(IterMutState); + +typedef struct Ht_(iter_t) { + const HtName_(Ht) *ht; ///< The hash table to iterate over. + ut32 ti; ///< Table index + ut32 bi; ///< Bucket index + const HT_(Kv) *kv; ///< Current Key-Value-pair. +} +HT_(IterState); + // Create a new Ht with the provided Options RZ_API RZ_OWN HtName_(Ht) *Ht_(new_opt)(RZ_NONNULL HT_(Options) *opt); // Create a new Ht with the provided Options and initial size @@ -190,6 +208,18 @@ RZ_API VALUE_TYPE Ht_(find)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE key, RZ_N // NOTE: cb can delete the current element, but it should be avoided RZ_API void Ht_(foreach)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(ForeachCallback) cb, RZ_NULLABLE void *user); +RZ_API ut32 Ht_(size)(RZ_NONNULL HtName_(Ht) *ht); + RZ_API RZ_BORROW HT_(Kv) *Ht_(find_kv)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE key, RZ_NULLABLE bool *found); RZ_API bool Ht_(insert_kv)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(Kv) *kv, bool update); RZ_API HtRetCode Ht_(insert_kv_ex)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(Kv) *kv, bool update, RZ_OUT RZ_NULLABLE HT_(Kv) **out_kv); + +RZ_API HT_(IterMutState) *Ht_(new_iter_mut_state)(RZ_NONNULL HtName_(Ht) *ht); +RZ_API HT_(IterState) *Ht_(new_iter_state)(const RZ_NONNULL HtName_(Ht) *ht); +RZ_API void Ht_(free_iter_state)(HT_(IterState) *state); + +RZ_API VALUE_TYPE *Ht_(iter_next_mut)(RzIterator *it); +RZ_API const VALUE_TYPE *Ht_(iter_next)(RzIterator *it); + +RZ_API RZ_OWN RzIterator *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht); +RZ_API RZ_OWN RzIterator *Ht_(as_iter)(const RZ_NONNULL HtName_(Ht) *ht); diff --git a/librz/include/rz_util/rz_set.h b/librz/include/rz_util/rz_set.h index d1c7ec5bd55..e575fb5c203 100644 --- a/librz/include/rz_util/rz_set.h +++ b/librz/include/rz_util/rz_set.h @@ -21,6 +21,8 @@ RZ_API void rz_set_s_add(RZ_NONNULL RzSetS *set, const char *str); RZ_API bool rz_set_s_contains(RZ_NONNULL RzSetS *set, const char *str); RZ_API void rz_set_s_delete(RZ_NONNULL RzSetS *set, const char *str); RZ_API RZ_OWN RzPVector /**/ *rz_set_s_to_vector(RZ_NONNULL RzSetS *set); +RZ_API RzIterator *rz_set_s_as_iter(const RZ_NONNULL RzSetS *set); +RZ_API RzIterator *rz_set_s_as_iter_mut(RZ_NONNULL RzSetS *set); typedef HtUP RzSetU; @@ -29,6 +31,8 @@ RZ_API void rz_set_u_free(RZ_NULLABLE RzSetU *set); RZ_API void rz_set_u_add(RZ_NONNULL RzSetU *set, ut64 u); RZ_API bool rz_set_u_contains(RZ_NONNULL RzSetU *set, ut64 u); RZ_API void rz_set_u_delete(RZ_NONNULL RzSetU *set, ut64 u); +RZ_API RzIterator *rz_set_u_as_iter(const RZ_NONNULL RzSetU *set); +RZ_API RzIterator *rz_set_u_as_iter_mut(RZ_NONNULL RzSetU *set); #ifdef __cplusplus } diff --git a/librz/util/ht/ht_inc.c b/librz/util/ht/ht_inc.c index 8ef1cf9c70c..29fdf9e1a07 100644 --- a/librz/util/ht/ht_inc.c +++ b/librz/util/ht/ht_inc.c @@ -5,6 +5,7 @@ // SPDX-License-Identifier: BSD-3-Clause #include +#include #include #define LOAD_FACTOR 1 @@ -512,3 +513,144 @@ RZ_API void Ht_(foreach)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(ForeachCallb } } } + +/** + * \brief Returns the number of elements stored in the hash map \p ht. + * + * \param ht The hash map. + * + * \return The number of elements saved in the hash map. + */ +RZ_API ut32 Ht_(size)(RZ_NONNULL HtName_(Ht) *ht) { + return ht->count; +} + +/** + * \brief Advances an RzIterator with over a hashtable to the next element in + * the hash table returns it. + * + * \param it The next mutable element or NULL if iteration terminated. + */ +RZ_API VALUE_TYPE *Ht_(iter_next_mut)(RzIterator *it) { + rz_return_val_if_fail(it, NULL); + + HT_(IterMutState) *state = it->u; + if (state->ti >= state->ht->size) { + // Iteration is done. No elements left to select. + return NULL; + } + // Iterate over tables until a table with an element is found. + for (; state->ti < state->ht->size; state->ti++) { + if (state->ht->table[state->ti].count == 0) { + // Table has no elements. Check next table. + continue; + } + if (state->bi < state->ht->table[state->ti].count) { + // Table has elements, select the element. + state->kv = &state->ht->table[state->ti].arr[state->bi]; + // For the next iteration, increment bucket index to the following element. + state->bi++; + return &state->kv->value; + } + // Reset bucket index to first bucket. + state->bi = 0; + // Go to next table + } + // Iteration is done. No elements left to select. + return NULL; +} + +/** + * \brief Advances an RzIterator with over a hashtable to the next element in + * the hash table returns it as const. + * + * \param it The next element as immutable or NULL if iteration terminated. + */ +RZ_API const VALUE_TYPE *Ht_(iter_next)(RzIterator *it) { + rz_return_val_if_fail(it, NULL); + + HT_(IterState) *state = it->u; + if (state->ti >= state->ht->size) { + // Iteration is done. No elements left to select. + return NULL; + } + // Iterate over tables until a table with an element is found. + for (; state->ti < state->ht->size; state->ti++) { + if (state->ht->table[state->ti].count == 0) { + // Table has no elements. Check next table. + continue; + } + if (state->bi < state->ht->table[state->ti].count) { + // Table has elements, select the element. + state->kv = &state->ht->table[state->ti].arr[state->bi]; + // For the next iteration, increment bucket index to the following element. + state->bi++; + return (const VALUE_TYPE *)&state->kv->value; + } + // Reset bucket index to first bucket. + state->bi = 0; + // Go to next table + } + // Iteration is done. No elements left to select. + return NULL; +} + +RZ_API HT_(IterMutState) *Ht_(new_iter_mut_state)(RZ_NONNULL HtName_(Ht) *ht) { + rz_return_val_if_fail(ht, NULL); + HT_(IterMutState) *state = RZ_NEW0(HT_(IterMutState)); + rz_return_val_if_fail(state, NULL); + state->ht = ht; + return state; +} + +RZ_API HT_(IterState) *Ht_(new_iter_state)(const RZ_NONNULL HtName_(Ht) *ht) { + rz_return_val_if_fail(ht, NULL); + HT_(IterState) *state = RZ_NEW0(HT_(IterState)); + rz_return_val_if_fail(state, NULL); + state->ht = ht; + return state; +} + +RZ_API void Ht_(free_iter_mut_state)(HT_(IterMutState) *state) { + if (state) { + free(state); + } +} + +RZ_API void Ht_(free_iter_state)(HT_(IterState) *state) { + if (state) { + free(state); + } +} + +/** + * \brief Returns an iterator over the hash table \p ht. The iterator yields mutable elements. + * + * \param ht The hash table to create the iterator for. + * + * \return The iterator over the hash table or NULL in case of failure. + */ +RZ_API RZ_OWN RzIterator *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht) { + rz_return_val_if_fail(ht, NULL); + HT_(IterMutState) *state = Ht_(new_iter_mut_state)(ht); + rz_return_val_if_fail(state, NULL); + + RzIterator *iter = rz_iterator_new((rz_iterator_next_cb)Ht_(iter_next_mut), NULL, (rz_iterator_free_cb)Ht_(free_iter_mut_state), state); + return iter; +} + +/** + * \brief Returns an iterator over the hash table \p ht. The iterator yields immutable elements. + * + * \param ht The hash table to create the iterator for. + * + * \return The iterator over the hash table or NULL in case of failure. + */ +RZ_API RZ_OWN RzIterator *Ht_(as_iter)(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), NULL, (rz_iterator_free_cb)Ht_(free_iter_state), state); + return iter; +} diff --git a/test/unit/test_sdb_hash.c b/test/unit/test_ht.c similarity index 81% rename from test/unit/test_sdb_hash.c rename to test/unit/test_ht.c index 3af4f7270a5..b34f8c79ec5 100644 --- a/test/unit/test_sdb_hash.c +++ b/test/unit/test_ht.c @@ -3,6 +3,7 @@ #include "minunit.h" #include +#include #include #include #include @@ -10,6 +11,7 @@ #include #include #include +#include typedef struct _test_struct { char *name; @@ -570,6 +572,138 @@ bool test_insert_update_ex(void) { mu_end; } +bool test_ht_size(void) { + HtUU *ht = ht_uu_new(); + mu_assert_eq(ht_uu_size(ht), 0, "Length wrong."); + ht_uu_insert(ht, 0x5050505, 0x5050505); + ht_uu_insert(ht, 0x5050505, 0x5050505); + ht_uu_insert(ht, 0x6060606, 0x6060606); + ht_uu_insert(ht, 0x7070707, 0x7070707); + ht_uu_insert(ht, 0x7070707, 0x7070707); + mu_assert_eq(ht_uu_size(ht), 3, "Length wrong."); + bool found = false; + ht_uu_find(ht, 0x5050505, &found); + mu_assert_true(found, "Value was not added."); + ht_uu_find(ht, 0x6060606, &found); + mu_assert_true(found, "Value was not added."); + ht_uu_find(ht, 0x7070707, &found); + mu_assert_true(found, "Value was not added."); + + ht_uu_delete(ht, 0x7070707); + ht_uu_find(ht, 0x7070707, &found); + mu_assert_false(found, "Value was not deleted."); + mu_assert_eq(ht_uu_size(ht), 2, "Length wrong."); + + // Double delete + ht_uu_delete(ht, 0x7070707); + ht_uu_find(ht, 0x7070707, &found); + mu_assert_false(found, "Value was not deleted."); + mu_assert_eq(ht_uu_size(ht), 2, "Length wrong."); + ht_uu_free(ht); + mu_end; +} + +bool test_ht_uu_iter(void) { + HtUU *ht = ht_uu_new(); + ut32 icnt = 0; + const ut64 *im_elem; + + RzIterator *it = ht_uu_as_iter(ht); + rz_iterator_foreach(it, im_elem) { + icnt++; + } + rz_iterator_free(it); + mu_assert_eq(icnt, 0, "Wrong number of iterations"); + ht_uu_insert(ht, 0x1010101, 0x1010101); + ht_uu_insert(ht, 0x2020202, 0x2020202); + ht_uu_insert(ht, 0x3030303, 0x3030303); + ht_uu_insert(ht, 0x4040404, 0x4040404); + ht_uu_insert(ht, 0x5050505, 0x5050505); + icnt = 0; + it = ht_uu_as_iter(ht); + rz_iterator_foreach(it, im_elem) { + icnt++; + mu_assert_true( + *im_elem == 0x1010101 || + *im_elem == 0x2020202 || + *im_elem == 0x3030303 || + *im_elem == 0x4040404 || + *im_elem == 0x5050505, + "Value mismtach"); + } + rz_iterator_free(it); + mu_assert_eq(icnt, 5, "Wrong number of iterations"); + icnt = 0; + // Test write of value + ut64 *m_elem; + it = ht_uu_as_iter_mut(ht); + rz_iterator_foreach(it, m_elem) { + icnt++; + if (*m_elem == 0x1010101) { + *m_elem = 0x0; + } + } + rz_iterator_free(it); + mu_assert_eq(icnt, 5, "Wrong number of iterations"); + bool found = false; + ut64 v = ht_uu_find(ht, 0x1010101, &found); + mu_assert_true(found, "Key not in hash map"); + mu_assert_eq(v, 0x0, "Value didn't change."); + ht_uu_free(ht); + mu_end; +} + +bool test_ht_ss_iter(void) { + HtSS *ht = ht_ss_new(HT_STR_CONST, HT_STR_CONST); + ut32 icnt = 0; + const char **im_elem; + + RzIterator *it = ht_ss_as_iter(ht); + rz_iterator_foreach(it, im_elem) { + icnt++; + } + rz_iterator_free(it); + mu_assert_eq(icnt, 0, "Wrong number of iterations"); + + ht_ss_insert(ht, "0x1010101", "0x1010101"); + ht_ss_insert(ht, "0x2020202", "0x2020202"); + ht_ss_insert(ht, "0x3030303", "0x3030303"); + ht_ss_insert(ht, "0x4040404", "0x4040404"); + ht_ss_insert(ht, "0x5050505", "0x5050505"); + icnt = 0; + it = ht_ss_as_iter(ht); + rz_iterator_foreach(it, im_elem) { + icnt++; + mu_assert_true( + RZ_STR_EQ(*im_elem, "0x1010101") || + RZ_STR_EQ(*im_elem, "0x2020202") || + RZ_STR_EQ(*im_elem, "0x3030303") || + RZ_STR_EQ(*im_elem, "0x4040404") || + RZ_STR_EQ(*im_elem, "0x5050505"), + "Value mismtach"); + } + rz_iterator_free(it); + mu_assert_eq(icnt, 5, "Wrong number of iterations"); + icnt = 0; + // Test write of value + char **m_elem; + it = ht_ss_as_iter_mut(ht); + rz_iterator_foreach(it, m_elem) { + icnt++; + if (RZ_STR_EQ(*m_elem, "0x1010101")) { + *m_elem = "0x0"; + } + } + rz_iterator_free(it); + mu_assert_eq(icnt, 5, "Wrong number of iterations"); + bool found = false; + const char *v = ht_ss_find(ht, "0x1010101", &found); + mu_assert_true(found, "Key not in hash map"); + mu_assert_streq(v, "0x0", "Value didn't change."); + ht_ss_free(ht); + mu_end; +} + int all_tests() { mu_run_test(test_ht_insert_lookup); mu_run_test(test_ht_update_lookup); @@ -591,6 +725,9 @@ int all_tests() { mu_run_test(test_update_key); mu_run_test(test_ht_pu_ops); mu_run_test(test_insert_update_ex); + mu_run_test(test_ht_size); + mu_run_test(test_ht_uu_iter); + mu_run_test(test_ht_ss_iter); return tests_passed != tests_run; } From 8fbd5a38b868021a3cdc17f8e4fb5a1b2ea71211 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 18 Sep 2024 04:00:18 -0500 Subject: [PATCH 02/10] Implement iterator over set. --- librz/include/rz_util/ht_inc.h | 2 + librz/include/rz_util/rz_set.h | 4 +- librz/util/ht/ht_inc.c | 67 ++++++++++++++-- librz/util/set.c | 34 ++++++++ test/unit/meson.build | 2 +- test/unit/test_ht.c | 137 +++++++++++++++++++++++++++++++++ 6 files changed, 235 insertions(+), 11 deletions(-) diff --git a/librz/include/rz_util/ht_inc.h b/librz/include/rz_util/ht_inc.h index fb87fb2af46..f82dc5997cf 100644 --- a/librz/include/rz_util/ht_inc.h +++ b/librz/include/rz_util/ht_inc.h @@ -220,6 +220,8 @@ RZ_API void Ht_(free_iter_state)(HT_(IterState) *state); RZ_API VALUE_TYPE *Ht_(iter_next_mut)(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 RZ_OWN RzIterator *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht); RZ_API RZ_OWN RzIterator *Ht_(as_iter)(const RZ_NONNULL HtName_(Ht) *ht); +RZ_API RZ_OWN RzIterator *Ht_(as_iter_keys)(const RZ_NONNULL HtName_(Ht) *ht); diff --git a/librz/include/rz_util/rz_set.h b/librz/include/rz_util/rz_set.h index e575fb5c203..c36a3a05973 100644 --- a/librz/include/rz_util/rz_set.h +++ b/librz/include/rz_util/rz_set.h @@ -20,9 +20,9 @@ RZ_API void rz_set_s_free(RZ_NULLABLE RzSetS *set); RZ_API void rz_set_s_add(RZ_NONNULL RzSetS *set, const char *str); RZ_API bool rz_set_s_contains(RZ_NONNULL RzSetS *set, const char *str); RZ_API void rz_set_s_delete(RZ_NONNULL RzSetS *set, const char *str); +RZ_API ut32 rz_set_s_size(RZ_NONNULL RzSetS *set); RZ_API RZ_OWN RzPVector /**/ *rz_set_s_to_vector(RZ_NONNULL RzSetS *set); RZ_API RzIterator *rz_set_s_as_iter(const RZ_NONNULL RzSetS *set); -RZ_API RzIterator *rz_set_s_as_iter_mut(RZ_NONNULL RzSetS *set); typedef HtUP RzSetU; @@ -31,8 +31,8 @@ RZ_API void rz_set_u_free(RZ_NULLABLE RzSetU *set); RZ_API void rz_set_u_add(RZ_NONNULL RzSetU *set, ut64 u); RZ_API bool rz_set_u_contains(RZ_NONNULL RzSetU *set, ut64 u); RZ_API void rz_set_u_delete(RZ_NONNULL RzSetU *set, ut64 u); +RZ_API ut32 rz_set_u_size(RZ_NULLABLE RzSetU *set); RZ_API RzIterator *rz_set_u_as_iter(const RZ_NONNULL RzSetU *set); -RZ_API RzIterator *rz_set_u_as_iter_mut(RZ_NONNULL RzSetU *set); #ifdef __cplusplus } diff --git a/librz/util/ht/ht_inc.c b/librz/util/ht/ht_inc.c index 29fdf9e1a07..3de4f9b51d9 100644 --- a/librz/util/ht/ht_inc.c +++ b/librz/util/ht/ht_inc.c @@ -526,10 +526,10 @@ RZ_API ut32 Ht_(size)(RZ_NONNULL HtName_(Ht) *ht) { } /** - * \brief Advances an RzIterator with over a hashtable to the next element in + * \brief Advances an RzIterator with over a hashtable to the next value in * the hash table returns it. * - * \param it The next mutable element or NULL if iteration terminated. + * \param it The next mutable value or NULL if iteration terminated. */ RZ_API VALUE_TYPE *Ht_(iter_next_mut)(RzIterator *it) { rz_return_val_if_fail(it, NULL); @@ -561,10 +561,10 @@ RZ_API VALUE_TYPE *Ht_(iter_next_mut)(RzIterator *it) { } /** - * \brief Advances an RzIterator with over a hashtable to the next element in + * \brief Advances an RzIterator with over a hash table to the next value in * the hash table returns it as const. * - * \param it The next element as immutable or NULL if iteration terminated. + * \param it The next value as immutable or NULL if iteration terminated. */ RZ_API const VALUE_TYPE *Ht_(iter_next)(RzIterator *it) { rz_return_val_if_fail(it, NULL); @@ -595,6 +595,41 @@ RZ_API const VALUE_TYPE *Ht_(iter_next)(RzIterator *it) { return NULL; } +/** + * \brief Advances an RzIterator over a hash table to the next key in + * the hash table returns it as const pointer. + * + * \param it The next key as immutable or NULL if iteration terminated. + */ +RZ_API const KEY_TYPE *Ht_(iter_next_key)(RzIterator *it) { + rz_return_val_if_fail(it, NULL); + + HT_(IterState) *state = it->u; + if (state->ti >= state->ht->size) { + // Iteration is done. No elements left to select. + return NULL; + } + // Iterate over tables until a table with an element is found. + for (; state->ti < state->ht->size; state->ti++) { + if (state->ht->table[state->ti].count == 0) { + // Table has no elements. Check next table. + continue; + } + if (state->bi < state->ht->table[state->ti].count) { + // Table has elements, select the element. + state->kv = &state->ht->table[state->ti].arr[state->bi]; + // For the next iteration, increment bucket index to the following element. + state->bi++; + return (const KEY_TYPE *)&state->kv->key; + } + // Reset bucket index to first bucket. + state->bi = 0; + // Go to next table + } + // Iteration is done. No elements left to select. + return NULL; +} + RZ_API HT_(IterMutState) *Ht_(new_iter_mut_state)(RZ_NONNULL HtName_(Ht) *ht) { rz_return_val_if_fail(ht, NULL); HT_(IterMutState) *state = RZ_NEW0(HT_(IterMutState)); @@ -624,11 +659,11 @@ RZ_API void Ht_(free_iter_state)(HT_(IterState) *state) { } /** - * \brief Returns an iterator over the hash table \p ht. The iterator yields mutable elements. + * \brief Returns an iterator over the hash table \p ht. The iterator yields mutable values. * * \param ht The hash table to create the iterator for. * - * \return The iterator over the hash table or NULL in case of failure. + * \return The iterator over the hash table values or NULL in case of failure. */ RZ_API RZ_OWN RzIterator *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht) { rz_return_val_if_fail(ht, NULL); @@ -640,11 +675,11 @@ RZ_API RZ_OWN RzIterator *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht) { } /** - * \brief Returns an iterator over the hash table \p ht. The iterator yields immutable elements. + * \brief Returns an iterator over the hash table \p ht. The iterator yields immutable values. * * \param ht The hash table to create the iterator for. * - * \return The iterator over the hash table or NULL in case of failure. + * \return The iterator over the hash table values or NULL in case of failure. */ RZ_API RZ_OWN RzIterator *Ht_(as_iter)(const RZ_NONNULL HtName_(Ht) *ht) { rz_return_val_if_fail(ht, NULL); @@ -654,3 +689,19 @@ RZ_API RZ_OWN RzIterator *Ht_(as_iter)(const RZ_NONNULL HtName_(Ht) *ht) { RzIterator *iter = rz_iterator_new((rz_iterator_next_cb)Ht_(iter_next), NULL, (rz_iterator_free_cb)Ht_(free_iter_state), state); return iter; } + +/** + * \brief Returns an iterator over the hash table \p ht. The iterator yields immutable keys. + * + * \param ht The hash table to create the iterator for. + * + * \return The iterator over the hash table keys or NULL in case of failure. + */ +RZ_API RZ_OWN RzIterator *Ht_(as_iter_keys)(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_key), NULL, (rz_iterator_free_cb)Ht_(free_iter_state), state); + return iter; +} diff --git a/librz/util/set.c b/librz/util/set.c index 7e4452437da..2cb76000abe 100644 --- a/librz/util/set.c +++ b/librz/util/set.c @@ -37,6 +37,16 @@ RZ_API void rz_set_s_delete(RZ_NONNULL RzSetS *set, const char *str) { ht_sp_delete(set, str); } +/** + * \brief Returns an iterator over the \p set with immutable elements. + * + * \return Iterator yielding immutable elements. + */ +RZ_API RzIterator *rz_set_s_as_iter(const RZ_NONNULL RzSetS *set) { + rz_return_val_if_fail(set, NULL); + return ht_sp_as_iter_keys((const HtSP *)set); +} + static bool push_to_pvector(void *user, const char *k, RZ_UNUSED const void *v) { RzPVector *vec = (RzPVector *)user; return !!rz_pvector_push(vec, (void *)k); @@ -65,6 +75,13 @@ RZ_API void rz_set_s_free(RZ_NULLABLE RzSetS *set) { ht_sp_free((HtSP *)set); } +/** + * \brief Return number of elements saved in the set. + */ +RZ_API ut32 rz_set_s_size(RZ_NULLABLE RzSetS *set) { + return ht_sp_size((HtSP *)set); +} + /** * \brief Create a new hash set with ut64 as elements. */ @@ -99,3 +116,20 @@ RZ_API void rz_set_u_delete(RZ_NONNULL RzSetU *set, ut64 u) { RZ_API void rz_set_u_free(RZ_NULLABLE RzSetU *set) { ht_up_free((HtUP *)set); } + +/** + * \brief Return number of elements saved in the set. + */ +RZ_API ut32 rz_set_u_size(RZ_NULLABLE RzSetU *set) { + return ht_up_size((HtUP *)set); +} + +/** + * \brief Returns an iterator over the \p set with immutable elements. + * + * \return Iterator yielding immutable elements. + */ +RZ_API RzIterator *rz_set_u_as_iter(const RZ_NONNULL RzSetU *set) { + rz_return_val_if_fail(set, NULL); + return ht_up_as_iter_keys((const HtUP *)set); +} diff --git a/test/unit/meson.build b/test/unit/meson.build index 99d44094b20..832c0009737 100644 --- a/test/unit/meson.build +++ b/test/unit/meson.build @@ -54,6 +54,7 @@ if get_option('enable_tests') 'graph', 'hash', 'hex', + 'ht', 'id_storage', 'idpool', 'idstorage', @@ -81,7 +82,6 @@ if get_option('enable_tests') 'rz_test', 'sdb_array', 'sdb_diff', - 'sdb_hash', 'sdb_sdb', 'sdb_util', 'serialize_analysis', diff --git a/test/unit/test_ht.c b/test/unit/test_ht.c index b34f8c79ec5..004d7192f88 100644 --- a/test/unit/test_ht.c +++ b/test/unit/test_ht.c @@ -4,6 +4,7 @@ #include "minunit.h" #include #include +#include #include #include #include @@ -704,6 +705,140 @@ bool test_ht_ss_iter(void) { mu_end; } +bool test_set_u(void) { + RzSetU *set_u = rz_set_u_new(); + rz_set_u_add(set_u, 0x5050505); + rz_set_u_add(set_u, 0x5050505); + rz_set_u_add(set_u, 0x6060606); + rz_set_u_add(set_u, 0x7070707); + rz_set_u_add(set_u, 0x7070707); + mu_assert_eq(rz_set_u_size(set_u), 3, "Length wrong."); + mu_assert_true(rz_set_u_contains(set_u, 0x5050505), "Value was not added."); + mu_assert_true(rz_set_u_contains(set_u, 0x6060606), "Value was not added."); + mu_assert_true(rz_set_u_contains(set_u, 0x7070707), "Value was not added."); + + rz_set_u_delete(set_u, 0x7070707); + mu_assert_false(rz_set_u_contains(set_u, 0x7070707), "Value was not deleted."); + mu_assert_eq(rz_set_u_size(set_u), 2, "Length wrong."); + + // Double delete + rz_set_u_delete(set_u, 0x7070707); + mu_assert_eq(rz_set_u_size(set_u), 2, "Length wrong."); + + size_t x = 0; + const ut64 *im_elem; + RzIterator *it = rz_set_u_as_iter(set_u); + rz_iterator_foreach(it, im_elem) { + x++; + bool matches = *im_elem == 0x5050505 || *im_elem == 0x6060606; + mu_assert_true(matches, "Set contained ill-formed value."); + } + rz_iterator_free(it); + mu_assert_eq(x, 2, "Foreach hasn't iterated the correct number of times."); + + rz_set_u_delete(set_u, 0x6060606); + mu_assert_eq(rz_set_u_size(set_u), 1, "Length wrong."); + rz_set_u_delete(set_u, 0x5050505); + mu_assert_eq(rz_set_u_size(set_u), 0, "Length wrong."); + + it = rz_set_u_as_iter(set_u); + rz_iterator_foreach(it, im_elem) { + mu_assert("Should not be reached.", false); + } + rz_iterator_free(it); + rz_set_u_add(set_u, 0x53e0); + rz_set_u_add(set_u, 0x53bc); + x = 0; + it = rz_set_u_as_iter(set_u); + rz_iterator_foreach(it, im_elem) { + x++; + } + rz_iterator_free(it); + mu_assert_eq(x, 2, "Foreach hasn't iterated the correct number of times."); + rz_set_u_delete(set_u, 0x53e0); + rz_set_u_delete(set_u, 0x53bc); + + rz_set_u_add(set_u, 0); + rz_set_u_add(set_u, 1); + rz_set_u_add(set_u, 2); + rz_set_u_add(set_u, 3); + + // Add an address as key which is far away from the heap addresses. + rz_set_u_add(set_u, 100000000); + mu_assert_true(rz_set_u_contains(set_u, 100000000), "Not contained."); + mu_assert_eq(set_u->count, 5, "count"); + mu_assert_false(rz_set_u_contains(set_u, 6), "should not be here."); + + x = 0; + it = rz_set_u_as_iter(set_u); + rz_iterator_foreach(it, im_elem) { + x++; + } + rz_iterator_free(it); + mu_assert_eq(x, 5, "Foreach hasn't iterated the correct number of times."); + + rz_set_u_free(set_u); + mu_end; +} + +bool test_set_s(void) { + RzSetS *set_s = rz_set_s_new(HT_STR_CONST); + rz_set_s_add(set_s, "0x5050505"); + rz_set_s_add(set_s, "0x5050505"); + rz_set_s_add(set_s, "0x6060606"); + rz_set_s_add(set_s, "0x7070707"); + rz_set_s_add(set_s, "0x7070707"); + mu_assert_eq(rz_set_s_size(set_s), 3, "Length wrong."); + mu_assert_true(rz_set_s_contains(set_s, "0x5050505"), "Value was not added."); + mu_assert_true(rz_set_s_contains(set_s, "0x6060606"), "Value was not added."); + mu_assert_true(rz_set_s_contains(set_s, "0x7070707"), "Value was not added."); + + rz_set_s_delete(set_s, "0x7070707"); + mu_assert_false(rz_set_s_contains(set_s, "0x7070707"), "Value was not deleted."); + mu_assert_eq(rz_set_s_size(set_s), 2, "Length wrong."); + + // Double delete + rz_set_s_delete(set_s, "0x7070707"); + mu_assert_eq(rz_set_s_size(set_s), 2, "Length wrong."); + + size_t x = 0; + const char **im_elem; + + RzIterator *it = rz_set_s_as_iter(set_s); + rz_iterator_foreach(it, im_elem) { + x++; + bool matches = RZ_STR_EQ(*im_elem, "0x5050505") || RZ_STR_EQ(*im_elem, "0x6060606"); + mu_assert_true(matches, "Set contained ill-formed value."); + } + rz_iterator_free(it); + mu_assert_eq(x, 2, "Foreach hasn't iterated the correct number of times."); + + rz_set_s_delete(set_s, "0x6060606"); + mu_assert_eq(rz_set_s_size(set_s), 1, "Length wrong."); + rz_set_s_delete(set_s, "0x5050505"); + mu_assert_eq(rz_set_s_size(set_s), 0, "Length wrong."); + + it = rz_set_s_as_iter(set_s); + rz_iterator_foreach(it, im_elem) { + mu_assert("Should not be reached.", false); + } + rz_iterator_free(it); + rz_set_s_add(set_s, "0x53e0"); + rz_set_s_add(set_s, "0x53bc"); + x = 0; + it = rz_set_s_as_iter(set_s); + rz_iterator_foreach(it, im_elem) { + x++; + } + rz_iterator_free(it); + mu_assert_eq(x, 2, "Foreach hasn't iterated the correct number of times."); + rz_set_s_delete(set_s, "0x53e0"); + rz_set_s_delete(set_s, "0x53bc"); + + rz_set_s_free(set_s); + mu_end; +} + int all_tests() { mu_run_test(test_ht_insert_lookup); mu_run_test(test_ht_update_lookup); @@ -728,6 +863,8 @@ int all_tests() { mu_run_test(test_ht_size); mu_run_test(test_ht_uu_iter); mu_run_test(test_ht_ss_iter); + mu_run_test(test_set_u); + mu_run_test(test_set_s); return tests_passed != tests_run; } From 69bb5c040ef82ad33fb4ea8b8736dac9f386c28b Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 18 Sep 2024 04:27:54 -0500 Subject: [PATCH 03/10] Constify get-size() of hash tables. --- librz/include/rz_util/ht_inc.h | 2 +- librz/include/rz_util/rz_set.h | 4 ++-- librz/util/ht/ht_inc.c | 3 ++- librz/util/set.c | 6 ++++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/librz/include/rz_util/ht_inc.h b/librz/include/rz_util/ht_inc.h index f82dc5997cf..8371cc1413a 100644 --- a/librz/include/rz_util/ht_inc.h +++ b/librz/include/rz_util/ht_inc.h @@ -208,7 +208,7 @@ RZ_API VALUE_TYPE Ht_(find)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE key, RZ_N // NOTE: cb can delete the current element, but it should be avoided RZ_API void Ht_(foreach)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(ForeachCallback) cb, RZ_NULLABLE void *user); -RZ_API ut32 Ht_(size)(RZ_NONNULL HtName_(Ht) *ht); +RZ_API ut32 Ht_(size)(const RZ_NONNULL HtName_(Ht) *ht); RZ_API RZ_BORROW HT_(Kv) *Ht_(find_kv)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE key, RZ_NULLABLE bool *found); RZ_API bool Ht_(insert_kv)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(Kv) *kv, bool update); diff --git a/librz/include/rz_util/rz_set.h b/librz/include/rz_util/rz_set.h index c36a3a05973..d496dd0baf2 100644 --- a/librz/include/rz_util/rz_set.h +++ b/librz/include/rz_util/rz_set.h @@ -20,7 +20,7 @@ RZ_API void rz_set_s_free(RZ_NULLABLE RzSetS *set); RZ_API void rz_set_s_add(RZ_NONNULL RzSetS *set, const char *str); RZ_API bool rz_set_s_contains(RZ_NONNULL RzSetS *set, const char *str); RZ_API void rz_set_s_delete(RZ_NONNULL RzSetS *set, const char *str); -RZ_API ut32 rz_set_s_size(RZ_NONNULL RzSetS *set); +RZ_API ut32 rz_set_s_size(const RZ_NONNULL RzSetS *set); RZ_API RZ_OWN RzPVector /**/ *rz_set_s_to_vector(RZ_NONNULL RzSetS *set); RZ_API RzIterator *rz_set_s_as_iter(const RZ_NONNULL RzSetS *set); @@ -31,7 +31,7 @@ RZ_API void rz_set_u_free(RZ_NULLABLE RzSetU *set); RZ_API void rz_set_u_add(RZ_NONNULL RzSetU *set, ut64 u); RZ_API bool rz_set_u_contains(RZ_NONNULL RzSetU *set, ut64 u); RZ_API void rz_set_u_delete(RZ_NONNULL RzSetU *set, ut64 u); -RZ_API ut32 rz_set_u_size(RZ_NULLABLE RzSetU *set); +RZ_API ut32 rz_set_u_size(const RZ_NONNULL RzSetU *set); RZ_API RzIterator *rz_set_u_as_iter(const RZ_NONNULL RzSetU *set); #ifdef __cplusplus diff --git a/librz/util/ht/ht_inc.c b/librz/util/ht/ht_inc.c index 3de4f9b51d9..fc1a30c6517 100644 --- a/librz/util/ht/ht_inc.c +++ b/librz/util/ht/ht_inc.c @@ -521,7 +521,8 @@ RZ_API void Ht_(foreach)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(ForeachCallb * * \return The number of elements saved in the hash map. */ -RZ_API ut32 Ht_(size)(RZ_NONNULL HtName_(Ht) *ht) { +RZ_API ut32 Ht_(size)(const RZ_NONNULL HtName_(Ht) *ht) { + rz_return_val_if_fail(ht, 0); return ht->count; } diff --git a/librz/util/set.c b/librz/util/set.c index 2cb76000abe..fdd965158ce 100644 --- a/librz/util/set.c +++ b/librz/util/set.c @@ -78,7 +78,8 @@ RZ_API void rz_set_s_free(RZ_NULLABLE RzSetS *set) { /** * \brief Return number of elements saved in the set. */ -RZ_API ut32 rz_set_s_size(RZ_NULLABLE RzSetS *set) { +RZ_API ut32 rz_set_s_size(const RZ_NONNULL RzSetS *set) { + rz_return_val_if_fail(set, 0); return ht_sp_size((HtSP *)set); } @@ -120,7 +121,8 @@ RZ_API void rz_set_u_free(RZ_NULLABLE RzSetU *set) { /** * \brief Return number of elements saved in the set. */ -RZ_API ut32 rz_set_u_size(RZ_NULLABLE RzSetU *set) { +RZ_API ut32 rz_set_u_size(const RZ_NONNULL RzSetU *set) { + rz_return_val_if_fail(set, 0); return ht_up_size((HtUP *)set); } From fb23832485b965ace8111032dd35d668a1907602 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 19 Sep 2024 02:34:52 -0500 Subject: [PATCH 04/10] Shorten documentation --- librz/util/ht/ht_inc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/librz/util/ht/ht_inc.c b/librz/util/ht/ht_inc.c index fc1a30c6517..782dc9791d0 100644 --- a/librz/util/ht/ht_inc.c +++ b/librz/util/ht/ht_inc.c @@ -527,10 +527,9 @@ RZ_API ut32 Ht_(size)(const RZ_NONNULL HtName_(Ht) *ht) { } /** - * \brief Advances an RzIterator with over a hashtable to the next value in - * the hash table returns it. + * \brief Advances an RzIterator over a hashtable to the next value and returns it. * - * \param it The next mutable value or NULL if iteration terminated. + * \param it The next value or NULL if iteration terminated. The value is mutable. */ RZ_API VALUE_TYPE *Ht_(iter_next_mut)(RzIterator *it) { rz_return_val_if_fail(it, NULL); @@ -562,8 +561,7 @@ RZ_API VALUE_TYPE *Ht_(iter_next_mut)(RzIterator *it) { } /** - * \brief Advances an RzIterator with over a hash table to the next value in - * the hash table returns it as const. + * \brief Advances an RzIterator over a hash table to the next value and returns it. * * \param it The next value as immutable or NULL if iteration terminated. */ @@ -598,7 +596,7 @@ RZ_API const VALUE_TYPE *Ht_(iter_next)(RzIterator *it) { /** * \brief Advances an RzIterator over a hash table to the next key in - * the hash table returns it as const pointer. + * and returns it. * * \param it The next key as immutable or NULL if iteration terminated. */ From b9a9950123ae4d7f79c5a0e888b72620008d1b5d Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 19 Sep 2024 02:35:28 -0500 Subject: [PATCH 05/10] Reverse condition. --- librz/util/ht/ht_inc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/librz/util/ht/ht_inc.c b/librz/util/ht/ht_inc.c index 782dc9791d0..f4a789ab0cf 100644 --- a/librz/util/ht/ht_inc.c +++ b/librz/util/ht/ht_inc.c @@ -646,15 +646,17 @@ RZ_API HT_(IterState) *Ht_(new_iter_state)(const RZ_NONNULL HtName_(Ht) *ht) { } RZ_API void Ht_(free_iter_mut_state)(HT_(IterMutState) *state) { - if (state) { - free(state); + if (!state) { + return; } + free(state); } RZ_API void Ht_(free_iter_state)(HT_(IterState) *state) { - if (state) { - free(state); + if (!state) { + return; } + free(state); } /** From 2a849d3818fb337dd703c17352ec6d9c99e4eb40 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 19 Sep 2024 02:41:04 -0500 Subject: [PATCH 06/10] Add type annotations --- librz/include/rz_util/ht_inc.h | 6 +++--- librz/include/rz_util/rz_set.h | 4 ++-- librz/util/ht/ht_inc.c | 6 +++--- librz/util/set.c | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/librz/include/rz_util/ht_inc.h b/librz/include/rz_util/ht_inc.h index 8371cc1413a..57de649d894 100644 --- a/librz/include/rz_util/ht_inc.h +++ b/librz/include/rz_util/ht_inc.h @@ -222,6 +222,6 @@ RZ_API VALUE_TYPE *Ht_(iter_next_mut)(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 RZ_OWN RzIterator *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht); -RZ_API RZ_OWN RzIterator *Ht_(as_iter)(const RZ_NONNULL HtName_(Ht) *ht); -RZ_API RZ_OWN RzIterator *Ht_(as_iter_keys)(const RZ_NONNULL HtName_(Ht) *ht); +RZ_API RZ_OWN RzIterator /* */ *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht); +RZ_API RZ_OWN RzIterator /* */ *Ht_(as_iter)(const RZ_NONNULL HtName_(Ht) *ht); +RZ_API RZ_OWN RzIterator /* */ *Ht_(as_iter_keys)(const RZ_NONNULL HtName_(Ht) *ht); diff --git a/librz/include/rz_util/rz_set.h b/librz/include/rz_util/rz_set.h index d496dd0baf2..9a8a4076390 100644 --- a/librz/include/rz_util/rz_set.h +++ b/librz/include/rz_util/rz_set.h @@ -22,7 +22,7 @@ RZ_API bool rz_set_s_contains(RZ_NONNULL RzSetS *set, const char *str); RZ_API void rz_set_s_delete(RZ_NONNULL RzSetS *set, const char *str); RZ_API ut32 rz_set_s_size(const RZ_NONNULL RzSetS *set); RZ_API RZ_OWN RzPVector /**/ *rz_set_s_to_vector(RZ_NONNULL RzSetS *set); -RZ_API RzIterator *rz_set_s_as_iter(const RZ_NONNULL RzSetS *set); +RZ_API RzIterator /* */ *rz_set_s_as_iter(const RZ_NONNULL RzSetS *set); typedef HtUP RzSetU; @@ -32,7 +32,7 @@ RZ_API void rz_set_u_add(RZ_NONNULL RzSetU *set, ut64 u); RZ_API bool rz_set_u_contains(RZ_NONNULL RzSetU *set, ut64 u); RZ_API void rz_set_u_delete(RZ_NONNULL RzSetU *set, ut64 u); RZ_API ut32 rz_set_u_size(const RZ_NONNULL RzSetU *set); -RZ_API RzIterator *rz_set_u_as_iter(const RZ_NONNULL RzSetU *set); +RZ_API RzIterator /* */ *rz_set_u_as_iter(const RZ_NONNULL RzSetU *set); #ifdef __cplusplus } diff --git a/librz/util/ht/ht_inc.c b/librz/util/ht/ht_inc.c index f4a789ab0cf..f9b8658c07f 100644 --- a/librz/util/ht/ht_inc.c +++ b/librz/util/ht/ht_inc.c @@ -666,7 +666,7 @@ RZ_API void Ht_(free_iter_state)(HT_(IterState) *state) { * * \return The iterator over the hash table values or NULL in case of failure. */ -RZ_API RZ_OWN RzIterator *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht) { +RZ_API RZ_OWN RzIterator /* */ *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht) { rz_return_val_if_fail(ht, NULL); HT_(IterMutState) *state = Ht_(new_iter_mut_state)(ht); rz_return_val_if_fail(state, NULL); @@ -682,7 +682,7 @@ RZ_API RZ_OWN RzIterator *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht) { * * \return The iterator over the hash table values or NULL in case of failure. */ -RZ_API RZ_OWN RzIterator *Ht_(as_iter)(const RZ_NONNULL HtName_(Ht) *ht) { +RZ_API RZ_OWN RzIterator /* */ *Ht_(as_iter)(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); @@ -698,7 +698,7 @@ RZ_API RZ_OWN RzIterator *Ht_(as_iter)(const RZ_NONNULL HtName_(Ht) *ht) { * * \return The iterator over the hash table keys or NULL in case of failure. */ -RZ_API RZ_OWN RzIterator *Ht_(as_iter_keys)(const RZ_NONNULL HtName_(Ht) *ht) { +RZ_API RZ_OWN RzIterator /* */ *Ht_(as_iter_keys)(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); diff --git a/librz/util/set.c b/librz/util/set.c index fdd965158ce..f870bcace46 100644 --- a/librz/util/set.c +++ b/librz/util/set.c @@ -42,7 +42,7 @@ RZ_API void rz_set_s_delete(RZ_NONNULL RzSetS *set, const char *str) { * * \return Iterator yielding immutable elements. */ -RZ_API RzIterator *rz_set_s_as_iter(const RZ_NONNULL RzSetS *set) { +RZ_API RzIterator /* */ *rz_set_s_as_iter(const RZ_NONNULL RzSetS *set) { rz_return_val_if_fail(set, NULL); return ht_sp_as_iter_keys((const HtSP *)set); } @@ -131,7 +131,7 @@ RZ_API ut32 rz_set_u_size(const RZ_NONNULL RzSetU *set) { * * \return Iterator yielding immutable elements. */ -RZ_API RzIterator *rz_set_u_as_iter(const RZ_NONNULL RzSetU *set) { +RZ_API RzIterator /* */ *rz_set_u_as_iter(const RZ_NONNULL RzSetU *set) { rz_return_val_if_fail(set, NULL); return ht_up_as_iter_keys((const HtUP *)set); } From 0033d5f2a7aa206096ae923b8cbba6722bb92d6c Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 19 Sep 2024 02:50:33 -0500 Subject: [PATCH 07/10] Mention iterators in docs. --- DEVELOPERS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DEVELOPERS.md b/DEVELOPERS.md index e2dad069407..89467bf82d9 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -203,6 +203,9 @@ rz_core_wrap.cxx:32103:61: error: assigning to 'RzDebugReasonType' from incompat int sum = 0; // set sum to 0 ``` +* If you want to iterate over values of your struct, implement `RzIterator *mystruct_as_iter()` and `RzIterator *mystruct_as_iter_mut()` for them. + See `rz_iterator.h` for details about the iterator. + * If you need bitmaps, do not shift and OR the bits manually on `ut32`. Use bit vectors from `rz_bitvector.h` instead. ### Shell Scripts From b8038fc1268c4ac93494f5d9246412979e2ec459 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 24 Sep 2024 00:26:44 -0500 Subject: [PATCH 08/10] Add missing ownership to pointers. --- librz/include/rz_util/ht_inc.h | 8 ++++---- librz/util/ht/ht_inc.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/librz/include/rz_util/ht_inc.h b/librz/include/rz_util/ht_inc.h index 57de649d894..19858a015cb 100644 --- a/librz/include/rz_util/ht_inc.h +++ b/librz/include/rz_util/ht_inc.h @@ -214,11 +214,11 @@ RZ_API RZ_BORROW HT_(Kv) *Ht_(find_kv)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYP RZ_API bool Ht_(insert_kv)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(Kv) *kv, bool update); RZ_API HtRetCode Ht_(insert_kv_ex)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(Kv) *kv, bool update, RZ_OUT RZ_NULLABLE HT_(Kv) **out_kv); -RZ_API HT_(IterMutState) *Ht_(new_iter_mut_state)(RZ_NONNULL HtName_(Ht) *ht); -RZ_API HT_(IterState) *Ht_(new_iter_state)(const RZ_NONNULL HtName_(Ht) *ht); -RZ_API void Ht_(free_iter_state)(HT_(IterState) *state); +RZ_API RZ_OWN HT_(IterMutState) *Ht_(new_iter_mut_state)(RZ_NONNULL HtName_(Ht) *ht); +RZ_API RZ_OWN HT_(IterState) *Ht_(new_iter_state)(const RZ_NONNULL HtName_(Ht) *ht); +RZ_API void Ht_(free_iter_state)(RZ_NULLABLE HT_(IterState) *state); -RZ_API 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 KEY_TYPE *Ht_(iter_next_key)(RzIterator *it); diff --git a/librz/util/ht/ht_inc.c b/librz/util/ht/ht_inc.c index f9b8658c07f..5397d38d925 100644 --- a/librz/util/ht/ht_inc.c +++ b/librz/util/ht/ht_inc.c @@ -531,7 +531,7 @@ RZ_API ut32 Ht_(size)(const RZ_NONNULL HtName_(Ht) *ht) { * * \param it The next value or NULL if iteration terminated. The value is mutable. */ -RZ_API VALUE_TYPE *Ht_(iter_next_mut)(RzIterator *it) { +RZ_API RZ_BORROW VALUE_TYPE *Ht_(iter_next_mut)(RzIterator *it) { rz_return_val_if_fail(it, NULL); HT_(IterMutState) *state = it->u; @@ -629,7 +629,7 @@ RZ_API const KEY_TYPE *Ht_(iter_next_key)(RzIterator *it) { return NULL; } -RZ_API 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); HT_(IterMutState) *state = RZ_NEW0(HT_(IterMutState)); rz_return_val_if_fail(state, NULL); @@ -637,7 +637,7 @@ RZ_API HT_(IterMutState) *Ht_(new_iter_mut_state)(RZ_NONNULL HtName_(Ht) *ht) { return state; } -RZ_API HT_(IterState) *Ht_(new_iter_state)(const RZ_NONNULL HtName_(Ht) *ht) { +RZ_API RZ_OWN HT_(IterState) *Ht_(new_iter_state)(const RZ_NONNULL HtName_(Ht) *ht) { rz_return_val_if_fail(ht, NULL); HT_(IterState) *state = RZ_NEW0(HT_(IterState)); rz_return_val_if_fail(state, NULL); @@ -652,7 +652,7 @@ RZ_API void Ht_(free_iter_mut_state)(HT_(IterMutState) *state) { free(state); } -RZ_API void Ht_(free_iter_state)(HT_(IterState) *state) { +RZ_API void Ht_(free_iter_state)(RZ_NULLABLE HT_(IterState) *state) { if (!state) { return; } From 2f84cafb10ece20dee5d9fe5a08ff8f61b5d656e Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 24 Sep 2024 00:30:34 -0500 Subject: [PATCH 09/10] Log explicitly an error if allocation fails. --- librz/util/ht/ht_inc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/librz/util/ht/ht_inc.c b/librz/util/ht/ht_inc.c index 5397d38d925..9e7b400bf8f 100644 --- a/librz/util/ht/ht_inc.c +++ b/librz/util/ht/ht_inc.c @@ -4,6 +4,7 @@ // SPDX-FileCopyrightText: 2024 pelijah // SPDX-License-Identifier: BSD-3-Clause +#include #include #include #include @@ -669,7 +670,10 @@ RZ_API void Ht_(free_iter_state)(RZ_NULLABLE HT_(IterState) *state) { RZ_API RZ_OWN RzIterator /* */ *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht) { rz_return_val_if_fail(ht, NULL); HT_(IterMutState) *state = Ht_(new_iter_mut_state)(ht); - rz_return_val_if_fail(state, NULL); + if (!state) { + RZ_LOG_ERROR("Could not allocate a new ht_iter state.\n"); + return NULL; + } RzIterator *iter = rz_iterator_new((rz_iterator_next_cb)Ht_(iter_next_mut), NULL, (rz_iterator_free_cb)Ht_(free_iter_mut_state), state); return iter; From 8f960644e470081fecfa05af32ed18b2055b12bd Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 24 Sep 2024 01:24:21 -0500 Subject: [PATCH 10/10] Fix up free functions --- librz/include/rz_util/ht_inc.h | 1 + librz/util/ht/ht_inc.c | 8 +------- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/librz/include/rz_util/ht_inc.h b/librz/include/rz_util/ht_inc.h index 19858a015cb..e5172112c80 100644 --- a/librz/include/rz_util/ht_inc.h +++ b/librz/include/rz_util/ht_inc.h @@ -216,6 +216,7 @@ RZ_API HtRetCode Ht_(insert_kv_ex)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(Kv RZ_API RZ_OWN HT_(IterMutState) *Ht_(new_iter_mut_state)(RZ_NONNULL HtName_(Ht) *ht); RZ_API RZ_OWN HT_(IterState) *Ht_(new_iter_state)(const RZ_NONNULL HtName_(Ht) *ht); +RZ_API void Ht_(free_iter_mut_state)(RZ_NULLABLE HT_(IterMutState) *state); RZ_API void Ht_(free_iter_state)(RZ_NULLABLE HT_(IterState) *state); RZ_API RZ_BORROW VALUE_TYPE *Ht_(iter_next_mut)(RzIterator *it); diff --git a/librz/util/ht/ht_inc.c b/librz/util/ht/ht_inc.c index 9e7b400bf8f..e436287a331 100644 --- a/librz/util/ht/ht_inc.c +++ b/librz/util/ht/ht_inc.c @@ -646,17 +646,11 @@ RZ_API RZ_OWN HT_(IterState) *Ht_(new_iter_state)(const RZ_NONNULL HtName_(Ht) * return state; } -RZ_API void Ht_(free_iter_mut_state)(HT_(IterMutState) *state) { - if (!state) { - return; - } +RZ_API void Ht_(free_iter_mut_state)(RZ_NULLABLE HT_(IterMutState) *state) { free(state); } RZ_API void Ht_(free_iter_state)(RZ_NULLABLE HT_(IterState) *state) { - if (!state) { - return; - } free(state); }