#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); }