2018-08-11 17:45:28 +00:00
|
|
|
#ifndef CMAYBE_H
|
|
|
|
#define CMAYBE_H
|
2018-08-11 07:37:24 +00:00
|
|
|
|
2018-08-11 07:28:30 +00:00
|
|
|
#define MAYBE_TYPE(name, type) struct maybe_##name {type value; char is_value;}
|
|
|
|
#define MAYBE(name) struct maybe_##name
|
|
|
|
|
2018-08-11 17:45:28 +00:00
|
|
|
#define ENABLE_RETURN(name) MAYBE(name) _return_value
|
2018-08-11 07:28:30 +00:00
|
|
|
#define RETURN_VALUE(x) {\
|
2018-08-11 17:45:28 +00:00
|
|
|
_return_value.is_value = 1;\
|
|
|
|
_return_value.value = x;\
|
|
|
|
return _return_value;\
|
2018-08-11 07:28:30 +00:00
|
|
|
}
|
|
|
|
#define RETURN_NOTHING() {\
|
2018-08-11 17:45:28 +00:00
|
|
|
_return_value.is_value = 0;\
|
|
|
|
return _return_value;\
|
2018-08-11 07:28:30 +00:00
|
|
|
}
|
|
|
|
|
2018-08-11 09:37:14 +00:00
|
|
|
#define IS_VALUE(x) if ((x).is_value)
|
|
|
|
#define IS_NOT_VALUE(x) if (!(x).is_value)
|
2018-08-11 07:28:30 +00:00
|
|
|
#define VALUE(x) (x).value
|
2018-08-11 07:37:24 +00:00
|
|
|
|
2018-08-11 17:45:28 +00:00
|
|
|
struct _free_list {
|
|
|
|
struct _free_list *next;
|
2018-08-11 09:37:14 +00:00
|
|
|
void *ptr;
|
2018-08-11 17:25:53 +00:00
|
|
|
void (*freer)(void*);
|
2018-08-11 09:37:14 +00:00
|
|
|
};
|
|
|
|
#define ENABLE_TRY() \
|
2018-08-11 17:45:28 +00:00
|
|
|
struct _free_list *_allocations = NULL, *_free_list_node;\
|
|
|
|
void *_allocation;\
|
|
|
|
jmp_buf _try_fail_jmp_buf;\
|
|
|
|
if (setjmp(_try_fail_jmp_buf)) {\
|
2018-08-11 17:25:53 +00:00
|
|
|
TRY_FAIL_HANDLE();\
|
2018-08-11 09:37:14 +00:00
|
|
|
RETURN_NOTHING();\
|
|
|
|
}
|
2018-08-11 17:45:28 +00:00
|
|
|
#define TRY_TYPE(name) MAYBE(name) _try_tmp_##name
|
2018-08-11 09:37:14 +00:00
|
|
|
#define TRY(name, maybe_value) (\
|
2018-08-11 17:45:28 +00:00
|
|
|
_try_tmp_##name = maybe_value,\
|
|
|
|
(_try_tmp_##name.is_value ? 0 :\
|
|
|
|
longjmp(_try_fail_jmp_buf, 1)\
|
2018-08-11 09:37:14 +00:00
|
|
|
),\
|
2018-08-11 17:45:28 +00:00
|
|
|
_try_tmp_##name.value\
|
2018-08-11 09:37:14 +00:00
|
|
|
)
|
|
|
|
|
2018-08-11 17:30:57 +00:00
|
|
|
#define TRY_HOF_HANDLE(freer_func, pointer) (\
|
2018-08-11 17:45:28 +00:00
|
|
|
_allocation = pointer,\
|
|
|
|
_free_list_node = malloc(sizeof(struct _free_list)),\
|
|
|
|
(_free_list_node == NULL ? (\
|
|
|
|
free(_allocation),\
|
|
|
|
longjmp(_try_fail_jmp_buf, 1)\
|
2018-08-11 09:37:14 +00:00
|
|
|
) : (\
|
2018-08-11 17:45:28 +00:00
|
|
|
_free_list_node->next = _allocations,\
|
|
|
|
_free_list_node->ptr = _allocation,\
|
|
|
|
_free_list_node->freer = freer_func,\
|
|
|
|
_allocations = _free_list_node\
|
2018-08-11 09:37:14 +00:00
|
|
|
)),\
|
2018-08-11 17:45:28 +00:00
|
|
|
_allocation\
|
2018-08-11 09:37:14 +00:00
|
|
|
)
|
2018-08-11 17:30:57 +00:00
|
|
|
#define FREE_ON_TRY_FAIL(pointer) TRY_HOF_HANDLE(free, pointer)
|
2018-08-11 09:37:14 +00:00
|
|
|
|
2018-08-11 17:30:57 +00:00
|
|
|
// free() is passed as an argument to avoid errors in case the program uses
|
|
|
|
// no TRY functionality and doesn't include stdlib.h
|
2018-08-11 17:45:28 +00:00
|
|
|
static void _remove_free_list(struct _free_list **head, void *ptr, void (*free)(void*)) {
|
|
|
|
struct _free_list **current = head;
|
2018-08-11 09:37:14 +00:00
|
|
|
while (*current != NULL) {
|
|
|
|
if (current[0]->ptr == ptr) {
|
2018-08-11 17:45:28 +00:00
|
|
|
struct _free_list *deleted = *current;
|
2018-08-11 17:25:53 +00:00
|
|
|
*current = deleted->next;
|
2018-08-11 16:45:41 +00:00
|
|
|
free(deleted);
|
2018-08-11 09:37:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
current = ¤t[0]->next;
|
|
|
|
}
|
|
|
|
}
|
2018-08-11 17:25:53 +00:00
|
|
|
|
2018-08-11 17:45:28 +00:00
|
|
|
#define TRY_HOF_REMOVE(allocation) _remove_free_list(&_allocations, allocation, free)
|
2018-08-11 17:25:53 +00:00
|
|
|
#define TRY_FAIL_HANDLE() \
|
2018-08-11 17:45:28 +00:00
|
|
|
while (_allocations != NULL) {\
|
|
|
|
struct _free_list *current = _allocations;\
|
2018-08-11 17:25:53 +00:00
|
|
|
void (*freer)(void*) = current->freer;\
|
|
|
|
freer(current->ptr);\
|
2018-08-11 17:45:28 +00:00
|
|
|
_allocations = current->next;\
|
2018-08-11 09:37:14 +00:00
|
|
|
free(current);\
|
|
|
|
}
|
|
|
|
|
2018-08-11 17:45:28 +00:00
|
|
|
static void _replace_free_list(struct _free_list **head, void *from, void *to) {
|
|
|
|
struct _free_list **current = head;
|
2018-08-11 09:37:14 +00:00
|
|
|
while (*current != NULL) {
|
|
|
|
if (current[0]->ptr == from) {
|
|
|
|
current[0]->ptr = to;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
current = ¤t[0]->next;
|
|
|
|
}
|
|
|
|
}
|
2018-08-11 17:45:28 +00:00
|
|
|
#define TRY_HOF_REPLACE(old_ptr, new_ptr) _replace_free_list(&_allocations, old_ptr, new_ptr)
|
2018-08-11 09:37:14 +00:00
|
|
|
|
2018-08-11 07:37:24 +00:00
|
|
|
#endif
|