A generic implementation of LinkedList in C

Example


#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


typedef struct {
    void *elem_head;
    void *elem_tail;
    size_t sz;
    void (*dealloc)(void *elem);
} LinkedList;

LinkedList *LinkedListInit();

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));
#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) { \
    uint64_t offset = offsetof(typename, next); \
    __LinkedListRemove(list, elem, offset); \
} while (0); \

#define LinkedListDestroy(typename, list, free_elem) { \
    uint64_t offset = offsetof(typename, next); \
    __LinkedListDestroy(list, offset, free_elem); \
} while (0); \

#define LinkedListGet(typename, list, elem)  { \
    uint64_t offset = offsetof(typename, next); \
    __LinkedListGet(list, offset, free_elem); \
} 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)); \
    } \
} \
                        

in file 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) {
            fatalf("deallocation function should be set");
        }
        void *curr = list->elem_head, *next;
        while (curr != list->elem_tail) {
            next = (*(void **)(curr + offset));
            free(curr);
            curr = next;
        }
        free(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;
}