summaryrefslogtreecommitdiff
path: root/src/list.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/list.c')
-rw-r--r--src/list.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/src/list.c b/src/list.c
new file mode 100644
index 0000000..8c67a09
--- /dev/null
+++ b/src/list.c
@@ -0,0 +1,247 @@
+#include "list.h"
+#include "util.h"
+#include <string.h>
+#include <stdio.h>
+
+struct List_s {
+ void **array; /* the array of elements */
+ NUM len; /* the length of the array */
+ NUM capacity; /* the number of pre-allocated bytes
+ for the array */
+};
+
+List *
+new_list()
+{
+ void **array = MYALLOC(void*, LIST_INIT_AMOUNT);
+
+ if (array == NULL) return NULL;
+
+ for (NUM i = 0; i < LIST_INIT_AMOUNT; i++)
+ *(array+i) = NULL;
+
+ List *list = MYALLOC(List, 1);
+
+ if (list == NULL) return NULL;
+
+ list->array = array;
+ list->len = 0;
+ list->capacity = LIST_INIT_AMOUNT;
+
+ return list;
+}
+
+H_ATTR
+unsigned char
+add_to_list(List *ls, void *element)
+{
+ if (!(ls->capacity)) {
+ /* The capacity can be zero only when the list has been destroyed,
+ in which case adding an element to that list is definitely an
+ error. */
+ eprintf("%s:%d, Adding an element to a destroyed list.\n",
+ __FILE__, __LINE__);
+ }
+
+ (ls->len)++;
+
+ if (ls->len >= ls->capacity) {
+ NUM new_capacity = ((ls->capacity) * 3) >> 1;
+
+ if (new_capacity < ls->capacity + LIST_INIT_AMOUNT)
+ new_capacity = ls->capacity + LIST_INIT_AMOUNT;
+
+ NUM max_diff = 1 << 20;
+ if (new_capacity >= ls->capacity + max_diff)
+ new_capacity = ls->capacity + max_diff;
+
+ void **array = MYALLOC(void *, ls->capacity);
+
+ if (array == NULL) {
+ ls->len -= 1;
+ return 1;
+ }
+
+ for (NUM i = 0; i < ls->capacity; i++)
+ *(array+i) = *(ls->array+i);
+
+ /* The new_capacity will not be zero, so upon failure it returns
+ NULL. */
+ ls->array = realloc(ls->array, sizeof(void*) * new_capacity);
+
+ if (ls->array == NULL) {
+ ls->len -= 1;
+ free(array);
+ return 1;
+ }
+
+ for (NUM i = 0; i < ls->capacity; i++)
+ *(ls->array+i) = *(array+i);
+
+ free(array);
+
+ for (NUM i = ls->capacity; i < new_capacity; i++)
+ *(ls->array+i) = NULL;
+
+ ls->capacity = new_capacity;
+ }
+
+ *(ls->array+ls->len-1) = element;
+
+ return 0;
+}
+
+H_ATTR
+void *
+pop_from_list(List *ls)
+{
+ if (!(ls->len)) return NULL;
+
+ return *(ls->array+--(ls->len));
+}
+
+H_ATTR
+void
+map_list(List *ls, acter f)
+{
+ for (NUM i = 0; i < ls->len; i++)
+ f(*(ls->array+i));
+}
+
+void
+print_list(List *ls, printer prt)
+{
+ printf("printing a list with length = %lu and capacity = %lu\n",
+ ls->len, ls->capacity);
+
+ map_list(ls, (acter) prt);
+
+ printf("printing terminated\n");
+}
+
+void *
+copy_num(void *p)
+{
+ NUM *pointer = malloc(sizeof *pointer);
+
+ if (pointer == NULL) return NULL;
+
+ *pointer = *((NUM *) p);
+
+ return pointer;
+}
+
+unsigned char
+copy_list(List *dest, List *source, copyer copyf)
+{
+ unsigned char sign = 0;
+
+ if ((sign = list_assure_size(dest, source->len)))
+ return sign;
+
+ dest->len = source->len;
+
+ for (NUM i = 0; i < source->len; i++) {
+ void *pointer = copyf(*(source->array+i));
+ if (pointer == NULL) return 1;
+ *(dest->array+i) = pointer;
+ }
+
+ return 0;
+}
+
+H_ATTR
+void *
+list_nth(List *ls, NUM n)
+{
+ return *(ls->array+n);
+}
+
+H_ATTR
+NUM
+list_length(List *ls)
+{
+ return ls->len;
+}
+
+unsigned char
+list_assure_size(List *ls, NUM size)
+{
+ if (ls->capacity >= size) return 0; /* we are good */
+
+ void **array = MYALLOC(void *, ls->capacity);
+
+ if (array == NULL) return 1;
+
+ for (NUM i = 0; i < ls->capacity; i++)
+ *(array+i) = *(ls->array+i);
+
+ ls->array = realloc(ls->array, sizeof(void*) * size);
+
+ if (ls->array == NULL) return 1;
+
+ for (NUM i = 0; i < ls->capacity; i++)
+ *(ls->array+i) = *(array+i);
+
+ free(array);
+
+ for (NUM i = ls->capacity; i < size; i++)
+ *(ls->array+i) = NULL;
+
+ ls->capacity = size;
+
+ return 0;
+}
+
+unsigned char
+list_set_length(List *ls, NUM len)
+{
+ if (ls->len >= len) return 0;
+
+ NUM *array = MYALLOC(NUM, len - ls->len);
+
+ if (array == NULL) return 1;
+
+ for (NUM i = ls->len; i < len; i++) {
+ *(array + i - ls->len) = -1;
+ *(ls->array+i) = array + i - ls->len;
+ }
+
+ ls->len = len;
+
+ return 0;
+}
+
+void *
+list_to_array(List *ls, NUM element_bytes, NUM *num)
+{
+ /* We shall not use a void pointer here, since standard C does not
+ allow doing arithmetic on void pointers. So we use a char
+ pointer here, since the size of char is 1. */
+ char *array = malloc(element_bytes * ls->len);
+
+ if (array == NULL) return NULL;
+
+ *num = ls->len;
+
+ for (NUM i = 0; i < *num; i++)
+ memcpy(array+(element_bytes*i), *(ls->array+i), element_bytes);
+
+ return array;
+}
+
+void
+destroy_list(List *ls, unsigned char all_free_p)
+{
+ if (all_free_p == 1)
+ for (NUM i = 0; i < ls->len; i++)
+ free(*(ls->array+i));
+
+ if (all_free_p == 2)
+ free(*(ls->array));
+
+ free(ls->array);
+ free(ls);
+
+ ls->len = (ls->capacity = 0);
+}