]> git.corax.cc Git - mwm/commitdiff
array: Add dynamic array type
authorMatthias Kruk <m@m10k.eu>
Sun, 2 May 2021 00:48:18 +0000 (09:48 +0900)
committerMatthias Kruk <m@m10k.eu>
Sun, 2 May 2021 00:48:18 +0000 (09:48 +0900)
For storage of monitors, a data type is needed that automatically
grows and shrinks as needed.
This commit adds a dynamic array implementation.

array.c [new file with mode: 0644]
array.h [new file with mode: 0644]

diff --git a/array.c b/array.c
new file mode 100644 (file)
index 0000000..3a143de
--- /dev/null
+++ b/array.c
@@ -0,0 +1,238 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#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 (file)
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 */