diff --git a/include/array_list.h b/include/array_list.h new file mode 100644 index 0000000..9d675a6 --- /dev/null +++ b/include/array_list.h @@ -0,0 +1,54 @@ +#pragma once + +#include + +#include "scoped.h" + +#define ARRAY_LIST_EMPTY ((struct array_list) { NULL, 0, 0 }) + +struct array_list { + void *buf; + size_t len; + size_t cap; +}; + +int array_list_raw_alloc(struct array_list *al, size_t cap, size_t elem_size); +void array_list_raw_cleanup(struct array_list *al); + +#define DEF_ARRAY_LIST_TYPE(NAME, TYPE, UNOCCUPIED, CLEANUP_FN) \ + static inline TYPE *array_list_##NAME##_get(struct array_list *al, size_t i) { \ + if (i >= al->len) \ + return NULL; \ + return &((TYPE *)al->buf)[i]; \ + } \ + static inline const TYPE *array_list_##NAME##_cget(const struct array_list *al, size_t i) { \ + if (i >= al->len) \ + return NULL; \ + return &((const TYPE *)al->buf)[i]; \ + } \ + static inline void array_list_##NAME##_cleanup(struct array_list *al) { \ + size_t i; \ + for (i = 0; i < al->len; i++) \ + CLEANUP_FN(array_list_##NAME##_get(al, i)); \ + array_list_raw_cleanup(al); \ + } \ + static inline int array_list_##NAME##_alloc(struct array_list *al, size_t cap) { \ + size_t i; \ + if (cap < al->len) { \ + for (i = cap; i < al->len; i++) \ + CLEANUP_FN(array_list_##NAME##_get(al, i)); \ + al->len = cap; \ + } \ + return array_list_raw_alloc(al, cap, sizeof(TYPE)); \ + } \ + static inline int array_list_##NAME##_push_noalloc_byval(struct array_list *al, TYPE elem) { \ + if (al->len >= al->cap) \ + return -1; \ + ((TYPE *)al->buf)[al->len++] = elem; \ + return 0; \ + } \ + DEF_SCOPED_TYPE( \ + array_list_##NAME, \ + struct array_list, \ + ARRAY_LIST_EMPTY, \ + array_list_##NAME##_cleanup) diff --git a/src/array_list.c b/src/array_list.c new file mode 100644 index 0000000..206d4b9 --- /dev/null +++ b/src/array_list.c @@ -0,0 +1,22 @@ +#include + +#include "array_list.h" + +int array_list_raw_alloc(struct array_list *al, size_t cap, size_t elem_size) { + void *buf; + + if (!(buf = realloc(al->buf, cap * elem_size))) + return -1; + al->buf = buf; + al->cap = cap; + return 0; +} + +void array_list_raw_cleanup(struct array_list *al) { + if (al->buf && al->cap) { + free(al->buf); + al->buf = NULL; + al->cap = 0; + al->len = 0; + } +}