Skip to content

Instantly share code, notes, and snippets.

@swick
Created January 18, 2025 00:03
Show Gist options
  • Select an option

  • Save swick/0ca0a495d158bcda3605097f33a85f17 to your computer and use it in GitHub Desktop.

Select an option

Save swick/0ca0a495d158bcda3605097f33a85f17 to your computer and use it in GitHub Desktop.
horrible C defer
/* Requires specific nested function extension */
#define G_INLINE_DEFER __DEFER(__COUNTER__)
#define __DEFER(N) __DEFER_(N)
#define __DEFER_(N) __DEFER__(__DEFER_FUNCTION_ ## N, __DEFER_VARIABLE_ ## N)
#define __DEFER__(F, V) \
auto void F(int*); \
__attribute__((cleanup(F))) int V; \
auto void F(int*)
/* Requires __VA_OPT__ from GNU C */
#define N_VA_ARGS_(_9,_8,_7,_6,_5,_4,_3,_2,_1, N, ...) N
#define N_VA_ARGS(...) N_VA_ARGS_(__VA_ARGS__ __VA_OPT__(,) 9,8,7,6,5,4,3,2,1,0)
#define FOREACH_0(FN, ...)
#define FOREACH_1(FN, DATA, E, ...) FN(E, DATA, 1)
#define FOREACH_2(FN, DATA, E, ...) FN(E, DATA, 2) FOREACH_1(FN, DATA, __VA_ARGS__)
#define FOREACH_3(FN, DATA, E, ...) FN(E, DATA, 3) FOREACH_2(FN, DATA, __VA_ARGS__)
#define FOREACH_4(FN, DATA, E, ...) FN(E, DATA, 4) FOREACH_3(FN, DATA, __VA_ARGS__)
#define FOREACH_5(FN, DATA, E, ...) FN(E, DATA, 5) FOREACH_4(FN, DATA, __VA_ARGS__)
#define FOREACH_6(FN, DATA, E, ...) FN(E, DATA, 6) FOREACH_5(FN, DATA, __VA_ARGS__)
#define FOREACH_7(FN, DATA, E, ...) FN(E, DATA, 7) FOREACH_6(FN, DATA, __VA_ARGS__)
#define FOREACH_8(FN, DATA, E, ...) FN(E, DATA, 8) FOREACH_7(FN, DATA, __VA_ARGS__)
#define FOREACH_9(FN, DATA, E, ...) FN(E, DATA, 9) FOREACH_8(FN, DATA, __VA_ARGS__)
#define FOREACH_10(FN, DATA, E, ...) FN(E, DATA, 10) FOREACH_9(FN, DATA, __VA_ARGS__)
#define FOREACH__(FN, DATA, NARGS, ...) FOREACH_##NARGS(FN, DATA, __VA_ARGS__)
#define FOREACH_(FN, DATA, NARGS, ...) FOREACH__(FN, DATA, NARGS, __VA_ARGS__)
#define FOREACH(FN, DATA, ...) FOREACH_(FN, DATA, N_VA_ARGS(__VA_ARGS__), __VA_ARGS__)
#define FOREACHPAIR_0(FN, LAST,...)
#define FOREACHPAIR_2(FN, LAST, E1, E2, ...) LAST(E1, E2, 1)
#define FOREACHPAIR_4(FN, LAST, E1, E2, ...) FN(E1, E2, 2) FOREACHPAIR_2(FN, LAST, __VA_ARGS__)
#define FOREACHPAIR_6(FN, LAST, E1, E2, ...) FN(E1, E2, 3) FOREACHPAIR_4(FN, LAST, __VA_ARGS__)
#define FOREACHPAIR_8(FN, LAST, E1, E2, ...) FN(E1, E2, 4) FOREACHPAIR_6(FN, LAST, __VA_ARGS__)
#define FOREACHPAIR_10(FN, LAST, E1, E2, ...) FN(E1, E2, 5) FOREACHPAIR_8(FN, LAST, __VA_ARGS__)
#define FOREACHPAIR__(FN, LAST, NARGS, ...) FOREACHPAIR_##NARGS(FN, LAST, __VA_ARGS__)
#define FOREACHPAIR_(FN, LAST, NARGS, ...) FOREACHPAIR__(FN, LAST, NARGS, __VA_ARGS__)
#define FOREACHPAIR(FN, LAST, ...) FOREACHPAIR_(FN, LAST, N_VA_ARGS(__VA_ARGS__), __VA_ARGS__)
#define _G_DEFER_DEFINE_FIELD(TYPE, NAME, N) TYPE *NAME;
#define _G_DEFER_DEFINE_ARG(TYPE, NAME, N) TYPE NAME,
#define _G_DEFER_DEFINE_ARG_LAST(TYPE, NAME, N) TYPE NAME
#define _G_DEFER_DEFINE_CALL_ARG(TYPE, NAME, N) (*instance->NAME),
#define _G_DEFER_DEFINE_CALL_ARG_LAST(TYPE, NAME, N) (*instance->NAME)
#define G_DEFINE_DEFER(name, ...) \
typedef struct \
{ \
gboolean _defer_active; \
FOREACHPAIR(_G_DEFER_DEFINE_FIELD, _G_DEFER_DEFINE_FIELD, __VA_ARGS__) \
} name; \
static void defer_ ## name (FOREACHPAIR(_G_DEFER_DEFINE_ARG, _G_DEFER_DEFINE_ARG_LAST, __VA_ARGS__)); \
static void defer_inter_ ## name (name *instance) \
{ \
if (!instance->_defer_active) return; \
defer_ ## name (FOREACHPAIR (_G_DEFER_DEFINE_CALL_ARG, _G_DEFER_DEFINE_CALL_ARG_LAST, __VA_ARGS__)); \
} \
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(name, defer_inter_ ## name); \
static void defer_ ## name (FOREACHPAIR(_G_DEFER_DEFINE_ARG, _G_DEFER_DEFINE_ARG_LAST, __VA_ARGS__))
#define _G_DEFER_SET_VALUE(ARG, INSTANCE, N) INSTANCE.ARG = &ARG;
#define G_DEFER(instance, ...) do { \
instance._defer_active = TRUE; \
FOREACH(_G_DEFER_SET_VALUE, instance, __VA_ARGS__) \
} while(0);
#define G_DEFER_INIT {0}
G_DEFINE_DEFER(TestThingDefer,
const char *,name,
gboolean ,foo)
{
g_print ("%s is %sfoo\n", name, foo ? "" : "not ");
}
static void
test_thing (void)
{
const char *name = "thing";
int foo = TRUE;
g_auto(TestThingDefer) defer = G_DEFER_INIT;
G_DEFER (defer, name, foo);
foo = FALSE;
return g_print ("done\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment