82 lines
2.0 KiB
C
82 lines
2.0 KiB
C
/*
|
|
Based on https://github.com/moon-chilled/Defer
|
|
|
|
Usage:
|
|
|
|
void foo(){
|
|
Deferral(16);
|
|
void* p = malloc(8);
|
|
Defer(free(p));
|
|
Return;
|
|
}
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#if defined(__GNUC__) || defined(__TINYC__)
|
|
|
|
#define Deferral(MAX_DEFER_STATEMENTS) \
|
|
unsigned char _num_deferrals = 0; \
|
|
void *_defer_return_loc = 0, *_deferrals[MAX_DEFER_STATEMENTS] = {0};
|
|
|
|
# define Defer(block) _Defer(block, __LINE__)
|
|
# define Return _Return(__LINE__)
|
|
|
|
#define _defer_token_cat(a, b) a ## b
|
|
|
|
#define _Defer(block, n) do { \
|
|
_deferrals[_num_deferrals++] = && _defer_token_cat(_defer_ini, n); \
|
|
if (0) { \
|
|
_defer_token_cat(_defer_ini, n): \
|
|
block; \
|
|
if (_num_deferrals) { \
|
|
goto *_deferrals[--_num_deferrals]; \
|
|
} else { \
|
|
goto *_defer_return_loc; \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
|
|
#define _Return(n) \
|
|
if (_num_deferrals \
|
|
/* this nonsense disables warning Wunused-but-set-variable */ \
|
|
&& _defer_return_loc == _defer_return_loc ) \
|
|
{ \
|
|
_defer_return_loc = && _defer_token_cat(_defer_fini_, n); \
|
|
goto *_deferrals[--_num_deferrals]; \
|
|
} else _defer_token_cat(_defer_fini_, n): \
|
|
return
|
|
|
|
#else /* !__GNUC__ && !__TINYCC__ */
|
|
|
|
#include <setjmp.h>
|
|
|
|
#ifdef _MSC_VER
|
|
# pragma message("You are using the unsafe longjmp()-based defer implementation. Expect bugs if you don't know what you're doing.")
|
|
#else
|
|
# warning You are using the unsafe longjmp()-based defer implementation. Expect bugs if you don't know what you're doing.
|
|
#endif
|
|
|
|
#define Deferral(MAX_DEFER_STATEMENTS) \
|
|
volatile unsigned char _num_deferrals = 0; \
|
|
jmp_buf _defer_return_loc = {0}, _deferrals[MAX_DEFER_STATEMENTS] = {0};
|
|
|
|
#define Defer(block) do { \
|
|
if (setjmp(_deferrals[_num_deferrals++])) { \
|
|
block; \
|
|
if (_num_deferrals) { \
|
|
longjmp(_deferrals[--_num_deferrals], 1); \
|
|
} else { \
|
|
longjmp(_defer_return_loc, 1); \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
|
|
#define Return \
|
|
if (!setjmp(_defer_return_loc)) { \
|
|
if (_num_deferrals) longjmp(_deferrals[--_num_deferrals], 1); \
|
|
} else return
|
|
|
|
#endif /* __GNUC__ */
|