#include "list.h" typedef struct IntElem { int data; struct IntElem *next; } IntElem_t; int main(int argc, char const *argv[]) { LinkedList *list = LinkedListInit(); IntElem_t *iter, *rm; for (int i = 0; i < 10; ++i) { IntElem_t *item = malloc(sizeof(IntElem_t)); item->data = i; if (i == 5) rm = item; LinkedListAppend(struct IntElem, list, item); } LinkedListForEach(IntElem_t, list, iter, { printf("%d\n", iter->data); }) LinkedListRemove(IntElem_t, list, rm); LinkedListForEach(IntElem_t, list, iter, { printf("%d\n", iter->data); }) return 0; }
in file linked_list.h
linked_list.h
/** * @brief General LinkedList data structure * Elements in the linked-list should be defined like * struct Element { * typename data; * struct Element *next; // the `next` member can be defined * // anywhere in the structure * } * */ typedef struct { void *elem_head; void *elem_tail; size_t sz; void (*dealloc)(void *elem); } LinkedList; LinkedList *LinkedListInit(); /** * @brief Implementation of appending an item to the linked-list * This function is wrapped by a macro function. * * @param list The linked-list * @param elem element to append * @param offset offset to the `next` member in the struct * @return uint8_t 0 on success and 1 on failure */ uint8_t __LinkedListAppend(LinkedList *list, void *elem, uint64_t offset); uint8_t __LinkedListRemove(LinkedList *list, void *elem, uint64_t offset); void __LinkedListDestroy(LinkedList *list, uint64_t offset, uint8_t free_elem); void *__LinkedListGet(LinkedList *list, size_t idx, uint64_t offset); void LinkedListSetDealloc(LinkedList *list, void (*dealloc)(void *elem)); void __LinkedListMergeSort(LinkedList *list, int (*compare)(void *, void *), uint64_t offset); #define LinkedListAppend(typename, list, elem) { \ uint64_t offset = offsetof(typename, next); \ if ((__LinkedListAppend(list, elem, offset))) { \ fatalf("LinkedList at <0x%x> append failed", list); \ }; \ } while (0); \ #define LinkedListRemove(typename, list, elem) ({ \ void *ret; \ do { \ uint64_t offset = offsetof(typename, next); \ ret = __LinkedListRemove(list, elem, offset); \ } while (0); \ ret; \ }) \ #define LinkedListDestroy(typename, list, free_elem) { \ uint64_t offset = offsetof(typename, next); \ __LinkedListDestroy(list, offset, free_elem); \ } while (0); \ #define LinkedListGet(typename, list, idx) ({ \ void *ret; \ do { \ uint64_t offset = offsetof(typename, next); \ ret = (void *)__LinkedListGet(list, idx, offset); \ } while (0); \ ret; \ }) \ #define LinkedListMergeSort(typename, list, compare) { \ uint64_t offset = offsetof(typename, next); \ __LinkedListMergeSort(list, compare, offset); \ } while (0); \ #define LinkedListForEach(typename, list, vvar, code) { \ uint64_t offset = offsetof(typename, next); \ vvar = (typename *) list->elem_head; \ while (vvar) { \ code; \ vvar = (typename *)(*(void **)((void *)vvar + offset)); \ } \ } \ #define LinkedListForEachInRange(typename, list, vvar, from, to, code) { \ uint64_t offset = offsetof(typename, next); \ vvar = (typename *) list->elem_head; \ while (vvar) { \ code; \ vvar = (typename *)(*(void **)((void *)vvar + offset)); \ } \ } \ #define LinkedListNext(typename, vvar) ((typename *)(*(void **)((void *)vvar + offsetof(typename, vvar))))
in file linked_list.c
linked_list.c
LinkedList *LinkedListInit() { LinkedList *list = malloc(sizeof(LinkedList)); memset(list, 0, sizeof(LinkedList)); return list; } uint8_t __LinkedListAppend(LinkedList *list, void *elem, uint64_t offset) { void *curr, **next; if (list->elem_head == NULL) { list->elem_head = list->elem_tail = elem; list->sz = 1; return 0; } else { next = (list->elem_tail + offset); *next = elem; list->elem_tail = elem; list->sz++; return 0; } return 1; } uint8_t __LinkedListRemove(LinkedList *list, void *elem, uint64_t offset) { void **curr = &list->elem_head; while ((*curr) != elem) { curr = (void **)(*curr + offset); } *curr = (*(void **)(elem + offset)); } void __LinkedListDestroy(LinkedList *list, uint64_t offset, uint8_t free_elem) { if (free_elem && (list->sz > 0)) { if (!list->dealloc) { warnf("No deallocation function found. Skip") } else { void *curr = list->elem_head, *next; while (curr != list->elem_tail) { next = (*(void **)(curr + offset)); list->dealloc(curr); curr = next; } list->dealloc(curr); } } free(list); } void *__LinkedListGet(LinkedList *list, size_t idx, uint64_t offset) { void *curr = list->elem_head; size_t i = 0; while (i < idx) { curr = (*(void **)(curr + offset)); i++; } return curr; } void LinkedListSetDealloc(LinkedList *list, void (*dealloc)(void *elem)) { list->dealloc = dealloc; } static void *LinkedListMerge(void *a, void *b, int (*compare)(void *, void *), uint64_t offset) { void *result = NULL; void **next; if (a == NULL) return b; else if (b == NULL) return a; if (compare(a, b) <= 0) { result = a; next = (void **)(result + offset); *next = LinkedListMerge((*(void **)(a + offset)), b, compare, offset); } else { result = b; next = (void **)(result + offset); *next = LinkedListMerge(a, ((*(void **)(b + offset))), compare, offset); } return result; } static void LinkedListSplit(void *source, void **front_ref, void **back_ref, uint64_t offset) { void *a, *b; void **next; a = source; b = (*(void **)(a + offset)); while (b != NULL) { b = (*(void **)(b + offset)); if (b != NULL) { a = (*(void **)(a + offset)); b = (*(void **)(b + offset)); } } *front_ref = source; *back_ref = (*(void **)(a + offset)); next = (void **)(a + offset); *next = NULL; } static void __LinkedListMergeSort_helper(void **head_ref, int (*compare)(void *, void *), uint64_t offset) { void *head = *head_ref; void *a, *b; if ((head == NULL) || ((*(void **)(head + offset)) == NULL)) { return; } LinkedListSplit(head, &a, &b, offset); __LinkedListMergeSort_helper(&a, compare, offset); __LinkedListMergeSort_helper(&b, compare, offset); *head_ref = LinkedListMerge(a, b, compare, offset); } void __LinkedListMergeSort(LinkedList *list, int (*compare)(void *, void *), uint64_t offset) { __LinkedListMergeSort_helper(&list->elem_head, compare, offset); void *curr = list->elem_head; for (size_t i = 0; i < list->sz - 1; ++i) { curr = (*(void **)(curr + offset)); } list->elem_tail = curr; }