For some reasons, I cannot compile correctly this library with inline functions using Meson and Ninja (commit adding Meson build file incoming). Some attributes are also added, such as an attribute for all functions receiving pointers as arguments telling these arguments cannot be null.
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);
|
||
}
|