From 8e29343f3e551f4e6840d250b17c72148c652406 Mon Sep 17 00:00:00 2001 From: Lucien Cartier-Tilet Date: Wed, 7 Oct 2020 17:13:28 +0200 Subject: [PATCH] Huge refactor, documentation incoming --- .clang-format | 2 +- .gitignore | 2 + README.org | 10 +++++ src/vector.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/vector.h | 74 ++++++++++++++++++++++++++++++++++++ vector.c | 84 ----------------------------------------- vector.h | 38 ------------------- 7 files changed, 188 insertions(+), 123 deletions(-) create mode 100644 .gitignore create mode 100644 README.org create mode 100644 src/vector.c create mode 100644 src/vector.h delete mode 100644 vector.c delete mode 100644 vector.h diff --git a/.clang-format b/.clang-format index 7e44223..3fe97b4 100644 --- a/.clang-format +++ b/.clang-format @@ -4,7 +4,7 @@ AlignAfterOpenBracket: Align AlignConsecutiveMacros: 'true' AlignConsecutiveAssignments: 'true' AlignConsecutiveDeclarations: 'true' -AlignEscapedNewlines: Left +AlignEscapedNewlines: Right AlignOperands: 'true' AlignTrailingComments: 'true' AllowAllArgumentsOnNextLine: 'true' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0aef5cc --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.out +vgcore* diff --git a/README.org b/README.org new file mode 100644 index 0000000..98a6340 --- /dev/null +++ b/README.org @@ -0,0 +1,10 @@ +#+TITLE: CVec: A Simple Vector Implementation in C +#+AUTHOR: Lucien Cartier-Tilet +#+EMAIL: lucien@phundrak.com +#+DATE: 2020-10-03 + +* What is this project? + CVec is a simple Vector implementation in C, inspired by C++’s ~std::vector~ + and Rust’s ~std::vec::Vec~. It doesn’t try to be on par with these in terms of + features, but simply tries to provide basic features most people will find + useful. diff --git a/src/vector.c b/src/vector.c new file mode 100644 index 0000000..fd29236 --- /dev/null +++ b/src/vector.c @@ -0,0 +1,101 @@ +#include "vector.h" + +Vector vec_new(Destructor destructor) +{ + 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; +} + +Vector vec_with_capacity(Destructor t_destructor, size_t t_capacity) +{ + Vector self = vec_new(t_destructor); + free(self.elements); + self.elements = (void **)malloc(self.offset * t_capacity); + self.capacity = t_capacity; + return self; +} + +void *vec_at(Vector *self, size_t t_index) +{ + return self->elements[t_index]; +} + +void *vec_safe_at(Vector *self, size_t t_index) +{ + return (t_index >= vec_length(self)) ? NULL : vec_at(self, t_index); +} + +static void vec_maybe_destroy_element(Vector *self, size_t t_index) +{ + void *element = vec_at(self, t_index); + if (self->destroy) { + self->destroy(element); + } +} + +void *vec_last(Vector *self) +{ + return vec_at(self, vec_length(self) - 1); +} + +size_t vec_length(Vector *self) +{ + return self->length; +} + +size_t vec_capacity(Vector *self) +{ + return self->capacity; +} + +static void vec_realloc(Vector *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); + } +} + +void vec_push(Vector *self, void *t_element) +{ + if (vec_length(self) >= vec_capacity(self)) { + vec_realloc(self); + } + self->elements[(*self).length++] = t_element; +} + +void vec_pop(Vector *self) +{ + if (vec_length(self) <= 0) { + return; + } + vec_maybe_destroy_element(self, vec_length(self) - 1); + --(*self).length; +} + +void vec_shrink_to_fit(Vector *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); + } +} + +void vec_delete(Vector *self) +{ + if (self->destroy) { + for (size_t i = 0; i < vec_length(self); ++i) { + self->destroy(self->elements[i]); + } + } + free(self->elements); +} diff --git a/src/vector.h b/src/vector.h new file mode 100644 index 0000000..3558b04 --- /dev/null +++ b/src/vector.h @@ -0,0 +1,74 @@ +#ifndef VECTOR_H +#define VECTOR_H + +#include +#include +#include + +#ifndef DEBUG +# define DEBUG 0 +#endif +#define ERR_MEM_ALLOC 1 +#define NO_COLOR "\x1b[0m" +#define RED "\x1b[31m" +#define GREEN "\x1b[32m" +#define BROWN "\x1b[33m" +#define BLUE "\x1b[34m" +#define MAGENTA "\x1b[35m" +#define CYAN "\x1b[36m" +#define GRAY "\x1b[37m" + +#define UNINPLEMENTED printf("%s:%d: Not yet implemented", __FILE__, __LINE__) +#define INITIAL_CAPACITY 4 +#define PDEB(format, ...) \ + if (DEBUG) { \ + fprintf(stderr, \ + GREEN "%s:%d\t" NO_COLOR format "\n", \ + __FILE__, \ + __LINE__, \ + __VA_ARGS__); \ + } +#define foreach(item, vector) \ + for (int keep = 1, \ + count = 0, \ + size = sizeof(vector->elements) / sizeof vector->elements; \ + keep && count != size; \ + keep = !keep, count++) \ + for (item = \ + (void *)((char *)(vector->elements) + (count * sizeof(void *))); \ + keep; \ + keep = !keep) + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// TODO +// `sizeof()' does NOT work with dynamically allocated memory. Vector capacity +// must be tracked manually + +/* Destructor typedef */ +typedef void (*Destructor)(void *element); + +typedef struct Vector_s { + size_t length; + size_t capacity; + size_t offset; + void ** elements; + Destructor destroy; +} Vector; + +Vector vec_new(Destructor destructor); +Vector vec_with_capacity(Destructor destructor, size_t capacity); + +void * vec_at(Vector *self, size_t index); +void * vec_safe_at(Vector *self, size_t index); +void * vec_last(Vector *self); +size_t vec_length(Vector *self); +size_t vec_capacity(Vector *self); +void vec_push(Vector *self, void *element); +void vec_pop(Vector *self); +void vec_shrink_to_fit(Vector *self); +void vec_delete(Vector *self); + +#endif /* VECTOR_H */ diff --git a/vector.c b/vector.c deleted file mode 100644 index c292fd3..0000000 --- a/vector.c +++ /dev/null @@ -1,84 +0,0 @@ -#include "vector.h" - -#include - -Vector *vec_new(uint32_t obj_size, Destructor destructor) -{ - Vector *self = (Vector *)malloc(sizeof(Vector)); - (*self).elements = NULL; - (*self).obj_size = obj_size; - (*self).len = 0; - (*self).destructor = destructor; - return self; -} - -Vector *vec_new_with_capacity(uint32_t obj_size, - uint32_t obj_number, - Destructor destructor) -{ - Vector *self = (Vector *)malloc(sizeof(Vector)); - (*self).elements = (void **)malloc(obj_number); - (*self).obj_size = obj_size; - (*self).len = 0; - (*self).destructor = destructor; - return self; -} - -uint32_t vec_len(Vector *self) -{ - return self->len; -} - -uint32_t vec_capacity(Vector *self) -{ - return sizeof(self->elements); -} - -uint8_t vec_realloc(Vector *self) -{ - void ** elements = self->elements; - uint32_t new_capacity = (vec_capacity(self) > 0) ? vec_capacity(self) * 2 : 1; - self->elements = realloc(self->elements, new_capacity); - if (!self->elements) { - self->elements = elements; - return 1; - } - return 0; -} - -uint8_t vec_push(Vector *self, void *element) -{ - UNINPLEMENTED; - return 1; - /* if (self->len + 1 > vec_capacity(self)) { */ - /* vec_realloc(self); */ - /* } */ - /* ++(*self).len; */ -} - -uint8_t vec_pop(Vector *self) { - UNINPLEMENTED; - return 1; -} // TODO - -void *vec_at(Vector *self, uint32_t index) -{ - return self->elements + (index * self->obj_size); -} - -void *vec_at_safe(Vector *self, uint32_t index) -{ - if (index < 0 || index >= self->len) { - return NULL; - } - return vec_at(self, index); -} - -void vec_delete(Vector *self) -{ - foreach (void *elem, self) { - self->destructor(elem); - } - free(self->elements); - free(self); -} diff --git a/vector.h b/vector.h deleted file mode 100644 index 66576be..0000000 --- a/vector.h +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include - -#define UNINPLEMENTED printf("%s:%d: Not yet implemented", __FILE__, __LINE__) - -#define foreach(item, vector) \ - for (int keep = 1, \ - count = 0, \ - size = sizeof(vector->elements) / sizeof *(vector->elements); \ - keep && count != size; \ - keep = !keep, count++) \ - for (item = (vector->elements) + (count * vector->obj_size); keep; \ - keep = !keep) - -typedef void (*Destructor)(void *element); - -struct Vector_s { - void ** elements; - uint32_t obj_size; - uint32_t len; - Destructor destructor; -}; - -typedef struct Vector_s Vector; - -Vector * vec_new_with_capacity(uint32_t obj_size, - uint32_t obj_number, - Destructor destructor); // DONE -Vector * vec_new(uint32_t obj_size, - Destructor destructor); // DONE -uint32_t vec_len(Vector *self); // DONE -uint32_t vec_capacity(Vector *self); // DONE -uint8_t vec_push(Vector *self, void *element); // TODO -uint8_t vec_pop(Vector *self); // TODO -void * vec_at(Vector *self, uint32_t index); // DONE -void * vec_at_safe(Vector *self, uint32_t index); // DONE -void vec_delete(Vector *self); // DONE