106 lines
2.7 KiB
C
106 lines
2.7 KiB
C
#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, void(*free)(void*)) {
|
|
struct __free_list **current = head;
|
|
while (*current != NULL) {
|
|
if (current[0]->ptr == ptr) {
|
|
struct __free_list *deleted = *current;
|
|
*current = current[0]->next;
|
|
free(deleted);
|
|
break;
|
|
}
|
|
current = ¤t[0]->next;
|
|
}
|
|
}
|
|
#define TRY_FREE(allocation) (\
|
|
free(allocation),\
|
|
__remove_free_list(&__allocations, allocation, free)\
|
|
)
|
|
#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
|