From 30c1e780a1e08caaa4498383e8a77b4ccdc35cea Mon Sep 17 00:00:00 2001 From: Sara Date: Sat, 14 Oct 2023 20:54:59 +0200 Subject: [PATCH] added contiguous dynamic length array List --- src/list.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/list.h | 31 +++++++++++ 2 files changed, 179 insertions(+) create mode 100644 src/list.c create mode 100644 src/list.h diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000..6676a39 --- /dev/null +++ b/src/list.c @@ -0,0 +1,148 @@ +#include "list.h" +#include "stdint.h" +#include "stdlib.h" +#include "string.h" +#include "debug.h" + +#ifndef LIST_DEFAULT_RESERVE +#define LIST_DEFAULT_RESERVE 4 +#endif + +List list_init(size_t element_size) { + List self = { + .element_size = element_size, + .cap = LIST_DEFAULT_RESERVE, + .len = 0, + .data = malloc(element_size * LIST_DEFAULT_RESERVE), + }; + + if(self.data == NULL) { + LOG_ERROR("Failed to allocate list with starting capacity of %d", LIST_DEFAULT_RESERVE); + self.cap = 0; + } + + return self; +} + +void list_empty(List* self) { + if(self->data == NULL || self->cap == 0) + return; + self->data = realloc(self->data, LIST_DEFAULT_RESERVE * self->element_size); + self->cap = LIST_DEFAULT_RESERVE; + self->len = 0; +} + +void list_reserve(List* self, size_t at_least) { + if(at_least < self->cap) + return; + + size_t new_cap = self->cap > 0 ? self->cap : LIST_DEFAULT_RESERVE; + while(at_least >= new_cap) { + new_cap *= 2; + } + + void* new = realloc(self->data, new_cap * self->element_size); + ASSERT_RETURN(new != NULL,, "Failed to reserve space for %zu extra elements in list", new_cap); + + self->data = new; + self->cap = new_cap; +} + +static inline +void* list_at_unchecked(List* self, size_t at) { + union { + uint8_t* as_byte; + void* as_void; + } data = { + .as_void = self->data + }; + + return data.as_byte + self->element_size * at; +} + +void* list_at(List* self, size_t at) { + ASSERT_RETURN(at < self->len, NULL, "Index %zu out of bounds", at); + return list_at_unchecked(self, at); +} + +size_t list_add(List* self, void* item) { + list_reserve(self, self->len + 1); + union { + uint8_t* as_byte; + void* as_void; + } data = { + .as_void = self->data + }; + + uint8_t* into = data.as_byte + self->element_size * self->len; + + memcpy(into, item, self->element_size); + ++self->len; + + return self->len - 1; +} + +void list_insert(List* self, void* item, size_t at) { + ASSERT_RETURN(at < self->len,, "Index %zu out of bounds", at); + + list_reserve(self, self->len + 1); + + if(at == self->len - 1) { + list_add(self, item); + return; + } + + union { + uint8_t* as_byte; + void* as_void; + } data = { + .as_void = self->data + }; + uint8_t* from = data.as_byte + self->element_size * at; + uint8_t* into = data.as_byte + self->element_size * (at + 1); + uint8_t* end = data.as_byte + self->element_size * self->len; + memmove(into, from, end - from); + memcpy(from, item, self->element_size); +} + +void list_erase(List* self, size_t at) { + ASSERT_RETURN(at < self->len,, "Index %zu out of bounds", at); + + union { + uint8_t* as_byte; + void* as_void; + } data = { + .as_void = self->data + }; + + uint8_t* into = data.as_byte + at * self->element_size; + uint8_t* from = data.as_byte + (at + 1) * self->element_size; + + if(at < self->len - 1) + memmove(into, from, (self->len - at) * self->element_size); + --self->len; + + size_t new_cap = self->cap; + while(new_cap > self->len) { + new_cap /= 2; + } + new_cap *= 2; + + + if(new_cap == self->cap) + return; + + void* shrunk = realloc(self->data, new_cap * self->element_size); + ASSERT_RETURN(shrunk != NULL || new_cap == 0,, "Failed to shrink List to %zu", new_cap); + + self->data = shrunk; + self->cap = new_cap; +} + +void* list_iterator_begin(List* self) { + return list_at_unchecked(self, 0); +} + +void* list_iterator_end(List* self) { + return list_at_unchecked(self, self->len); +} diff --git a/src/list.h b/src/list.h new file mode 100644 index 0000000..4b2e37c --- /dev/null +++ b/src/list.h @@ -0,0 +1,31 @@ +#ifndef _fencer_list_h +#define _fencer_list_h + +#include "stddef.h" + +typedef struct List List; +struct List { + void* data; + size_t cap; + size_t len; + + size_t element_size; +}; + +extern List list_init(size_t element_size); +extern void list_empty(List* list); + +extern void list_reserve(List* self, size_t at_least); +extern void* list_at(List* list, size_t at); + +extern size_t list_add(List* self, void* item); +extern void list_insert(List* self, void* item, size_t at); +extern void list_erase(List* self, size_t at); + +extern void* list_iterator_begin(List* self); +extern void* list_iterator_end(List* self); + +#define list_from_type(T) list_init(sizeof(T)) +#define list_foreach(T, iter, list) for(T* iter = list_iterator_begin(list); iter != (T*)list_iterator_end(list); ++iter) + +#endif // !_fencer_list_h