Skip to content

Instantly share code, notes, and snippets.

@mortie
Last active July 16, 2018 19:06
Show Gist options
  • Save mortie/0696f1cf717d192a33b7d842144dcf4a to your computer and use it in GitHub Desktop.
Save mortie/0696f1cf717d192a33b7d842144dcf4a to your computer and use it in GitHub Desktop.
#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