2018-01-17 19:22:57 +01:00
|
|
|
#include "vector.h"
|
|
|
|
#include <assert.h>
|
2018-03-17 19:53:38 +01:00
|
|
|
#include <string.h>
|
2018-01-17 19:22:57 +01:00
|
|
|
|
2019-08-27 14:04:54 +02:00
|
|
|
struct f_vector {
|
2018-01-17 19:22:57 +01:00
|
|
|
size_t m_size;
|
|
|
|
void *m_data;
|
|
|
|
size_t m_capacity;
|
|
|
|
size_t m_item_size;
|
|
|
|
};
|
|
|
|
|
2018-11-17 21:55:05 +01:00
|
|
|
|
2019-08-27 14:04:54 +02:00
|
|
|
static int vector_reallocate_(f_vector_t *vector, size_t new_capacity)
|
2018-01-17 19:22:57 +01:00
|
|
|
{
|
|
|
|
assert(vector);
|
|
|
|
assert(new_capacity > vector->m_capacity);
|
|
|
|
|
|
|
|
size_t new_size = new_capacity * vector->m_item_size;
|
2018-04-01 18:10:43 +02:00
|
|
|
vector->m_data = F_REALLOC(vector->m_data, new_size);
|
2018-01-17 19:22:57 +01:00
|
|
|
if (vector->m_data == NULL)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-17 21:55:05 +01:00
|
|
|
|
2018-09-01 18:42:57 +02:00
|
|
|
FT_INTERNAL
|
2019-08-27 14:04:54 +02:00
|
|
|
f_vector_t *create_vector(size_t item_size, size_t capacity)
|
2018-01-17 19:22:57 +01:00
|
|
|
{
|
2019-08-27 14:04:54 +02:00
|
|
|
f_vector_t *vector = (f_vector_t *)F_MALLOC(sizeof(f_vector_t));
|
2018-01-17 19:22:57 +01:00
|
|
|
if (vector == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t init_size = MAX(item_size * capacity, 1);
|
2018-04-01 18:10:43 +02:00
|
|
|
vector->m_data = F_MALLOC(init_size);
|
2018-01-17 19:22:57 +01:00
|
|
|
if (vector->m_data == NULL) {
|
2018-04-01 18:10:43 +02:00
|
|
|
F_FREE(vector);
|
2018-01-17 19:22:57 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector->m_size = 0;
|
|
|
|
vector->m_capacity = capacity;
|
|
|
|
vector->m_item_size = item_size;
|
|
|
|
|
|
|
|
return vector;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-01 18:42:57 +02:00
|
|
|
FT_INTERNAL
|
2019-08-27 14:04:54 +02:00
|
|
|
void destroy_vector(f_vector_t *vector)
|
2018-01-17 19:22:57 +01:00
|
|
|
{
|
|
|
|
assert(vector);
|
2018-04-01 18:10:43 +02:00
|
|
|
F_FREE(vector->m_data);
|
|
|
|
F_FREE(vector);
|
2018-01-17 19:22:57 +01:00
|
|
|
}
|
|
|
|
|
2018-02-25 09:39:41 +01:00
|
|
|
|
2018-09-01 18:42:57 +02:00
|
|
|
FT_INTERNAL
|
2019-08-27 14:04:54 +02:00
|
|
|
size_t vector_size(const f_vector_t *vector)
|
2018-01-17 19:22:57 +01:00
|
|
|
{
|
|
|
|
assert(vector);
|
|
|
|
return vector->m_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-01 18:42:57 +02:00
|
|
|
FT_INTERNAL
|
2019-08-27 14:04:54 +02:00
|
|
|
size_t vector_capacity(const f_vector_t *vector)
|
2018-01-17 19:22:57 +01:00
|
|
|
{
|
|
|
|
assert(vector);
|
|
|
|
return vector->m_capacity;
|
|
|
|
}
|
|
|
|
|
2018-11-17 21:55:05 +01:00
|
|
|
|
2018-09-01 18:42:57 +02:00
|
|
|
FT_INTERNAL
|
2019-08-27 14:04:54 +02:00
|
|
|
int vector_push(f_vector_t *vector, const void *item)
|
2018-01-17 19:22:57 +01:00
|
|
|
{
|
|
|
|
assert(vector);
|
|
|
|
assert(item);
|
|
|
|
|
|
|
|
if (vector->m_size == vector->m_capacity) {
|
|
|
|
if (vector_reallocate_(vector, vector->m_capacity * 2) == -1)
|
2018-03-19 21:07:18 +01:00
|
|
|
return FT_ERROR;
|
2018-01-17 19:22:57 +01:00
|
|
|
vector->m_capacity = vector->m_capacity * 2;
|
|
|
|
}
|
|
|
|
|
2019-01-01 16:50:08 +01:00
|
|
|
size_t offset = vector->m_size * vector->m_item_size;
|
|
|
|
memcpy((char *)vector->m_data + offset, item, vector->m_item_size);
|
2018-01-17 19:22:57 +01:00
|
|
|
|
|
|
|
++(vector->m_size);
|
|
|
|
|
2018-03-19 21:07:18 +01:00
|
|
|
return FT_SUCCESS;
|
2018-01-17 19:22:57 +01:00
|
|
|
}
|
|
|
|
|
2020-01-08 13:32:06 +01:00
|
|
|
FT_INTERNAL
|
|
|
|
int vector_insert(f_vector_t *vector, const void *item, size_t pos)
|
|
|
|
{
|
|
|
|
assert(vector);
|
|
|
|
assert(item);
|
|
|
|
size_t needed_capacity = MAX(pos + 1, vector->m_size + 1);
|
|
|
|
if (vector->m_capacity < needed_capacity) {
|
|
|
|
if (vector_reallocate_(vector, needed_capacity) == -1)
|
|
|
|
return FT_ERROR;
|
|
|
|
vector->m_capacity = needed_capacity;
|
|
|
|
}
|
|
|
|
size_t offset = pos * vector->m_item_size;
|
|
|
|
if (pos >= vector->m_size) {
|
|
|
|
/* Data in the middle are not initialized */
|
|
|
|
memcpy((char *)vector->m_data + offset, item, vector->m_item_size);
|
|
|
|
vector->m_size = pos + 1;
|
|
|
|
return FT_SUCCESS;
|
|
|
|
} else {
|
|
|
|
/* Shift following data by one position */
|
|
|
|
memmove((char *)vector->m_data + offset + vector->m_item_size,
|
|
|
|
(char *)vector->m_data + offset,
|
|
|
|
vector->m_item_size * (vector->m_size - pos));
|
|
|
|
memcpy((char *)vector->m_data + offset, item, vector->m_item_size);
|
|
|
|
++(vector->m_size);
|
|
|
|
return FT_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FT_INTERNAL
|
|
|
|
f_vector_t *vector_split(f_vector_t *vector, size_t pos)
|
|
|
|
{
|
|
|
|
size_t trailing_sz = vector->m_size > pos ? vector->m_size - pos : 0;
|
|
|
|
f_vector_t *new_vector = create_vector(vector->m_item_size, trailing_sz);
|
|
|
|
if (!new_vector)
|
|
|
|
return new_vector;
|
|
|
|
if (new_vector->m_capacity < trailing_sz) {
|
|
|
|
destroy_vector(new_vector);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trailing_sz == 0)
|
|
|
|
return new_vector;
|
|
|
|
|
|
|
|
size_t offset = vector->m_item_size * pos;
|
|
|
|
memcpy(new_vector->m_data, (char *)vector->m_data + offset,
|
|
|
|
trailing_sz * vector->m_item_size);
|
|
|
|
new_vector->m_size = trailing_sz;
|
|
|
|
vector->m_size = pos;
|
|
|
|
return new_vector;
|
|
|
|
}
|
2018-01-17 19:22:57 +01:00
|
|
|
|
2018-09-01 18:42:57 +02:00
|
|
|
FT_INTERNAL
|
2019-08-27 14:04:54 +02:00
|
|
|
const void *vector_at_c(const f_vector_t *vector, size_t index)
|
2018-02-25 09:39:41 +01:00
|
|
|
{
|
|
|
|
if (index >= vector->m_size)
|
|
|
|
return NULL;
|
|
|
|
|
2018-03-31 12:33:37 +02:00
|
|
|
return (char *)vector->m_data + index * vector->m_item_size;
|
2018-02-25 09:39:41 +01:00
|
|
|
}
|
2018-01-17 19:22:57 +01:00
|
|
|
|
|
|
|
|
2018-09-01 18:42:57 +02:00
|
|
|
FT_INTERNAL
|
2019-08-27 14:04:54 +02:00
|
|
|
void *vector_at(f_vector_t *vector, size_t index)
|
2018-01-17 19:22:57 +01:00
|
|
|
{
|
|
|
|
if (index >= vector->m_size)
|
|
|
|
return NULL;
|
|
|
|
|
2018-03-31 12:33:37 +02:00
|
|
|
return (char *)vector->m_data + index * vector->m_item_size;
|
2018-01-17 19:22:57 +01:00
|
|
|
}
|
|
|
|
|
2018-09-01 18:42:57 +02:00
|
|
|
|
|
|
|
FT_INTERNAL
|
2019-08-27 14:04:54 +02:00
|
|
|
f_status vector_swap(f_vector_t *cur_vec, f_vector_t *mv_vec, size_t pos)
|
2018-04-22 20:42:22 +02:00
|
|
|
{
|
|
|
|
assert(cur_vec);
|
|
|
|
assert(mv_vec);
|
2018-04-22 20:49:36 +02:00
|
|
|
assert(cur_vec != mv_vec);
|
2018-04-22 20:42:22 +02:00
|
|
|
assert(cur_vec->m_item_size == mv_vec->m_item_size);
|
|
|
|
|
|
|
|
size_t cur_sz = vector_size(cur_vec);
|
|
|
|
size_t mv_sz = vector_size(mv_vec);
|
|
|
|
if (mv_sz == 0) {
|
|
|
|
return FT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t min_targ_size = pos + mv_sz;
|
2018-05-12 11:45:42 +02:00
|
|
|
if (vector_capacity(cur_vec) < min_targ_size) {
|
2018-04-22 20:42:22 +02:00
|
|
|
if (vector_reallocate_(cur_vec, min_targ_size) == -1)
|
|
|
|
return FT_ERROR;
|
|
|
|
cur_vec->m_capacity = min_targ_size;
|
|
|
|
}
|
|
|
|
|
2019-01-01 16:50:08 +01:00
|
|
|
size_t offset = pos * cur_vec->m_item_size;
|
2018-04-22 20:42:22 +02:00
|
|
|
void *tmp = NULL;
|
|
|
|
size_t new_mv_sz = 0;
|
|
|
|
if (cur_sz > pos) {
|
|
|
|
new_mv_sz = MIN(cur_sz - pos, mv_sz);
|
|
|
|
tmp = F_MALLOC(cur_vec->m_item_size * new_mv_sz);
|
|
|
|
if (tmp == NULL) {
|
|
|
|
return FT_MEMORY_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-12 12:09:07 +02:00
|
|
|
if (tmp) {
|
|
|
|
memcpy(tmp,
|
2019-01-01 16:50:08 +01:00
|
|
|
(char *)cur_vec->m_data + offset,
|
2018-05-12 12:09:07 +02:00
|
|
|
cur_vec->m_item_size * new_mv_sz);
|
|
|
|
}
|
|
|
|
|
2019-01-01 16:50:08 +01:00
|
|
|
memcpy((char *)cur_vec->m_data + offset,
|
2018-04-22 20:42:22 +02:00
|
|
|
mv_vec->m_data,
|
|
|
|
cur_vec->m_item_size * mv_sz);
|
2018-05-12 12:09:07 +02:00
|
|
|
|
|
|
|
if (tmp) {
|
|
|
|
memcpy(mv_vec->m_data,
|
|
|
|
tmp,
|
|
|
|
cur_vec->m_item_size * new_mv_sz);
|
|
|
|
}
|
2018-04-22 20:42:22 +02:00
|
|
|
|
2018-05-12 11:45:42 +02:00
|
|
|
cur_vec->m_size = MAX(cur_vec->m_size, min_targ_size);
|
2018-04-22 20:42:22 +02:00
|
|
|
mv_vec->m_size = new_mv_sz;
|
|
|
|
F_FREE(tmp);
|
|
|
|
return FT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-01-08 13:32:06 +01:00
|
|
|
FT_INTERNAL
|
|
|
|
void vector_clear(f_vector_t *vector)
|
|
|
|
{
|
|
|
|
vector->m_size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
FT_INTERNAL
|
|
|
|
int vector_erase(f_vector_t *vector, size_t index)
|
|
|
|
{
|
|
|
|
assert(vector);
|
|
|
|
|
|
|
|
if (vector->m_size == 0 || index >= vector->m_size)
|
|
|
|
return FT_ERROR;
|
|
|
|
|
|
|
|
memmove((char *)vector->m_data + vector->m_item_size * index,
|
|
|
|
(char *)vector->m_data + vector->m_item_size * (index + 1),
|
|
|
|
(vector->m_size - 1 - index) * vector->m_item_size);
|
|
|
|
vector->m_size--;
|
|
|
|
return FT_SUCCESS;
|
|
|
|
}
|
2018-11-03 07:14:02 +01:00
|
|
|
|
|
|
|
#ifdef FT_TEST_BUILD
|
|
|
|
|
2019-08-27 14:04:54 +02:00
|
|
|
f_vector_t *copy_vector(f_vector_t *v)
|
2018-09-01 18:42:57 +02:00
|
|
|
{
|
|
|
|
if (v == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2019-08-27 14:04:54 +02:00
|
|
|
f_vector_t *new_vector = create_vector(v->m_item_size, v->m_capacity);
|
2018-09-01 18:42:57 +02:00
|
|
|
if (new_vector == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
memcpy(new_vector->m_data, v->m_data, v->m_item_size * v->m_size);
|
|
|
|
new_vector->m_size = v->m_size ;
|
|
|
|
new_vector->m_item_size = v->m_item_size ;
|
|
|
|
return new_vector;
|
|
|
|
}
|
|
|
|
|
2019-08-27 14:04:54 +02:00
|
|
|
size_t vector_index_of(const f_vector_t *vector, const void *item)
|
2018-09-01 18:42:57 +02:00
|
|
|
{
|
|
|
|
assert(vector);
|
|
|
|
assert(item);
|
2018-01-17 19:22:57 +01:00
|
|
|
|
2018-09-01 18:42:57 +02:00
|
|
|
size_t i = 0;
|
|
|
|
for (i = 0; i < vector->m_size; ++i) {
|
|
|
|
void *data_pos = (char *)vector->m_data + i * vector->m_item_size;
|
|
|
|
if (memcmp(data_pos, item, vector->m_item_size) == 0) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return INVALID_VEC_INDEX;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|