mirror of
https://github.com/rizinorg/rizin.git
synced 2026-10-12 02:21:57 +00:00
librz/util: add rz_vector_contains() and rz_vector_insert_sorted() (#5892)
* Add rz_vector_contains(). * Add rz_vector_insert_sorted(). * Pointer arithmetic fix for Windows.
This commit is contained in:
@@ -48,6 +48,7 @@ typedef struct rz_vector_t {
|
||||
size_t len;
|
||||
size_t capacity;
|
||||
size_t elem_size;
|
||||
bool reverse_sorted;
|
||||
RzVectorFree free;
|
||||
void *free_user;
|
||||
} RzVector;
|
||||
@@ -142,6 +143,8 @@ RZ_API void *rz_vector_insert(RzVector *vec, size_t index, void *x);
|
||||
// insert count values of size vec->elem_size into vec starting at the given index.
|
||||
RZ_API void *rz_vector_insert_range(RzVector *vec, size_t index, RZ_NULLABLE void *first, size_t count);
|
||||
|
||||
RZ_API void *rz_vector_insert_sorted(RZ_NONNULL RzVector *vec, RZ_NONNULL void *elem, RzVectorComparator cmp, void *user);
|
||||
|
||||
// like rz_vector_remove_at for the last element
|
||||
RZ_API void rz_vector_pop(RzVector *vec, void *into);
|
||||
|
||||
@@ -154,6 +157,8 @@ RZ_API void *rz_vector_push(RzVector *vec, void *x);
|
||||
// like rz_vector_insert for the beginning of vec
|
||||
RZ_API void *rz_vector_push_front(RzVector *vec, void *x);
|
||||
|
||||
RZ_API bool rz_vector_contains(const RZ_NONNULL RzVector *vec, const RZ_NONNULL void *elem);
|
||||
|
||||
/**
|
||||
* \brief Swap two elements of the vector
|
||||
* \param index_a index of the first element to swap
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
RZ_API void rz_vector_init(RzVector *vec, size_t elem_size, RzVectorFree free, void *free_user) {
|
||||
rz_return_if_fail(vec);
|
||||
vec->a = NULL;
|
||||
vec->reverse_sorted = false;
|
||||
vec->capacity = vec->len = 0;
|
||||
vec->elem_size = elem_size;
|
||||
vec->free = free;
|
||||
@@ -255,6 +256,41 @@ RZ_API void *rz_vector_insert_range(RzVector *vec, size_t index, RZ_NULLABLE voi
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Inserts an element into a sorted vector keeping the order.
|
||||
* NOTE: This function assumes the vector is already sorted!
|
||||
* If it isn't the final position of the element is undefined.
|
||||
*
|
||||
* \param vec A sorted vector to insert the element into.
|
||||
* \param elem Pointer to the element to insert into the vector.
|
||||
* \param cmp The comparator for the elements.
|
||||
* \param user The user data passed to the comparator.
|
||||
*
|
||||
* \return Pointer to the position in the vector where the element was placed.
|
||||
* Or NULL in case of failure.
|
||||
*/
|
||||
RZ_API void *rz_vector_insert_sorted(RZ_NONNULL RzVector *vec, RZ_NONNULL void *elem, RzVectorComparator cmp, void *user) {
|
||||
rz_return_val_if_fail(vec && elem, NULL);
|
||||
if (rz_vector_empty(vec)) {
|
||||
return rz_vector_push(vec, elem);
|
||||
}
|
||||
size_t i = vec->reverse_sorted ? rz_vector_len(vec) - 1 : 0;
|
||||
int inc = vec->reverse_sorted ? -1 : 1;
|
||||
|
||||
do {
|
||||
void *velem = ((char *)vec->a) + (vec->elem_size * i);
|
||||
if (cmp(velem, elem, user) >= 0) {
|
||||
return rz_vector_insert(vec, vec->reverse_sorted ? i + 1 : i, elem);
|
||||
}
|
||||
if (i == 0 && inc == -1) {
|
||||
// Overflow is undefined. So lets not depend on it.
|
||||
break;
|
||||
}
|
||||
i += inc;
|
||||
} while (i >= 0 && i < rz_vector_len(vec));
|
||||
return vec->reverse_sorted ? rz_vector_push_front(vec, elem) : rz_vector_push(vec, elem);
|
||||
}
|
||||
|
||||
RZ_API void rz_vector_pop(RzVector *vec, void *into) {
|
||||
if (rz_vector_empty(vec)) {
|
||||
return;
|
||||
@@ -289,6 +325,26 @@ RZ_API void *rz_vector_push_front(RzVector *vec, void *x) {
|
||||
return rz_vector_insert(vec, 0, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks if the given element is in the vector.
|
||||
*
|
||||
* \param vec The vector to search in.
|
||||
* \param elem Pointer to the element to search.
|
||||
*
|
||||
* \return True if the vector contains the element, false otherwise.
|
||||
*/
|
||||
RZ_API bool rz_vector_contains(const RZ_NONNULL RzVector *vec, const RZ_NONNULL void *elem) {
|
||||
rz_return_val_if_fail(vec && elem, false);
|
||||
for (size_t i = 0; i < vec->len; i++) {
|
||||
// Casts to make Windows happy.
|
||||
char *elem_v = ((char *)vec->a) + (vec->elem_size * i);
|
||||
if (memcmp(elem_v, (char *)elem, vec->elem_size) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RZ_API bool rz_vector_swap(RzVector *vec, size_t index_a, size_t index_b) {
|
||||
rz_return_val_if_fail(vec && index_a < vec->len && index_b < vec->len, false);
|
||||
ut8 *tmp = malloc(vec->elem_size);
|
||||
@@ -378,6 +434,7 @@ static void vector_quick_sort(void *a, size_t elem_size, size_t len, RzVectorCom
|
||||
*/
|
||||
RZ_API void rz_vector_sort(RzVector *vec, RzVectorComparator cmp, bool reverse, void *user) {
|
||||
rz_return_if_fail(vec && cmp);
|
||||
vec->reverse_sorted = reverse;
|
||||
if (rz_vector_empty(vec)) {
|
||||
return;
|
||||
}
|
||||
@@ -438,6 +495,14 @@ RZ_API void rz_pvector_free(RzPVector *vec) {
|
||||
free(vec);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks if a the pointer \p x is in the vector.
|
||||
*
|
||||
* \param vec The vector to search in.
|
||||
* \param x The pointer to search.
|
||||
*
|
||||
* \return Returns the pointer to the \p x pointer in the vector if found. NULL otherwise.
|
||||
*/
|
||||
RZ_API void **rz_pvector_contains(RzPVector *vec, const void *x) {
|
||||
rz_return_val_if_fail(vec, NULL);
|
||||
size_t i;
|
||||
|
||||
@@ -241,6 +241,7 @@ static bool test_vector_sort(void) {
|
||||
mu_assert_streq(rz_vector_index_ptr(v, 1), "abb", "sorted strings");
|
||||
mu_assert_streq(rz_vector_index_ptr(v, 2), "caa", "sorted strings");
|
||||
mu_assert_streq(rz_vector_index_ptr(v, 3), "ccc", "sorted strings");
|
||||
mu_assert_false(v->reverse_sorted, "Flag not set.");
|
||||
|
||||
// do dec sort
|
||||
num = 55;
|
||||
@@ -250,6 +251,55 @@ static bool test_vector_sort(void) {
|
||||
mu_assert_streq(rz_vector_index_ptr(v, 1), "caa", "sorted strings");
|
||||
mu_assert_streq(rz_vector_index_ptr(v, 2), "abb", "sorted strings");
|
||||
mu_assert_streq(rz_vector_index_ptr(v, 3), "abb", "sorted strings");
|
||||
mu_assert_true(v->reverse_sorted, "Flag not set.");
|
||||
|
||||
rz_vector_free(v);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
static int uint_cmp(ut64 *a, ut64 *b, void *user) {
|
||||
if (*a > *b) {
|
||||
return 1;
|
||||
} else if (*a < *b) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool test_vector_insert_sorted(void) {
|
||||
RzVector *v = rz_vector_new(sizeof(ut64), NULL, NULL);
|
||||
ut64 n[] = { 0, 1, 2, 3, 4, 5 };
|
||||
rz_vector_insert_sorted(v, &n[1], (RzVectorComparator)uint_cmp, NULL);
|
||||
mu_assert_eq(*(ut64 *)rz_vector_index_ptr(v, 0), 1, "Insert failed");
|
||||
|
||||
rz_vector_insert_sorted(v, &n[0], (RzVectorComparator)uint_cmp, NULL);
|
||||
mu_assert_eq(*(ut64 *)rz_vector_index_ptr(v, 0), 0, "Insert failed");
|
||||
mu_assert_eq(*(ut64 *)rz_vector_index_ptr(v, 1), 1, "Insert failed");
|
||||
|
||||
rz_vector_push(v, &n[2]);
|
||||
rz_vector_push(v, &n[4]);
|
||||
rz_vector_sort(v, (RzVectorComparator)uint_cmp, true, NULL);
|
||||
|
||||
rz_vector_insert_sorted(v, &n[3], (RzVectorComparator)uint_cmp, NULL);
|
||||
rz_vector_insert_sorted(v, &n[5], (RzVectorComparator)uint_cmp, NULL);
|
||||
|
||||
size_t i = 5;
|
||||
ut64 *it = NULL;
|
||||
rz_vector_foreach (v, it) {
|
||||
mu_assert_eq(*it, n[i--], "Compare failed");
|
||||
}
|
||||
|
||||
rz_vector_sort(v, (RzVectorComparator)uint_cmp, false, NULL);
|
||||
rz_vector_remove_at(v, 5, NULL);
|
||||
rz_vector_remove_at(v, 1, NULL);
|
||||
rz_vector_remove_at(v, 0, NULL);
|
||||
rz_vector_insert_sorted(v, &n[5], (RzVectorComparator)uint_cmp, NULL);
|
||||
rz_vector_insert_sorted(v, &n[0], (RzVectorComparator)uint_cmp, NULL);
|
||||
rz_vector_insert_sorted(v, &n[1], (RzVectorComparator)uint_cmp, NULL);
|
||||
i = 0;
|
||||
rz_vector_foreach (v, it) {
|
||||
mu_assert_eq(*it, n[i++], "Compare failed");
|
||||
}
|
||||
|
||||
rz_vector_free(v);
|
||||
mu_end;
|
||||
@@ -653,6 +703,23 @@ static bool test_vector_push_front(void) {
|
||||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_vector_contains(void) {
|
||||
RzVector v;
|
||||
init_test_vector(&v, 6, 0, NULL, NULL);
|
||||
ut64 a = 0;
|
||||
ut64 b = 5;
|
||||
ut64 c = 6;
|
||||
mu_assert_true(rz_vector_contains(&v, &a), "Should contain");
|
||||
mu_assert_true(rz_vector_contains(&v, &b), "Should contain");
|
||||
mu_assert_false(rz_vector_contains(&v, &c), "Should not contain");
|
||||
rz_vector_pop(&v, NULL);
|
||||
mu_assert_false(rz_vector_contains(&v, &b), "Should contain");
|
||||
rz_vector_pop_front(&v, NULL);
|
||||
mu_assert_false(rz_vector_contains(&v, &a), "Should contain");
|
||||
rz_vector_clear(&v);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_vector_swap(void) {
|
||||
RzVector v;
|
||||
init_test_vector(&v, 3, 0, NULL, NULL);
|
||||
@@ -1494,10 +1561,12 @@ static int all_tests(void) {
|
||||
mu_run_test(test_vector_remove_range);
|
||||
mu_run_test(test_vector_insert);
|
||||
mu_run_test(test_vector_insert_range);
|
||||
mu_run_test(test_vector_insert_sorted);
|
||||
mu_run_test(test_vector_pop);
|
||||
mu_run_test(test_vector_pop_front);
|
||||
mu_run_test(test_vector_push);
|
||||
mu_run_test(test_vector_push_front);
|
||||
mu_run_test(test_vector_contains);
|
||||
mu_run_test(test_vector_swap);
|
||||
mu_run_test(test_vector_reserve);
|
||||
mu_run_test(test_vector_shrink);
|
||||
|
||||
Reference in New Issue
Block a user