Last active
July 16, 2018 19:06
-
-
Save mortie/0696f1cf717d192a33b7d842144dcf4a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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