145 lines
3.6 KiB
C
145 lines
3.6 KiB
C
#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);
|
||
}
|