mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-11 06:55:01 +00:00
ee40472c9f
* Add binary heap (as priority queue) to util/binheap.c * Change cmp_less in r_vector.h to 3-way cmp
285 lines
6.3 KiB
C
285 lines
6.3 KiB
C
#include "r_vector.h"
|
|
|
|
// Optimize memory usage on glibc
|
|
#if __WORDSIZE == 32
|
|
// Chunk size 24, minus 4 (chunk header), minus 8 for capacity and len, 12 bytes remaining for 3 void *
|
|
#define INITIAL_VECTOR_LEN 3
|
|
#else
|
|
// For __WORDSIZE == 64
|
|
// Chunk size 48, minus 8 (chunk header), minus 8 for capacity and len, 32 bytes remaining for 4 void *
|
|
#define INITIAL_VECTOR_LEN 4
|
|
#endif
|
|
|
|
#define NEXT_VECTOR_CAPACITY (vec->capacity < INITIAL_VECTOR_LEN \
|
|
? INITIAL_VECTOR_LEN \
|
|
: vec->capacity <= 12 ? vec->capacity * 2 \
|
|
: vec->capacity + (vec->capacity >> 1))
|
|
|
|
#define RESIZE_OR_RETURN_NULL(next_capacity) do { \
|
|
int new_capacity = next_capacity; \
|
|
void **new_a = realloc (vec->a, sizeof(void *) * new_capacity); \
|
|
if (!new_a) { \
|
|
return NULL; \
|
|
} \
|
|
vec->a = new_a; \
|
|
vec->capacity = new_capacity; \
|
|
} while (0)
|
|
|
|
R_API void r_vector_clear(RVector *vec, void (*elem_free)(void *)) {
|
|
if (elem_free) {
|
|
while (vec->len > 0) {
|
|
elem_free (vec->a[--vec->len]);
|
|
}
|
|
} else {
|
|
vec->len = 0;
|
|
}
|
|
R_FREE (vec->a);
|
|
vec->capacity = 0;
|
|
}
|
|
|
|
R_API RVector *r_vector_clone(RVector *vec) {
|
|
RVector *ret = R_NEW (RVector);
|
|
if (ret) {
|
|
ret->capacity = vec->capacity;
|
|
ret->len = vec->len;
|
|
if (!vec->len) {
|
|
ret->a = NULL;
|
|
} else {
|
|
ret->a = malloc (sizeof (void *) * vec->len);
|
|
if (!ret->a) {
|
|
R_FREE (ret);
|
|
} else {
|
|
memcpy (ret->a, vec->a, sizeof (void *) * vec->len);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
R_API void **r_vector_contains(RVector *vec, void *x) {
|
|
int i;
|
|
for (i = 0; i < vec->len; i++) {
|
|
if (vec->a[i] == x) {
|
|
return &vec->a[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
R_API void *r_vector_delete_at(RVector *vec, int n) {
|
|
void *ret = vec->a[n];
|
|
vec->len--;
|
|
for (; n < vec->len; n++) {
|
|
vec->a[n] = vec->a[n+1];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
R_API bool r_vector_empty(RVector *vec) {
|
|
return vec->len == 0;
|
|
}
|
|
|
|
R_API void r_vector_free(RVector *vec, void (*elem_free)(void *)) {
|
|
if (elem_free) {
|
|
while (vec->len > 0) {
|
|
elem_free (vec->a[--vec->len]);
|
|
}
|
|
} else {
|
|
vec->len = 0;
|
|
}
|
|
free (vec->a);
|
|
free (vec);
|
|
}
|
|
|
|
R_API void r_vector_init(RVector *vec) {
|
|
vec->a = NULL;
|
|
vec->capacity = vec->len = 0;
|
|
}
|
|
|
|
R_API void **r_vector_insert(RVector *vec, int n, void *x) {
|
|
if (vec->len >= vec->capacity) {
|
|
RESIZE_OR_RETURN_NULL (NEXT_VECTOR_CAPACITY);
|
|
}
|
|
int i;
|
|
for (i = vec->len++; i > n; i--) {
|
|
vec->a[i] = vec->a[i-1];
|
|
}
|
|
vec->a[n] = x;
|
|
return &vec->a[n];
|
|
}
|
|
|
|
R_API void **r_vector_insert_range(RVector *vec, int n, void **first, void **last) {
|
|
if (last - first + vec->len > vec->capacity) {
|
|
RESIZE_OR_RETURN_NULL (R_MAX (NEXT_VECTOR_CAPACITY, last - first + vec->len));
|
|
}
|
|
int i;
|
|
for (i = vec->len; i > n; ) {
|
|
i--;
|
|
vec->a[last - first + i] = vec->a[i];
|
|
}
|
|
vec->len += last - first;
|
|
i = n;
|
|
while (first != last) {
|
|
vec->a[i++] = *first++;
|
|
}
|
|
return &vec->a[n];
|
|
}
|
|
|
|
R_API RVector *r_vector_new(void) {
|
|
return R_NEW0 (RVector);
|
|
}
|
|
|
|
R_API void *r_vector_pop(RVector *vec) {
|
|
return vec->a[--vec->len];
|
|
}
|
|
|
|
R_API void *r_vector_pop_front(RVector *vec) {
|
|
return r_vector_delete_at (vec, 0);
|
|
}
|
|
|
|
R_API void **r_vector_push(RVector *vec, void *x) {
|
|
if (vec->len >= vec->capacity) {
|
|
RESIZE_OR_RETURN_NULL (NEXT_VECTOR_CAPACITY);
|
|
}
|
|
vec->a[vec->len] = x;
|
|
return &vec->a[vec->len++];
|
|
}
|
|
|
|
R_API void **r_vector_push_front(RVector *vec, void *x) {
|
|
return r_vector_insert (vec, 0, x);
|
|
}
|
|
|
|
R_API void **r_vector_reserve(RVector *vec, int capacity) {
|
|
if (vec->capacity < capacity) {
|
|
RESIZE_OR_RETURN_NULL (capacity);
|
|
}
|
|
return vec->a;
|
|
}
|
|
|
|
R_API void **r_vector_shrink(RVector *vec) {
|
|
if (vec->len < vec->capacity) {
|
|
RESIZE_OR_RETURN_NULL (vec->len);
|
|
}
|
|
return vec->a;
|
|
}
|
|
|
|
// CLRS Quicksort. It is slow, but simple.
|
|
static void quick_sort(void **a, int n, RVectorComparator cmp) {
|
|
if (n <= 1) return;
|
|
int i = rand() % n, j = 0;
|
|
void *t, *pivot = a[i];
|
|
a[i] = a[n - 1];
|
|
for (i = 0; i < n - 1; i++)
|
|
if (cmp (a[i], pivot) < 0) {
|
|
t = a[i];
|
|
a[i] = a[j];
|
|
a[j] = t;
|
|
j++;
|
|
}
|
|
a[n - 1] = a[j];
|
|
a[j] = pivot;
|
|
quick_sort (a, j, cmp);
|
|
quick_sort (a + j + 1, n - j - 1, cmp);
|
|
}
|
|
|
|
R_API void r_vector_sort(RVector *vec, RVectorComparator cmp) {
|
|
quick_sort (vec->a, vec->len, cmp);
|
|
}
|
|
|
|
#if TEST
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
|
|
int my_cmp(const void *a, const void *b) {
|
|
return strcmp (a, b) < 0;
|
|
}
|
|
|
|
// TODO: move into t/vector.c
|
|
int main () {
|
|
ptrdiff_t i;
|
|
void **it;
|
|
RVector *v = r_vector_new ();
|
|
assert (*r_vector_push (v, (void *)1337) == (void *)1337);
|
|
for (i = 0; i < 10; i++) {
|
|
r_vector_push (v, (void *)i);
|
|
assert (v->len == i + 2);
|
|
}
|
|
assert (r_vector_pop_front (v) == (void *)1337);
|
|
assert (r_vector_contains (v, (void *)9));
|
|
|
|
assert (r_vector_delete_at (v, 9) == (void *)9);
|
|
assert (!r_vector_contains (v, (void *)9));
|
|
|
|
i = 0;
|
|
r_vector_foreach (v, it) {
|
|
assert (*it == (void *)i++);
|
|
}
|
|
|
|
r_vector_shrink (v);
|
|
assert (v->len == 9);
|
|
RVector *v1 = r_vector_clone (v);
|
|
r_vector_clear (v, NULL);
|
|
assert (v->capacity == 0 && v->len == 0);
|
|
assert (v1->len == 9);
|
|
|
|
r_vector_free (v, NULL);
|
|
r_vector_free (v1, NULL);
|
|
|
|
RVector s;
|
|
r_vector_init (&s);
|
|
r_vector_reserve (&s, 10);
|
|
r_vector_clear (&s, NULL);
|
|
|
|
r_vector_reserve (&s, 10);
|
|
r_vector_push (&s, (void *)-1);
|
|
assert (s.len == 1 && s.capacity == 10);
|
|
for (i = 0; i < 20; i++) {
|
|
r_vector_push (&s, (void *)i);
|
|
}
|
|
r_vector_reserve (&s, 10);
|
|
r_vector_clear (&s, NULL);
|
|
|
|
{
|
|
void *a[] = {(void*)0, (void*)2, (void*)4, (void*)6, (void*)8};
|
|
RVector s = {0};
|
|
int l;
|
|
r_vector_insert_range (&s, 0, a + 2, a + 5);
|
|
r_vector_insert_range (&s, 0, a, a + 2);
|
|
|
|
#define CMP(x, y) x < y
|
|
r_vector_lower_bound (&s, (void *)4, l, CMP);
|
|
assert (s.a[l] == (void *)4);
|
|
r_vector_lower_bound (&s, (void *)5, l, CMP);
|
|
assert (s.a[l] == (void *)6);
|
|
r_vector_lower_bound (&s, (void *)6, l, CMP);
|
|
assert (s.a[l] == (void *)6);
|
|
r_vector_lower_bound (&s, (void *)9, l, CMP);
|
|
assert (l == s.len);
|
|
|
|
r_vector_upper_bound (&s, (void *)4, l, CMP);
|
|
assert (s.a[l] == (void *)6);
|
|
r_vector_upper_bound (&s, (void *)5, l, CMP);
|
|
assert (s.a[l] == (void *)6);
|
|
r_vector_upper_bound (&s, (void *)6, l, CMP);
|
|
assert (s.a[l] == (void *)8);
|
|
#undef CMP
|
|
|
|
r_vector_clear (&s, NULL);
|
|
|
|
r_vector_push (&s, strdup ("Charmander"));
|
|
r_vector_push (&s, strdup ("Squirtle"));
|
|
r_vector_push (&s, strdup ("Bulbasaur"));
|
|
r_vector_push (&s, strdup ("Meowth"));
|
|
r_vector_push (&s, strdup ("Caterpie"));
|
|
r_vector_sort (&s, my_cmp);
|
|
|
|
r_vector_lower_bound (&s, "Meow", l, strcmp);
|
|
assert (!strcmp (s.a[l], "Meowth"));
|
|
|
|
r_vector_clear (&s, free);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|