From: Matthias Kruk Date: Sun, 2 May 2021 00:48:18 +0000 (+0900) Subject: array: Add dynamic array type X-Git-Url: https://git.corax.cc/?a=commitdiff_plain;h=9e902569007c4680a5f082fc9f73e15af3244627;p=mwm array: Add dynamic array type For storage of monitors, a data type is needed that automatically grows and shrinks as needed. This commit adds a dynamic array implementation. --- diff --git a/array.c b/array.c new file mode 100644 index 0000000..3a143de --- /dev/null +++ b/array.c @@ -0,0 +1,238 @@ +#include +#include +#include +#include "array.h" + +#define ARRAY_GROW_SIZE 8 +#define ARRAY_SHRINK_SIZE 8 + +struct array { + int size; + void **data; + char *flags; +}; + +static int _array_grow(struct array *array) +{ + int new_size; + void **new_data; + char *new_flags; + + if(!array) { + return(-EINVAL); + } + + new_size = array->size + ARRAY_GROW_SIZE; + new_data = malloc(sizeof(*array->data) * new_size); + + if(!new_data) { + return(-ENOMEM); + } + + new_flags = malloc(sizeof(*array->flags) * new_size); + + if(!new_flags) { + free(new_data); + return(-ENOMEM); + } + + if(array->data) { + memcpy(new_data, array->data, + array->size * sizeof(*new_data)); + free(array->data); + } + memset(new_data + array->size, 0, + ARRAY_GROW_SIZE * sizeof(*new_data)); + + if(array->flags) { + memcpy(new_flags, array->flags, + array->size * sizeof(*new_flags)); + free(array->flags); + } + memset(new_flags + array->size, 0, + ARRAY_GROW_SIZE * sizeof(*new_flags)); + + array->data = new_data; + array->flags = new_flags; + array->size = new_size; + + return(0); +} + +static int _array_last_used(struct array *array) +{ + int last; + + if(!array) { + return(-EINVAL); + } + + for(last = array->size - 1; last >= 0; last--) { + if(array->flags[last]) { + break; + } + } + + return(last); +} + +static int _array_shrink(struct array *array) +{ + int unused_tail; + int new_size; + void **new_data; + char *new_flags; + + if(!array) { + return(-EINVAL); + } + + new_data = NULL; + new_flags = NULL; + + unused_tail = array->size - _array_last_used(array); + + if(unused_tail < ARRAY_SHRINK_SIZE) { + return(0); + } + + unused_tail -= unused_tail % ARRAY_SHRINK_SIZE; + new_size = array->size - unused_tail; + + if(new_size > 0) { + new_data = malloc(new_size * sizeof(*new_data)); + + if(!new_data) { + return(-ENOMEM); + } + + new_flags = malloc(new_size * sizeof(*new_flags)); + + if(!new_flags) { + free(new_data); + return(-ENOMEM); + } + + memcpy(new_data, array->data, + new_size * sizeof(*new_data)); + memcpy(new_flags, array->flags, + new_size * sizeof(*new_flags)); + } + + free(array->data); + free(array->flags); + + array->data = new_data; + array->flags = new_flags; + array->size = new_size; + + return(0); +} + +int array_new(struct array **array) +{ + struct array *a; + + if(!array) { + return(-EINVAL); + } + + a = malloc(sizeof(*a)); + + if(!a) { + return(-ENOMEM); + } + + memset(a, 0, sizeof(*a)); + + if(_array_grow(a) < 0) { + free(a); + return(-ENOMEM); + } + + *array = a; + return(0); +} + +int array_free(struct array **array) +{ + if(!array) { + return(-EINVAL); + } + + if(!*array) { + return(-EALREADY); + } + + if((*array)->data) { + free((*array)->data); + } + if((*array)->flags) { + free((*array)->flags); + } + + free(*array); + *array = NULL; + + return(0); +} + +int array_set(struct array *array, int idx, void *data) +{ + if(!array) { + return(-EINVAL); + } + + while(idx > array->size) { + if(_array_grow(array) < 0) { + return(-ENOMEM); + } + } + + array->data[idx] = data; + array->flags[idx] = 1; + + return(0); +} + +int array_get(struct array *array, int idx, void **data) +{ + int real_idx; + + if(!array || !data) { + return(-EINVAL); + } + + if(array->size == 0) { + return(-ENODATA); + } + + real_idx = idx % array->size; + *data = array->data[real_idx]; + + return(0); +} + +int array_take(struct array *array, int idx, void **data) +{ + int real_idx; + + if(!array) { + return(-EINVAL); + } + + if(array->size == 0) { + return(-ENODATA); + } + + real_idx = idx % array->size; + + if(data) { + *data = array->data[real_idx]; + } + + array->flags[real_idx] = 0; + _array_shrink(array); + + return(0); +} diff --git a/array.h b/array.h new file mode 100644 index 0000000..8b15d80 --- /dev/null +++ b/array.h @@ -0,0 +1,13 @@ +#ifndef ARRAY_H +#define ARRAY_H + +struct array; + +int array_new(struct array **array); +int array_free(struct array **array); + +int array_set(struct array*, int, void*); +int array_get(struct array*, int, void**); +int array_take(struct array*, int, void**); + +#endif /* ARRAY_H */