#include "list.h" #include "util.h" #include #include 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 BOOL 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)); } H_ATTR void map_list_between(List *ls, acter f, doer d) { for (NUM i = 0; i < ls->len; i++) { f(*(ls->array+i)); if (i + 1 < ls->len) d(); } } 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; } BOOL copy_list(List *dest, List *source, copyer copyf) { BOOL 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(const List * const ls, NUM n) { return *(ls->array+n); } H_ATTR NUM list_length(const List * const restrict ls) { return ls->len; } BOOL 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->len; 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->len; 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; } BOOL list_set_length(List *ls, NUM len) { list_assure_size(ls, 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; } List * array_to_list(void **array, NUM size) { List *ls = MYALLOC(List, 1); ls->array = array; ls->len = ls->capacity = size; return ls; } void destroy_list(List *ls, BOOL 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)); ls->len = (ls->capacity = 0); free(ls->array); free(ls); } void destroy_list_free_all(void *ls) { List *list = (List *) ls; destroy_list(list, 1); } void destroy_list_free_first(void *ls) { List *list = (List *) ls; destroy_list(list, 2); } void destroy_list_no_free(void *ls) { List *list = (List *) ls; destroy_list(list, 0); }