Created
January 18, 2025 00:03
-
-
Save swick/0ca0a495d158bcda3605097f33a85f17 to your computer and use it in GitHub Desktop.
horrible C defer
This file contains hidden or 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
| /* 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