summaryrefslogtreecommitdiffstats
path: root/src/GenericList.h
diff options
context:
space:
mode:
authorMarkus Mittendrein <git@maxmitti.tk>2018-08-15 22:46:40 +0200
committerMarkus Mittendrein <git@maxmitti.tk>2018-08-15 23:15:15 +0200
commit0d1ae015fef8e15442dafa61b9c8d929ce467969 (patch)
treea8d56fd12f5c5366e1f6fa3ecc20c78c0202f747 /src/GenericList.h
parente04f662a42c75cb202684e7254d3b7600e6e1756 (diff)
downloadcc4group-0d1ae015fef8e15442dafa61b9c8d929ce467969.tar.gz
cc4group-0d1ae015fef8e15442dafa61b9c8d929ce467969.zip
Refactor code into a library and implement basic file management methods
Diffstat (limited to 'src/GenericList.h')
-rw-r--r--src/GenericList.h142
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)