diff options
Diffstat (limited to 'src/GenericList.h')
| -rw-r--r-- | src/GenericList.h | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/GenericList.h b/src/GenericList.h new file mode 100644 index 0000000..0679bb7 --- /dev/null +++ b/src/GenericList.h @@ -0,0 +1,142 @@ +#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 <stdbool.h> +#include <stdlib.h> + +#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) |
