#pragma once /** * * A collection of macros to create a doubly linked list of an arbitrary type. * * For normal usage just use LIST_AUTO(type, listTypeName) where type is the type to be stored and listTypeName is the desired typeName of the list container. * List nodes get the type listTypeName##Entry. * * LIST_AUTO generates a list container struct of the name listTypeName, * a list entry struct of the name listTypeName##Entry and * functions of the name listTypeName##function for each function of * New, Destroy, Empty (checks if the list is empty), Size, First, Last, Insert and Remove. * * For a simple foreach loop over a list use LIST_FOREACH(listTypeName, list, loopVariable), * where listTypeName is the same as for LIST_AUTO, list is the list to be looped over and loopVariable is the name of the currently iterated list entry. * * (c) Markus Mittendrein - 2017-2018 * **/ #include #include #define LIST_ENTRY_STRUCT(typeName, type) struct list_entry_##typeName {\ type value;\ struct list_entry_##typeName* next;\ struct list_entry_##typeName* prev;\ } #define LIST_STRUCT(type) struct list_##type\ {\ struct list_entry_##type* head;\ struct list_entry_##type* tail;\ size_t size;\ } #define LIST_NEW(type, name) struct list_##type* name(void)\ {\ struct list_##type* ret = malloc(sizeof(*ret));\ if(ret != NULL)\ {\ ret->head = NULL;\ ret->tail = NULL;\ ret->size = 0;\ }\ return ret;\ } #define LIST_DESTROY(type, name) void name(struct list_##type* list)\ {\ for(struct list_entry_##type* entry = list->head; entry != NULL; )\ {\ struct list_entry_##type* tmp = entry;\ entry = entry->next; free(tmp);\ }\ free(list);\ } #define LIST_EMPTY(type, name) bool name(struct list_##type* list) { return list->size == 0; } #define LIST_SIZE(type, name) size_t name(struct list_##type* list) { return list->size; } #define LIST_FIRST(type, name) struct list_entry_##type* name(struct list_##type* list) { return list->head; } #define LIST_LAST(type, name) struct list_entry_##type* name(struct list_##type* list) { return list->tail; } #define LIST_INSERT(typeName, type, name) struct list_entry_##typeName* name(struct list_##typeName* list, struct list_entry_##typeName* after, type value)\ {\ struct list_entry_##typeName* newEntry = malloc(sizeof(*newEntry));\ if(newEntry == NULL)\ {\ return NULL;\ }\ \ newEntry->value = value;\ newEntry->prev = after;\ \ if(after != NULL)\ {\ newEntry->next = after->next;\ after->next = newEntry;\ }\ else\ {\ newEntry->next = list->head;\ list->head = newEntry;\ }\ \ if(newEntry->next != NULL)\ {\ newEntry->next->prev = newEntry;\ }\ \ if(after == list->tail)\ {\ list->tail = newEntry;\ }\ \ ++list->size;\ return newEntry;\ } #define LIST_REMOVE(type, name) void name(struct list_##type* list, struct list_entry_##type* entry)\ {\ if(entry == list->head)\ {\ list->head = entry->next;\ }\ if(entry == list->tail)\ {\ list->tail = entry->prev;\ }\ \ if(entry->next != NULL)\ {\ entry->next->prev = entry->prev;\ }\ \ if(entry->prev != NULL)\ {\ entry->prev->next = entry->next;\ }\ \ free(entry);\ --list->size;\ } #define LIST_AUTO(type, listTypeName) typedef LIST_ENTRY_STRUCT(listTypeName, type) listTypeName##Entry;\ typedef LIST_STRUCT(listTypeName) listTypeName;\ LIST_NEW(listTypeName, listTypeName##New)\ LIST_DESTROY(listTypeName, listTypeName##Destroy)\ LIST_EMPTY(listTypeName, listTypeName##Empty)\ LIST_SIZE(listTypeName, listTypeName##Size)\ LIST_FIRST(listTypeName, listTypeName##First)\ LIST_LAST(listTypeName, listTypeName##Last)\ LIST_INSERT(listTypeName, type, listTypeName##Insert)\ LIST_REMOVE(listTypeName, listTypeName##Remove)\ struct list_entry_##listTypeName* listTypeName##Append(struct list_##listTypeName* list, type value) { return listTypeName##Insert(list, list->tail, value); }\ struct list_entry_##listTypeName* listTypeName##Prepend(struct list_##listTypeName* list, type value) { return listTypeName##Insert(list, NULL, value); } #define LIST_FOREACH(listTypeName, list, var) for(listTypeName##Entry* var = listTypeName##First(list); var != NULL; var = var->next)