diff --git a/Makefile b/Makefile index 76666c5..609e17b 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,12 @@ CC = gcc CFLAGS = -Wall -Wextra -pedantic -std=c99 -Werror -CPPFLAGS = -Iinclude/ -Itests/ +CPPFLAGS = -Iinclude/ -Itests/ -D_DEFAULT_SOURCE VPATH = src/ tests/ SRC = \ src/avl.c \ src/list.c \ + src/vector.c \ OBJS = $(SRC:.c=.o) diff --git a/include/tupperware/vector.h b/include/tupperware/vector.h new file mode 100644 index 0000000..7c84bdb --- /dev/null +++ b/include/tupperware/vector.h @@ -0,0 +1,34 @@ +#ifndef TUPPERWARE_VECTOR_H +#define TUPPERWARE_VECTOR_H + +#include +#include + +struct vector { + void *arr; + size_t size; + size_t nmemb; + size_t cap; +}; + +bool vector_init(struct vector *v, size_t size); +bool vector_with_cap(struct vector *v, size_t size, size_t cap); +void vector_clear(struct vector *v, + void (*dtor)(void *v, void *cookie), void *cookie); + +bool vector_reserve(struct vector *v, size_t cap); + +size_t vector_length(const struct vector *v); +size_t vector_capacity(const struct vector *v); +size_t vector_elem_size(const struct vector *v); +bool vector_empty(const struct vector *v); + +void *vector_at(const struct vector *v, size_t i); + +bool vector_push_back(struct vector *v, void *elem); +bool vector_insert_at(struct vector *v, void *elem, size_t i); + +bool vector_pop_back(struct vector *v, void *output); +bool vector_pop_at(struct vector *v, void *output, size_t i); + +#endif /* !TUPPERWARE_VECTOR_H */ diff --git a/src/vector.c b/src/vector.c new file mode 100644 index 0000000..c9d4bec --- /dev/null +++ b/src/vector.c @@ -0,0 +1,148 @@ +#include "tupperware/vector.h" + +#include +#include + +#define VEC_AT(Vec, Ind) ((void *)((char *)(Vec)->arr + ((Vec)->size * (Ind)))) + +bool vector_init(struct vector *v, size_t size) { + if (!v || !size) + return false; + + v->arr = NULL; + v->size = size; + v->nmemb = 0; + v->cap = 0; + + return true; +} + +bool vector_with_cap(struct vector *v, size_t size, size_t cap) { + if (!v || !size) + return false; + + v->arr = calloc(cap, size); + if (!v->arr) + return false; + + v->size = size; + v->nmemb = 0; + v->cap = cap; + + return true; +} + +void vector_clear(struct vector *v, + void (*dtor)(void *v, void *cookie), void *cookie) { + if (!v) + return; + + if (dtor) + for (size_t i = 0; i < v->nmemb; ++i) + dtor(VEC_AT(v, i), cookie); + + v->cap = 0; + v->size = 0; + v->nmemb = 0; + free(v->arr); + v->arr = NULL; +} + +bool vector_reserve(struct vector *v, size_t cap) { + if (!v) + return false; + if (v->cap >= cap) + return true; + + void *tmp = reallocarray(v->arr, cap, v->size); + if (!tmp) + return false; + + v->arr = tmp; + v->cap = cap; + + return true; +} + +size_t vector_length(const struct vector *v) { + if (!v) + return 0; + return v->nmemb; +} + +size_t vector_capacity(const struct vector *v) { + if (!v) + return 0; + return v->cap; +} + +size_t vector_elem_size(const struct vector *v) { + if (!v) + return 0; + return v->size; +} + +bool vector_empty(const struct vector *v) { + return vector_length(v) == 0; +} + +void *vector_at(const struct vector *v, size_t i) { + if (!v) + return NULL; + if (v->nmemb <= i) + return NULL; + + return VEC_AT(v, i); +} + +bool vector_push_back(struct vector *v, void *elem) { + if (!v) + return false; + + return vector_insert_at(v, elem, v->nmemb); +} + +bool vector_insert_at(struct vector *v, void *elem, size_t i) { + if (!v || !elem) + return false; + + if (v->nmemb == v->cap) + if (!vector_reserve(v, (v->cap ? v->cap * 2 : 2))) + return false; + + if (v->nmemb < i) + i = v->nmemb; + if (i < v->nmemb) + memmove(VEC_AT(v, i + 1), + VEC_AT(v, i), + (v->nmemb - i) * v->size); + + memmove(VEC_AT(v, i), elem, v->size); + v->nmemb += 1; + + return true; +} + +bool vector_pop_back(struct vector *v, void *output) { + if (!v || !v->nmemb) + return false; + return vector_pop_at(v, output, v->nmemb - 1); +} + +bool vector_pop_at(struct vector *v, void *output, size_t i) { + if (!v || !v->nmemb) + return false; + + v->nmemb -= 1; + if (i >= v->nmemb) + i = v->nmemb; + + if (output) + memmove(output, VEC_AT(v, i), v->size); + + if (i < v->nmemb) { + memmove(VEC_AT(v, i), VEC_AT(v, i + 1), v->size * (v->nmemb - i)); + } + + return true; +}