You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
3.6 KiB
144 lines
3.6 KiB
#include "vector.h" |
|
|
|
static void vec_maybe_destroy_element(Vector const *self, |
|
size_t const t_index) NONNULL; |
|
static Result vec_realloc(Vector *const self) NONNULL; |
|
static Result vec_warn_error(Result error); |
|
|
|
Result vec_warn_error(Result error) |
|
{ |
|
PERR("%s", error.result.message); |
|
return error; |
|
} |
|
|
|
Result vec_new(Destructor destructor) |
|
{ |
|
Vector *self = NULL; |
|
self = (Vector *)malloc(sizeof(Vector)); |
|
if (!self) { /* Error handling */ |
|
return vec_warn_error((Result){ |
|
.error = true, |
|
.result = {.message = "Could not allocate memory for Vector structure"}}); |
|
} |
|
(*self).length = 0; |
|
(*self).capacity = INITIAL_CAPACITY; |
|
*(size_t *)&self->offset = sizeof(void *); /* weird syntax due to constness */ |
|
(*self).elements = (void *)malloc(self->offset * INITIAL_CAPACITY); |
|
if (!self->elements) { /* Error handling */ |
|
free(self); |
|
return vec_warn_error((Result){ |
|
.error = true, |
|
.result = {.message = "Could not allocate memory for Vector’s array"}}); |
|
} |
|
(*self).destroy = destructor; |
|
return (Result){.error = false, .result.value = self}; |
|
} |
|
|
|
Result vec_with_capacity(Destructor const t_destructor, size_t const t_capacity) |
|
{ |
|
Result vec = vec_new(t_destructor); |
|
if (vec.error) { /* Error handling */ |
|
return vec; |
|
} |
|
Vector *self = vec.result.value; |
|
free((*self).elements); |
|
(*self).elements = (void **)malloc(self->offset * t_capacity); |
|
if (!self->elements) { /* Error handling */ |
|
free(self); |
|
return vec_warn_error((Result){ |
|
.error = true, |
|
.result = {.message = "Could not allocate memory for Vector’s array"}}); |
|
} |
|
(*self).capacity = t_capacity; |
|
vec.result.value = self; |
|
return vec; |
|
} |
|
|
|
void *vec_safe_at(Vector const *const self, size_t const t_index) |
|
{ |
|
return (t_index >= vec_length(self)) ? NULL : vec_at(self, t_index); |
|
} |
|
|
|
void vec_maybe_destroy_element(Vector const *self, size_t const t_index) |
|
{ |
|
if (self->destroy) { |
|
void *element = vec_at(self, t_index); |
|
self->destroy(element); |
|
} |
|
} |
|
|
|
Result vec_realloc(Vector *const self) |
|
{ |
|
self->capacity *= 2; |
|
self->elements = realloc(self->elements, sizeof(void *) * vec_capacity(self)); |
|
if (!self->elements) { |
|
return (Result){ |
|
.error = true, |
|
.result = {.message = "Could not reallocate Vector’s array"}}; |
|
} |
|
return (Result){.error = false, .result = {.value = NULL}}; |
|
} |
|
|
|
Result vec_push(Vector *const self, void *const t_element) |
|
{ |
|
if (vec_length(self) >= vec_capacity(self)) { |
|
Result res_realloc = vec_realloc(self); |
|
if (res_realloc.error) { |
|
return res_realloc; |
|
} |
|
} |
|
self->elements[(*self).length++] = t_element; |
|
return (Result){.error = false, .result = {.value = NULL}}; |
|
} |
|
|
|
void vec_pop(Vector *const self) |
|
{ |
|
if (vec_length(self) <= 0) { |
|
return; |
|
} |
|
vec_maybe_destroy_element(self, vec_length(self) - 1); |
|
--(*self).length; |
|
} |
|
|
|
Result vec_shrink_to_fit(Vector *const self) |
|
{ |
|
self->capacity = self->length; |
|
self->elements = realloc(self->elements, sizeof(void *) * vec_capacity(self)); |
|
if (!self->elements) { |
|
return (Result){ |
|
.error = true, |
|
.result = {.message = "Could not reallocate Vector’s memory"}}; |
|
} |
|
return (Result){.error = false, .result = {.value = NULL}}; |
|
} |
|
|
|
void vec_delete(Vector *const self) |
|
{ |
|
if (self->destroy) { |
|
for (size_t i = 0; i < vec_length(self); ++i) { |
|
self->destroy(self->elements[i]); |
|
} |
|
} |
|
free(self->elements); |
|
free(self); |
|
} |
|
|
|
size_t vec_length(Vector const *const self) |
|
{ |
|
return self->length; |
|
} |
|
|
|
size_t vec_capacity(Vector const *const self) |
|
{ |
|
return self->capacity; |
|
} |
|
|
|
void *vec_at(Vector const *const self, size_t const index) |
|
{ |
|
return self->elements[index]; |
|
} |
|
|
|
void *vec_last(Vector const *const self) |
|
{ |
|
return vec_at(self, vec_length(self) - 1); |
|
}
|
|
|