#ifndef __CMAYBE_H__ #define __CMAYBE_H__ #define MAYBE_TYPE(name, type) struct maybe_##name {type value; char is_value;} #define MAYBE(name) struct maybe_##name #define ENABLE_RETURN(name) MAYBE(name) __return_value #define RETURN_VALUE(x) {\ __return_value.is_value = 1;\ __return_value.value = x;\ return __return_value;\ } #define RETURN_NOTHING() {\ __return_value.is_value = 0;\ return __return_value;\ } #define IS_VALUE(x) if ((x).is_value) #define IS_NOT_VALUE(x) if (!(x).is_value) #define VALUE(x) (x).value struct __free_list { struct __free_list *next; void *ptr; }; #define ENABLE_TRY() \ struct __free_list *__allocations = NULL, *__free_list_node;\ void *__allocation, *__old_allocation;\ jmp_buf __try_fail_jmp_buf;\ if (setjmp(__try_fail_jmp_buf)) {\ TRY_FREE_ALL();\ RETURN_NOTHING();\ } #define TRY_TYPE(name) MAYBE(name) __try_tmp_##name #define TRY(name, maybe_value) (\ __try_tmp_##name = maybe_value,\ (__try_tmp_##name.is_value ? 0 :\ longjmp(__try_fail_jmp_buf, 1)\ ),\ __try_tmp_##name.value\ ) #define TRY_MEMALLOC(allocator, ...) (\ __free_list_node = malloc(sizeof(struct __free_list)),\ (__free_list_node == NULL ? longjmp(__try_fail_jmp_buf, 1) : 0),\ __allocation = allocator(__VA_ARGS__),\ (__allocation == NULL ? (\ free(__free_list_node),\ longjmp(__try_fail_jmp_buf, 1)\ ) : (\ __free_list_node->next = __allocations,\ __free_list_node->ptr = __allocation,\ __allocations = __free_list_node\ )),\ __allocation\ ) #define TRY_MALLOC(size) TRY_MEMALLOC(malloc, size) static void __remove_free_list(struct __free_list **head, void *ptr) { struct __free_list **current = head; while (*current != NULL) { if (current[0]->ptr == ptr) { *current = current[0]->next; break; } current = ¤t[0]->next; } } #define TRY_FREE(allocation) (\ free(allocation),\ __remove_free_list(&__allocations, allocation)\ ) #define TRY_FREE_ALL() \ while (__allocations != NULL) {\ struct __free_list *current = __allocations;\ free(current->ptr);\ __allocations = current->next;\ free(current);\ } static void __replace_free_list(struct __free_list **head, void *from, void *to) { struct __free_list **current = head; while (*current != NULL) { if (current[0]->ptr == from) { current[0]->ptr = to; break; } current = ¤t[0]->next; } } #define TRY_MEMREALLOC(reallocator, old, ...) (\ __old_allocation = old,\ __allocation = reallocator(old, __VA_ARGS__),\ (__allocation == NULL ? (\ longjmp(__try_fail_jmp_buf, 1)\ ) : \ __replace_free_list(&__allocations, __old_allocation, __allocation)\ ),\ __allocation\ ) #define TRY_REALLOC(old, size) TRY_MEMREALLOC(realloc, old, size) #endif