tlibc/include/tlibc/defer.h
2025-08-09 21:42:12 +03:00

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__ */