commit 143a64f7de7857209716c0379849698fb7b3b6bd Author: brnrs Date: Sat Mar 27 14:04:52 2021 +0100 v0.0.1: initial implementation diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5b79a54 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +.cache/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..023696f --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# barray + +This is a tiny library containing a dynamic array implementation \ No newline at end of file diff --git a/include/barray.h b/include/barray.h new file mode 100644 index 0000000..a345c0a --- /dev/null +++ b/include/barray.h @@ -0,0 +1,35 @@ +#ifndef _BARRAY_H +#define _BARRAY_H + +#include +#include + +typedef struct { + void* ptr; + size_t len; + size_t cap; + size_t elem_size; +} BArray; + +typedef enum { + BARRAY_NO_ERR, + BARRAY_ERR_ALLOC_ERR, + BARRAY_ERR_OUT_OF_BOUNDS, + BARRAY_ERR_SIZE_OVERFLOW, + BARRAY_ERR_NULL, + BARRAY_ERR_ELEM_SIZE_ZERO +} BArray_ErrCode; + +BArray barray_create(size_t elem_size, size_t initial_cap, BArray_ErrCode* errc); +void barray_grow(BArray* array, BArray_ErrCode* errc); +void barray_grow_to(BArray* array, size_t new_cap, BArray_ErrCode* errc); +void barray_shrink_to_fit(BArray* array, BArray_ErrCode* errc); +void barray_force_shrink(BArray* array, size_t new_cap, BArray_ErrCode* errc); +void* barray_get(BArray* array, size_t ix, BArray_ErrCode* errc); +void barray_set(BArray* array, size_t ix, void* value, BArray_ErrCode* errc); +void barray_put(BArray* array, size_t ix, void* value, BArray_ErrCode* errc); +void barray_append(BArray* array, void* value, BArray_ErrCode* errc); +void barray_remove(BArray* array, size_t ix, BArray_ErrCode* errc); +void barray_clear(BArray* array, BArray_ErrCode* errc); +void barray_destroy(BArray* array, BArray_ErrCode* errc); +#endif /* _BARRAY_H */ diff --git a/include/meson.build b/include/meson.build new file mode 100644 index 0000000..ca1d962 --- /dev/null +++ b/include/meson.build @@ -0,0 +1 @@ +include = include_directories('.') \ No newline at end of file diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..d4c9d0c --- /dev/null +++ b/meson.build @@ -0,0 +1,10 @@ +project('barray', 'c', + version: '0.0.1', + meson_version: '>=0.50.0', + default_options: [ 'warning_level=3', + 'c_std=c2x', + ] +) + +subdir('include') +subdir('src') \ No newline at end of file diff --git a/src/barray.c b/src/barray.c new file mode 100644 index 0000000..ad34b3a --- /dev/null +++ b/src/barray.c @@ -0,0 +1,285 @@ +#include "barray.h" + +#include +#include +#include + +static BArray BARRAY_INVALID = { NULL, 0, 0, 0 }; + +BArray barray_create(size_t elem_size, size_t initial_cap, BArray_ErrCode* errc) { + assert(errc != NULL); + if (elem_size == 0) { + *errc = BARRAY_ERR_ELEM_SIZE_ZERO; + return BARRAY_INVALID; + } + if (initial_cap == 0) { + *errc = BARRAY_NO_ERR; + return (BArray) { NULL, 0, 0, elem_size }; + } + void* ptr = malloc(elem_size * initial_cap); + if (ptr == NULL) { + *errc = BARRAY_ERR_ALLOC_ERR; + return BARRAY_INVALID; + } + *errc = BARRAY_NO_ERR; + return (BArray) { ptr, 0, initial_cap, elem_size }; +} + +void barray_grow(BArray* array, BArray_ErrCode* errc) { + assert(errc != NULL); + if (array == NULL) { + *errc = BARRAY_ERR_NULL; + return; + } + if (array->elem_size == 0) { + *errc = BARRAY_ERR_ELEM_SIZE_ZERO; + return; + } + size_t cap = array->cap; + size_t new_cap; + if (cap <= 8) { + new_cap = 16; + } else if (cap <= 16) { + new_cap = 32; + } else if (cap <= 32) { + new_cap = 64; + } else if (cap <= 64) { + new_cap = 128; + } else if (cap <= 128) { + new_cap = 256; + } else if (cap <= 256) { + new_cap = 512; + } else if (cap <= 512) { + new_cap = 1024; + } else { + new_cap = (cap / 512) + (cap % 512 == 0 ? 1 : 2); + if (new_cap < cap) { + *errc = BARRAY_ERR_SIZE_OVERFLOW; + return; + } + } + + void* new_ptr = realloc(array->ptr, new_cap * array->elem_size); + if (new_ptr == NULL) { + *errc = BARRAY_ERR_ALLOC_ERR; + return; + } + *errc = BARRAY_NO_ERR; + array->ptr = new_ptr; + array->cap = new_cap; +} + +void barray_grow_to(BArray* array, size_t new_cap, BArray_ErrCode* errc) { + assert(errc != NULL); + if (array == NULL) { + *errc = BARRAY_ERR_NULL; + return; + } + if (array->elem_size == 0) { + *errc = BARRAY_ERR_ELEM_SIZE_ZERO; + return; + } + + if (new_cap < array->cap) { + *errc = BARRAY_NO_ERR; + return; + } + void* new_ptr = realloc(array->ptr, new_cap * array->elem_size); + if (new_ptr == NULL) { + *errc = BARRAY_ERR_ALLOC_ERR; + return; + } + *errc = BARRAY_NO_ERR; + array->ptr = new_ptr; + array->cap = new_cap; +} + +void barray_shrink_to_fit(BArray* array, BArray_ErrCode* errc) { + assert(errc != NULL); + if (array == NULL) { + *errc = BARRAY_ERR_NULL; + return; + } + if (array->elem_size == 0) { + *errc = BARRAY_ERR_ELEM_SIZE_ZERO; + return; + } + assert(array->cap >= array->len); + if (array->cap == array->len) { + *errc = BARRAY_NO_ERR; + return; + } + size_t new_cap = array->len; + void* new_ptr = realloc(array->ptr, new_cap * array->elem_size); + if (new_ptr == NULL) { + *errc = BARRAY_ERR_ALLOC_ERR; + return; + } + *errc = BARRAY_NO_ERR; + array->ptr = new_ptr; + array->cap = new_cap; +} + +void barray_force_shrink(BArray* array, size_t new_cap, BArray_ErrCode* errc) { + assert(errc != NULL); + if (array == NULL) { + *errc = BARRAY_ERR_NULL; + return; + } + if (array->elem_size == 0) { + *errc = BARRAY_ERR_ELEM_SIZE_ZERO; + return; + } + + if (new_cap >= array->cap) { + *errc = BARRAY_NO_ERR; + return; + } + void* new_ptr = realloc(array->ptr, new_cap * array->elem_size); + if (new_ptr == NULL) { + *errc = BARRAY_ERR_ALLOC_ERR; + return; + } + *errc = BARRAY_NO_ERR; + array->ptr = new_ptr; + array->cap = new_cap; + array->len = new_cap; +} + +void* barray_get(BArray* array, size_t ix, BArray_ErrCode* errc) { + assert(errc != NULL); + if (array == NULL) { + *errc = BARRAY_ERR_NULL; + return NULL; + } + if (array->elem_size == 0) { + *errc = BARRAY_ERR_ELEM_SIZE_ZERO; + return NULL; + } + if (ix >= array->len) { + *errc = BARRAY_ERR_OUT_OF_BOUNDS; + return NULL; + } + *errc = BARRAY_NO_ERR; + unsigned char* ptr = array->ptr; + return (void*) &ptr[(ix * array->elem_size)]; +} + +void barray_set(BArray* array, size_t ix, void* value, BArray_ErrCode* errc) { + assert(errc != NULL); + if (array == NULL) { + *errc = BARRAY_ERR_NULL; + return; + } + if (array->elem_size == 0) { + *errc = BARRAY_ERR_ELEM_SIZE_ZERO; + return; + } + if (ix >= array->len) { + *errc = BARRAY_ERR_OUT_OF_BOUNDS; + return; + } + if (value == NULL) { + *errc = BARRAY_ERR_NULL; + return; + } + *errc = BARRAY_NO_ERR; + unsigned char* ptr = array->ptr; + void* elem_ptr = (void*) &ptr[(ix * array->elem_size)]; + memcpy(elem_ptr, value, array->elem_size); +} + +void barray_put(BArray* array, size_t ix, void* value, BArray_ErrCode* errc) { + assert(errc != NULL); + if (array == NULL) { + *errc = BARRAY_ERR_NULL; + return; + } + if (array->elem_size == 0) { + *errc = BARRAY_ERR_ELEM_SIZE_ZERO; + return; + } + if (ix > array->len) { + *errc = BARRAY_ERR_OUT_OF_BOUNDS; + return; + } + if (value == NULL) { + *errc = BARRAY_ERR_NULL; + return; + } + if (array->cap > (array->len + 1)) { + barray_grow(array, errc); + if (*errc != BARRAY_NO_ERR) { + return; + } + } + unsigned char* ptr = array->ptr; + if (ix == array->len) { + goto nomove; + } + void* src = (void*) &ptr[(ix * array->elem_size)]; + void* dest = (void*) &ptr[((ix + 1) * array->elem_size)]; + memmove(dest, src, array->elem_size * (array->len - ix)); + nomove: + *errc = BARRAY_NO_ERR; + void* elem_ptr = (void*) &ptr[(ix * array->elem_size)]; + memcpy(elem_ptr, value, array->elem_size); + array->len = array->len + 1; +} + +void barray_append(BArray* array, void* value, BArray_ErrCode* errc) { + assert(errc != NULL); + if (array == NULL) { + *errc = BARRAY_ERR_NULL; + return; + } + barray_put(array, array->len, value, errc); +} + +void barray_remove(BArray *array, size_t ix, BArray_ErrCode *errc) { + assert(errc != NULL); + if (array == NULL) { + *errc = BARRAY_ERR_NULL; + return; + } + if (array->elem_size == 0) { + *errc = BARRAY_ERR_ELEM_SIZE_ZERO; + return; + } + if (ix >= array->len) { + *errc = BARRAY_ERR_OUT_OF_BOUNDS; + return; + } + unsigned char* ptr = array->ptr; + if (ix == array->len) { + goto nomove; + } + void* src = (void*) &ptr[(ix * array->elem_size)]; + void* dest = (void*) &ptr[((ix - 1) * array->elem_size)]; + memmove(dest, src, array->elem_size * (array->len - ix)); + nomove: + *errc = BARRAY_NO_ERR; + array->len = array->len - 1; +} + +void barray_clear(BArray *array, BArray_ErrCode *errc) { + assert(errc != NULL); + if (array == NULL) { + *errc = BARRAY_ERR_NULL; + return; + } + *errc = BARRAY_NO_ERR; + array->len = 0; +} + +void barray_destroy(BArray *array, BArray_ErrCode* errc) { + assert(errc != NULL); + if (array == NULL) { + *errc = BARRAY_ERR_NULL; + } + if (array->ptr != NULL) { + free(array->ptr); + } + *errc = BARRAY_NO_ERR; + *array = BARRAY_INVALID; +} diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..a2f1605 --- /dev/null +++ b/src/meson.build @@ -0,0 +1,2 @@ +src = ['barray.c'] +library('barray', src, include_directories: include) \ No newline at end of file