2017-08-26 11:05:14 +00:00
|
|
|
#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 { \
|
2018-07-27 17:31:58 +00:00
|
|
|
size_t new_capacity = next_capacity; \
|
|
|
|
void **new_a = realloc (vec->a, vec->elem_size * new_capacity); \
|
2017-08-26 11:05:14 +00:00
|
|
|
if (!new_a) { \
|
|
|
|
return NULL; \
|
|
|
|
} \
|
|
|
|
vec->a = new_a; \
|
|
|
|
vec->capacity = new_capacity; \
|
|
|
|
} while (0)
|
2018-07-29 15:05:19 +00:00
|
|
|
|
|
|
|
|
2018-07-27 17:31:58 +00:00
|
|
|
|
2018-08-03 10:04:19 +00:00
|
|
|
R_API void r_vector_init(RVector *vec, size_t elem_size, RVectorFree free, void *free_user) {
|
2018-07-27 17:31:58 +00:00
|
|
|
vec->a = NULL;
|
|
|
|
vec->capacity = vec->len = 0;
|
|
|
|
vec->elem_size = elem_size;
|
2018-08-03 10:04:19 +00:00
|
|
|
vec->free = free;
|
|
|
|
vec->free_user = free_user;
|
2018-07-27 17:31:58 +00:00
|
|
|
}
|
|
|
|
|
2018-08-03 10:04:19 +00:00
|
|
|
R_API RVector *r_vector_new(size_t elem_size, RVectorFree free, void *free_user) {
|
2018-07-27 17:31:58 +00:00
|
|
|
RVector *vec = R_NEW (RVector);
|
|
|
|
if (!vec) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-08-03 10:04:19 +00:00
|
|
|
r_vector_init (vec, elem_size, free, free_user);
|
2018-07-27 17:31:58 +00:00
|
|
|
return vec;
|
|
|
|
}
|
|
|
|
|
2018-08-03 10:04:19 +00:00
|
|
|
static void vector_free_elems(RVector *vec) {
|
|
|
|
if (vec->free) {
|
2017-08-26 11:05:14 +00:00
|
|
|
while (vec->len > 0) {
|
2018-08-03 10:04:19 +00:00
|
|
|
vec->free (r_vector_index_ptr (vec, --vec->len), vec->free_user);
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
vec->len = 0;
|
|
|
|
}
|
2018-07-27 17:31:58 +00:00
|
|
|
}
|
|
|
|
|
2018-08-03 10:04:19 +00:00
|
|
|
R_API void r_vector_clear(RVector *vec) {
|
|
|
|
vector_free_elems (vec);
|
2017-08-26 11:05:14 +00:00
|
|
|
R_FREE (vec->a);
|
|
|
|
vec->capacity = 0;
|
|
|
|
}
|
|
|
|
|
2018-08-03 10:04:19 +00:00
|
|
|
R_API void r_vector_free(RVector *vec) {
|
|
|
|
vector_free_elems (vec);
|
2018-07-30 13:33:05 +00:00
|
|
|
free (vec->a);
|
|
|
|
free (vec);
|
|
|
|
}
|
|
|
|
|
2018-07-30 12:54:47 +00:00
|
|
|
static bool vector_clone(RVector *dst, RVector *src) {
|
|
|
|
dst->capacity = src->capacity;
|
|
|
|
dst->len = src->len;
|
|
|
|
dst->elem_size = src->elem_size;
|
2018-08-03 10:04:19 +00:00
|
|
|
dst->free = src->free;
|
|
|
|
dst->free_user = src->free_user;
|
2018-07-30 12:54:47 +00:00
|
|
|
if (!dst->len) {
|
|
|
|
dst->a = NULL;
|
|
|
|
} else {
|
|
|
|
dst->a = malloc (src->elem_size * src->capacity);
|
|
|
|
if (!dst->a) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
memcpy (dst->a, src->a, src->elem_size * src->len);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-08-26 11:05:14 +00:00
|
|
|
R_API RVector *r_vector_clone(RVector *vec) {
|
|
|
|
RVector *ret = R_NEW (RVector);
|
2018-07-30 12:54:47 +00:00
|
|
|
if (!ret) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (!vector_clone (ret, vec)) {
|
|
|
|
free (ret);
|
|
|
|
return NULL;
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-07-29 15:05:19 +00:00
|
|
|
|
2018-07-30 18:35:30 +00:00
|
|
|
R_API void *r_vector_index_ptr(RVector *vec, size_t index) {
|
2018-07-29 15:05:19 +00:00
|
|
|
return (char *)vec->a + vec->elem_size * index;
|
|
|
|
}
|
|
|
|
|
2018-07-30 18:35:30 +00:00
|
|
|
R_API void r_vector_assign(RVector *vec, void *p, void *elem) {
|
2018-07-29 15:05:19 +00:00
|
|
|
memcpy (p, elem, vec->elem_size);
|
|
|
|
}
|
|
|
|
|
2018-07-30 18:35:30 +00:00
|
|
|
R_API void *r_vector_assign_at(RVector *vec, size_t index, void *elem) {
|
2018-07-29 15:05:19 +00:00
|
|
|
void *p = r_vector_index_ptr (vec, index);
|
|
|
|
r_vector_assign (vec, p, elem);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2018-07-30 12:54:47 +00:00
|
|
|
R_API void r_vector_remove_at(RVector *vec, size_t index, void *into) {
|
2018-07-29 15:05:19 +00:00
|
|
|
void *p = r_vector_index_ptr (vec, index);
|
2018-07-27 17:31:58 +00:00
|
|
|
if (into) {
|
2018-07-29 15:05:19 +00:00
|
|
|
r_vector_assign (vec, into, p);
|
2018-07-27 17:31:58 +00:00
|
|
|
}
|
2017-08-26 11:05:14 +00:00
|
|
|
vec->len--;
|
2018-07-27 17:31:58 +00:00
|
|
|
if (index < vec->len) {
|
2018-07-30 15:54:19 +00:00
|
|
|
memmove (p, (char *)p + vec->elem_size, vec->elem_size * (vec->len - index));
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-07-27 17:31:58 +00:00
|
|
|
R_API void *r_vector_insert(RVector *vec, size_t index, void *x) {
|
2017-08-26 11:05:14 +00:00
|
|
|
if (vec->len >= vec->capacity) {
|
|
|
|
RESIZE_OR_RETURN_NULL (NEXT_VECTOR_CAPACITY);
|
|
|
|
}
|
2018-07-29 15:05:19 +00:00
|
|
|
void *p = r_vector_index_ptr (vec, index);
|
2018-07-27 17:31:58 +00:00
|
|
|
if (index < vec->len) {
|
2018-07-30 15:54:19 +00:00
|
|
|
memmove ((char *)p + vec->elem_size, p, vec->elem_size * (vec->len - index));
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|
2018-07-29 15:05:19 +00:00
|
|
|
vec->len++;
|
2018-08-31 08:04:08 +00:00
|
|
|
if (x) {
|
|
|
|
r_vector_assign (vec, p, x);
|
|
|
|
}
|
2018-07-27 17:31:58 +00:00
|
|
|
return p;
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|
|
|
|
|
2018-07-27 17:31:58 +00:00
|
|
|
R_API void *r_vector_insert_range(RVector *vec, size_t index, void *first, size_t count) {
|
|
|
|
if (vec->len + count > vec->capacity) {
|
|
|
|
RESIZE_OR_RETURN_NULL (R_MAX (NEXT_VECTOR_CAPACITY, vec->len + count));
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|
2018-07-27 17:31:58 +00:00
|
|
|
size_t sz = count * vec->elem_size;
|
2018-07-29 15:05:19 +00:00
|
|
|
void *p = r_vector_index_ptr (vec, index);
|
2018-07-27 17:31:58 +00:00
|
|
|
if (index < vec->len) {
|
2018-07-30 15:54:19 +00:00
|
|
|
memmove ((char *)p + sz, p, vec->elem_size * (vec->len - index));
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|
2018-07-27 17:31:58 +00:00
|
|
|
vec->len += count;
|
2018-08-31 08:04:08 +00:00
|
|
|
if (first) {
|
|
|
|
memcpy (p, first, sz);
|
|
|
|
}
|
2018-07-27 17:31:58 +00:00
|
|
|
return p;
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|
|
|
|
|
2018-07-27 17:31:58 +00:00
|
|
|
R_API void r_vector_pop(RVector *vec, void *into) {
|
|
|
|
if (into) {
|
2018-07-29 15:05:19 +00:00
|
|
|
r_vector_assign (vec, into, r_vector_index_ptr (vec, vec->len - 1));
|
2018-07-27 17:31:58 +00:00
|
|
|
}
|
|
|
|
vec->len--;
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|
|
|
|
|
2018-07-27 17:31:58 +00:00
|
|
|
R_API void r_vector_pop_front(RVector *vec, void *into) {
|
2018-08-20 06:52:02 +00:00
|
|
|
r_vector_remove_at (vec, 0, into);
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|
|
|
|
|
2018-07-27 17:31:58 +00:00
|
|
|
R_API void *r_vector_push(RVector *vec, void *x) {
|
2017-08-26 11:05:14 +00:00
|
|
|
if (vec->len >= vec->capacity) {
|
|
|
|
RESIZE_OR_RETURN_NULL (NEXT_VECTOR_CAPACITY);
|
|
|
|
}
|
2018-08-31 08:04:08 +00:00
|
|
|
void *p = r_vector_index_ptr (vec, vec->len++);
|
|
|
|
if (x) {
|
|
|
|
r_vector_assign (vec, p, x);
|
|
|
|
}
|
|
|
|
return p;
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|
|
|
|
|
2018-07-27 17:31:58 +00:00
|
|
|
R_API void *r_vector_push_front(RVector *vec, void *x) {
|
2017-08-26 11:05:14 +00:00
|
|
|
return r_vector_insert (vec, 0, x);
|
|
|
|
}
|
|
|
|
|
2018-07-27 17:31:58 +00:00
|
|
|
R_API void *r_vector_reserve(RVector *vec, size_t capacity) {
|
2017-08-26 11:05:14 +00:00
|
|
|
if (vec->capacity < capacity) {
|
|
|
|
RESIZE_OR_RETURN_NULL (capacity);
|
|
|
|
}
|
|
|
|
return vec->a;
|
|
|
|
}
|
|
|
|
|
2018-07-27 17:31:58 +00:00
|
|
|
R_API void *r_vector_shrink(RVector *vec) {
|
2017-08-26 11:05:14 +00:00
|
|
|
if (vec->len < vec->capacity) {
|
|
|
|
RESIZE_OR_RETURN_NULL (vec->len);
|
|
|
|
}
|
|
|
|
return vec->a;
|
|
|
|
}
|
|
|
|
|
2018-07-27 17:31:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pvector_free_elem(void *e, void *user) {
|
|
|
|
void *p = *((void **)e);
|
|
|
|
RPVectorFree elem_free = (RPVectorFree)user;
|
|
|
|
elem_free (p);
|
|
|
|
}
|
|
|
|
|
2018-07-30 12:54:47 +00:00
|
|
|
|
|
|
|
R_API void r_pvector_init(RPVector *vec, RPVectorFree free) {
|
2018-08-03 10:04:19 +00:00
|
|
|
r_vector_init (&vec->v, sizeof (void *), free ? pvector_free_elem : NULL, free);
|
2018-07-27 17:31:58 +00:00
|
|
|
}
|
|
|
|
|
2018-07-30 12:54:47 +00:00
|
|
|
R_API RPVector *r_pvector_new(RPVectorFree free) {
|
|
|
|
RPVector *v = R_NEW (RPVector);
|
|
|
|
if (!v) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
r_pvector_init (v, free);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_pvector_clear(RPVector *vec) {
|
2018-08-03 10:04:19 +00:00
|
|
|
r_vector_clear (&vec->v);
|
2018-07-30 12:54:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_pvector_free(RPVector *vec) {
|
2018-08-03 10:04:19 +00:00
|
|
|
if (!vec) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
r_vector_clear (&vec->v);
|
|
|
|
free (vec);
|
2018-07-30 12:54:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API void **r_pvector_contains(RPVector *vec, void *x) {
|
2018-07-27 17:31:58 +00:00
|
|
|
size_t i;
|
2018-07-30 12:54:47 +00:00
|
|
|
for (i = 0; i < vec->v.len; i++) {
|
|
|
|
if (((void **)vec->v.a)[i] == x) {
|
|
|
|
return &((void **)vec->v.a)[i];
|
2018-07-27 17:31:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-07-30 12:54:47 +00:00
|
|
|
R_API void *r_pvector_remove_at(RPVector *vec, size_t index) {
|
2018-07-27 17:31:58 +00:00
|
|
|
void *r = r_pvector_at (vec, index);
|
2018-07-30 12:54:47 +00:00
|
|
|
r_vector_remove_at (&vec->v, index, NULL);
|
2018-07-27 17:31:58 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2018-07-30 12:54:47 +00:00
|
|
|
R_API void *r_pvector_pop(RPVector *vec) {
|
|
|
|
void *r = r_pvector_at (vec, vec->v.len - 1);
|
|
|
|
r_vector_pop (&vec->v, NULL);
|
2018-07-27 17:31:58 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2018-07-30 12:54:47 +00:00
|
|
|
R_API void *r_pvector_pop_front(RPVector *vec) {
|
2018-07-27 17:31:58 +00:00
|
|
|
void *r = r_pvector_at (vec, 0);
|
2018-07-30 12:54:47 +00:00
|
|
|
r_vector_pop_front (&vec->v, NULL);
|
2018-07-27 17:31:58 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2017-08-26 11:05:14 +00:00
|
|
|
// CLRS Quicksort. It is slow, but simple.
|
2018-07-27 17:31:58 +00:00
|
|
|
static void quick_sort(void **a, size_t n, RPVectorComparator cmp) {
|
2017-08-26 11:05:14 +00:00
|
|
|
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++)
|
2017-08-27 16:05:58 +00:00
|
|
|
if (cmp (a[i], pivot) < 0) {
|
2017-08-26 11:05:14 +00:00
|
|
|
t = a[i];
|
|
|
|
a[i] = a[j];
|
|
|
|
a[j] = t;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
a[n - 1] = a[j];
|
|
|
|
a[j] = pivot;
|
2017-08-27 16:05:58 +00:00
|
|
|
quick_sort (a, j, cmp);
|
|
|
|
quick_sort (a + j + 1, n - j - 1, cmp);
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|
|
|
|
|
2018-07-30 12:54:47 +00:00
|
|
|
R_API void r_pvector_sort(RPVector *vec, RPVectorComparator cmp) {
|
|
|
|
quick_sort (vec->v.a, vec->v.len, cmp);
|
2017-08-26 11:05:14 +00:00
|
|
|
}
|