* util/vector: hoist quicksort scratch buffers out of the recursion
vector_quick_sort allocated its two element-sized scratch buffers (t and
pivot) with malloc/free on every recursive call. For a vector of n elements
the sort makes O(n) recursive calls, i.e. O(n) malloc/free pairs purely for
scratch space, and each call could also fail half-way through the sort.
Split the function into a small entry point that allocates the two buffers
once and a recursive worker that receives them as scratch. The buffers are
reused across the whole recursion (each partition step finishes using them
before recursing, and the recursion is sequential, so sharing one pair is
safe). Small elements -- the common case, including every RzPVector-backed
sort -- use stack buffers and allocate nothing at all; only elements larger
than 256 bytes fall back to a single heap allocation for the whole sort.
The element movement and rand()-based pivot selection are unchanged, so the
result is identical for any input (verified byte-for-byte against the previous
implementation for ascending and descending orders over many random arrays).
* util/vector: evaluate the comparator once per element in the quicksort
The partition loop tested the element against the pivot with two separate
calls to the comparator:
if ((cmp(VEC_INDEX(a, i), pivot, user) < 0 && !reverse) ||
(cmp(VEC_INDEX(a, i), pivot, user) > 0 && reverse)) {
Because cmp is an opaque function pointer the compiler cannot common up the
two calls, so depending on the result and the reverse flag the comparator was
invoked up to twice per element. Compute the result once into a local and test
that:
int c = cmp(VEC_INDEX(a, i), pivot, user);
if ((c < 0 && !reverse) || (c > 0 && reverse)) {
This halves comparator calls in the worst case and is a clear win whenever the
comparator is non-trivial (the common case for struct elements). Measured on a
shared host: ~12-14% faster for int sorting and ~30% faster with a moderately
expensive comparator. The ordering is unchanged (verified byte-for-byte).
* util/vector: simplify rz_pvector_remove_data index computation
The index of the located slot was computed as
size_t index = (el - (void **)vec->v.a) * sizeof(void **) / vec->v.elem_size;
For an RzPVector the element size is always sizeof(void *), so the
`* sizeof(void **) / vec->v.elem_size` factor is identically 1 and the pointer
difference `el - (void **)vec->v.a` already yields the index directly. Drop the
redundant scaling, which removes a multiply and a divide and makes the intent
clear. Behaviour is unchanged.
* test/unit: add RzVector sort and rz_pvector_remove_data regression tests
The existing sort tests only sort 4-5 small elements and there was no test for
rz_pvector_remove_data. Add coverage for the code paths exercised by the sort
changes and the remove_data cleanup:
- test_vector_sort_large sort 2000 heavily-duplicated ut32 values
ascending and descending, verifying the result
is ordered and a permutation of the input (vs a
reference qsort). Drives the recursion deeply
and the shared scratch buffers.
- test_vector_sort_large_elem sort 400 elements of 304 bytes each, taking the
heap-allocated scratch fallback, and check the
full payload (not just the key) stays consistent
through all the element moves.
- test_pvector_remove_data remove interior, first and last elements by
value while preserving order, and confirm
removing an absent value is a no-op.
All pass on both the previous and the optimized implementation (the sort and
remove_data changes are behaviour-preserving).
* test/bench: benchmark rz_vector_sort and rz_pvector_sort
bench_vector.c benchmarked only remove_at and swap. Add sort benchmarks so the
suite covers the functions touched by the sort optimizations and can be run
against the old and new librz for before/after numbers:
- rz_vector_sort over 4k ut64 with a cheap comparator
- rz_vector_sort over 4k ut64 with a deliberately expensive comparator
(shows the effect of evaluating the comparator once per element)
- rz_pvector_sort over 4k pointers (reference; pvector sort is unchanged)
Each iteration refills the buffer from an unsorted master copy via a single
memcpy before sorting; that overhead is identical across builds so the measured
delta reflects the sort.
---------
Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
1912 lines
67 KiB
C
1912 lines
67 KiB
C
// SPDX-FileCopyrightText: 2018 Florian Märkl <info@florianmaerkl.de>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_util.h>
|
|
#include <rz_vector.h>
|
|
#include "minunit.h"
|
|
|
|
// allocates a vector of len ut32 values from 0 to len
|
|
// with capacity len + padding
|
|
static bool _init_test_vector(RzVector *v, size_t len, size_t padding, RzVectorFree free, void *free_user) {
|
|
rz_vector_init(v, sizeof(ut32), free, free_user);
|
|
rz_vector_reserve(v, len + padding);
|
|
|
|
ut32 i;
|
|
for (i = 0; i < len; i++) {
|
|
rz_vector_push(v, &i);
|
|
}
|
|
|
|
return v->len == len && v->capacity == len + padding;
|
|
}
|
|
|
|
#define init_test_vector(v, len, padding, free, free_user) \
|
|
{ \
|
|
bool _r = _init_test_vector((v), (len), (padding), (free), (free_user)); \
|
|
mu_assert("init_test_vector", _r); \
|
|
}
|
|
|
|
// allocates a pvector of len pointers to ut32 values from 0 to len
|
|
// with capacity len + padding
|
|
static bool _init_test_pvector(RzPVector *v, size_t len, size_t padding) {
|
|
rz_pvector_init(v, free);
|
|
rz_pvector_reserve(v, len + padding);
|
|
|
|
ut32 i;
|
|
for (i = 0; i < len; i++) {
|
|
ut32 *e = malloc(sizeof(ut32));
|
|
*e = i;
|
|
rz_pvector_push(v, e);
|
|
}
|
|
|
|
return v->v.len == len && v->v.capacity == len + padding;
|
|
}
|
|
|
|
#define init_test_pvector(v, len, padding) \
|
|
{ \
|
|
bool _r = _init_test_pvector((v), (len), (padding)); \
|
|
mu_assert("init_test_pvector", _r); \
|
|
}
|
|
|
|
// allocates a pvector of len pointers with values from 0 to len
|
|
// with capacity len + padding
|
|
static bool _init_test_pvector2(RzPVector *v, size_t len, size_t padding) {
|
|
rz_pvector_init(v, NULL);
|
|
rz_pvector_reserve(v, len + padding);
|
|
|
|
int i;
|
|
for (i = 0; (size_t)i < len; i++) {
|
|
rz_pvector_push(v, (void *)((size_t)i));
|
|
}
|
|
|
|
return v->v.len == len && v->v.capacity == len + padding;
|
|
}
|
|
|
|
#define init_test_pvector2(v, len, padding) \
|
|
{ \
|
|
bool _r = _init_test_pvector2((v), (len), (padding)); \
|
|
mu_assert("init_test_pvector2", _r); \
|
|
}
|
|
|
|
static bool test_vector_fini(void) {
|
|
RzVector v;
|
|
rz_vector_init(&v, sizeof(void *), NULL, free);
|
|
rz_vector_push(&v, &v);
|
|
mu_assert_eq(v.elem_size, sizeof(void *), "init elem_size");
|
|
mu_assert_eq(v.len, 1, "init len");
|
|
mu_assert_notnull(v.a, "init a");
|
|
mu_assert_null(v.free, "init free");
|
|
mu_assert_ptreq(v.free_user, free, "init free_user");
|
|
rz_vector_clear(&v);
|
|
mu_assert_eq(v.elem_size, sizeof(void *), "init elem_size");
|
|
mu_assert_eq(v.len, 0, "init len");
|
|
mu_assert_null(v.a, "init a");
|
|
mu_assert_eq(v.capacity, 0, "init capacity");
|
|
mu_assert_null(v.free, "init free");
|
|
mu_assert_ptreq(v.free_user, free, "init free_user");
|
|
rz_vector_fini(&v);
|
|
mu_assert_eq(v.elem_size, sizeof(void *), "init elem_size");
|
|
mu_assert_eq(v.len, 0, "init len");
|
|
mu_assert_null(v.a, "init a");
|
|
mu_assert_eq(v.capacity, 0, "init capacity");
|
|
mu_assert_null(v.free, "init free");
|
|
mu_assert_null(v.free_user, "init free_user");
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_init(void) {
|
|
RzVector v;
|
|
rz_vector_init(&v, 42, (void *)1337, (void *)42);
|
|
mu_assert_eq(v.elem_size, 42UL, "init elem_size");
|
|
mu_assert_eq(v.len, 0UL, "init len");
|
|
mu_assert_null(v.a, "init a");
|
|
mu_assert_eq(v.capacity, 0UL, "init capacity");
|
|
mu_assert_eq((size_t)v.free, 1337, "init free");
|
|
mu_assert_eq((size_t)v.free_user, 42, "init free_user");
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_new(void) {
|
|
RzVector *v = rz_vector_new(42, (void *)1337, (void *)42);
|
|
mu_assert("new", v);
|
|
mu_assert_eq(v->elem_size, 42UL, "new elem_size");
|
|
mu_assert_eq(v->len, 0UL, "new len");
|
|
mu_assert_null(v->a, "new a");
|
|
mu_assert_eq(v->capacity, 0UL, "new capacity");
|
|
mu_assert_eq((size_t)v->free, 1337, "init free");
|
|
mu_assert_eq((size_t)v->free_user, 42, "init free_user");
|
|
free(v);
|
|
mu_end;
|
|
}
|
|
|
|
#define FREE_TEST_COUNT 10
|
|
|
|
static void elem_free_test(void *e, void *user) {
|
|
ut32 e_val = *((ut32 *)e);
|
|
int *acc = (int *)user;
|
|
if (e_val > FREE_TEST_COUNT) {
|
|
e_val = FREE_TEST_COUNT;
|
|
}
|
|
acc[e_val]++;
|
|
}
|
|
|
|
static bool test_vector_clear(void) {
|
|
RzVector v;
|
|
int acc[FREE_TEST_COUNT + 1] = { 0 };
|
|
init_test_vector(&v, FREE_TEST_COUNT, 0, elem_free_test, acc);
|
|
rz_vector_clear(&v);
|
|
|
|
// see test_vector_free
|
|
|
|
ut32 i;
|
|
for (i = 0; i < FREE_TEST_COUNT; i++) {
|
|
mu_assert_eq(acc[i], 1, "free individual elements");
|
|
}
|
|
|
|
mu_assert_eq(acc[FREE_TEST_COUNT], 0, "invalid free calls");
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_free(void) {
|
|
RzVector *v = rz_vector_new(4, NULL, NULL);
|
|
int acc[FREE_TEST_COUNT + 1] = { 0 };
|
|
init_test_vector(v, FREE_TEST_COUNT, 0, elem_free_test, acc);
|
|
|
|
rz_vector_free(v);
|
|
|
|
// elem_free_test does acc[i]++ for element value i
|
|
// => acc[0] through acc[FREE_TEST_COUNT-1] == 1
|
|
// acc[FREE_TEST_COUNT] is for potentially invalid calls of elem_free_test
|
|
|
|
ut32 i;
|
|
for (i = 0; i < FREE_TEST_COUNT; i++) {
|
|
mu_assert_eq(acc[i], 1, "free individual elements");
|
|
}
|
|
|
|
mu_assert_eq(acc[FREE_TEST_COUNT], 0, "invalid free calls");
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_set(void) {
|
|
RzVector *v = rz_vector_new(sizeof(ut32), NULL, NULL);
|
|
rz_vector_reserve(v, 10);
|
|
mu_assert_eq(rz_vector_len(v), 0, "Should be empty");
|
|
ut32 data = 0xffeeddcc;
|
|
rz_vector_set(v, 5, &data);
|
|
mu_assert_memeq((ut8 *)v->a + (v->elem_size * 5), (ut8 *)&data, sizeof(ut32), "Data was not written");
|
|
mu_assert_eq(rz_vector_len(v), 0, "_set should not change the length");
|
|
rz_vector_free(v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_clone(void) {
|
|
RzVector v;
|
|
init_test_vector(&v, 5, 0, NULL, NULL);
|
|
RzVector *v1 = rz_vector_clone(&v);
|
|
rz_vector_clear(&v);
|
|
mu_assert("rz_vector_clone", v1);
|
|
mu_assert_eq(v1->len, 5UL, "rz_vector_clone => len");
|
|
mu_assert_eq(v1->capacity, 5UL, "rz_vector_clone => capacity");
|
|
mu_assert_null(v1->free, "rz_vector_clone => no free");
|
|
mu_assert_null(v1->free_user, "rz_vector_clone => no free_user");
|
|
ut32 i;
|
|
for (i = 0; i < 5; i++) {
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(v1, i)), i, "rz_vector_clone => content");
|
|
}
|
|
rz_vector_free(v1);
|
|
|
|
int acc[FREE_TEST_COUNT + 1] = { 0 };
|
|
init_test_vector(&v, FREE_TEST_COUNT, 0, elem_free_test, acc);
|
|
v1 = rz_vector_clone(&v);
|
|
rz_vector_clear(&v);
|
|
mu_assert("rz_vector_clone (+free)", v1);
|
|
mu_assert_eq(v1->len, FREE_TEST_COUNT, "rz_vector_clone (+free) => len");
|
|
mu_assert_eq(v1->capacity, FREE_TEST_COUNT, "rz_vector_clone (+free) => capacity");
|
|
mu_assert_null(v1->free, "rz_vector_clone (+free) => no free");
|
|
mu_assert_null(v1->free_user, "rz_vector_clone (+free) => no free_user");
|
|
for (i = 0; i < FREE_TEST_COUNT; i++) {
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(v1, i)), i, "rz_vector_clone (+free) => content");
|
|
}
|
|
rz_vector_free(v1);
|
|
for (i = 0; i < FREE_TEST_COUNT; i++) {
|
|
mu_assert_eq(acc[i], 1, "free individual elements");
|
|
}
|
|
mu_assert_eq(acc[FREE_TEST_COUNT], 0, "invalid free calls");
|
|
|
|
init_test_vector(&v, 5, 5, NULL, NULL);
|
|
v1 = rz_vector_clone(&v);
|
|
rz_vector_clear(&v);
|
|
mu_assert("rz_vector_clone (+capacity)", v1);
|
|
mu_assert_eq(v1->len, 5UL, "rz_vector_clone (+capacity) => len");
|
|
mu_assert_eq(v1->capacity, 10UL, "rz_vector_clone (+capacity) => capacity");
|
|
mu_assert_null(v1->free, "rz_vector_clone => no free");
|
|
mu_assert_null(v1->free_user, "rz_vector_clone => no free_user");
|
|
for (i = 0; i < 5; i++) {
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(v1, i)), i, "rz_vector_clone => content");
|
|
}
|
|
// write over whole capacity to trigger potential errors with valgrind or asan
|
|
for (i = 0; i < 10; i++) {
|
|
*((ut32 *)rz_vector_index_ptr(v1, i)) = 1337;
|
|
}
|
|
rz_vector_free(v1);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static int compare_string(const char *a, const char *b, void *user) {
|
|
int *num = user;
|
|
*num = 44;
|
|
return strcmp(a, b);
|
|
}
|
|
|
|
static bool test_vector_sort(void) {
|
|
RzVector *v = rz_vector_new(sizeof("aaa"), NULL, NULL);
|
|
rz_vector_push(v, "abb");
|
|
rz_vector_push(v, "caa");
|
|
rz_vector_push(v, "abb");
|
|
rz_vector_push(v, "ccc");
|
|
|
|
// do inc sort
|
|
int num = 88;
|
|
rz_vector_sort(v, (RzVectorComparator)compare_string, false, &num);
|
|
mu_assert_eq(num, 44, "check user pointer");
|
|
mu_assert_streq(rz_vector_index_ptr(v, 0), "abb", "sorted strings");
|
|
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;
|
|
rz_vector_sort(v, (RzVectorComparator)compare_string, true, &num);
|
|
mu_assert_eq(num, 44, "check user pointer");
|
|
mu_assert_streq(rz_vector_index_ptr(v, 0), "ccc", "sorted strings");
|
|
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;
|
|
}
|
|
|
|
static bool test_vector_find_sorted(void) {
|
|
RzVector *v = rz_vector_new(sizeof(ut64), NULL, NULL);
|
|
for (ut64 i = 1; i < 13; i++) {
|
|
rz_vector_push(v, &i);
|
|
}
|
|
ut64 i = UT64_MAX;
|
|
rz_vector_push(v, &i);
|
|
|
|
rz_vector_sort(v, (RzVectorComparator)uint_cmp, false, NULL);
|
|
|
|
i = 5;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), 4, "Not found");
|
|
i = 6;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), 5, "Not found");
|
|
i = 7;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), 6, "Not found");
|
|
i = 8;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), 7, "Not found");
|
|
i = 12;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), 11, "Not found");
|
|
i = UT64_MAX;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), 12, "Not found");
|
|
|
|
i = 0;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), SZT_MAX, "Not failed");
|
|
i = 13;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), SZT_MAX, "Not failed");
|
|
i = UT64_MAX - 1;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), SZT_MAX, "Not failed");
|
|
|
|
rz_vector_sort(v, (RzVectorComparator)uint_cmp, true, NULL);
|
|
|
|
i = 5;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), 8, "Not found");
|
|
i = 6;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), 7, "Not found");
|
|
i = 7;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), 6, "Not found");
|
|
i = 8;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), 5, "Not found");
|
|
i = 12;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), 1, "Not found");
|
|
i = UT64_MAX;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), 0, "Not found");
|
|
|
|
i = 0;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), SZT_MAX, "Not failed");
|
|
i = 13;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), SZT_MAX, "Not failed");
|
|
i = UT64_MAX - 1;
|
|
mu_assert_eq(rz_vector_find_sorted(v, &i, (RzVectorComparator)uint_cmp, NULL), SZT_MAX, "Not failed");
|
|
|
|
rz_vector_free(v);
|
|
mu_end;
|
|
}
|
|
|
|
static int cmp_u32(const void *a, const void *b, void *user) {
|
|
(void)user;
|
|
ut32 x = *(const ut32 *)a, y = *(const ut32 *)b;
|
|
return (x > y) - (x < y);
|
|
}
|
|
static int qsort_u32_asc(const void *a, const void *b) {
|
|
ut32 x = *(const ut32 *)a, y = *(const ut32 *)b;
|
|
return (x > y) - (x < y);
|
|
}
|
|
static int qsort_u32_desc(const void *a, const void *b) {
|
|
ut32 x = *(const ut32 *)a, y = *(const ut32 *)b;
|
|
return (y > x) - (y < x);
|
|
}
|
|
|
|
// Sort a large vector with many duplicates, ascending and descending, and check
|
|
// the result is fully ordered and a permutation of the input (verified against
|
|
// a reference qsort). Exercises the recursion deeply and the shared scratch
|
|
// buffers, which the small existing sort tests do not.
|
|
static bool test_vector_sort_large(void) {
|
|
const size_t n = 2000;
|
|
ut32 *ref = malloc(sizeof(ut32) * n);
|
|
mu_assert_notnull(ref, "ref alloc");
|
|
RzVector v;
|
|
rz_vector_init(&v, sizeof(ut32), NULL, NULL);
|
|
srand(0xC0FFEE);
|
|
for (size_t i = 0; i < n; i++) {
|
|
ut32 x = (ut32)(rand() % 100); // heavy duplication
|
|
ref[i] = x;
|
|
rz_vector_push(&v, &x);
|
|
}
|
|
|
|
rz_vector_sort(&v, cmp_u32, false, NULL);
|
|
mu_assert_eq(v.len, n, "len after sort");
|
|
bool ok = true;
|
|
for (size_t i = 1; i < v.len; i++) {
|
|
if (*(ut32 *)rz_vector_index_ptr(&v, i - 1) > *(ut32 *)rz_vector_index_ptr(&v, i)) {
|
|
ok = false;
|
|
}
|
|
}
|
|
mu_assert_true(ok, "ascending order");
|
|
qsort(ref, n, sizeof(ut32), qsort_u32_asc);
|
|
bool perm = true;
|
|
for (size_t i = 0; i < n; i++) {
|
|
if (*(ut32 *)rz_vector_index_ptr(&v, i) != ref[i]) {
|
|
perm = false;
|
|
}
|
|
}
|
|
mu_assert_true(perm, "ascending is a permutation of the input");
|
|
|
|
rz_vector_sort(&v, cmp_u32, true, NULL);
|
|
ok = true;
|
|
for (size_t i = 1; i < v.len; i++) {
|
|
if (*(ut32 *)rz_vector_index_ptr(&v, i - 1) < *(ut32 *)rz_vector_index_ptr(&v, i)) {
|
|
ok = false;
|
|
}
|
|
}
|
|
mu_assert_true(ok, "descending order");
|
|
qsort(ref, n, sizeof(ut32), qsort_u32_desc);
|
|
perm = true;
|
|
for (size_t i = 0; i < n; i++) {
|
|
if (*(ut32 *)rz_vector_index_ptr(&v, i) != ref[i]) {
|
|
perm = false;
|
|
}
|
|
}
|
|
mu_assert_true(perm, "descending is a permutation of the input");
|
|
|
|
rz_vector_fini(&v);
|
|
free(ref);
|
|
mu_end;
|
|
}
|
|
|
|
typedef struct {
|
|
ut32 key;
|
|
ut8 pad[300];
|
|
} SortBlob304; // > 256 bytes: exercises the heap-fallback scratch path in the sort
|
|
|
|
static int cmp_blob304(const void *a, const void *b, void *user) {
|
|
(void)user;
|
|
ut32 x = ((const SortBlob304 *)a)->key, y = ((const SortBlob304 *)b)->key;
|
|
return (x > y) - (x < y);
|
|
}
|
|
|
|
// Sort elements larger than the on-stack scratch threshold, so the sort takes
|
|
// the heap-allocated scratch fallback. Also checks the whole element (not just
|
|
// the key) is moved consistently.
|
|
static bool test_vector_sort_large_elem(void) {
|
|
const size_t n = 400;
|
|
RzVector v;
|
|
rz_vector_init(&v, sizeof(SortBlob304), NULL, NULL);
|
|
srand(0xBEEF);
|
|
for (size_t i = 0; i < n; i++) {
|
|
SortBlob304 b;
|
|
b.key = (ut32)(rand() % 1000);
|
|
memset(b.pad, (int)(b.key & 0xff), sizeof(b.pad)); // pad tied to key
|
|
rz_vector_push(&v, &b);
|
|
}
|
|
rz_vector_sort(&v, cmp_blob304, false, NULL);
|
|
mu_assert_eq(v.len, n, "len after large-elem sort");
|
|
bool ok = true;
|
|
for (size_t i = 0; i < v.len; i++) {
|
|
SortBlob304 *b = rz_vector_index_ptr(&v, i);
|
|
if (i > 0 && ((SortBlob304 *)rz_vector_index_ptr(&v, i - 1))->key > b->key) {
|
|
ok = false;
|
|
}
|
|
// the payload must still match its key after all the memcpy shuffling
|
|
if (b->pad[0] != (ut8)(b->key & 0xff) || b->pad[299] != (ut8)(b->key & 0xff)) {
|
|
ok = false;
|
|
}
|
|
}
|
|
mu_assert_true(ok, "large-element sort ordered with intact payloads");
|
|
rz_vector_fini(&v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_empty(void) {
|
|
RzVector v;
|
|
rz_vector_init(&v, 1, NULL, NULL);
|
|
bool empty = rz_vector_empty(&v);
|
|
mu_assert_eq(empty, true, "rz_vector_init => rz_vector_empty");
|
|
uint8_t e = 0;
|
|
rz_vector_push(&v, &e);
|
|
empty = rz_vector_empty(&v);
|
|
mu_assert_eq(empty, false, "rz_vector_push => !rz_vector_empty");
|
|
rz_vector_pop(&v, &e);
|
|
empty = rz_vector_empty(&v);
|
|
mu_assert_eq(empty, true, "rz_vector_pop => rz_vector_empty");
|
|
rz_vector_clear(&v);
|
|
|
|
RzVector *vp = rz_vector_new(42, NULL, NULL);
|
|
empty = rz_vector_empty(&v);
|
|
mu_assert_eq(empty, true, "rz_vector_new => rz_vector_empty");
|
|
rz_vector_free(vp);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_remove_at(void) {
|
|
RzVector v = { 0 };
|
|
// Check it doesn't read/writes OOB.
|
|
rz_vector_remove_at(&v, 0, NULL);
|
|
|
|
init_test_vector(&v, 5, 0, NULL, NULL);
|
|
|
|
ut32 e;
|
|
rz_vector_remove_at(&v, 2, &e);
|
|
mu_assert_eq(e, 2, "rz_vector_remove_at => into");
|
|
mu_assert_eq(v.len, 4UL, "rz_vector_remove_at => len");
|
|
|
|
mu_assert_eq(((ut32 *)v.a)[0], 0, "rz_vector_remove_at => remaining elements");
|
|
mu_assert_eq(((ut32 *)v.a)[1], 1, "rz_vector_remove_at => remaining elements");
|
|
mu_assert_eq(((ut32 *)v.a)[2], 3, "rz_vector_remove_at => remaining elements");
|
|
mu_assert_eq(((ut32 *)v.a)[3], 4, "rz_vector_remove_at => remaining elements");
|
|
|
|
rz_vector_remove_at(&v, 3, &e);
|
|
mu_assert_eq(e, 4, "rz_vector_remove_at (end) => into");
|
|
mu_assert_eq(v.len, 3UL, "rz_vector_remove_at (end) => len");
|
|
|
|
mu_assert_eq(((ut32 *)v.a)[0], 0, "rz_vector_remove_at (end) => remaining elements");
|
|
mu_assert_eq(((ut32 *)v.a)[1], 1, "rz_vector_remove_at (end) => remaining elements");
|
|
mu_assert_eq(((ut32 *)v.a)[2], 3, "rz_vector_remove_at (end) => remaining elements");
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_remove_at_unsorted(void) {
|
|
RzVector v = { 0 };
|
|
// Check it doesn't read/writes OOB.
|
|
rz_vector_remove_at_unsorted(&v, 0, NULL);
|
|
|
|
init_test_vector(&v, 5, 0, NULL, NULL);
|
|
|
|
ut32 e;
|
|
rz_vector_remove_at_unsorted(&v, 2, &e);
|
|
mu_assert_eq(e, 2, "rz_vector_remove_at_unsorted => into");
|
|
mu_assert_eq(v.len, 4UL, "rz_vector_remove_at_unsorted => len");
|
|
|
|
mu_assert_eq(((ut32 *)v.a)[0], 0, "rz_vector_remove_at_unsorted => remaining elements");
|
|
mu_assert_eq(((ut32 *)v.a)[1], 1, "rz_vector_remove_at_unsorted => remaining elements");
|
|
mu_assert_eq(((ut32 *)v.a)[2], 4, "rz_vector_remove_at_unsorted => remaining elements");
|
|
mu_assert_eq(((ut32 *)v.a)[3], 3, "rz_vector_remove_at_unsorted => remaining elements");
|
|
|
|
rz_vector_remove_at_unsorted(&v, 3, &e);
|
|
mu_assert_eq(e, 3, "rz_vector_remove_at_unsorted (end) => into");
|
|
mu_assert_eq(v.len, 3UL, "rz_vector_remove_at_unsorted (end) => len");
|
|
|
|
mu_assert_eq(((ut32 *)v.a)[0], 0, "rz_vector_remove_at_unsorted (end) => remaining elements");
|
|
mu_assert_eq(((ut32 *)v.a)[1], 1, "rz_vector_remove_at_unsorted (end) => remaining elements");
|
|
mu_assert_eq(((ut32 *)v.a)[2], 4, "rz_vector_remove_at_unsorted (end) => remaining elements");
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_remove_range(void) {
|
|
RzVector v;
|
|
init_test_vector(&v, 5, 0, NULL, NULL);
|
|
|
|
ut32 e[3];
|
|
rz_vector_remove_range(&v, 2, 2, e);
|
|
mu_assert_eq(e[0], 2, "rz_vector_remove_at => into");
|
|
mu_assert_eq(e[1], 3, "rz_vector_remove_at => into");
|
|
mu_assert_eq(v.len, 3UL, "rz_vector_remove_at => len");
|
|
|
|
mu_assert_eq(((ut32 *)v.a)[0], 0, "rz_vector_remove_at => remaining elements");
|
|
mu_assert_eq(((ut32 *)v.a)[1], 1, "rz_vector_remove_at => remaining elements");
|
|
mu_assert_eq(((ut32 *)v.a)[2], 4, "rz_vector_remove_at => remaining elements");
|
|
|
|
rz_vector_remove_range(&v, 0, 3, e);
|
|
mu_assert_eq(e[0], 0, "rz_vector_remove_at (end) => into");
|
|
mu_assert_eq(e[1], 1, "rz_vector_remove_at (end) => into");
|
|
mu_assert_eq(e[2], 4, "rz_vector_remove_at (end) => into");
|
|
mu_assert_eq(v.len, 0UL, "rz_vector_remove_at (end) => len");
|
|
|
|
rz_vector_fini(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_insert(void) {
|
|
RzVector v;
|
|
|
|
init_test_vector(&v, 4, 2, NULL, NULL);
|
|
ut32 e = 1337;
|
|
e = *((ut32 *)rz_vector_insert(&v, 1, &e));
|
|
mu_assert_eq(v.len, 5UL, "rz_vector_insert => len");
|
|
mu_assert_eq(e, 1337, "rz_vector_insert => content at returned ptr");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 0, "rz_vector_insert => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 1)), 1337, "rz_vector_insert => content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 2)), 1, "rz_vector_insert => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 3)), 2, "rz_vector_insert => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 4)), 3, "rz_vector_insert => old content");
|
|
rz_vector_clear(&v);
|
|
|
|
init_test_vector(&v, 4, 2, NULL, NULL);
|
|
ut32 *p = rz_vector_insert(&v, 1, NULL);
|
|
*p = 1337;
|
|
mu_assert_eq(v.len, 5UL, "rz_vector_insert (null) => len");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 0, "rz_vector_insert (null) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 1)), 1337, "rz_vector_insert (null) => content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 2)), 1, "rz_vector_insert (null) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 3)), 2, "rz_vector_insert (null) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 4)), 3, "rz_vector_insert (null) => old content");
|
|
rz_vector_clear(&v);
|
|
|
|
init_test_vector(&v, 4, 0, NULL, NULL);
|
|
e = 1337;
|
|
e = *((ut32 *)rz_vector_insert(&v, 1, &e));
|
|
mu_assert("rz_vector_insert (resize) => capacity", v.capacity >= 5);
|
|
mu_assert_eq(v.len, 5UL, "rz_vector_insert => len");
|
|
mu_assert_eq(e, 1337, "rz_vector_insert => content at returned ptr");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 0, "rz_vector_insert (resize) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 1)), 1337, "rz_vector_insert (resize) => content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 2)), 1, "rz_vector_insert (resize) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 3)), 2, "rz_vector_insert (resize) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 4)), 3, "rz_vector_insert (resize) => old content");
|
|
rz_vector_clear(&v);
|
|
|
|
init_test_vector(&v, 4, 2, NULL, NULL);
|
|
e = 1337;
|
|
e = *((ut32 *)rz_vector_insert(&v, 4, &e));
|
|
mu_assert_eq(v.len, 5UL, "rz_vector_insert (end) => len");
|
|
mu_assert_eq(e, 1337, "rz_vector_insert (end) => content at returned ptr");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 0, "rz_vector_insert (end) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 1)), 1, "rz_vector_insert (end) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 2)), 2, "rz_vector_insert (end) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 3)), 3, "rz_vector_insert (end) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 4)), 1337, "rz_vector_insert (end) => content");
|
|
rz_vector_clear(&v);
|
|
|
|
init_test_vector(&v, 4, 0, NULL, NULL);
|
|
e = 1337;
|
|
e = *((ut32 *)rz_vector_insert(&v, 4, &e));
|
|
mu_assert("rz_vector_insert (resize) => capacity", v.capacity >= 5);
|
|
mu_assert_eq(v.len, 5UL, "rz_vector_insert (end) => len");
|
|
mu_assert_eq(e, 1337, "rz_vector_insert (end) => content at returned ptr");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 0, "rz_vector_insert (end, resize) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 1)), 1, "rz_vector_insert (end, resize) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 2)), 2, "rz_vector_insert (end, resize) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 3)), 3, "rz_vector_insert (end, resize) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 4)), 1337, "rz_vector_insert (end, resize) => content");
|
|
rz_vector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_insert_range(void) {
|
|
RzVector v;
|
|
ut32 range[] = { 0xC0, 0xFF, 0xEE };
|
|
|
|
rz_vector_init(&v, 4, NULL, NULL);
|
|
ut32 *p = (ut32 *)rz_vector_insert_range(&v, 0, range, 3);
|
|
mu_assert_ptreq(p, rz_vector_index_ptr(&v, 0), "rz_vector_insert_range (empty) returned ptr");
|
|
mu_assert_eq(v.len, 3UL, "rz_vector_insert_range (empty) => len");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 0xC0, "rz_vector_insert_range (empty) => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 1)), 0xFF, "rz_vector_insert_range (empty) => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 2)), 0xEE, "rz_vector_insert_range (empty) => new content");
|
|
rz_vector_clear(&v);
|
|
|
|
init_test_vector(&v, 3, 3, NULL, NULL);
|
|
p = (ut32 *)rz_vector_insert_range(&v, 2, range, 3);
|
|
mu_assert_ptreq(p, rz_vector_index_ptr(&v, 2), "rz_vector_insert_range returned ptr");
|
|
mu_assert_eq(v.len, 6UL, "rz_vector_insert_range => len");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 0, "rz_vector_insert_range => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 1)), 1, "rz_vector_insert_range => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 2)), 0xC0, "rz_vector_insert_range => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 3)), 0xFF, "rz_vector_insert_range => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 4)), 0xEE, "rz_vector_insert_range => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 5)), 2, "rz_vector_insert_range => old content");
|
|
rz_vector_clear(&v);
|
|
|
|
init_test_vector(&v, 3, 3, NULL, NULL);
|
|
p = (ut32 *)rz_vector_insert_range(&v, 2, NULL, 3);
|
|
mu_assert_ptreq(p, rz_vector_index_ptr(&v, 2), "rz_vector_insert_range (null) returned ptr");
|
|
mu_assert_eq(v.len, 6UL, "rz_vector_insert_range (null) => len");
|
|
p[0] = 0xC0;
|
|
p[1] = 0xFF;
|
|
p[2] = 0xEE;
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 0, "rz_vector_insert_range (null) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 1)), 1, "rz_vector_insert_range (null) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 2)), 0xC0, "rz_vector_insert_range (null) => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 3)), 0xFF, "rz_vector_insert_range (null) => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 4)), 0xEE, "rz_vector_insert_range (null) => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 5)), 2, "rz_vector_insert_range (null) => old content");
|
|
rz_vector_clear(&v);
|
|
|
|
init_test_vector(&v, 3, 3, NULL, NULL);
|
|
p = (ut32 *)rz_vector_insert_range(&v, 3, range, 3);
|
|
mu_assert_ptreq(p, rz_vector_index_ptr(&v, 3), "rz_vector_insert_range (end) returned ptr");
|
|
mu_assert_eq(v.len, 6UL, "rz_vector_insert_range (end) => len");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 0, "rz_vector_insert_range (end) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 1)), 1, "rz_vector_insert_range (end) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 2)), 2, "rz_vector_insert_range (end) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 3)), 0xC0, "rz_vector_insert_range (end) => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 4)), 0xFF, "rz_vector_insert_range (end) => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 5)), 0xEE, "rz_vector_insert_range (end) => new content");
|
|
rz_vector_clear(&v);
|
|
|
|
init_test_vector(&v, 3, 0, NULL, NULL);
|
|
p = (ut32 *)rz_vector_insert_range(&v, 2, range, 3);
|
|
mu_assert_ptreq(p, rz_vector_index_ptr(&v, 2), "rz_vector_insert_range (resize) returned ptr");
|
|
mu_assert_eq(v.len, 6UL, "rz_vector_insert_range (resize) => len");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 0, "rz_vector_insert_range (resize) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 1)), 1, "rz_vector_insert_range (resize) => old content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 2)), 0xC0, "rz_vector_insert_range (resize) => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 3)), 0xFF, "rz_vector_insert_range (resize) => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 4)), 0xEE, "rz_vector_insert_range (resize) => new content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 5)), 2, "rz_vector_insert_range (resize) => old content");
|
|
rz_vector_clear(&v);
|
|
|
|
init_test_vector(&v, 3, 0, NULL, NULL);
|
|
rz_vector_insert_range(&v, rz_vector_len(&v), NULL, v.capacity - rz_vector_len(&v));
|
|
p = (ut32 *)rz_vector_insert_range(&v, rz_vector_len(&v), NULL, 0);
|
|
mu_assert_ptreq(p, (ut32 *)rz_vector_tail(&v) + 1,
|
|
"rz_vector_insert_range (0 count at vector end) returned ptr");
|
|
rz_vector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_pop(void) {
|
|
RzVector v = { 0 };
|
|
// Check it doesn't read/writes OOB.
|
|
rz_vector_pop(&v, NULL);
|
|
init_test_vector(&v, 3, 0, NULL, NULL);
|
|
|
|
ut32 e;
|
|
rz_vector_pop(&v, &e);
|
|
mu_assert_eq(e, 2, "rz_vector_pop into");
|
|
mu_assert_eq(v.len, 2UL, "rz_vector_pop => len");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 0, "rz_vector_pop => remaining content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 1)), 1, "rz_vector_pop => remaining content");
|
|
|
|
rz_vector_pop(&v, &e);
|
|
mu_assert_eq(e, 1, "rz_vector_pop into");
|
|
mu_assert_eq(v.len, 1UL, "rz_vector_pop => len");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 0, "rz_vector_pop => remaining content");
|
|
|
|
rz_vector_pop(&v, &e);
|
|
mu_assert_eq(e, 0, "rz_vector_pop (last) into");
|
|
mu_assert_eq(v.len, 0UL, "rz_vector_pop (last) => len");
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_pop_front(void) {
|
|
RzVector v = { 0 };
|
|
// Check it doesn't read/writes OOB.
|
|
rz_vector_pop_front(&v, NULL);
|
|
init_test_vector(&v, 3, 0, NULL, NULL);
|
|
|
|
ut32 e;
|
|
rz_vector_pop_front(&v, &e);
|
|
mu_assert_eq(e, 0, "rz_vector_pop_front into");
|
|
mu_assert_eq(v.len, 2UL, "rz_vector_pop_front => len");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 1, "rz_vector_pop_front => remaining content");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 1)), 2, "rz_vector_pop_front => remaining content");
|
|
|
|
rz_vector_pop_front(&v, &e);
|
|
mu_assert_eq(e, 1, "rz_vector_pop_front into");
|
|
mu_assert_eq(v.len, 1UL, "rz_vector_pop_front => len");
|
|
mu_assert_eq(*((ut32 *)rz_vector_index_ptr(&v, 0)), 2, "rz_vector_pop_front => remaining content");
|
|
|
|
rz_vector_pop_front(&v, &e);
|
|
mu_assert_eq(e, 2, "rz_vector_pop_front (last) into");
|
|
mu_assert_eq(v.len, 0UL, "rz_vector_pop_front (last) => len");
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_push(void) {
|
|
RzVector v;
|
|
rz_vector_init(&v, 4, NULL, NULL);
|
|
|
|
ut32 *p = rz_vector_push(&v, NULL);
|
|
*p = 1337;
|
|
mu_assert_eq(v.len, 1UL, "rz_vector_push (null, empty, assign) => len == 1");
|
|
ut32 e = *((ut32 *)rz_vector_index_ptr(&v, 0));
|
|
mu_assert_eq(e, 1337, "rz_vector_push (null, empty, assign) => content");
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
rz_vector_init(&v, 4, NULL, NULL);
|
|
|
|
e = 1337;
|
|
e = *((ut32 *)rz_vector_push(&v, &e));
|
|
mu_assert_eq(v.len, 1UL, "rz_vector_push (empty) => len == 1");
|
|
mu_assert_eq(e, 1337, "rz_vector_push (empty) => content at returned ptr");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 0));
|
|
mu_assert_eq(e, 1337, "rz_vector_push (empty) => content");
|
|
|
|
e = 0xDEAD;
|
|
e = *((ut32 *)rz_vector_push(&v, &e));
|
|
mu_assert_eq(v.len, 2UL, "rz_vector_push => len == 2");
|
|
mu_assert_eq(e, 0xDEAD, "rz_vector_push (empty) => content at returned ptr");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 0));
|
|
mu_assert_eq(e, 1337, "rz_vector_push => old content");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 1));
|
|
mu_assert_eq(e, 0xDEAD, "rz_vector_push => content");
|
|
|
|
e = 0xBEEF;
|
|
e = *((ut32 *)rz_vector_push(&v, &e));
|
|
mu_assert_eq(v.len, 3UL, "rz_vector_push => len == 3");
|
|
mu_assert_eq(e, 0xBEEF, "rz_vector_push (empty) => content at returned ptr");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 0));
|
|
mu_assert_eq(e, 1337, "rz_vector_push => old content");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 1));
|
|
mu_assert_eq(e, 0xDEAD, "rz_vector_push => old content");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 2));
|
|
mu_assert_eq(e, 0xBEEF, "rz_vector_push => content");
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
init_test_vector(&v, 5, 0, NULL, NULL);
|
|
e = 1337;
|
|
e = *((ut32 *)rz_vector_push(&v, &e));
|
|
mu_assert("rz_vector_push (resize) => capacity", v.capacity >= 6);
|
|
mu_assert_eq(v.len, 6UL, "rz_vector_push (resize) => len");
|
|
mu_assert_eq(e, 1337, "rz_vector_push (empty) => content at returned ptr");
|
|
|
|
size_t i;
|
|
for (i = 0; i < v.len - 1; i++) {
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, i));
|
|
mu_assert_eq(e, (ut32)i, "rz_vector_push (resize) => old content");
|
|
}
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 5));
|
|
mu_assert_eq(e, 1337, "rz_vector_push (resize) => content");
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_push_front(void) {
|
|
RzVector v;
|
|
rz_vector_init(&v, 4, NULL, NULL);
|
|
|
|
ut32 *p = rz_vector_push_front(&v, NULL);
|
|
*p = 1337;
|
|
mu_assert_eq(v.len, 1UL, "rz_vector_push_front (null, empty, assign) => len == 1");
|
|
ut32 e = *((ut32 *)rz_vector_index_ptr(&v, 0));
|
|
mu_assert_eq(e, 1337, "rz_vector_push_front (null, empty, assign) => content");
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
rz_vector_init(&v, 4, NULL, NULL);
|
|
|
|
e = 1337;
|
|
e = *((ut32 *)rz_vector_push_front(&v, &e));
|
|
mu_assert_eq(v.len, 1UL, "rz_vector_push_front (empty) => len == 1");
|
|
mu_assert_eq(e, 1337, "rz_vector_push_front (empty) => content at returned ptr");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 0));
|
|
mu_assert_eq(e, 1337, "rz_vector_push (empty) => content");
|
|
|
|
e = 0xDEAD;
|
|
e = *((ut32 *)rz_vector_push_front(&v, &e));
|
|
mu_assert_eq(v.len, 2UL, "rz_vector_push_front => len == 2");
|
|
mu_assert_eq(e, 0xDEAD, "rz_vector_push_front (empty) => content at returned ptr");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 0));
|
|
mu_assert_eq(e, 0xDEAD, "rz_vector_push_front => content");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 1));
|
|
mu_assert_eq(e, 1337, "rz_vector_push_front => old content");
|
|
|
|
e = 0xBEEF;
|
|
e = *((ut32 *)rz_vector_push_front(&v, &e));
|
|
mu_assert_eq(v.len, 3UL, "rz_vector_push_front => len == 3");
|
|
mu_assert_eq(e, 0xBEEF, "rz_vector_push_front (empty) => content at returned ptr");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 0));
|
|
mu_assert_eq(e, 0xBEEF, "rz_vector_push_front => content");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 1));
|
|
mu_assert_eq(e, 0xDEAD, "rz_vector_push_front => old content");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 2));
|
|
mu_assert_eq(e, 1337, "rz_vector_push_front => old content");
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
init_test_vector(&v, 5, 0, NULL, NULL);
|
|
e = 1337;
|
|
e = *((ut32 *)rz_vector_push_front(&v, &e));
|
|
mu_assert("rz_vector_push_front (resize) => capacity", v.capacity >= 6);
|
|
mu_assert_eq(v.len, 6UL, "rz_vector_push_front (resize) => len");
|
|
mu_assert_eq(e, 1337, "rz_vector_push_front (empty) => content at returned ptr");
|
|
|
|
size_t i;
|
|
for (i = 1; i < v.len; i++) {
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, i));
|
|
mu_assert_eq(e, (ut32)i - 1, "rz_vector_push (resize) => old content");
|
|
}
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 0));
|
|
mu_assert_eq(e, 1337, "rz_vector_push (resize) => content");
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_contains(void) {
|
|
RzVector v;
|
|
init_test_vector(&v, 6, 0, NULL, NULL);
|
|
ut32 a = 0;
|
|
ut32 b = 5;
|
|
ut32 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);
|
|
|
|
rz_vector_swap(&v, 0, 2);
|
|
mu_assert_eq(v.len, 3UL, "rz_vector_swap (valid indexes) => len == 3");
|
|
ut32 e = *((ut32 *)rz_vector_index_ptr(&v, 0));
|
|
mu_assert_eq(e, 2, "rz_vector_swap (valid indexes) => content");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 1));
|
|
mu_assert_eq(e, 1, "rz_vector_swap (valid indexes) => old content");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 2));
|
|
mu_assert_eq(e, 0, "rz_vector_swap (valid indexes) => content");
|
|
|
|
rz_vector_swap(&v, 2, 2);
|
|
mu_assert_eq(v.len, 3UL, "rz_vector_swap (same index) => len == 3");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 0));
|
|
mu_assert_eq(e, 2, "rz_vector_swap (same index) => old content");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 1));
|
|
mu_assert_eq(e, 1, "rz_vector_swap (same index) => old content");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 2));
|
|
mu_assert_eq(e, 0, "rz_vector_swap (same index) => content");
|
|
|
|
rz_vector_swap(&v, 1, 2);
|
|
mu_assert_eq(v.len, 3UL, "rz_vector_swap (bad index) => len == 3");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 0));
|
|
mu_assert_eq(e, 2, "rz_vector_swap (bad index) => old content");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 1));
|
|
mu_assert_eq(e, 0, "rz_vector_swap (bad index) => old content");
|
|
e = *((ut32 *)rz_vector_index_ptr(&v, 2));
|
|
mu_assert_eq(e, 1, "rz_vector_swap (bad index) => old content");
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_reserve(void) {
|
|
RzVector v;
|
|
rz_vector_init(&v, 4, NULL, NULL);
|
|
|
|
rz_vector_reserve(&v, 42);
|
|
mu_assert_eq(rz_vector_capacity(&v), 42UL, "rz_vector_reserve (empty) => capacity");
|
|
mu_assert("rz_vector_reserve (empty) => a", v.a);
|
|
size_t i;
|
|
for (i = 0; i < rz_vector_capacity(&v); i++) {
|
|
*((ut32 *)rz_vector_index_ptr(&v, i)) = 1337;
|
|
}
|
|
v.len = 20;
|
|
|
|
rz_vector_reserve(&v, 100);
|
|
mu_assert_eq(rz_vector_capacity(&v), 100UL, "rz_vector_reserve => capacity");
|
|
mu_assert("rz_vector_reserve => a", v.a);
|
|
for (i = 0; i < rz_vector_capacity(&v); i++) {
|
|
*((ut32 *)rz_vector_index_ptr(&v, i)) = 1337;
|
|
}
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_shrink(void) {
|
|
RzVector v;
|
|
init_test_vector(&v, 5, 5, NULL, NULL);
|
|
void *a = rz_vector_shrink(&v);
|
|
mu_assert_ptreq(a, v.a, "rz_vector_shrink ret");
|
|
mu_assert_eq(v.len, 5UL, "rz_vector_shrink => len");
|
|
mu_assert_eq(rz_vector_capacity(&v), 5UL, "rz_vector_shrink => capacity");
|
|
rz_vector_fini(&v);
|
|
|
|
init_test_vector(&v, 5, 0, NULL, NULL);
|
|
a = rz_vector_shrink(&v);
|
|
mu_assert_ptreq(a, v.a, "rz_vector_shrink (already minimal) ret");
|
|
mu_assert_eq(v.len, 5UL, "rz_vector_shrink (already minimal) => len");
|
|
mu_assert_eq(rz_vector_capacity(&v), 5UL, "rz_vector_shrink (already minimal) => capacity");
|
|
rz_vector_fini(&v);
|
|
|
|
init_test_vector(&v, 0, 8, NULL, NULL);
|
|
rz_vector_shrink(&v);
|
|
rz_vector_fini(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_flush(void) {
|
|
RzVector v;
|
|
init_test_vector(&v, 5, 5, NULL, NULL);
|
|
ut32 *r = rz_vector_take_array(&v);
|
|
rz_vector_fini(&v);
|
|
for (size_t i = 0; i < 5; i++) {
|
|
mu_assert_eq(r[i], i, "flushed contents");
|
|
}
|
|
free(r);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_foreach(void) {
|
|
RzVector v;
|
|
init_test_vector(&v, 5, 5, NULL, NULL);
|
|
|
|
int i = 1;
|
|
ut32 *it;
|
|
int acc[5] = { 0 };
|
|
rz_vector_foreach (&v, it) {
|
|
mu_assert_eq(acc[*it], 0, "unset acc element");
|
|
acc[*it] = i++;
|
|
}
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
mu_assert_eq(acc[i], i + 1, "acc");
|
|
}
|
|
|
|
int acc_prev[5] = { 0 };
|
|
i = 5;
|
|
rz_vector_foreach_prev (&v, it) {
|
|
mu_assert_eq(acc_prev[*it], 0, "unset acc_prev element");
|
|
acc_prev[*it] = i++;
|
|
}
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
mu_assert_eq(acc_prev[i], 10 - i - 1, "acc_prev");
|
|
}
|
|
|
|
rz_vector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_bounds(void) {
|
|
RzVector v;
|
|
rz_vector_init(&v, sizeof(st64), NULL, NULL);
|
|
st64 a[] = { 0, 2, 4, 6, 8 };
|
|
rz_vector_insert_range(&v, 0, a, 5);
|
|
|
|
size_t l;
|
|
#define CMP(x, y) x - (*(st64 *)y)
|
|
rz_vector_lower_bound(&v, 3, l, CMP);
|
|
mu_assert_eq(l, 2, "lower_bound");
|
|
rz_vector_upper_bound(&v, 3, l, CMP);
|
|
mu_assert_eq(l, 2, "upper_bound");
|
|
|
|
rz_vector_lower_bound(&v, 4, l, CMP);
|
|
mu_assert_eq(l, 2, "lower_bound");
|
|
rz_vector_upper_bound(&v, 4, l, CMP);
|
|
mu_assert_eq(l, 3, "upper_bound");
|
|
|
|
rz_vector_lower_bound(&v, -1, l, CMP);
|
|
mu_assert_eq(l, 0, "lower_bound");
|
|
rz_vector_upper_bound(&v, -1, l, CMP);
|
|
mu_assert_eq(l, 0, "upper_bound");
|
|
|
|
rz_vector_lower_bound(&v, 0, l, CMP);
|
|
mu_assert_eq(l, 0, "lower_bound");
|
|
rz_vector_upper_bound(&v, 0, l, CMP);
|
|
mu_assert_eq(l, 1, "upper_bound");
|
|
|
|
rz_vector_lower_bound(&v, 2, l, CMP);
|
|
mu_assert_eq(l, 1, "lower_bound");
|
|
rz_vector_upper_bound(&v, 2, l, CMP);
|
|
mu_assert_eq(l, 2, "upper_bound");
|
|
|
|
rz_vector_lower_bound(&v, 42, l, CMP);
|
|
mu_assert_eq(l, 5, "lower_bound");
|
|
rz_vector_upper_bound(&v, 42, l, CMP);
|
|
mu_assert_eq(l, 5, "upper_bound");
|
|
#undef CMP
|
|
rz_vector_clear(&v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_vector_tips(void) {
|
|
RzVector v;
|
|
st64 t;
|
|
rz_vector_init(&v, sizeof(st64), NULL, NULL);
|
|
st64 a = 42;
|
|
rz_vector_insert(&v, 0, &a);
|
|
t = *(st64 *)rz_vector_head(&v);
|
|
mu_assert_eq(t, 42, "head_same");
|
|
t = *(st64 *)rz_vector_tail(&v);
|
|
mu_assert_eq(t, 42, "tail_same");
|
|
rz_vector_clear(&v);
|
|
|
|
rz_vector_init(&v, sizeof(st64), NULL, NULL);
|
|
st64 b[] = { 0, 2, 4, 6, 8 };
|
|
rz_vector_insert_range(&v, 0, b, 5);
|
|
t = *(st64 *)rz_vector_head(&v);
|
|
mu_assert_eq(t, 0, "head");
|
|
t = *(st64 *)rz_vector_tail(&v);
|
|
mu_assert_eq(t, 8, "tail");
|
|
rz_vector_clear(&v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_init(void) {
|
|
RzPVector v;
|
|
rz_pvector_init(&v, (void *)1337);
|
|
mu_assert_eq(v.v.elem_size, sizeof(void *), "elem_size");
|
|
mu_assert_eq(v.v.len, 0UL, "len");
|
|
mu_assert_null(v.v.a, "a");
|
|
mu_assert_eq(rz_pvector_capacity(&v), 0UL, "capacity");
|
|
mu_assert_eq((size_t)v.v.free_user, 1337, "free");
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_new(void) {
|
|
RzPVector *v = rz_pvector_new((void *)1337);
|
|
mu_assert_eq(v->v.elem_size, sizeof(void *), "elem_size");
|
|
mu_assert_eq(v->v.len, 0UL, "len");
|
|
mu_assert_null(v->v.a, "a");
|
|
mu_assert_eq(v->v.capacity, 0UL, "capacity");
|
|
mu_assert_eq((size_t)v->v.free_user, 1337, "free");
|
|
free(v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_clear(void) {
|
|
// run with asan or valgrind
|
|
RzPVector v;
|
|
init_test_pvector(&v, 5, 5);
|
|
mu_assert_eq(v.v.len, 5UL, "initial len");
|
|
mu_assert("initial a", v.v.a);
|
|
mu_assert_eq(rz_pvector_capacity(&v), 10UL, "initial capacity");
|
|
rz_pvector_clear(&v);
|
|
mu_assert_eq(v.v.len, 0UL, "len");
|
|
mu_assert_null(v.v.a, "a");
|
|
mu_assert_eq(rz_pvector_capacity(&v), 0UL, "capacity");
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_free(void) {
|
|
// run with asan or valgrind
|
|
RzPVector *v = RZ_NEW(RzPVector);
|
|
init_test_pvector(v, 5, 5);
|
|
mu_assert_eq(v->v.len, 5UL, "initial len");
|
|
mu_assert("initial a", v->v.a);
|
|
mu_assert_eq(v->v.capacity, 10UL, "initial capacity");
|
|
rz_pvector_free(v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_at(void) {
|
|
RzPVector v;
|
|
init_test_pvector(&v, 5, 0);
|
|
ut32 i;
|
|
for (i = 0; i < 5; i++) {
|
|
ut32 e = *((ut32 *)rz_pvector_at(&v, i));
|
|
mu_assert_eq(e, i, "at");
|
|
}
|
|
rz_pvector_clear(&v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_set(void) {
|
|
RzPVector v;
|
|
init_test_pvector(&v, 5, 0);
|
|
free(((void **)v.v.a)[3]);
|
|
rz_pvector_set(&v, 3, (void *)1337);
|
|
mu_assert_eq((size_t)((void **)v.v.a)[3], 1337, "set");
|
|
rz_pvector_set(&v, 3, NULL);
|
|
mu_assert_null(((void **)v.v.a)[3], "set");
|
|
rz_pvector_clear(&v);
|
|
mu_end;
|
|
}
|
|
|
|
static int compare_int(const void *a, const void *b, void *user) {
|
|
int *num = user;
|
|
*num = 44;
|
|
return *(ut32 *)a - *(ut32 *)b;
|
|
}
|
|
|
|
static bool test_pvector_find(void) {
|
|
RzPVector v;
|
|
init_test_pvector(&v, 5, 0);
|
|
void *e = ((void **)v.v.a)[3];
|
|
int num = 77;
|
|
ut32 e_val = 3;
|
|
void **p = rz_pvector_find(&v, &e_val, compare_int, &num);
|
|
mu_assert_ptreq(*p, e, "find");
|
|
mu_assert_eq(num, 44, "ensure user is passed");
|
|
rz_pvector_clear(&v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_find_index(void) {
|
|
RzPVector v;
|
|
init_test_pvector(&v, 5, 0);
|
|
int num = 77;
|
|
ut32 e_val0 = 0;
|
|
ut32 e_val2 = 2;
|
|
ut32 e_val6 = 6;
|
|
size_t index = rz_pvector_find_index(&v, &e_val2, compare_int, &num);
|
|
mu_assert_eq(index, 2, "find index");
|
|
mu_assert_eq(num, 44, "ensure user is passed");
|
|
index = rz_pvector_find_index(&v, &e_val6, compare_int, &num);
|
|
mu_assert_eq(index, SZT_MAX, "not found index");
|
|
index = rz_pvector_find_index(&v, &e_val0, compare_int, &num);
|
|
mu_assert_eq(index, 0, "find index 0");
|
|
rz_pvector_clear(&v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_join(void) {
|
|
RzPVector m, n;
|
|
init_test_pvector(&m, 5, 0);
|
|
init_test_pvector(&n, 3, 0);
|
|
mu_assert_eq(rz_pvector_len(&m), 5, "length is 5 before join");
|
|
rz_pvector_join(&m, &n);
|
|
mu_assert_eq(rz_pvector_len(&m), 8, "length is 8 after join");
|
|
mu_assert_eq(*((ut32 *)rz_pvector_at(&m, 6)), 1, "m[6] = n[1]");
|
|
rz_pvector_clear(&m);
|
|
rz_pvector_clear(&n);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_contains(void) {
|
|
RzPVector v;
|
|
init_test_pvector(&v, 5, 0);
|
|
void *e = ((void **)v.v.a)[3];
|
|
void **p = rz_pvector_contains(&v, e);
|
|
mu_assert_ptreq(p, (void **)v.v.a + 3, "contains");
|
|
p = rz_pvector_contains(&v, 0);
|
|
mu_assert_null(p, "!contains");
|
|
rz_pvector_clear(&v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_assign_at(void) {
|
|
RzPVector v;
|
|
init_test_pvector(&v, 5, 0);
|
|
ut32 *x = malloc(sizeof(ut32));
|
|
*x = 123467890;
|
|
ut32 *e = rz_pvector_assign_at(&v, 3, x);
|
|
mu_assert_eq(*e, 3, "assign_at ret");
|
|
free(e);
|
|
mu_assert_eq(v.v.len, 5UL, "assign_at => len");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[0], 0, "assign_at => content at 0");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[1], 1, "assign_at => content at 1");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[2], 2, "assign_at => content at 2");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[3], 123467890, "assign_at => content at 3");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[4], 4, "assign_at => content at 4");
|
|
|
|
x = malloc(sizeof(ut32));
|
|
e = rz_pvector_assign_at(&v, 5, x);
|
|
mu_assert_null(e, "Was not NULL");
|
|
|
|
rz_pvector_reserve(&v, 10);
|
|
mu_assert_eq(rz_pvector_capacity(&v), 10, "Reserve failed");
|
|
// Test lengthening the vector.
|
|
rz_pvector_assign_at(&v, 6, NULL);
|
|
mu_assert_eq(rz_pvector_len(&v), 7, "Length was not updated.");
|
|
|
|
ut32 *zeroed[1] = { 0 };
|
|
mu_assert_memeq((ut8 *)v.v.a + sizeof(ut32 *) * 5, (ut8 *)zeroed, sizeof(ut32 *), "Memory was not zeroed");
|
|
// If this line fails on a machine, it might be because NULL != 0 on it.
|
|
mu_assert_memeq((ut8 *)v.v.a + sizeof(ut32 *) * 6, (ut8 *)zeroed, sizeof(ut32 *), "Memory was not zeroed");
|
|
|
|
x = malloc(sizeof(ut32));
|
|
*x = 9;
|
|
e = rz_pvector_assign_at(&v, 9, x);
|
|
mu_assert_null(e, "No element at this index before, should be NULL.");
|
|
mu_assert_eq(rz_pvector_len(&v), 10, "Length was not updated.");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[9], 9, "Value was not set.");
|
|
|
|
mu_assert_memeq((ut8 *)v.v.a + sizeof(ut32 *) * 7, (ut8 *)zeroed, sizeof(ut32 *), "Memory was not zeroed");
|
|
mu_assert_memeq((ut8 *)v.v.a + sizeof(ut32 *) * 8, (ut8 *)zeroed, sizeof(ut32 *), "Memory was not zeroed");
|
|
|
|
rz_pvector_purge(&v);
|
|
mu_assert_eq(rz_pvector_len(&v), 0, "Length after purge.");
|
|
mu_assert_eq(rz_pvector_capacity(&v), 10, "Capacity stays the same after purge.");
|
|
|
|
rz_pvector_clear(&v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_remove_at(void) {
|
|
RzPVector v;
|
|
init_test_pvector(&v, 5, 0);
|
|
ut32 *e = rz_pvector_remove_at(&v, 3);
|
|
mu_assert_eq(*e, 3, "remove_at ret");
|
|
free(e);
|
|
mu_assert_eq(v.v.len, 4UL, "remove_at => len");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[0], 0, "remove_at => remaining content");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[1], 1, "remove_at => remaining content");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[2], 2, "remove_at => remaining content");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[3], 4, "remove_at => remaining content");
|
|
rz_pvector_clear(&v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_remove_at_unsorted(void) {
|
|
RzPVector v;
|
|
init_test_pvector(&v, 5, 0);
|
|
|
|
ut32 *e = rz_pvector_remove_at_unsorted(&v, 0);
|
|
mu_assert_eq(*e, 0, "remove_at_unsorted ret");
|
|
free(e);
|
|
mu_assert_eq(v.v.len, 4UL, "remove_at_unsorted => len");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[0], 4, "remove_at_unsorted => remaining content");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[1], 1, "remove_at_unsorted => remaining content");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[2], 2, "remove_at_unsorted => remaining content");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[3], 3, "remove_at_unsorted => remaining content");
|
|
|
|
e = rz_pvector_remove_at_unsorted(&v, 3);
|
|
mu_assert_eq(*e, 3, "remove_at_unsorted ret");
|
|
free(e);
|
|
mu_assert_eq(v.v.len, 3UL, "remove_at_unsorted => len");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[0], 4, "remove_at_unsorted => remaining content");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[1], 1, "remove_at_unsorted => remaining content");
|
|
mu_assert_eq(*((ut32 **)v.v.a)[2], 2, "remove_at_unsorted => remaining content");
|
|
|
|
rz_pvector_clear(&v);
|
|
mu_end;
|
|
}
|
|
|
|
// clang-format off
|
|
static bool test_pvector_insert(void) {
|
|
RzPVector v;
|
|
|
|
init_test_pvector2(&v, 4, 2);
|
|
void *e = (void *)1337;
|
|
e = *rz_pvector_insert(&v, 1, e);
|
|
mu_assert_eq(v.v.len, 5UL, "insert => len");
|
|
mu_assert_eq((size_t)e, 1337, "insert => content at returned ptr");
|
|
mu_assert_null(*((void **)rz_vector_index_ptr(&v.v, 0)), "insert => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 1)), 1337, "insert => content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 2)), 1, "insert => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 3)), 2, "insert => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 4)), 3, "insert => old content");
|
|
rz_pvector_clear(&v);
|
|
|
|
init_test_pvector2(&v, 4, 0);
|
|
e = (void *)1337;
|
|
e = *rz_pvector_insert(&v, 1, e);
|
|
mu_assert("insert (resize) => capacity", rz_pvector_capacity(&v) >= 5);
|
|
mu_assert_eq(v.v.len, 5UL, "insert (resize) => len");
|
|
mu_assert_eq((size_t)e, 1337, "insert (resize) => content at returned ptr");
|
|
mu_assert_null(*((void **)rz_vector_index_ptr(&v.v, 0)), "insert (resize) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 1)), 1337, "insert => content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 2)), 1, "insert => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 3)), 2, "insert => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 4)), 3, "insert => old content");
|
|
rz_pvector_clear(&v);
|
|
|
|
init_test_pvector2(&v, 4, 2);
|
|
e = (void *)1337;
|
|
e = *rz_pvector_insert(&v, 4, e);
|
|
mu_assert_eq(v.v.len, 5UL, "insert (end) => len");
|
|
mu_assert_eq((size_t)e, 1337, "insert (end) => content at returned ptr");
|
|
mu_assert_null(*((void **)rz_vector_index_ptr(&v.v, 0)), "insert (end) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 1)), 1, "insert (end) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 2)), 2, "insert (end) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 3)), 3, "insert (end) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 4)), 1337, "insert (end) => content");
|
|
rz_pvector_clear(&v);
|
|
|
|
init_test_pvector2(&v, 4, 2);
|
|
e = (void *)1337;
|
|
e = *rz_pvector_insert(&v, 4, e);
|
|
mu_assert("rz_vector_insert (resize, resize) => capacity", rz_pvector_capacity(&v) >= 5);
|
|
mu_assert_eq(v.v.len, 5UL, "rz_vector_insert (end, resize) => len");
|
|
mu_assert_eq((size_t)e, 1337, "rz_vector_insert (end, resize) => content at returned ptr");
|
|
mu_assert_null(*((void **)rz_vector_index_ptr(&v.v, 0)), "rz_vector_insert (end, resize) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 1)), 1, "rz_vector_insert (end, resize) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 2)), 2, "rz_vector_insert (end, resize) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 3)), 3, "rz_vector_insert (end, resize) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 4)), 1337, "rz_vector_insert (end, resize) => content");
|
|
rz_pvector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_insert_range(void) {
|
|
RzPVector v;
|
|
void *range[] = { (void *)0xC0, (void *)0xFF, (void *)0xEE };
|
|
|
|
rz_pvector_init(&v, NULL);
|
|
void **p = rz_pvector_insert_range(&v, 0, range, 3);
|
|
mu_assert_ptreq(p, rz_vector_index_ptr(&v.v, 0), "insert_range (empty) returned ptr");
|
|
mu_assert_eq(v.v.len, 3UL, "insert_range (empty) => len");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 0)), 0xC0, "insert_range (empty) => new content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 1)), 0xFF, "insert_range (empty) => new content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 2)), 0xEE, "insert_range (empty) => new content");
|
|
rz_pvector_clear(&v);
|
|
|
|
init_test_pvector2(&v, 3, 3);
|
|
p = rz_pvector_insert_range(&v, 2, range, 3);
|
|
mu_assert_ptreq(p, rz_vector_index_ptr(&v.v, 2), "insert_range returned ptr");
|
|
mu_assert_eq(v.v.len, 6UL, "insert_range => len");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 0)), 0, "insert_range => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 1)), 1, "insert_range => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 2)), 0xC0, "insert_range => new content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 3)), 0xFF, "insert_range => new content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 4)), 0xEE, "insert_range => new content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 5)), 2, "insert_range => old content");
|
|
rz_pvector_clear(&v);
|
|
|
|
init_test_pvector2(&v, 3, 3);
|
|
p = rz_pvector_insert_range(&v, 3, range, 3);
|
|
mu_assert_ptreq(p, rz_vector_index_ptr(&v.v, 3), "insert_range (end) returned ptr");
|
|
mu_assert_eq(v.v.len, 6UL, "insert_range (end) => len");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 0)), 0, "insert_range (end) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 1)), 1, "insert_range (end) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 2)), 2, "insert_range (end) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 3)), 0xC0, "insert_range (end) => new content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 4)), 0xFF, "insert_range (end) => new content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 5)), 0xEE, "insert_range (end) => new content");
|
|
rz_pvector_clear(&v);
|
|
|
|
init_test_pvector2(&v, 3, 0);
|
|
p = rz_pvector_insert_range(&v, 2, range, 3);
|
|
mu_assert_ptreq(p, rz_vector_index_ptr(&v.v, 2), "insert_range (resize) returned ptr");
|
|
mu_assert_eq(v.v.len, 6UL, "insert_range (resize) => len");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 0)), 0, "insert_range (resize) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 1)), 1, "insert_range (resize) => old content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 2)), 0xC0, "insert_range (resize) => new content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 3)), 0xFF, "insert_range (resize) => new content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 4)), 0xEE, "insert_range (resize) => new content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 5)), 2, "insert_range (resize) => old content");
|
|
rz_pvector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_pop(void) {
|
|
RzPVector v;
|
|
init_test_pvector2(&v, 3, 0);
|
|
|
|
void *e = rz_pvector_pop(&v);
|
|
mu_assert_eq((size_t)e, 2, "pop ret");
|
|
mu_assert_eq(v.v.len, 2UL, "pop => len");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 0)), 0, "pop => remaining content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 1)), 1, "pop => remaining content");
|
|
|
|
e = rz_pvector_pop(&v);
|
|
mu_assert_eq((size_t)e, 1, "pop ret");
|
|
mu_assert_eq(v.v.len, 1UL, "pop => len");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 0)), 0, "pop => remaining content");
|
|
|
|
e = rz_pvector_pop(&v);
|
|
mu_assert_eq((size_t)e, 0, "pop (last) into");
|
|
mu_assert_eq(v.v.len, 0UL, "pop (last) => len");
|
|
|
|
rz_pvector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_pop_front(void) {
|
|
RzPVector v;
|
|
init_test_pvector2(&v, 3, 0);
|
|
|
|
void *e = rz_pvector_pop_front(&v);
|
|
mu_assert_null(e, "pop_front into");
|
|
mu_assert_eq(v.v.len, 2UL, "pop_front => len");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 0)), 1, "pop_front => remaining content");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 1)), 2, "pop_front => remaining content");
|
|
|
|
e = rz_pvector_pop_front(&v);
|
|
mu_assert_eq((size_t)e, 1, "rz_vector_pop_front into");
|
|
mu_assert_eq(v.v.len, 1UL, "rz_vector_pop_front => len");
|
|
mu_assert_eq((size_t)*((void **)rz_vector_index_ptr(&v.v, 0)), 2, "pop_front => remaining content");
|
|
|
|
e = rz_pvector_pop_front(&v);
|
|
mu_assert_eq((size_t)e, 2, "pop_front (last) into");
|
|
mu_assert_eq(v.v.len, 0UL, "pop_front (last) => len");
|
|
|
|
rz_pvector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
// clang-format on
|
|
|
|
static bool test_pvector_push(void) {
|
|
RzPVector v;
|
|
rz_pvector_init(&v, NULL);
|
|
|
|
void *e = (void *)1337;
|
|
e = *rz_pvector_push(&v, e);
|
|
mu_assert_eq(v.v.len, 1UL, "push (empty) => len == 1");
|
|
mu_assert_eq((size_t)e, 1337, "push (empty) => content at returned ptr");
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 0));
|
|
mu_assert_eq((size_t)e, 1337, "rz_vector_push (empty) => content");
|
|
|
|
e = (void *)0xDEAD;
|
|
e = *rz_pvector_push(&v, e);
|
|
mu_assert_eq(v.v.len, 2UL, "push => len == 2");
|
|
mu_assert_eq((size_t)e, 0xDEAD, "push => content at returned ptr");
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 0));
|
|
mu_assert_eq((size_t)e, 1337, "push => old content");
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 1));
|
|
mu_assert_eq((size_t)e, 0xDEAD, "push => content");
|
|
|
|
e = (void *)0xBEEF;
|
|
e = *rz_pvector_push(&v, e);
|
|
mu_assert_eq(v.v.len, 3UL, "push => len == 3");
|
|
mu_assert_eq((size_t)e, 0xBEEF, "push => content at returned ptr");
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 0));
|
|
mu_assert_eq((size_t)e, 1337, "rz_vector_push => old content");
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 1));
|
|
mu_assert_eq((size_t)e, 0xDEAD, "rz_vector_push => old content");
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 2));
|
|
mu_assert_eq((size_t)e, 0xBEEF, "rz_vector_push => content");
|
|
|
|
rz_vector_clear(&v.v);
|
|
|
|
init_test_pvector2(&v, 5, 0);
|
|
e = (void *)1337;
|
|
e = *rz_pvector_push(&v, e);
|
|
mu_assert("push (resize) => capacity", rz_pvector_capacity(&v) >= 6);
|
|
mu_assert_eq(v.v.len, 6UL, "push (resize) => len");
|
|
mu_assert_eq((size_t)e, 1337, "push (empty) => content at returned ptr");
|
|
|
|
size_t i;
|
|
for (i = 0; i < v.v.len - 1; i++) {
|
|
e = *((void **)rz_vector_index_ptr(&v.v, i));
|
|
mu_assert_eq((size_t)e, i, "push (resize) => old content");
|
|
}
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 5));
|
|
mu_assert_eq((size_t)e, 1337, "rz_vector_push (resize) => content");
|
|
|
|
rz_vector_clear(&v.v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_push_front(void) {
|
|
RzPVector v;
|
|
rz_pvector_init(&v, NULL);
|
|
|
|
void *e = (void *)1337;
|
|
e = *rz_pvector_push_front(&v, e);
|
|
mu_assert_eq(v.v.len, 1UL, "push_front (empty) => len == 1");
|
|
mu_assert_eq((size_t)e, 1337, "push_front (empty) => content at returned ptr");
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 0));
|
|
mu_assert_eq((size_t)e, 1337, "push_front (empty) => content");
|
|
|
|
e = (void *)0xDEAD;
|
|
e = *rz_pvector_push_front(&v, e);
|
|
mu_assert_eq(v.v.len, 2UL, "push_front => len == 2");
|
|
mu_assert_eq((size_t)e, 0xDEAD, "push_front (empty) => content at returned ptr");
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 0));
|
|
mu_assert_eq((size_t)e, 0xDEAD, "push_front => content");
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 1));
|
|
mu_assert_eq((size_t)e, 1337, "push_front => old content");
|
|
|
|
e = (void *)0xBEEF;
|
|
e = *rz_pvector_push_front(&v, e);
|
|
mu_assert_eq(v.v.len, 3UL, "push_front => len == 3");
|
|
mu_assert_eq((size_t)e, 0xBEEF, "push_front (empty) => content at returned ptr");
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 0));
|
|
mu_assert_eq((size_t)e, 0xBEEF, "push_front => content");
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 1));
|
|
mu_assert_eq((size_t)e, 0xDEAD, "push_front => old content");
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 2));
|
|
mu_assert_eq((size_t)e, 1337, "push_front => old content");
|
|
|
|
rz_pvector_clear(&v);
|
|
|
|
init_test_pvector2(&v, 5, 0);
|
|
e = (void *)1337;
|
|
e = *rz_pvector_push_front(&v, e);
|
|
mu_assert("push_front (resize) => capacity", rz_pvector_capacity(&v) >= 6);
|
|
mu_assert_eq(v.v.len, 6UL, "push_front (resize) => len");
|
|
mu_assert_eq((size_t)e, 1337, "push_front (empty) => content at returned ptr");
|
|
|
|
size_t i;
|
|
for (i = 1; i < v.v.len; i++) {
|
|
e = *((void **)rz_vector_index_ptr(&v.v, i));
|
|
mu_assert_eq((size_t)e, i - 1, "push_front (resize) => old content");
|
|
}
|
|
e = *((void **)rz_vector_index_ptr(&v.v, 0));
|
|
mu_assert_eq((size_t)e, 1337, "push_front (resize) => content");
|
|
|
|
rz_pvector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_sort(void) {
|
|
int num = 66;
|
|
RzPVector v;
|
|
rz_pvector_init(&v, free);
|
|
rz_pvector_push(&v, strdup("Charmander"));
|
|
rz_pvector_push(&v, strdup("Squirtle"));
|
|
rz_pvector_push(&v, strdup("Bulbasaur"));
|
|
rz_pvector_push(&v, strdup("Meowth"));
|
|
rz_pvector_push(&v, strdup("Caterpie"));
|
|
rz_pvector_sort(&v, (RzPVectorComparator)compare_string, &num);
|
|
|
|
mu_assert_eq(v.v.len, 5UL, "sort len");
|
|
mu_assert_eq(num, 44, "sort user pointer check");
|
|
mu_assert_streq((const char *)((void **)v.v.a)[0], "Bulbasaur", "sorted strings");
|
|
mu_assert_streq((const char *)((void **)v.v.a)[1], "Caterpie", "sorted strings");
|
|
mu_assert_streq((const char *)((void **)v.v.a)[2], "Charmander", "sorted strings");
|
|
mu_assert_streq((const char *)((void **)v.v.a)[3], "Meowth", "sorted strings");
|
|
mu_assert_streq((const char *)((void **)v.v.a)[4], "Squirtle", "sorted strings");
|
|
rz_pvector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
// rz_pvector_remove_data finds the slot whose stored pointer equals x and
|
|
// removes it while preserving order. Covers the simplified index computation.
|
|
static bool test_pvector_remove_data(void) {
|
|
RzPVector v;
|
|
rz_pvector_init(&v, NULL);
|
|
for (size_t i = 1; i <= 6; i++) {
|
|
rz_pvector_push(&v, (void *)i);
|
|
}
|
|
rz_pvector_remove_data(&v, (void *)4); // expect 1,2,3,5,6
|
|
mu_assert_eq(rz_pvector_len(&v), 5UL, "len after remove_data");
|
|
void *exp[] = { (void *)1, (void *)2, (void *)3, (void *)5, (void *)6 };
|
|
bool ok = true;
|
|
for (size_t i = 0; i < 5; i++) {
|
|
if (rz_pvector_at(&v, i) != exp[i]) {
|
|
ok = false;
|
|
}
|
|
}
|
|
mu_assert_true(ok, "remove_data removes the right element and keeps order");
|
|
|
|
// removing the first and last elements
|
|
rz_pvector_remove_data(&v, (void *)1); // 2,3,5,6
|
|
rz_pvector_remove_data(&v, (void *)6); // 2,3,5
|
|
mu_assert_eq(rz_pvector_len(&v), 3UL, "len after removing ends");
|
|
mu_assert_ptreq(rz_pvector_at(&v, 0), (void *)2, "head after removing ends");
|
|
mu_assert_ptreq(rz_pvector_at(&v, 2), (void *)5, "tail after removing ends");
|
|
|
|
// removing an absent pointer is a no-op
|
|
rz_pvector_remove_data(&v, (void *)999);
|
|
mu_assert_eq(rz_pvector_len(&v), 3UL, "remove_data of absent value is a no-op");
|
|
|
|
rz_pvector_clear(&v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_foreach(void) {
|
|
RzPVector v;
|
|
init_test_pvector2(&v, 5, 5);
|
|
|
|
int i = 1;
|
|
void **it;
|
|
int acc[5] = { 0 };
|
|
rz_pvector_foreach (&v, it) {
|
|
void *e = *it;
|
|
int ev = (int)((size_t)e);
|
|
mu_assert_eq(acc[ev], 0, "unset acc element");
|
|
acc[ev] = i++;
|
|
}
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
mu_assert_eq(acc[i], i + 1, "acc");
|
|
}
|
|
|
|
int acc_prev[5] = { 0 };
|
|
i = 5;
|
|
rz_pvector_foreach_prev(&v, it) {
|
|
void *e = *it;
|
|
int ev = (int)((size_t)e);
|
|
mu_assert_eq(acc_prev[ev], 0, "unset acc_prev element");
|
|
acc_prev[ev] = i++;
|
|
}
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
mu_assert_eq(acc_prev[i], 10 - i - 1, "acc_prev");
|
|
}
|
|
|
|
int idx;
|
|
rz_pvector_enumerate (&v, it, idx) {
|
|
void *e = *it;
|
|
int ev = (int)((size_t)e);
|
|
mu_assert_eq(ev, idx, "rz_pvector_enumerate index");
|
|
}
|
|
|
|
rz_pvector_clear(&v);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_bounds(void) {
|
|
void *a[] = { (void *)0, (void *)2, (void *)4, (void *)6, (void *)8 };
|
|
RzPVector s;
|
|
rz_pvector_init(&s, NULL);
|
|
s.v.a = malloc(sizeof(void *) * 5);
|
|
s.v.capacity = 5;
|
|
memcpy(s.v.a, a, sizeof(void *) * 5);
|
|
s.v.len = 5;
|
|
|
|
size_t l;
|
|
#define CMP(x, y) ((char *)(x) - (char *)(y))
|
|
rz_pvector_lower_bound(&s, 4, l, CMP);
|
|
mu_assert_ptreq(rz_pvector_at(&s, l), (void *)4, "lower_bound");
|
|
rz_pvector_upper_bound(&s, 4, l, CMP);
|
|
mu_assert_ptreq(rz_pvector_at(&s, l), (void *)6, "upper_bound");
|
|
|
|
rz_pvector_lower_bound(&s, 5, l, CMP);
|
|
mu_assert_ptreq(rz_pvector_at(&s, l), (void *)6, "lower_bound 2");
|
|
rz_pvector_upper_bound(&s, 5, l, CMP);
|
|
mu_assert_ptreq(rz_pvector_at(&s, l), (void *)6, "upper_bound 2");
|
|
|
|
rz_pvector_lower_bound(&s, 6, l, CMP);
|
|
mu_assert_ptreq(rz_pvector_at(&s, l), (void *)6, "lower_bound 3");
|
|
rz_pvector_upper_bound(&s, 6, l, CMP);
|
|
mu_assert_ptreq(rz_pvector_at(&s, l), (void *)8, "upper_bound 3");
|
|
|
|
rz_pvector_lower_bound(&s, 8, l, CMP);
|
|
mu_assert_ptreq(rz_pvector_at(&s, l), (void *)8, "lower_bound 4");
|
|
rz_pvector_upper_bound(&s, 8, l, CMP);
|
|
mu_assert_eq(l, s.v.len, "upper_bound 4");
|
|
|
|
rz_pvector_lower_bound(&s, 9, l, CMP);
|
|
mu_assert_eq(l, s.v.len, "lower_bound 4");
|
|
rz_pvector_upper_bound(&s, 9, l, CMP);
|
|
mu_assert_eq(l, s.v.len, "lower_bound 4");
|
|
#undef CMP
|
|
|
|
rz_pvector_clear(&s);
|
|
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_tips(void) {
|
|
RzPVector v;
|
|
void *t;
|
|
rz_pvector_init(&v, NULL);
|
|
rz_pvector_push(&v, (void *)42);
|
|
t = rz_pvector_head(&v);
|
|
mu_assert_eq((size_t)t, 42, "head_same");
|
|
t = rz_pvector_tail(&v);
|
|
mu_assert_eq((size_t)t, 42, "tail_same");
|
|
rz_pvector_clear(&v);
|
|
|
|
rz_pvector_init(&v, NULL);
|
|
void *b[] = { (void *)0, (void *)2, (void *)4, (void *)6, (void *)8 };
|
|
v.v.a = malloc(sizeof(void *) * 5);
|
|
v.v.capacity = 5;
|
|
memcpy(v.v.a, b, sizeof(void *) * 5);
|
|
v.v.len = 5;
|
|
|
|
t = rz_pvector_head(&v);
|
|
mu_assert_eq((size_t)t, 0, "head");
|
|
t = rz_pvector_tail(&v);
|
|
mu_assert_eq((size_t)t, 8, "tail");
|
|
rz_pvector_clear(&v);
|
|
mu_end;
|
|
}
|
|
|
|
static bool test_pvector_uniq(void) {
|
|
RzPVector v;
|
|
int num = 77;
|
|
int arr[10] = { 42, 43, 44, 42, 43, 44, 45, 48, 49, 49 };
|
|
rz_pvector_init(&v, NULL);
|
|
for (int i = 0; i < 10; i++) {
|
|
rz_pvector_push(&v, (void *)&arr[i]);
|
|
}
|
|
RzPVector *uv = rz_pvector_uniq(&v, compare_int, &num);
|
|
mu_assert_eq(rz_pvector_len(uv), 6, "uniq values count");
|
|
rz_pvector_clear(&v);
|
|
rz_pvector_free(uv);
|
|
mu_end;
|
|
}
|
|
|
|
static size_t lower_bound_slow(st64 *a, size_t count, st64 v) {
|
|
size_t i;
|
|
for (i = 0; i < count; i++) {
|
|
if (a[i] >= v) {
|
|
break;
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
|
|
static size_t upper_bound_slow(st64 *a, size_t count, st64 v) {
|
|
size_t i;
|
|
for (i = 0; i < count; i++) {
|
|
if (a[i] > v) {
|
|
break;
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
|
|
static bool test_array_bounds_fuzz(void) {
|
|
#define COUNT_MIN 4
|
|
#define COUNT_MAX 256
|
|
#define PADDING 32
|
|
#define STEP_MIN 0
|
|
#define STEP_MAX 8
|
|
#define FUZZ_COUNT 512
|
|
#define CMP(x, y) (x - y)
|
|
for (size_t i = 0; i < FUZZ_COUNT; i++) {
|
|
size_t count = (rand() % (COUNT_MAX - COUNT_MIN)) + COUNT_MIN;
|
|
st64 *a = RZ_NEWS(st64, count);
|
|
for (size_t j = 0; j < count; j++) {
|
|
a[j] = (j ? a[j - 1] : rand() % PADDING) + (rand() % (STEP_MAX - STEP_MIN)) + STEP_MIN;
|
|
}
|
|
st64 v = rand() % (a[count - 1] + PADDING);
|
|
|
|
size_t index_expect = lower_bound_slow(a, count, v);
|
|
size_t index_actual;
|
|
rz_array_lower_bound(a, count, v, index_actual, CMP);
|
|
mu_assert_eq(index_actual, index_expect, "lower bound");
|
|
|
|
index_expect = upper_bound_slow(a, count, v);
|
|
rz_array_upper_bound(a, count, v, index_actual, CMP);
|
|
mu_assert_eq(index_actual, index_expect, "upper bound");
|
|
|
|
free(a);
|
|
}
|
|
mu_end;
|
|
}
|
|
|
|
static int all_tests(void) {
|
|
time_t seed = time(0);
|
|
printf("Gillian Seed: %" PFMT64u "\n", (ut64)seed);
|
|
srand(seed);
|
|
mu_run_test(test_vector_init);
|
|
mu_run_test(test_vector_new);
|
|
mu_run_test(test_vector_fini);
|
|
mu_run_test(test_vector_clear);
|
|
mu_run_test(test_vector_free);
|
|
mu_run_test(test_vector_set);
|
|
mu_run_test(test_vector_clone);
|
|
mu_run_test(test_vector_empty);
|
|
mu_run_test(test_vector_remove_at);
|
|
mu_run_test(test_vector_remove_at_unsorted);
|
|
mu_run_test(test_vector_sort);
|
|
mu_run_test(test_vector_sort_large);
|
|
mu_run_test(test_vector_sort_large_elem);
|
|
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_find_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);
|
|
mu_run_test(test_vector_flush);
|
|
mu_run_test(test_vector_foreach);
|
|
mu_run_test(test_vector_bounds);
|
|
mu_run_test(test_vector_tips);
|
|
|
|
mu_run_test(test_pvector_init);
|
|
mu_run_test(test_pvector_new);
|
|
mu_run_test(test_pvector_clear);
|
|
mu_run_test(test_pvector_free);
|
|
mu_run_test(test_pvector_at);
|
|
mu_run_test(test_pvector_set);
|
|
mu_run_test(test_pvector_find);
|
|
mu_run_test(test_pvector_find_index);
|
|
mu_run_test(test_pvector_join);
|
|
mu_run_test(test_pvector_contains);
|
|
mu_run_test(test_pvector_remove_at);
|
|
mu_run_test(test_pvector_remove_at_unsorted);
|
|
mu_run_test(test_pvector_assign_at);
|
|
mu_run_test(test_pvector_insert);
|
|
mu_run_test(test_pvector_insert_range);
|
|
mu_run_test(test_pvector_pop);
|
|
mu_run_test(test_pvector_pop_front);
|
|
mu_run_test(test_pvector_push);
|
|
mu_run_test(test_pvector_push_front);
|
|
mu_run_test(test_pvector_sort);
|
|
mu_run_test(test_pvector_foreach);
|
|
mu_run_test(test_pvector_bounds);
|
|
mu_run_test(test_pvector_tips);
|
|
mu_run_test(test_pvector_uniq);
|
|
mu_run_test(test_pvector_remove_data);
|
|
|
|
mu_run_test(test_array_bounds_fuzz);
|
|
|
|
return tests_passed != tests_run;
|
|
}
|
|
|
|
mu_main(all_tests)
|