diff --git a/cmaybe.h b/cmaybe.h index 7e2993b..80f0461 100644 --- a/cmaybe.h +++ b/cmaybe.h @@ -22,13 +22,14 @@ struct __free_list { struct __free_list *next; void *ptr; + void (*freer)(void*); }; #define ENABLE_TRY() \ struct __free_list *__allocations = NULL, *__free_list_node;\ - void *__allocation, *__old_allocation;\ + void *__allocation;\ jmp_buf __try_fail_jmp_buf;\ if (setjmp(__try_fail_jmp_buf)) {\ - TRY_FREE_ALL();\ + TRY_FAIL_HANDLE();\ RETURN_NOTHING();\ } #define TRY_TYPE(name) MAYBE(name) __try_tmp_##name @@ -40,42 +41,41 @@ struct __free_list { __try_tmp_##name.value\ ) -#define TRY_MEMALLOC(allocator, ...) (\ +#define HANDLE_ON_TRY_FAIL(freer_func, pointer) (\ + __allocation = pointer,\ __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),\ + (__free_list_node == NULL ? (\ + free(__allocation),\ longjmp(__try_fail_jmp_buf, 1)\ ) : (\ __free_list_node->next = __allocations,\ __free_list_node->ptr = __allocation,\ + __free_list_node->freer = freer_func,\ __allocations = __free_list_node\ )),\ __allocation\ ) -#define TRY_MALLOC(size) TRY_MEMALLOC(malloc, size) +#define FREE_ON_TRY_FAIL(pointer) HANDLE_ON_TRY_FAIL(free, pointer) -static void __remove_free_list(struct __free_list **head, void *ptr, void(*free)(void*)) { +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; + *current = deleted->next; free(deleted); break; } current = ¤t[0]->next; } } -#define TRY_FREE(allocation) (\ - free(allocation),\ - __remove_free_list(&__allocations, allocation, free)\ -) -#define TRY_FREE_ALL() \ + +#define TRY_HOF_REMOVE(allocation) __remove_free_list(&__allocations, allocation, free) +#define TRY_FAIL_HANDLE() \ while (__allocations != NULL) {\ struct __free_list *current = __allocations;\ - free(current->ptr);\ + void (*freer)(void*) = current->freer;\ + freer(current->ptr);\ __allocations = current->next;\ free(current);\ } @@ -90,16 +90,6 @@ static void __replace_free_list(struct __free_list **head, void *from, void *to) 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) +#define TRY_HOF_REPLACE(old_ptr, new_ptr) __replace_free_list(&__allocations, old_ptr, new_ptr) #endif diff --git a/convert_to_ints.c b/convert_to_ints.c index 32de1be..772d784 100644 --- a/convert_to_ints.c +++ b/convert_to_ints.c @@ -21,6 +21,26 @@ MAYBE(voidptr) strchr_maybe(const void *s, int c) { } } +MAYBE(voidptr) malloc_maybe(size_t size) { + ENABLE_RETURN(voidptr); + void *allocation = malloc(size); + if(allocation == NULL && size != 0) { + RETURN_NOTHING(); + } else { + RETURN_VALUE(allocation); + } +} + +MAYBE(voidptr) realloc_maybe(void *old, size_t size) { + ENABLE_RETURN(voidptr); + void *allocation = realloc(old, size); + if(allocation == NULL && size != 0) { + RETURN_NOTHING(); + } else { + RETURN_VALUE(allocation); + } +} + MAYBE_TYPE(intmax_t, intmax_t); MAYBE(intmax_t) str2int(const char *string) { @@ -43,15 +63,44 @@ struct intmax_t_array { MAYBE_TYPE(intmax_t_array, struct intmax_t_array); +MAYBE(intmax_t_array) create_array(void) { + ENABLE_RETURN(intmax_t_array); + ENABLE_TRY(); + TRY_TYPE(voidptr); + + struct intmax_t_array array; + array.length = 0; + array.alloc_size = sizeof(intmax_t); + array.data = TRY(voidptr, malloc_maybe(array.alloc_size)); + RETURN_VALUE(array); +} + +MAYBE(intmax_t_array) resize_array(struct intmax_t_array array, size_t length) { + ENABLE_RETURN(intmax_t_array); + ENABLE_TRY(); + TRY_TYPE(voidptr); + + struct intmax_t_array resized_array = {array.data, length, array.alloc_size}; + + if(resized_array.alloc_size / sizeof(intmax_t) < resized_array.length) { + if(SIZE_MAX / 2 < resized_array.alloc_size) { + RETURN_NOTHING(); + } + resized_array.alloc_size *= 2; + resized_array.data = TRY(voidptr, realloc_maybe(resized_array.data, resized_array.alloc_size)); + } + + RETURN_VALUE(resized_array); +} + MAYBE(intmax_t_array) convert_to_numbers(char *line) { ENABLE_RETURN(intmax_t_array); ENABLE_TRY(); TRY_TYPE(intmax_t); + TRY_TYPE(intmax_t_array); - struct intmax_t_array numbers; - numbers.length = 0; - numbers.alloc_size = 8 * sizeof(intmax_t); - numbers.data = TRY_MALLOC(numbers.alloc_size * sizeof(intmax_t)); + struct intmax_t_array numbers = TRY(intmax_t_array, create_array()); + FREE_ON_TRY_FAIL(numbers.data); char *strtok_saveptr = NULL; for (;;) { @@ -69,15 +118,11 @@ MAYBE(intmax_t_array) convert_to_numbers(char *line) { intmax_t num = TRY(intmax_t, str2int(num_str)); size_t index = numbers.length; - numbers.length++; - if(numbers.alloc_size / sizeof(intmax_t) < numbers.length) { - if(SIZE_MAX / 2 < numbers.alloc_size) { - TRY_FREE(numbers.data); - RETURN_NOTHING(); - } - numbers.alloc_size *= 2; - numbers.data = TRY_REALLOC(numbers.data, numbers.alloc_size); - } + + void *old_ptr = numbers.data; + numbers = TRY(intmax_t_array, resize_array(numbers, numbers.length + 1)); + TRY_HOF_REPLACE(old_ptr, numbers.data); + numbers.data[index] = num; }