| #include <stdlib.h> | |
| /* | |
| * Defer an expression. | |
| * This requires a block in an outer scope to have called defer_init, | |
| * and the deferred statements will run once defer_run is called. | |
| */ | |
| #define defer(expr) \ | |
| do { \ | |
| __label__ _defer_label; \ | |
| _defer_label: \ | |
| if (_defer_rundefer) { \ | |
| expr; \ | |
| /* Go to the previous defer, or the end of the `it` block */ \ | |
| if (_defer_labels.count > 0) \ | |
| goto *_defer_labels.labels[--_defer_labels.count]; \ | |
| else \ | |
| goto *_defer_label_done; \ | |
| } else { \ | |
| _defer_labels.count += 1; \ | |
| /* Realloc labels array if necessary */ \ | |
| if (_defer_labels.count >= _defer_labels.size) { \ | |
| if (_defer_labels.size == 0) \ | |
| _defer_labels.size = 16; \ | |
| else \ | |
| _defer_labels.size *= 2; \ | |
| _defer_labels.labels = realloc( \ | |
| _defer_labels.labels, \ | |
| _defer_labels.size * sizeof(*_defer_labels.labels)); \ | |
| } \ | |
| /* Add pointer to _defer_label to labels array */ \ | |
| _defer_labels.labels[_defer_labels.count - 1] = \ | |
| &&_defer_label; \ | |
| } \ | |
| } while (0) | |
| /* | |
| * Init defer for the scope defer_init is called from. | |
| * It has to be the very first line in a block. | |
| */ | |
| #define defer_init() \ | |
| void __attribute__((unused)) *_defer_label_done; \ | |
| int __attribute__((unused)) _defer_rundefer = 0; \ | |
| struct { \ | |
| void **labels; size_t size; size_t count; \ | |
| } _defer_labels; \ | |
| _defer_labels.size = _defer_labels.count = 0; \ | |
| _defer_labels.labels = NULL; \ | |
| /* | |
| * Run all the defers registered for the corresponding defer_init. | |
| */ | |
| #define defer_run() \ | |
| do { \ | |
| __label__ _defer_done; \ | |
| _defer_done: \ | |
| _defer_label_done = &&_defer_done; \ | |
| _defer_rundefer = 1; \ | |
| if (_defer_labels.count > 0) { \ | |
| _defer_labels.count -= 1; \ | |
| goto *_defer_labels.labels[_defer_labels.count]; \ | |
| } \ | |
| } while (0) | |
| /* | |
| * Run all the defers, then return x | |
| */ | |
| #define defer_return(x) \ | |
| do { defer_run(); return x; } while (0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment