Better error handling, inline functions, new PERR
Functions that end up calling a `malloc' or `realloc' return the new struct `Result' which indicates if the memory allocation or reallocation worked or not. If not, it holds a message, otherwise it holds the value the function is meant to return (can be a null pointer if the function returned a `void' before). The library will no longer forcibly exit the program on such error in case it can be recovered by the code calling it. The modifications described above lead to vector-creating functions returning a pointer to the newly created vector, and the function for deleting vectors also frees the vector. This commit also inlines some functions to make the compiled code a bit lighter and calls to these functions possibly a bit faster. `PDEB' is redefined following the new `PCOMMON' macro that is also used by `PERR' for desplaying debug error messages. Some lines are also modified to avoid potential memory leaks in case of a memory (re)allocation.
This commit is contained in:
parent
193bf1d75f
commit
fbed1b21d6
96
src/vector.c
96
src/vector.c
@ -1,28 +1,52 @@
|
||||
#include "vector.h"
|
||||
|
||||
Vector vec_new(Destructor destructor)
|
||||
static Result vec_warn_error(Result error)
|
||||
{
|
||||
Vector self;
|
||||
self.length = 0;
|
||||
self.capacity = INITIAL_CAPACITY;
|
||||
self.offset = sizeof(void *);
|
||||
self.elements = (void *)malloc(self.offset * INITIAL_CAPACITY);
|
||||
self.destroy = destructor;
|
||||
return self;
|
||||
PERR("%s", error.result.message);
|
||||
return error;
|
||||
}
|
||||
|
||||
Vector vec_with_capacity(Destructor const t_destructor, size_t const t_capacity)
|
||||
Result vec_new(Destructor destructor)
|
||||
{
|
||||
Vector self = vec_new(t_destructor);
|
||||
free(self.elements);
|
||||
self.elements = (void **)malloc(self.offset * t_capacity);
|
||||
self.capacity = t_capacity;
|
||||
return self;
|
||||
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};
|
||||
}
|
||||
|
||||
void *vec_at(Vector const *const self, size_t const t_index)
|
||||
Result vec_with_capacity(Destructor const t_destructor, size_t const t_capacity)
|
||||
{
|
||||
return self->elements[t_index];
|
||||
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)
|
||||
@ -38,37 +62,28 @@ static void vec_maybe_destroy_element(Vector const *self, size_t const t_index)
|
||||
}
|
||||
}
|
||||
|
||||
void *vec_last(Vector const *const self)
|
||||
{
|
||||
return vec_at(self, vec_length(self) - 1);
|
||||
}
|
||||
|
||||
size_t vec_length(Vector const *const self)
|
||||
{
|
||||
return self->length;
|
||||
}
|
||||
|
||||
size_t vec_capacity(Vector const *const self)
|
||||
{
|
||||
return self->capacity;
|
||||
}
|
||||
|
||||
static void vec_realloc(Vector *const self)
|
||||
static Result vec_realloc(Vector *const self)
|
||||
{
|
||||
self->capacity *= 2;
|
||||
self->elements = realloc(self->elements, sizeof(void *) * vec_capacity(self));
|
||||
if (!self->elements) {
|
||||
PDEB("Could not reallocate Vector’s memory, aborting...", NULL);
|
||||
exit(ERR_MEM_ALLOC);
|
||||
return (Result){
|
||||
.error = true,
|
||||
.result = {.message = "Could not reallocate Vector’s array"}};
|
||||
}
|
||||
return (Result){.error = false, .result = {.value = NULL}};
|
||||
}
|
||||
|
||||
void vec_push(Vector *const self, void const *const t_element)
|
||||
Result vec_push(Vector *const self, void *const t_element)
|
||||
{
|
||||
if (vec_length(self) >= vec_capacity(self)) {
|
||||
vec_realloc(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)
|
||||
@ -80,14 +95,16 @@ void vec_pop(Vector *const self)
|
||||
--(*self).length;
|
||||
}
|
||||
|
||||
void vec_shrink_to_fit(Vector *const self)
|
||||
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) {
|
||||
PDEB("Could not reallocate Vector’s memory, aborting...", NULL);
|
||||
exit(ERR_MEM_ALLOC);
|
||||
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)
|
||||
@ -98,4 +115,5 @@ void vec_delete(Vector *const self)
|
||||
}
|
||||
}
|
||||
free(self->elements);
|
||||
free(self);
|
||||
}
|
||||
|
54
src/vector.h
54
src/vector.h
@ -1,6 +1,7 @@
|
||||
#ifndef VECTOR_H
|
||||
#define VECTOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -20,14 +21,16 @@
|
||||
|
||||
#define UNINPLEMENTED printf("%s:%d: Not yet implemented", __FILE__, __LINE__)
|
||||
#define INITIAL_CAPACITY 4
|
||||
#define PDEB(format, ...) \
|
||||
if (DEBUG) { \
|
||||
#define PCOMMON(color, format, ...) \
|
||||
fprintf(stderr, \
|
||||
GREEN "%s:%d\t" NO_COLOR format "\n", \
|
||||
"%s%s:%d%s\t" format "\n", \
|
||||
color, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
__VA_ARGS__); \
|
||||
}
|
||||
NO_COLOR, \
|
||||
__VA_ARGS__)
|
||||
#define PDEB(format, ...) PCOMMON(GREEN, format, __VA_ARGS__)
|
||||
#define PERR(format, ...) PCOMMON(RED, format, __VA_ARGS__)
|
||||
|
||||
/* Destructor typedef */
|
||||
typedef void (*Destructor)(void *element);
|
||||
@ -35,22 +38,45 @@ typedef void (*Destructor)(void *element);
|
||||
typedef struct Vector_s {
|
||||
size_t length;
|
||||
size_t capacity;
|
||||
size_t offset;
|
||||
const size_t offset;
|
||||
void ** elements;
|
||||
Destructor destroy;
|
||||
} Vector;
|
||||
|
||||
Vector vec_new(Destructor destructor);
|
||||
Vector vec_with_capacity(Destructor const destructor, size_t const capacity);
|
||||
typedef struct Result_s {
|
||||
union {
|
||||
const char *message;
|
||||
void * value;
|
||||
} result;
|
||||
bool error;
|
||||
} Result;
|
||||
|
||||
void * vec_at(Vector const *const self, size_t const index);
|
||||
Result vec_new(Destructor destructor);
|
||||
Result vec_with_capacity(Destructor const destructor, size_t const capacity);
|
||||
Result vec_push(Vector *const self, void *const element);
|
||||
Result vec_shrink_to_fit(Vector *const self);
|
||||
void * vec_safe_at(Vector const *const self, size_t const index);
|
||||
void * vec_last(Vector const *const self);
|
||||
size_t vec_length(Vector const *const self);
|
||||
size_t vec_capacity(Vector const *const self);
|
||||
void vec_push(Vector *const self, void const *const element);
|
||||
void vec_pop(Vector *const self);
|
||||
void vec_shrink_to_fit(Vector *const self);
|
||||
void vec_delete(Vector *const self);
|
||||
|
||||
inline size_t vec_length(Vector const *const self)
|
||||
{
|
||||
return self->length;
|
||||
}
|
||||
|
||||
inline size_t vec_capacity(Vector const *const self)
|
||||
{
|
||||
return self->capacity;
|
||||
}
|
||||
|
||||
inline void *vec_at(Vector const *const self, size_t const index)
|
||||
{
|
||||
return self->elements[index];
|
||||
}
|
||||
|
||||
inline void *vec_last(Vector const *const self)
|
||||
{
|
||||
return vec_at(self, vec_length(self) - 1);
|
||||
}
|
||||
|
||||
#endif /* VECTOR_H */
|
||||
|
Loading…
Reference in New Issue
Block a user