From 239f248456ad00f894dc26dceefa968898738c9d Mon Sep 17 00:00:00 2001 From: Stefan Zabka Date: Mon, 22 Jun 2020 16:43:42 +0200 Subject: Getting make to run --- 04_exercise/CMakeLists.txt | 15 +- 04_exercise/arena/arena_list.c | 164 ----------- 04_exercise/arena/arena_list.h | 57 ---- 04_exercise/arena/arena_test.c | 30 -- 04_exercise/ppmlib.h | 592 ++++++++++++++++++++++++++++++++++++++ 04_exercise/ppmlib/ppmlib.h | 592 -------------------------------------- 04_exercise/rwlock.c | 69 +++++ 04_exercise/rwlock.h | 16 ++ 04_exercise/rwlock/rwlock.c | 69 ----- 04_exercise/rwlock/rwlock.h | 16 -- 04_exercise/slotmap.c | 48 ++++ 04_exercise/slotmap.h | 37 +++ 04_exercise/slotmap/slomap_test.c | 19 -- 04_exercise/slotmap/slotmap.c | 48 ---- 04_exercise/slotmap/slotmap.h | 36 --- 04_exercise/threadpool.c | 2 +- 04_exercise/threadpool.h | 2 +- 17 files changed, 766 insertions(+), 1046 deletions(-) delete mode 100644 04_exercise/arena/arena_list.c delete mode 100644 04_exercise/arena/arena_list.h delete mode 100644 04_exercise/arena/arena_test.c create mode 100644 04_exercise/ppmlib.h delete mode 100644 04_exercise/ppmlib/ppmlib.h create mode 100644 04_exercise/rwlock.c create mode 100644 04_exercise/rwlock.h delete mode 100644 04_exercise/rwlock/rwlock.c delete mode 100644 04_exercise/rwlock/rwlock.h create mode 100644 04_exercise/slotmap.c create mode 100644 04_exercise/slotmap.h delete mode 100644 04_exercise/slotmap/slomap_test.c delete mode 100644 04_exercise/slotmap/slotmap.c delete mode 100644 04_exercise/slotmap/slotmap.h diff --git a/04_exercise/CMakeLists.txt b/04_exercise/CMakeLists.txt index 4e89060..06364c2 100644 --- a/04_exercise/CMakeLists.txt +++ b/04_exercise/CMakeLists.txt @@ -14,24 +14,13 @@ add_executable(fibonacci main.c) target_link_libraries(fibonacci PRIVATE threadpool) target_link_libraries(fibonacci INTERFACE warnings) -add_library(arena_list arena/arena_list.c) -target_include_directories(arena_list PUBLIC arena) -target_link_libraries(arena_list INTERFACE warnings) -target_link_libraries(arena_list PRIVATE rwlock) - -add_executable(arena_test arena/arena_test.c) -target_link_libraries(arena_test PRIVATE arena_list) - -add_library(rwlock rwlock/rwlock.c) +add_library(rwlock rwlock.c) target_include_directories(rwlock PUBLIC rwlock) target_link_libraries(rwlock INTERFACE warnings) add_library(ppmlib INTERFACE) target_include_directories(ppmlib INTERFACE ppmlib) -add_library(slotmap slotmap/slotmap.c) +add_library(slotmap slotmap.c) target_include_directories(slotmap PUBLIC slotmap) target_link_libraries(slotmap INTERFACE warnings) - -add_executable(slotmap_test slotmap/slomap_test.c) -target_link_libraries(slotmap_test PRIVATE slotmap) diff --git a/04_exercise/arena/arena_list.c b/04_exercise/arena/arena_list.c deleted file mode 100644 index 1453297..0000000 --- a/04_exercise/arena/arena_list.c +++ /dev/null @@ -1,164 +0,0 @@ -// -// Created by stefan on 10.06.20. -// -#include "arena_list.h" -#include -#include -#include - -#include -static const bool DEBUG = false; - -bool listContains(List const * const list ,Node const * const needle) { - for(Node * current = list ->first; current != NULL; current = current->next) { - if(current == needle) { - return true; - } - } - return false; -} -Node *listPopFront(List *list) { - Node *front = list->first; - if (front == NULL) { - return NULL; - } - - list->first = front->next; - if (front == list->last) { - // Only Node in the list - list->last = NULL; - return front; - } - - list->first->prev = NULL; - front->next = NULL; - - return front; -} - -Node *listPopBack(List *list) { - Node *back = list->last; - if (back == NULL) { - return NULL; - } - - list->last = back->prev; - if (back == list->first) { - // Only Node in the list - list->last = NULL; - return back; - } - - list->last->next = NULL; - back->prev = NULL; - - return back; -} - -void listPushFront(List *list, Node *new) { - if (list->first == NULL) { - // List was empty - list->first = new; - list->last = new; - return; - } - new->prev = NULL; - new->next = list->first; - new->next->prev = new; - list->first = new; -} - -// void listPushBack(List *list, Node *value) {} - -AtomicArenaList alInit(Node *arena, size_t size) { - AtomicArenaList al = {.activeList = (List){.first = NULL, .last = NULL}, - .freeList = (List){.first = arena, .last = &arena[size - 1]}, - .arena = arena, - .size = size}; - atomic_init(&al.lock, RW_UNLOCKED); - arena[0] = (Node){.value = NULL, .prev = NULL, .next = &arena[1]}; - for (size_t i = 1; i < size - 1; ++i) { - arena[i] = (Node){.value = NULL, .prev = &arena[i - 1], .next = &arena[i + 1]}; - } - arena[size - 1] = (Node){.value = NULL, .prev = &arena[size - 2], .next = NULL}; - return al; -} - -int alPush(AtomicArenaList *al, void *value) { - if(DEBUG) - fprintf(stderr, "Thread %lu: Pushing \n", pthread_self() % 1000); - rwLockWrite(&al->lock); - Node *current = listPopFront(&al->freeList); - // List is empty - if (current == NULL) { - rwUnlockWrite(&al->lock); - return -1; - } - current->value = value; - listPushFront(&al->activeList, current); - rwUnlockWrite(&al->lock); - return 0; -} - -int alRemoveElem(AtomicArenaList *al, void *value) { - if(DEBUG) - fprintf(stderr, "Thread %lu: Removing element \n", pthread_self() % 1000); - rwLockWrite(&al->lock); - size_t i = 0; - for (; i < al->size; ++i) { - if (al->arena[i].value != value) { - continue; - } - } - Node *node = &al->arena[i]; - // Irgendwie removen wir das Element zwei Mal und ich verstehe nicht warum - if(i == al->size || listContains(&al->activeList,node)) { - rwUnlockWrite(&al->lock); - return -1; - } - - if (node == al->activeList.first) { - listPopFront(&al->activeList); - listPushFront(&al->freeList, node); - atomic_char *a = &al->lock; - rwUnlockWrite(a); - return 0; - } - if (node == al->activeList.last) { - listPopBack(&al->activeList); - listPushFront(&al->freeList, node); - rwUnlockWrite(&al->lock); - return 0; - } - // The node is somewhere in the middle - Node *prev = node->prev; - Node *next = node->next; - - next->prev = prev; - prev->next = next; - - listPushFront(&al->freeList, node); - rwUnlockWrite(&al->lock); - return 0; -} - -void *alFindLastElem(AtomicArenaList *al, SearchFunction f) { - if(DEBUG) - fprintf(stderr, "Thread %lu: Finding last element \n", pthread_self() % 1000); - - rwLockRead(&al->lock); - - List const *const actList = &al->activeList; - if (actList->last == NULL) { - rwUnlockRead(&al->lock); - return NULL; - } - for (Node *current = actList->last; current != NULL; current = current->prev) { - if (f(current->value)) { - rwUnlockRead(&al->lock); - return current; - } - } - rwUnlockRead(&al->lock); - return NULL; -} diff --git a/04_exercise/arena/arena_list.h b/04_exercise/arena/arena_list.h deleted file mode 100644 index 304209c..0000000 --- a/04_exercise/arena/arena_list.h +++ /dev/null @@ -1,57 +0,0 @@ -// -// Created by stefan on 10.06.20. -// - -#ifndef BETRIEBSYSTEME_ARENA_LIST_H -#define BETRIEBSYSTEME_ARENA_LIST_H - -#include -#include -#include - -typedef struct Node { - void * value; - struct Node * next; - struct Node * prev; -} Node; - -typedef struct List { - Node * first; - Node * last; -} List; - - -// Should we have a free list or just a bit set relative to the size of the slab? -/** This structure manages an arena / memory slab to be used - * This structure is thread-safe as it locks internally - * It will spin until a request is safe to access the items - * This also means this structure shouldn't be read externally - * unless the thread doing so managed to aquire the atomic_flag - */ -typedef struct ArenaList { - List freeList; - List activeList; - Node * arena; - size_t size; - atomic_char lock; -} AtomicArenaList; - -typedef bool (*SearchFunction)(void const *); -//Initializes the node array -AtomicArenaList alInit(Node * arena, size_t size); -// Return -1 if the List is full -int alPush(AtomicArenaList * al, void * value); - -// Return -1 if the Node was already deleted -int alRemoveElem(AtomicArenaList * al, void * value); - -/** - * Searches the activeList for an element - * for which the search function returns true - * The function will be passed the value pointer - * of a given Node - * @return the Element pointed or NULL if nothing matched - */ -void *alFindLastElem(AtomicArenaList *al, SearchFunction f); - -#endif // BETRIEBSYSTEME_ARENA_LIST_H diff --git a/04_exercise/arena/arena_test.c b/04_exercise/arena/arena_test.c deleted file mode 100644 index 51a9b0c..0000000 --- a/04_exercise/arena/arena_test.c +++ /dev/null @@ -1,30 +0,0 @@ -// -// Created by stefan on 10.06.20. -// -#include "arena_list.h" -#include -#include -bool isEqualTo3(void const *data) { - int *value = (void *)data; - return *value == 3; -} -int main() { - Node arena[5]; - AtomicArenaList al = alInit(arena, 5); - int data[5] = {1, 2, 3, 4, 5}; - for (int i = 0; i < 5; ++i) { - alPush(&al, &data[4 - i]); - } - - for (Node *cur = al.activeList.first; cur != NULL; cur = cur->next) { - printf("Got digit %d \n", *(int *)cur->value); - } - Node const * node = alFindLastElem(&al, &isEqualTo3); - int * value = (int *) node->value; - printf("The value was actually %d \n", *value); - assert(*value == 3); - for (int i = 0; i < 5; ++i) { - alRemoveElem(&al, &data[4 - i]); - } - -} diff --git a/04_exercise/ppmlib.h b/04_exercise/ppmlib.h new file mode 100644 index 0000000..7a7f3db --- /dev/null +++ b/04_exercise/ppmlib.h @@ -0,0 +1,592 @@ +/***************************************************************************//** + * @file ppmlib.h + * @author Dorian Weber + * @brief Contains a small macro library used for preprocessor programming. + * + * @details + * Preprocessor metaprogramming is very valuable in larger C projects. It's + * efficient and can manipulate code at a very basic level. This small library + * is intended to facilitate macro programming by collecting commonly used + * macro functions. It supports argument lists with a size of up to 32. + ******************************************************************************/ + +#ifndef PPMLIB_H_INCLUDED +#define PPMLIB_H_INCLUDED + +#include + +/**@brief Tests if the integer type of a variable is signed. + * @attention Due to the integer promotion rules in C, this will only work for + * variables of type \c int and upwards, not for char and short. + * @note Credit goes to Jens Gustedt for this typeless type cast for integer. + */ +#define IS_SIGNED(VAR) \ + ((1 ? -1 : VAR) < 0) + +/**@brief Number of bits in inttype_MAX, or in any (1< FOO() + * EXPAND(DEFER(FOO)()) // EXPAND(DEFER(FOO)()) -> EXPAND(FOO()) -> foo + * @endcode + */ +#define DEFER(...) \ + __VA_ARGS__ FORGET() + +/**@brief Expands the macro arguments and adds a comma to them. + */ +#define EXPAND_W_COMMA(...) \ + __VA_ARGS__, + +/**@brief Expands two macro arguments as a pair. + */ +#define EXPAND_AS_PAIR(E1, E2) \ + (E1, E2) + +/**@brief Replaces the macro arguments with the empty argument. + */ +#define FORGET(...) + +/**@brief Stringifies the arguments. + */ +#define STR(...) \ + STR_(__VA_ARGS__) + +/**@brief Generates a unique name using the current line in the code. + * This is useful for variable names in macro-expansions. + */ +#define UID(VAR) \ + CONCAT(VAR, _, __LINE__) + +/**@}*/ + +/**@brief Constructs a comma separated list that can be transformed using a + * unary macro. + * + * @param M the unary macro function that is applied for each argument + * @param ... variadic argument list + */ +#define VECM(M,...) \ + FOREACH(EXPAND_W_COMMA, M, (__VA_ARGS__)) + +/**@brief Construct a comma separated list that can be transformed using a + * unary macro and takes an additional static argument. + * + * This macro behaves exactly like VECM but allows for an additional argument. + */ +#define VECMP(M,P, ...) \ + FOREACHP(EXPAND_W_COMMA, M, P, (__VA_ARGS__)) + +/**@brief Applies the unary macro to each element of a variadic argument list. + * + * This is the less powerful version of the FOREACH macro. It simply applies a + * unary macro to each of its arguments. + * + * @param M the macro function to apply + * @param ... variadic argument list + * @sa FOLD, FOREACH + */ +#define MAP(M, ...) \ + FOREACH(EXPAND, M, (__VA_ARGS__)) + +/**@brief Applies a binary macro for each element of a variadic argument list. + * + * The macro receives both a static argument as well as the current element. + * The static argument is given as the \p P parameter during invokation. + * @sa MAP, FOREACHP + */ +#define FOLD(M,P, ...) \ + FOREACHP(EXPAND, M, P, (__VA_ARGS__)) + +/**@brief Splices together two variadic sequences into a sequence of pairs. + * + * The number of elements in the combined sequence is always equal to the + * number of elements in the first sequence. If the first sequence contains + * more elements, the final sequence's tail has empty second arguments. + * @sa ZIP_MAP +*/ +#define ZIP(SEQ_A, SEQ_B) \ + ZIP_MAP(EXPAND_AS_PAIR, SEQ_A, SEQ_B) + +/**@brief Splices together two variadic sequences using a binary macro. + * + * Like the ZIP-macro, the number of combined elements is always equal to the + * number of elements in the first sequence. This operator is slightly more + * generic since it allows arbitrary operations on every pair of elements + * through the binary macro. + * @sa ZIP + */ +#define ZIP_MAP(M, SEQ_A, SEQ_B) \ + CONCAT(ZIP_, NUM_ARGS SEQ_A)(M, SEQ_A, SEQ_B) + +/**@brief Selects an argument from a variadic list. + * + * This macro function can be used to index into a variadic argument list. It + * is possible to select a higher index than the list is long. In this case the + * result is the empty argument. + * + * @param N index of the argument to select + * @param ... variadic argument list + */ +#define ARG(N, ...) \ + CONCAT_2(ARG_,N)(__VA_ARGS__,) + +/**@brief Selects and returns the first argument from a variadic list. + */ +#define ARG_FIRST(...) \ + ARG_1_(__VA_ARGS__,) + +/**@brief Selects and returns the last argument from a variadic list. + */ +#define ARG_LAST(...) \ + ARG(NUM_PARGS(__VA_ARGS__),__VA_ARGS__) + +/**@brief Selects the remainder of an argument list after removing the first. + */ +#define ARG_REST(...) \ + IF_COMMA(__VA_ARGS__)(ARG_REST_(__VA_ARGS__))() + +/**@brief Selects every argument except for the last of a variadic list. + */ +#define ARG_CHOP(...) \ + FOREACH_(EXPAND_W_COMMA, NUM_ARGS(ARG_REST(__VA_ARGS__)), EXPAND, (__VA_ARGS__)) + +/**@brief Concatenates a variable number of arguments. + * + * Since it is not specified by the C standard: concatenation occurs from left + * to right with left associativity. To give an example `CONCAT(a,b,c)` would + * be treated as `(a ## b) ## c`. + * + * @param ... variadic list of valid preprocessor tokens + */ +#define CONCAT(...) \ + CONCAT_(NUM_PARGS(__VA_ARGS__), __VA_ARGS__) + +/**@name Inline conditionals + * Macros that support the conditional generation of text. + * @{ + */ + +/**@brief Tests if two numbers are equal and generates code according to the + * result. + * + * The numbers are expanded first. The syntax for this tool is like + * @code + * IF_EQ(a,b)()() + * @endcode + * The code in the first branch is generated if `a` equals `b`, the code in the + * second branch otherwise. + * + * @param A first number + * @param B second number + */ +#define IF_EQ(A, B) \ + _IF_CLAUSE(CONCAT_4(_IS_,A,_EQ_,B)()) + +/**@brief Tests if the number of arguments is equal to a number and generates + * code according to the result. + * + * The numbers are expanded first. The syntax for this tool is like + * @code + * IF_LEN(a,__VA_ARGS__)()() + * @endcode + * The code in the first branch is generated if `a` equals the length of + * `__VA_ARGS__`, the code in the second branch otherwise. + * + * @param A first number + * @param ... argument list + */ +#define IF_LEN(A, ...) \ + _IF_CLAUSE(CONCAT_4(_IS_,A,_EQ_,NUM_ARGS(__VA_ARGS__)())) + +/**@brief Tests if the argument list passed is empty and generates code + * according to the result. + * + * The argument list is empty iff it only contains one argument that is the + * empty token. Use this function like this: + * @code + * IF_EMPTY()()() + * @endcode + * The branch labeled with `` gets generated if the passed `` + * is indeed empty, the other branch if it isn't. + * + * @param ... variadic argument list + * @sa IS_EMPTY + */ +#define IF_EMPTY(...) \ + IF_EQ(1, IS_EMPTY(__VA_ARGS__)) + +/**@brief Tests if the argument list contains a comma and generates code + * according to the result. + * + * If the argument list contains a comma, it must contain at least two + * arguments. Use this tool like: + * @code + * IF_COMMA()()() + * @endcode + * The result is the branch labeled with `` if the `` + * contains at least two arguments, otherwise the contents of the other branch + * are produced. + * + * @param ... variadic argument list + * @sa HAS_COMMA + */ +#define IF_COMMA(...) \ + IF_EQ(1, HAS_COMMA(__VA_ARGS__)) + +/**@}*/ + +/**@cond Internal */ +#define NUM_ARGS_(_20,_1F,_1E,_1D,_1C,_1B,_1A,_19,_18,_17,_16,_15,_14,_13,_12,_11, \ + _10, _F, _E, _D, _C, _B, _A, _9, _8, _7, _6, _5, _4, _3, _2, _1, N,...) N + +#define FOREACH_(E,N,M, LIST) FOREACH__(E,N,M,LIST) +#define FOREACH__(E,N,M, LIST) FOREACH_N##N(E,M,LIST) + +#define FOREACHP_(E,N,M,P, LIST) FOREACHP__(E,N,M,P,LIST) +#define FOREACHP__(E,N,M,P, LIST) FOREACH_P##N(E,M,P,LIST) + +#define FOREACH_P0(E,M,P, LIST) /* empty */ +#define FOREACH_P1(E,M,P, LIST) M(P,ARG_1 LIST) +#define FOREACH_P2(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P1(E,M,P, (ARG_REST LIST)) +#define FOREACH_P3(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P2(E,M,P, (ARG_REST LIST)) +#define FOREACH_P4(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P3(E,M,P, (ARG_REST LIST)) +#define FOREACH_P5(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P4(E,M,P, (ARG_REST LIST)) +#define FOREACH_P6(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P5(E,M,P, (ARG_REST LIST)) +#define FOREACH_P7(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P6(E,M,P, (ARG_REST LIST)) +#define FOREACH_P8(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P7(E,M,P, (ARG_REST LIST)) +#define FOREACH_P9(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P8(E,M,P, (ARG_REST LIST)) +#define FOREACH_P10(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P9(E,M,P, (ARG_REST LIST)) +#define FOREACH_P11(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P10(E,M,P, (ARG_REST LIST)) +#define FOREACH_P12(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P11(E,M,P, (ARG_REST LIST)) +#define FOREACH_P13(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P12(E,M,P, (ARG_REST LIST)) +#define FOREACH_P14(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P13(E,M,P, (ARG_REST LIST)) +#define FOREACH_P15(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P14(E,M,P, (ARG_REST LIST)) +#define FOREACH_P16(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P15(E,M,P, (ARG_REST LIST)) +#define FOREACH_P17(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P16(E,M,P, (ARG_REST LIST)) +#define FOREACH_P18(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P17(E,M,P, (ARG_REST LIST)) +#define FOREACH_P19(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P18(E,M,P, (ARG_REST LIST)) +#define FOREACH_P20(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P19(E,M,P, (ARG_REST LIST)) +#define FOREACH_P21(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P20(E,M,P, (ARG_REST LIST)) +#define FOREACH_P22(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P21(E,M,P, (ARG_REST LIST)) +#define FOREACH_P23(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P22(E,M,P, (ARG_REST LIST)) +#define FOREACH_P24(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P23(E,M,P, (ARG_REST LIST)) +#define FOREACH_P25(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P24(E,M,P, (ARG_REST LIST)) +#define FOREACH_P26(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P25(E,M,P, (ARG_REST LIST)) +#define FOREACH_P27(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P26(E,M,P, (ARG_REST LIST)) +#define FOREACH_P28(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P27(E,M,P, (ARG_REST LIST)) +#define FOREACH_P29(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P28(E,M,P, (ARG_REST LIST)) +#define FOREACH_P30(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P29(E,M,P, (ARG_REST LIST)) +#define FOREACH_P31(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P30(E,M,P, (ARG_REST LIST)) +#define FOREACH_P32(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P31(E,M,P, (ARG_REST LIST)) + +#define FOREACH_N0(E,M, LIST) /* empty */ +#define FOREACH_N1(E,M, LIST) M(ARG_1 LIST) +#define FOREACH_N2(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N1(E,M, (ARG_REST LIST)) +#define FOREACH_N3(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N2(E,M, (ARG_REST LIST)) +#define FOREACH_N4(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N3(E,M, (ARG_REST LIST)) +#define FOREACH_N5(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N4(E,M, (ARG_REST LIST)) +#define FOREACH_N6(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N5(E,M, (ARG_REST LIST)) +#define FOREACH_N7(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N6(E,M, (ARG_REST LIST)) +#define FOREACH_N8(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N7(E,M, (ARG_REST LIST)) +#define FOREACH_N9(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N8(E,M, (ARG_REST LIST)) +#define FOREACH_N10(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N9(E,M, (ARG_REST LIST)) +#define FOREACH_N11(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N10(E,M, (ARG_REST LIST)) +#define FOREACH_N12(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N11(E,M, (ARG_REST LIST)) +#define FOREACH_N13(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N12(E,M, (ARG_REST LIST)) +#define FOREACH_N14(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N13(E,M, (ARG_REST LIST)) +#define FOREACH_N15(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N14(E,M, (ARG_REST LIST)) +#define FOREACH_N16(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N15(E,M, (ARG_REST LIST)) +#define FOREACH_N17(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N16(E,M, (ARG_REST LIST)) +#define FOREACH_N18(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N17(E,M, (ARG_REST LIST)) +#define FOREACH_N19(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N18(E,M, (ARG_REST LIST)) +#define FOREACH_N20(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N19(E,M, (ARG_REST LIST)) +#define FOREACH_N21(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N20(E,M, (ARG_REST LIST)) +#define FOREACH_N22(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N21(E,M, (ARG_REST LIST)) +#define FOREACH_N23(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N22(E,M, (ARG_REST LIST)) +#define FOREACH_N24(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N23(E,M, (ARG_REST LIST)) +#define FOREACH_N25(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N24(E,M, (ARG_REST LIST)) +#define FOREACH_N26(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N25(E,M, (ARG_REST LIST)) +#define FOREACH_N27(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N26(E,M, (ARG_REST LIST)) +#define FOREACH_N28(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N27(E,M, (ARG_REST LIST)) +#define FOREACH_N29(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N28(E,M, (ARG_REST LIST)) +#define FOREACH_N30(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N29(E,M, (ARG_REST LIST)) +#define FOREACH_N31(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N30(E,M, (ARG_REST LIST)) +#define FOREACH_N32(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N31(E,M, (ARG_REST LIST)) + +#define ZIP_0(M, SEQ_A, SEQ_B) /* empty */ +#define ZIP_1(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B) +#define ZIP_2(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_1(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_3(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_2(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_4(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_3(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_5(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_4(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_6(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_5(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_7(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_6(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_8(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_7(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_9(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_8(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_10(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_9(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_11(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_10(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_12(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_11(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_13(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_12(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_14(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_13(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_15(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_14(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_16(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_15(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_17(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_16(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_18(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_17(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_19(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_18(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_20(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_19(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_21(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_20(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_22(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_21(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_23(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_22(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_24(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_23(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_25(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_24(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_26(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_25(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_27(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_26(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_28(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_27(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_29(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_28(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_30(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_29(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_31(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_30(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) +#define ZIP_32(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_31(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) + +#define CONCAT_(C, ...) CONCAT__(C,__VA_ARGS__) +#define CONCAT__(C, ...) CONCAT_ ## C(__VA_ARGS__) + +#define CONCAT_1(_1) _1 +#define CONCAT_2(_1,_2) _1 ## _2 +#define CONCAT_3(_1,_2,...) CONCAT_2(_1 ## _2, __VA_ARGS__) +#define CONCAT_4(_1,_2,...) CONCAT_3(_1 ## _2, __VA_ARGS__) +#define CONCAT_5(_1,_2,...) CONCAT_4(_1 ## _2, __VA_ARGS__) +#define CONCAT_6(_1,_2,...) CONCAT_5(_1 ## _2, __VA_ARGS__) +#define CONCAT_7(_1,_2,...) CONCAT_6(_1 ## _2, __VA_ARGS__) +#define CONCAT_8(_1,_2,...) CONCAT_7(_1 ## _2, __VA_ARGS__) +#define CONCAT_9(_1,_2,...) CONCAT_8(_1 ## _2, __VA_ARGS__) +#define CONCAT_10(_1,_2,...) CONCAT_9(_1 ## _2, __VA_ARGS__) +#define CONCAT_11(_1,_2,...) CONCAT_10(_1 ## _2, __VA_ARGS__) +#define CONCAT_12(_1,_2,...) CONCAT_11(_1 ## _2, __VA_ARGS__) +#define CONCAT_13(_1,_2,...) CONCAT_12(_1 ## _2, __VA_ARGS__) +#define CONCAT_14(_1,_2,...) CONCAT_13(_1 ## _2, __VA_ARGS__) +#define CONCAT_15(_1,_2,...) CONCAT_14(_1 ## _2, __VA_ARGS__) +#define CONCAT_16(_1,_2,...) CONCAT_15(_1 ## _2, __VA_ARGS__) +#define CONCAT_17(_1,_2,...) CONCAT_16(_1 ## _2, __VA_ARGS__) +#define CONCAT_18(_1,_2,...) CONCAT_17(_1 ## _2, __VA_ARGS__) +#define CONCAT_19(_1,_2,...) CONCAT_18(_1 ## _2, __VA_ARGS__) +#define CONCAT_20(_1,_2,...) CONCAT_19(_1 ## _2, __VA_ARGS__) +#define CONCAT_21(_1,_2,...) CONCAT_20(_1 ## _2, __VA_ARGS__) +#define CONCAT_22(_1,_2,...) CONCAT_21(_1 ## _2, __VA_ARGS__) +#define CONCAT_23(_1,_2,...) CONCAT_22(_1 ## _2, __VA_ARGS__) +#define CONCAT_24(_1,_2,...) CONCAT_23(_1 ## _2, __VA_ARGS__) +#define CONCAT_25(_1,_2,...) CONCAT_24(_1 ## _2, __VA_ARGS__) +#define CONCAT_26(_1,_2,...) CONCAT_25(_1 ## _2, __VA_ARGS__) +#define CONCAT_27(_1,_2,...) CONCAT_26(_1 ## _2, __VA_ARGS__) +#define CONCAT_28(_1,_2,...) CONCAT_27(_1 ## _2, __VA_ARGS__) +#define CONCAT_29(_1,_2,...) CONCAT_28(_1 ## _2, __VA_ARGS__) +#define CONCAT_30(_1,_2,...) CONCAT_29(_1 ## _2, __VA_ARGS__) +#define CONCAT_31(_1,_2,...) CONCAT_30(_1 ## _2, __VA_ARGS__) +#define CONCAT_32(_1,_2,...) CONCAT_31(_1 ## _2, __VA_ARGS__) + +#define ARG_REST_(_1, ...) \ + __VA_ARGS__ + +#define ARG_(...) /* empty */ +#define ARG_0(...) /* empty */ +#define ARG_1_(_1, ...) _1 +#define ARG_1(...) ARG_1_(__VA_ARGS__,) +#define ARG_2(...) ARG_1(ARG_REST_(__VA_ARGS__,)) +#define ARG_3(...) ARG_2(ARG_REST_(__VA_ARGS__,)) +#define ARG_4(...) ARG_3(ARG_REST_(__VA_ARGS__,)) +#define ARG_5(...) ARG_4(ARG_REST_(__VA_ARGS__,)) +#define ARG_6(...) ARG_5(ARG_REST_(__VA_ARGS__,)) +#define ARG_7(...) ARG_6(ARG_REST_(__VA_ARGS__,)) +#define ARG_8(...) ARG_7(ARG_REST_(__VA_ARGS__,)) +#define ARG_9(...) ARG_8(ARG_REST_(__VA_ARGS__,)) +#define ARG_10(...) ARG_9(ARG_REST_(__VA_ARGS__,)) +#define ARG_11(...) ARG_10(ARG_REST_(__VA_ARGS__,)) +#define ARG_12(...) ARG_11(ARG_REST_(__VA_ARGS__,)) +#define ARG_13(...) ARG_12(ARG_REST_(__VA_ARGS__,)) +#define ARG_14(...) ARG_13(ARG_REST_(__VA_ARGS__,)) +#define ARG_15(...) ARG_14(ARG_REST_(__VA_ARGS__,)) +#define ARG_16(...) ARG_15(ARG_REST_(__VA_ARGS__,)) +#define ARG_17(...) ARG_16(ARG_REST_(__VA_ARGS__,)) +#define ARG_18(...) ARG_17(ARG_REST_(__VA_ARGS__,)) +#define ARG_19(...) ARG_18(ARG_REST_(__VA_ARGS__,)) +#define ARG_20(...) ARG_19(ARG_REST_(__VA_ARGS__,)) +#define ARG_21(...) ARG_20(ARG_REST_(__VA_ARGS__,)) +#define ARG_22(...) ARG_21(ARG_REST_(__VA_ARGS__,)) +#define ARG_23(...) ARG_22(ARG_REST_(__VA_ARGS__,)) +#define ARG_24(...) ARG_23(ARG_REST_(__VA_ARGS__,)) +#define ARG_25(...) ARG_24(ARG_REST_(__VA_ARGS__,)) +#define ARG_26(...) ARG_25(ARG_REST_(__VA_ARGS__,)) +#define ARG_27(...) ARG_26(ARG_REST_(__VA_ARGS__,)) +#define ARG_28(...) ARG_27(ARG_REST_(__VA_ARGS__,)) +#define ARG_29(...) ARG_28(ARG_REST_(__VA_ARGS__,)) +#define ARG_30(...) ARG_29(ARG_REST_(__VA_ARGS__,)) +#define ARG_31(...) ARG_30(ARG_REST_(__VA_ARGS__,)) +#define ARG_32(...) ARG_31(ARG_REST_(__VA_ARGS__,)) + +#define _CLAUSE1(...) __VA_ARGS__ FORGET +#define _CLAUSE2(...) EXPAND + +#define __IF_CLAUSE(A,B,C,...) C +#define _IF_CLAUSE(EXP) __IF_CLAUSE(EXP, _CLAUSE1, _CLAUSE2,) + +#define _IS_0_EQ_0 , +#define _IS_1_EQ_1 , +#define _IS_2_EQ_2 , +#define _IS_3_EQ_3 , +#define _IS_4_EQ_4 , +#define _IS_5_EQ_5 , +#define _IS_6_EQ_6 , +#define _IS_7_EQ_7 , +#define _IS_8_EQ_8 , +#define _IS_9_EQ_9 , +#define _IS_10_EQ_10 , +#define _IS_11_EQ_11 , +#define _IS_12_EQ_12 , +#define _IS_13_EQ_13 , +#define _IS_14_EQ_14 , +#define _IS_15_EQ_15 , +#define _IS_16_EQ_16 , +#define _IS_17_EQ_17 , +#define _IS_18_EQ_18 , +#define _IS_19_EQ_19 , +#define _IS_20_EQ_20 , +#define _IS_21_EQ_21 , +#define _IS_22_EQ_22 , +#define _IS_23_EQ_23 , +#define _IS_24_EQ_24 , +#define _IS_25_EQ_25 , +#define _IS_26_EQ_26 , +#define _IS_27_EQ_27 , +#define _IS_28_EQ_28 , +#define _IS_29_EQ_29 , +#define _IS_30_EQ_30 , +#define _IS_31_EQ_31 , +#define _IS_32_EQ_32 , + +#define STR_(...) #__VA_ARGS__ + +/* detect empty arguments */ +#define _IS_EMPTY(_0, _1, _2, _3) \ + HAS_COMMA(CONCAT_5(_IS_EMPTY_CASE_, _0, _1, _2, _3)) +#define _IS_EMPTY_CASE_0001 , +#define _IS_EMPTY_FN(...) , + +/**@endcond*/ + +#endif /* PPMLIB_H_INCLUDED */ diff --git a/04_exercise/ppmlib/ppmlib.h b/04_exercise/ppmlib/ppmlib.h deleted file mode 100644 index 7a7f3db..0000000 --- a/04_exercise/ppmlib/ppmlib.h +++ /dev/null @@ -1,592 +0,0 @@ -/***************************************************************************//** - * @file ppmlib.h - * @author Dorian Weber - * @brief Contains a small macro library used for preprocessor programming. - * - * @details - * Preprocessor metaprogramming is very valuable in larger C projects. It's - * efficient and can manipulate code at a very basic level. This small library - * is intended to facilitate macro programming by collecting commonly used - * macro functions. It supports argument lists with a size of up to 32. - ******************************************************************************/ - -#ifndef PPMLIB_H_INCLUDED -#define PPMLIB_H_INCLUDED - -#include - -/**@brief Tests if the integer type of a variable is signed. - * @attention Due to the integer promotion rules in C, this will only work for - * variables of type \c int and upwards, not for char and short. - * @note Credit goes to Jens Gustedt for this typeless type cast for integer. - */ -#define IS_SIGNED(VAR) \ - ((1 ? -1 : VAR) < 0) - -/**@brief Number of bits in inttype_MAX, or in any (1< FOO() - * EXPAND(DEFER(FOO)()) // EXPAND(DEFER(FOO)()) -> EXPAND(FOO()) -> foo - * @endcode - */ -#define DEFER(...) \ - __VA_ARGS__ FORGET() - -/**@brief Expands the macro arguments and adds a comma to them. - */ -#define EXPAND_W_COMMA(...) \ - __VA_ARGS__, - -/**@brief Expands two macro arguments as a pair. - */ -#define EXPAND_AS_PAIR(E1, E2) \ - (E1, E2) - -/**@brief Replaces the macro arguments with the empty argument. - */ -#define FORGET(...) - -/**@brief Stringifies the arguments. - */ -#define STR(...) \ - STR_(__VA_ARGS__) - -/**@brief Generates a unique name using the current line in the code. - * This is useful for variable names in macro-expansions. - */ -#define UID(VAR) \ - CONCAT(VAR, _, __LINE__) - -/**@}*/ - -/**@brief Constructs a comma separated list that can be transformed using a - * unary macro. - * - * @param M the unary macro function that is applied for each argument - * @param ... variadic argument list - */ -#define VECM(M,...) \ - FOREACH(EXPAND_W_COMMA, M, (__VA_ARGS__)) - -/**@brief Construct a comma separated list that can be transformed using a - * unary macro and takes an additional static argument. - * - * This macro behaves exactly like VECM but allows for an additional argument. - */ -#define VECMP(M,P, ...) \ - FOREACHP(EXPAND_W_COMMA, M, P, (__VA_ARGS__)) - -/**@brief Applies the unary macro to each element of a variadic argument list. - * - * This is the less powerful version of the FOREACH macro. It simply applies a - * unary macro to each of its arguments. - * - * @param M the macro function to apply - * @param ... variadic argument list - * @sa FOLD, FOREACH - */ -#define MAP(M, ...) \ - FOREACH(EXPAND, M, (__VA_ARGS__)) - -/**@brief Applies a binary macro for each element of a variadic argument list. - * - * The macro receives both a static argument as well as the current element. - * The static argument is given as the \p P parameter during invokation. - * @sa MAP, FOREACHP - */ -#define FOLD(M,P, ...) \ - FOREACHP(EXPAND, M, P, (__VA_ARGS__)) - -/**@brief Splices together two variadic sequences into a sequence of pairs. - * - * The number of elements in the combined sequence is always equal to the - * number of elements in the first sequence. If the first sequence contains - * more elements, the final sequence's tail has empty second arguments. - * @sa ZIP_MAP -*/ -#define ZIP(SEQ_A, SEQ_B) \ - ZIP_MAP(EXPAND_AS_PAIR, SEQ_A, SEQ_B) - -/**@brief Splices together two variadic sequences using a binary macro. - * - * Like the ZIP-macro, the number of combined elements is always equal to the - * number of elements in the first sequence. This operator is slightly more - * generic since it allows arbitrary operations on every pair of elements - * through the binary macro. - * @sa ZIP - */ -#define ZIP_MAP(M, SEQ_A, SEQ_B) \ - CONCAT(ZIP_, NUM_ARGS SEQ_A)(M, SEQ_A, SEQ_B) - -/**@brief Selects an argument from a variadic list. - * - * This macro function can be used to index into a variadic argument list. It - * is possible to select a higher index than the list is long. In this case the - * result is the empty argument. - * - * @param N index of the argument to select - * @param ... variadic argument list - */ -#define ARG(N, ...) \ - CONCAT_2(ARG_,N)(__VA_ARGS__,) - -/**@brief Selects and returns the first argument from a variadic list. - */ -#define ARG_FIRST(...) \ - ARG_1_(__VA_ARGS__,) - -/**@brief Selects and returns the last argument from a variadic list. - */ -#define ARG_LAST(...) \ - ARG(NUM_PARGS(__VA_ARGS__),__VA_ARGS__) - -/**@brief Selects the remainder of an argument list after removing the first. - */ -#define ARG_REST(...) \ - IF_COMMA(__VA_ARGS__)(ARG_REST_(__VA_ARGS__))() - -/**@brief Selects every argument except for the last of a variadic list. - */ -#define ARG_CHOP(...) \ - FOREACH_(EXPAND_W_COMMA, NUM_ARGS(ARG_REST(__VA_ARGS__)), EXPAND, (__VA_ARGS__)) - -/**@brief Concatenates a variable number of arguments. - * - * Since it is not specified by the C standard: concatenation occurs from left - * to right with left associativity. To give an example `CONCAT(a,b,c)` would - * be treated as `(a ## b) ## c`. - * - * @param ... variadic list of valid preprocessor tokens - */ -#define CONCAT(...) \ - CONCAT_(NUM_PARGS(__VA_ARGS__), __VA_ARGS__) - -/**@name Inline conditionals - * Macros that support the conditional generation of text. - * @{ - */ - -/**@brief Tests if two numbers are equal and generates code according to the - * result. - * - * The numbers are expanded first. The syntax for this tool is like - * @code - * IF_EQ(a,b)()() - * @endcode - * The code in the first branch is generated if `a` equals `b`, the code in the - * second branch otherwise. - * - * @param A first number - * @param B second number - */ -#define IF_EQ(A, B) \ - _IF_CLAUSE(CONCAT_4(_IS_,A,_EQ_,B)()) - -/**@brief Tests if the number of arguments is equal to a number and generates - * code according to the result. - * - * The numbers are expanded first. The syntax for this tool is like - * @code - * IF_LEN(a,__VA_ARGS__)()() - * @endcode - * The code in the first branch is generated if `a` equals the length of - * `__VA_ARGS__`, the code in the second branch otherwise. - * - * @param A first number - * @param ... argument list - */ -#define IF_LEN(A, ...) \ - _IF_CLAUSE(CONCAT_4(_IS_,A,_EQ_,NUM_ARGS(__VA_ARGS__)())) - -/**@brief Tests if the argument list passed is empty and generates code - * according to the result. - * - * The argument list is empty iff it only contains one argument that is the - * empty token. Use this function like this: - * @code - * IF_EMPTY()()() - * @endcode - * The branch labeled with `` gets generated if the passed `` - * is indeed empty, the other branch if it isn't. - * - * @param ... variadic argument list - * @sa IS_EMPTY - */ -#define IF_EMPTY(...) \ - IF_EQ(1, IS_EMPTY(__VA_ARGS__)) - -/**@brief Tests if the argument list contains a comma and generates code - * according to the result. - * - * If the argument list contains a comma, it must contain at least two - * arguments. Use this tool like: - * @code - * IF_COMMA()()() - * @endcode - * The result is the branch labeled with `` if the `` - * contains at least two arguments, otherwise the contents of the other branch - * are produced. - * - * @param ... variadic argument list - * @sa HAS_COMMA - */ -#define IF_COMMA(...) \ - IF_EQ(1, HAS_COMMA(__VA_ARGS__)) - -/**@}*/ - -/**@cond Internal */ -#define NUM_ARGS_(_20,_1F,_1E,_1D,_1C,_1B,_1A,_19,_18,_17,_16,_15,_14,_13,_12,_11, \ - _10, _F, _E, _D, _C, _B, _A, _9, _8, _7, _6, _5, _4, _3, _2, _1, N,...) N - -#define FOREACH_(E,N,M, LIST) FOREACH__(E,N,M,LIST) -#define FOREACH__(E,N,M, LIST) FOREACH_N##N(E,M,LIST) - -#define FOREACHP_(E,N,M,P, LIST) FOREACHP__(E,N,M,P,LIST) -#define FOREACHP__(E,N,M,P, LIST) FOREACH_P##N(E,M,P,LIST) - -#define FOREACH_P0(E,M,P, LIST) /* empty */ -#define FOREACH_P1(E,M,P, LIST) M(P,ARG_1 LIST) -#define FOREACH_P2(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P1(E,M,P, (ARG_REST LIST)) -#define FOREACH_P3(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P2(E,M,P, (ARG_REST LIST)) -#define FOREACH_P4(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P3(E,M,P, (ARG_REST LIST)) -#define FOREACH_P5(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P4(E,M,P, (ARG_REST LIST)) -#define FOREACH_P6(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P5(E,M,P, (ARG_REST LIST)) -#define FOREACH_P7(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P6(E,M,P, (ARG_REST LIST)) -#define FOREACH_P8(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P7(E,M,P, (ARG_REST LIST)) -#define FOREACH_P9(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P8(E,M,P, (ARG_REST LIST)) -#define FOREACH_P10(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P9(E,M,P, (ARG_REST LIST)) -#define FOREACH_P11(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P10(E,M,P, (ARG_REST LIST)) -#define FOREACH_P12(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P11(E,M,P, (ARG_REST LIST)) -#define FOREACH_P13(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P12(E,M,P, (ARG_REST LIST)) -#define FOREACH_P14(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P13(E,M,P, (ARG_REST LIST)) -#define FOREACH_P15(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P14(E,M,P, (ARG_REST LIST)) -#define FOREACH_P16(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P15(E,M,P, (ARG_REST LIST)) -#define FOREACH_P17(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P16(E,M,P, (ARG_REST LIST)) -#define FOREACH_P18(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P17(E,M,P, (ARG_REST LIST)) -#define FOREACH_P19(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P18(E,M,P, (ARG_REST LIST)) -#define FOREACH_P20(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P19(E,M,P, (ARG_REST LIST)) -#define FOREACH_P21(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P20(E,M,P, (ARG_REST LIST)) -#define FOREACH_P22(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P21(E,M,P, (ARG_REST LIST)) -#define FOREACH_P23(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P22(E,M,P, (ARG_REST LIST)) -#define FOREACH_P24(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P23(E,M,P, (ARG_REST LIST)) -#define FOREACH_P25(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P24(E,M,P, (ARG_REST LIST)) -#define FOREACH_P26(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P25(E,M,P, (ARG_REST LIST)) -#define FOREACH_P27(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P26(E,M,P, (ARG_REST LIST)) -#define FOREACH_P28(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P27(E,M,P, (ARG_REST LIST)) -#define FOREACH_P29(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P28(E,M,P, (ARG_REST LIST)) -#define FOREACH_P30(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P29(E,M,P, (ARG_REST LIST)) -#define FOREACH_P31(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P30(E,M,P, (ARG_REST LIST)) -#define FOREACH_P32(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P31(E,M,P, (ARG_REST LIST)) - -#define FOREACH_N0(E,M, LIST) /* empty */ -#define FOREACH_N1(E,M, LIST) M(ARG_1 LIST) -#define FOREACH_N2(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N1(E,M, (ARG_REST LIST)) -#define FOREACH_N3(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N2(E,M, (ARG_REST LIST)) -#define FOREACH_N4(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N3(E,M, (ARG_REST LIST)) -#define FOREACH_N5(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N4(E,M, (ARG_REST LIST)) -#define FOREACH_N6(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N5(E,M, (ARG_REST LIST)) -#define FOREACH_N7(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N6(E,M, (ARG_REST LIST)) -#define FOREACH_N8(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N7(E,M, (ARG_REST LIST)) -#define FOREACH_N9(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N8(E,M, (ARG_REST LIST)) -#define FOREACH_N10(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N9(E,M, (ARG_REST LIST)) -#define FOREACH_N11(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N10(E,M, (ARG_REST LIST)) -#define FOREACH_N12(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N11(E,M, (ARG_REST LIST)) -#define FOREACH_N13(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N12(E,M, (ARG_REST LIST)) -#define FOREACH_N14(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N13(E,M, (ARG_REST LIST)) -#define FOREACH_N15(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N14(E,M, (ARG_REST LIST)) -#define FOREACH_N16(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N15(E,M, (ARG_REST LIST)) -#define FOREACH_N17(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N16(E,M, (ARG_REST LIST)) -#define FOREACH_N18(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N17(E,M, (ARG_REST LIST)) -#define FOREACH_N19(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N18(E,M, (ARG_REST LIST)) -#define FOREACH_N20(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N19(E,M, (ARG_REST LIST)) -#define FOREACH_N21(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N20(E,M, (ARG_REST LIST)) -#define FOREACH_N22(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N21(E,M, (ARG_REST LIST)) -#define FOREACH_N23(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N22(E,M, (ARG_REST LIST)) -#define FOREACH_N24(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N23(E,M, (ARG_REST LIST)) -#define FOREACH_N25(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N24(E,M, (ARG_REST LIST)) -#define FOREACH_N26(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N25(E,M, (ARG_REST LIST)) -#define FOREACH_N27(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N26(E,M, (ARG_REST LIST)) -#define FOREACH_N28(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N27(E,M, (ARG_REST LIST)) -#define FOREACH_N29(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N28(E,M, (ARG_REST LIST)) -#define FOREACH_N30(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N29(E,M, (ARG_REST LIST)) -#define FOREACH_N31(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N30(E,M, (ARG_REST LIST)) -#define FOREACH_N32(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N31(E,M, (ARG_REST LIST)) - -#define ZIP_0(M, SEQ_A, SEQ_B) /* empty */ -#define ZIP_1(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B) -#define ZIP_2(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_1(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_3(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_2(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_4(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_3(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_5(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_4(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_6(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_5(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_7(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_6(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_8(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_7(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_9(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_8(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_10(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_9(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_11(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_10(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_12(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_11(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_13(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_12(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_14(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_13(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_15(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_14(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_16(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_15(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_17(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_16(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_18(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_17(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_19(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_18(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_20(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_19(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_21(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_20(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_22(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_21(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_23(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_22(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_24(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_23(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_25(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_24(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_26(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_25(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_27(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_26(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_28(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_27(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_29(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_28(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_30(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_29(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_31(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_30(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) -#define ZIP_32(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_31(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B)) - -#define CONCAT_(C, ...) CONCAT__(C,__VA_ARGS__) -#define CONCAT__(C, ...) CONCAT_ ## C(__VA_ARGS__) - -#define CONCAT_1(_1) _1 -#define CONCAT_2(_1,_2) _1 ## _2 -#define CONCAT_3(_1,_2,...) CONCAT_2(_1 ## _2, __VA_ARGS__) -#define CONCAT_4(_1,_2,...) CONCAT_3(_1 ## _2, __VA_ARGS__) -#define CONCAT_5(_1,_2,...) CONCAT_4(_1 ## _2, __VA_ARGS__) -#define CONCAT_6(_1,_2,...) CONCAT_5(_1 ## _2, __VA_ARGS__) -#define CONCAT_7(_1,_2,...) CONCAT_6(_1 ## _2, __VA_ARGS__) -#define CONCAT_8(_1,_2,...) CONCAT_7(_1 ## _2, __VA_ARGS__) -#define CONCAT_9(_1,_2,...) CONCAT_8(_1 ## _2, __VA_ARGS__) -#define CONCAT_10(_1,_2,...) CONCAT_9(_1 ## _2, __VA_ARGS__) -#define CONCAT_11(_1,_2,...) CONCAT_10(_1 ## _2, __VA_ARGS__) -#define CONCAT_12(_1,_2,...) CONCAT_11(_1 ## _2, __VA_ARGS__) -#define CONCAT_13(_1,_2,...) CONCAT_12(_1 ## _2, __VA_ARGS__) -#define CONCAT_14(_1,_2,...) CONCAT_13(_1 ## _2, __VA_ARGS__) -#define CONCAT_15(_1,_2,...) CONCAT_14(_1 ## _2, __VA_ARGS__) -#define CONCAT_16(_1,_2,...) CONCAT_15(_1 ## _2, __VA_ARGS__) -#define CONCAT_17(_1,_2,...) CONCAT_16(_1 ## _2, __VA_ARGS__) -#define CONCAT_18(_1,_2,...) CONCAT_17(_1 ## _2, __VA_ARGS__) -#define CONCAT_19(_1,_2,...) CONCAT_18(_1 ## _2, __VA_ARGS__) -#define CONCAT_20(_1,_2,...) CONCAT_19(_1 ## _2, __VA_ARGS__) -#define CONCAT_21(_1,_2,...) CONCAT_20(_1 ## _2, __VA_ARGS__) -#define CONCAT_22(_1,_2,...) CONCAT_21(_1 ## _2, __VA_ARGS__) -#define CONCAT_23(_1,_2,...) CONCAT_22(_1 ## _2, __VA_ARGS__) -#define CONCAT_24(_1,_2,...) CONCAT_23(_1 ## _2, __VA_ARGS__) -#define CONCAT_25(_1,_2,...) CONCAT_24(_1 ## _2, __VA_ARGS__) -#define CONCAT_26(_1,_2,...) CONCAT_25(_1 ## _2, __VA_ARGS__) -#define CONCAT_27(_1,_2,...) CONCAT_26(_1 ## _2, __VA_ARGS__) -#define CONCAT_28(_1,_2,...) CONCAT_27(_1 ## _2, __VA_ARGS__) -#define CONCAT_29(_1,_2,...) CONCAT_28(_1 ## _2, __VA_ARGS__) -#define CONCAT_30(_1,_2,...) CONCAT_29(_1 ## _2, __VA_ARGS__) -#define CONCAT_31(_1,_2,...) CONCAT_30(_1 ## _2, __VA_ARGS__) -#define CONCAT_32(_1,_2,...) CONCAT_31(_1 ## _2, __VA_ARGS__) - -#define ARG_REST_(_1, ...) \ - __VA_ARGS__ - -#define ARG_(...) /* empty */ -#define ARG_0(...) /* empty */ -#define ARG_1_(_1, ...) _1 -#define ARG_1(...) ARG_1_(__VA_ARGS__,) -#define ARG_2(...) ARG_1(ARG_REST_(__VA_ARGS__,)) -#define ARG_3(...) ARG_2(ARG_REST_(__VA_ARGS__,)) -#define ARG_4(...) ARG_3(ARG_REST_(__VA_ARGS__,)) -#define ARG_5(...) ARG_4(ARG_REST_(__VA_ARGS__,)) -#define ARG_6(...) ARG_5(ARG_REST_(__VA_ARGS__,)) -#define ARG_7(...) ARG_6(ARG_REST_(__VA_ARGS__,)) -#define ARG_8(...) ARG_7(ARG_REST_(__VA_ARGS__,)) -#define ARG_9(...) ARG_8(ARG_REST_(__VA_ARGS__,)) -#define ARG_10(...) ARG_9(ARG_REST_(__VA_ARGS__,)) -#define ARG_11(...) ARG_10(ARG_REST_(__VA_ARGS__,)) -#define ARG_12(...) ARG_11(ARG_REST_(__VA_ARGS__,)) -#define ARG_13(...) ARG_12(ARG_REST_(__VA_ARGS__,)) -#define ARG_14(...) ARG_13(ARG_REST_(__VA_ARGS__,)) -#define ARG_15(...) ARG_14(ARG_REST_(__VA_ARGS__,)) -#define ARG_16(...) ARG_15(ARG_REST_(__VA_ARGS__,)) -#define ARG_17(...) ARG_16(ARG_REST_(__VA_ARGS__,)) -#define ARG_18(...) ARG_17(ARG_REST_(__VA_ARGS__,)) -#define ARG_19(...) ARG_18(ARG_REST_(__VA_ARGS__,)) -#define ARG_20(...) ARG_19(ARG_REST_(__VA_ARGS__,)) -#define ARG_21(...) ARG_20(ARG_REST_(__VA_ARGS__,)) -#define ARG_22(...) ARG_21(ARG_REST_(__VA_ARGS__,)) -#define ARG_23(...) ARG_22(ARG_REST_(__VA_ARGS__,)) -#define ARG_24(...) ARG_23(ARG_REST_(__VA_ARGS__,)) -#define ARG_25(...) ARG_24(ARG_REST_(__VA_ARGS__,)) -#define ARG_26(...) ARG_25(ARG_REST_(__VA_ARGS__,)) -#define ARG_27(...) ARG_26(ARG_REST_(__VA_ARGS__,)) -#define ARG_28(...) ARG_27(ARG_REST_(__VA_ARGS__,)) -#define ARG_29(...) ARG_28(ARG_REST_(__VA_ARGS__,)) -#define ARG_30(...) ARG_29(ARG_REST_(__VA_ARGS__,)) -#define ARG_31(...) ARG_30(ARG_REST_(__VA_ARGS__,)) -#define ARG_32(...) ARG_31(ARG_REST_(__VA_ARGS__,)) - -#define _CLAUSE1(...) __VA_ARGS__ FORGET -#define _CLAUSE2(...) EXPAND - -#define __IF_CLAUSE(A,B,C,...) C -#define _IF_CLAUSE(EXP) __IF_CLAUSE(EXP, _CLAUSE1, _CLAUSE2,) - -#define _IS_0_EQ_0 , -#define _IS_1_EQ_1 , -#define _IS_2_EQ_2 , -#define _IS_3_EQ_3 , -#define _IS_4_EQ_4 , -#define _IS_5_EQ_5 , -#define _IS_6_EQ_6 , -#define _IS_7_EQ_7 , -#define _IS_8_EQ_8 , -#define _IS_9_EQ_9 , -#define _IS_10_EQ_10 , -#define _IS_11_EQ_11 , -#define _IS_12_EQ_12 , -#define _IS_13_EQ_13 , -#define _IS_14_EQ_14 , -#define _IS_15_EQ_15 , -#define _IS_16_EQ_16 , -#define _IS_17_EQ_17 , -#define _IS_18_EQ_18 , -#define _IS_19_EQ_19 , -#define _IS_20_EQ_20 , -#define _IS_21_EQ_21 , -#define _IS_22_EQ_22 , -#define _IS_23_EQ_23 , -#define _IS_24_EQ_24 , -#define _IS_25_EQ_25 , -#define _IS_26_EQ_26 , -#define _IS_27_EQ_27 , -#define _IS_28_EQ_28 , -#define _IS_29_EQ_29 , -#define _IS_30_EQ_30 , -#define _IS_31_EQ_31 , -#define _IS_32_EQ_32 , - -#define STR_(...) #__VA_ARGS__ - -/* detect empty arguments */ -#define _IS_EMPTY(_0, _1, _2, _3) \ - HAS_COMMA(CONCAT_5(_IS_EMPTY_CASE_, _0, _1, _2, _3)) -#define _IS_EMPTY_CASE_0001 , -#define _IS_EMPTY_FN(...) , - -/**@endcond*/ - -#endif /* PPMLIB_H_INCLUDED */ diff --git a/04_exercise/rwlock.c b/04_exercise/rwlock.c new file mode 100644 index 0000000..941d176 --- /dev/null +++ b/04_exercise/rwlock.c @@ -0,0 +1,69 @@ +// +// Created by stefan on 11.06.20. +// + +#include "rwlock.h" +#include +#include +#include +#include + +static const bool DEBUG = false; + + +void rwLockWrite(atomic_char *lock) { + char status; + bool succeeded; + do { + status = RW_UNLOCKED; + succeeded = atomic_compare_exchange_weak(lock, &status, RW_WRITE_LOCKED); + } while (!succeeded); + if(DEBUG) { + fprintf(stderr, "Thread %lu: Aquired Write Lock \n", pthread_self() % 1000); + } + +} + +void rwUnlockWrite(atomic_char *lock) { + char expected = RW_WRITE_LOCKED; + if (!atomic_compare_exchange_strong(lock, &expected, RW_UNLOCKED)) { + fprintf(stderr, "Couldn't unlock from writelock. Lock was at %d", expected); + perror("Lock got into undefined state"); + exit(-1); + } + if(DEBUG) { + fprintf(stderr, "Thread %lu: Released Write Lock \n", pthread_self() % 1000); + } + // Avoid starvation of readers/all other threads + if (sched_yield() < 0) { + perror("Couldn't sleep. This shouldn't happen."); + exit(-1); + } + +} +void rwLockRead(atomic_char *lock) { + while (atomic_load(lock) == RW_WRITE_LOCKED) { + + } + atomic_fetch_add(lock, 1); + if(DEBUG) { + fprintf(stderr, "Thread %lu: Aquired Read Lock \n", pthread_self() % 1000); + } +} +void rwUnlockRead(atomic_char *lock) { + char value = atomic_load(lock); + if (value < 1) { + fprintf(stderr, "Couldn't unlock from readlock. Lock was at %d", value); + perror("Lock got into undefined state"); + exit(-1); + } + atomic_fetch_sub(lock, 1); + if(DEBUG) { + fprintf(stderr, "Thread %lu: Released Read Lock \n", pthread_self() % 1000); + } + // Avoid starvation of writer/all other threads + if (sched_yield() < 0) { + perror("Couldn't sleep. This shouldn't happen."); + exit(-1); + } +} \ No newline at end of file diff --git a/04_exercise/rwlock.h b/04_exercise/rwlock.h new file mode 100644 index 0000000..aa27f09 --- /dev/null +++ b/04_exercise/rwlock.h @@ -0,0 +1,16 @@ +// +// Created by stefan on 11.06.20. +// + +#ifndef BETRIEBSYSTEME_RWLOCK_H +#define BETRIEBSYSTEME_RWLOCK_H +#include + +static const char RW_WRITE_LOCKED = -1; +static const char RW_UNLOCKED = 0; +void rwLockWrite(atomic_char *lock); +void rwUnlockWrite(atomic_char *lock); +void rwLockRead(atomic_char *lock); +void rwUnlockRead(atomic_char *lock); + +#endif // BETRIEBSYSTEME_RWLOCK_H diff --git a/04_exercise/rwlock/rwlock.c b/04_exercise/rwlock/rwlock.c deleted file mode 100644 index 941d176..0000000 --- a/04_exercise/rwlock/rwlock.c +++ /dev/null @@ -1,69 +0,0 @@ -// -// Created by stefan on 11.06.20. -// - -#include "rwlock.h" -#include -#include -#include -#include - -static const bool DEBUG = false; - - -void rwLockWrite(atomic_char *lock) { - char status; - bool succeeded; - do { - status = RW_UNLOCKED; - succeeded = atomic_compare_exchange_weak(lock, &status, RW_WRITE_LOCKED); - } while (!succeeded); - if(DEBUG) { - fprintf(stderr, "Thread %lu: Aquired Write Lock \n", pthread_self() % 1000); - } - -} - -void rwUnlockWrite(atomic_char *lock) { - char expected = RW_WRITE_LOCKED; - if (!atomic_compare_exchange_strong(lock, &expected, RW_UNLOCKED)) { - fprintf(stderr, "Couldn't unlock from writelock. Lock was at %d", expected); - perror("Lock got into undefined state"); - exit(-1); - } - if(DEBUG) { - fprintf(stderr, "Thread %lu: Released Write Lock \n", pthread_self() % 1000); - } - // Avoid starvation of readers/all other threads - if (sched_yield() < 0) { - perror("Couldn't sleep. This shouldn't happen."); - exit(-1); - } - -} -void rwLockRead(atomic_char *lock) { - while (atomic_load(lock) == RW_WRITE_LOCKED) { - - } - atomic_fetch_add(lock, 1); - if(DEBUG) { - fprintf(stderr, "Thread %lu: Aquired Read Lock \n", pthread_self() % 1000); - } -} -void rwUnlockRead(atomic_char *lock) { - char value = atomic_load(lock); - if (value < 1) { - fprintf(stderr, "Couldn't unlock from readlock. Lock was at %d", value); - perror("Lock got into undefined state"); - exit(-1); - } - atomic_fetch_sub(lock, 1); - if(DEBUG) { - fprintf(stderr, "Thread %lu: Released Read Lock \n", pthread_self() % 1000); - } - // Avoid starvation of writer/all other threads - if (sched_yield() < 0) { - perror("Couldn't sleep. This shouldn't happen."); - exit(-1); - } -} \ No newline at end of file diff --git a/04_exercise/rwlock/rwlock.h b/04_exercise/rwlock/rwlock.h deleted file mode 100644 index aa27f09..0000000 --- a/04_exercise/rwlock/rwlock.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// Created by stefan on 11.06.20. -// - -#ifndef BETRIEBSYSTEME_RWLOCK_H -#define BETRIEBSYSTEME_RWLOCK_H -#include - -static const char RW_WRITE_LOCKED = -1; -static const char RW_UNLOCKED = 0; -void rwLockWrite(atomic_char *lock); -void rwUnlockWrite(atomic_char *lock); -void rwLockRead(atomic_char *lock); -void rwUnlockRead(atomic_char *lock); - -#endif // BETRIEBSYSTEME_RWLOCK_H diff --git a/04_exercise/slotmap.c b/04_exercise/slotmap.c new file mode 100644 index 0000000..57c4ef5 --- /dev/null +++ b/04_exercise/slotmap.c @@ -0,0 +1,48 @@ +// +// Created by stefan on 18.06.20. +// + +#include "slotmap.h" +#include +smHeader smInit(smEntry * slab, size_t size) { + for (int i = 0; i < size; ++i) { + slab[i].value = (intptr_t)NULL; + } + return (smHeader){.slab = slab, .size=size}; +} +int smInsert(smHeader const * header, void * value) { + for (size_t i = 0; i< header->size; ++i ) { + intptr_t ptr = atomic_load(&header->slab[i].value); + if((void *)ptr == NULL) { + intptr_t expected = (intptr_t) NULL; + if(atomic_compare_exchange_strong(&header->slab[i].value, &expected, (intptr_t) value)){ + return 0; + } + } + } + return -1; +} +void smDelete(smEntry * node) { + intptr_t oldval = atomic_exchange(&node->value, (intptr_t)(NULL)); + if((void *) oldval == NULL) { + fprintf(stderr, "A Node has been double deleted"); + } +} +void smDeleteValue(smHeader const * header, void * value){ + for (size_t i = 0; i< header->size; ++i ) { + intptr_t ptr = atomic_load(&header->slab[i].value); + if((void *)ptr == value) { + smDelete(&header->slab[i]); + } + } +} +smEntry *smFindEntry(smHeader const * header, SearchFunction func){ + for (size_t i = 0; i< header->size; ++i ) { + void * value = (void *) atomic_load(&header->slab[i].value); + + if(value != NULL && func(value)) { + return &header->slab[i]; + } + } + return NULL; +} diff --git a/04_exercise/slotmap.h b/04_exercise/slotmap.h new file mode 100644 index 0000000..d4044d4 --- /dev/null +++ b/04_exercise/slotmap.h @@ -0,0 +1,37 @@ +// +// Created by stefan on 18.06.20. +// + +#ifndef BETRIEBSYSTEME_SLOTMAP_H +#define BETRIEBSYSTEME_SLOTMAP_H +#include +#include +#include +#include + +typedef struct smNode { + atomic_intptr_t value; +} smEntry; + +typedef struct smHeader { + smEntry *slab; + size_t size; +} smHeader; + +typedef bool (*SearchFunction)(void const *); + +smHeader smInit(smEntry * slab, size_t size); +int smInsert(smHeader const * header, void * value); +void smDelete(smEntry * node); +void smDeleteValue(smHeader const * header, void * value); +/** + * Returns a node whose value is accepted by the SearchFunction + * @param header The header of the slotmap to be searched + * @param func The search function, that will be applied to each element until one is found + * @return the Entry that was found + */ +smEntry *smFindEntry(smHeader const * header, SearchFunction func); + + + +#endif // BETRIEBSYSTEME_SLOTMAP_H diff --git a/04_exercise/slotmap/slomap_test.c b/04_exercise/slotmap/slomap_test.c deleted file mode 100644 index 930bfa8..0000000 --- a/04_exercise/slotmap/slomap_test.c +++ /dev/null @@ -1,19 +0,0 @@ -// -// Created by stefan on 18.06.20. -// -#include -#include -#include - -bool find1(void const * ptr) { - return * (int const *) ptr == 1; -} -int main() { - smEntry slab [10]; - int data [6] = {0, 1, 2,3,4,5}; - smHeader header = smInit((smEntry *)&slab, 10); - smInsert(&header, &data[1]); - smEntry * entry = smFindEntry(&header, &find1); - assert(*(int *)entry->value == 1); - return 0; -} diff --git a/04_exercise/slotmap/slotmap.c b/04_exercise/slotmap/slotmap.c deleted file mode 100644 index 57c4ef5..0000000 --- a/04_exercise/slotmap/slotmap.c +++ /dev/null @@ -1,48 +0,0 @@ -// -// Created by stefan on 18.06.20. -// - -#include "slotmap.h" -#include -smHeader smInit(smEntry * slab, size_t size) { - for (int i = 0; i < size; ++i) { - slab[i].value = (intptr_t)NULL; - } - return (smHeader){.slab = slab, .size=size}; -} -int smInsert(smHeader const * header, void * value) { - for (size_t i = 0; i< header->size; ++i ) { - intptr_t ptr = atomic_load(&header->slab[i].value); - if((void *)ptr == NULL) { - intptr_t expected = (intptr_t) NULL; - if(atomic_compare_exchange_strong(&header->slab[i].value, &expected, (intptr_t) value)){ - return 0; - } - } - } - return -1; -} -void smDelete(smEntry * node) { - intptr_t oldval = atomic_exchange(&node->value, (intptr_t)(NULL)); - if((void *) oldval == NULL) { - fprintf(stderr, "A Node has been double deleted"); - } -} -void smDeleteValue(smHeader const * header, void * value){ - for (size_t i = 0; i< header->size; ++i ) { - intptr_t ptr = atomic_load(&header->slab[i].value); - if((void *)ptr == value) { - smDelete(&header->slab[i]); - } - } -} -smEntry *smFindEntry(smHeader const * header, SearchFunction func){ - for (size_t i = 0; i< header->size; ++i ) { - void * value = (void *) atomic_load(&header->slab[i].value); - - if(value != NULL && func(value)) { - return &header->slab[i]; - } - } - return NULL; -} diff --git a/04_exercise/slotmap/slotmap.h b/04_exercise/slotmap/slotmap.h deleted file mode 100644 index 1d687fc..0000000 --- a/04_exercise/slotmap/slotmap.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// Created by stefan on 18.06.20. -// - -#ifndef BETRIEBSYSTEME_SLOTMAP_H -#define BETRIEBSYSTEME_SLOTMAP_H -#include -#include -#include - -typedef struct smNode { - atomic_intptr_t value; -} smEntry; - -typedef struct smHeader { - smEntry *slab; - size_t size; -} smHeader; - -typedef bool (*SearchFunction)(void const *); - -smHeader smInit(smEntry * slab, size_t size); -int smInsert(smHeader const * header, void * value); -void smDelete(smEntry * node); -void smDeleteValue(smHeader const * header, void * value); -/** - * Returns a node whose value is accepted by the SearchFunction - * @param header The header of the slotmap to be searched - * @param func The search function, that will be applied to each element until one is found - * @return the Entry that was found - */ -smEntry *smFindEntry(smHeader const * header, SearchFunction func); - - - -#endif // BETRIEBSYSTEME_SLOTMAP_H diff --git a/04_exercise/threadpool.c b/04_exercise/threadpool.c index 9d73013..d40b1da 100644 --- a/04_exercise/threadpool.c +++ b/04_exercise/threadpool.c @@ -1,8 +1,8 @@ #include "threadpool.h" #include "array.h" +#include "slotmap.h" #include -#include #include #include #include diff --git a/04_exercise/threadpool.h b/04_exercise/threadpool.h index 745c4dd..6b5945b 100644 --- a/04_exercise/threadpool.h +++ b/04_exercise/threadpool.h @@ -1,9 +1,9 @@ #ifndef THREADPOOL_H_INCLUDED #define THREADPOOL_H_INCLUDED +#include "ppmlib.h" #include #include -#include /**@brief Funktionszeiger auf eine asynchron auszuführende Funktion. * -- cgit v1.2.3-54-g00ecf