From f2a3da5be94a465db61c865190e5ea7d77c41232 Mon Sep 17 00:00:00 2001 From: anon Date: Sat, 13 Sep 2025 16:38:18 +0200 Subject: +REQUIRE --- chad/experimental/require.h | 60 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 chad/experimental/require.h (limited to 'chad') diff --git a/chad/experimental/require.h b/chad/experimental/require.h new file mode 100644 index 0000000..e9a8ea8 --- /dev/null +++ b/chad/experimental/require.h @@ -0,0 +1,60 @@ +#ifndef REQUIRE_H +#define REQUIRE_H + +#include + +/* Require macros for easy uniform error handling. + * They can be used to replace repeated error handling logic + * or some messier solutions. + * + * REQUIRE() and REQUIRE_EX() assert a statement, + * on failure they invoke REQUIRE_TERMINATOR, + * on success they return the resulting value. + * + * REQUIRE_EX() takes a custom error value as its first argument, + * REQUIRE() assumes standard C truthliness. + * + * Example: + * int extreme_example(int i) { + * switch (i) { + * case 1: return 4; + * case 2: return 5; + * default: return 0; + * } + * } + * + * signed main(void) { + * FILE * f = REQUIRE(fopen("a.txt", "r")); + * + * REQUIRE(3 < 5); + * + * int i = REQUIRE(extreme_example(1)); + * + * return 0; + * } + * Possible (stderr) output: + * Required operation 'fopen("a.txt", "r")' failed. + */ + +thread_local long long require_v; + +#ifndef REQUIRE_TERMINATOR +# define REQUIRE_TERMINATOR default_require_terminator +#endif + +[[ noreturn ]] +static inline +void require_default_terminator(const char * const argv) { + fprintf(stderr, "Required operation '%s' failed.\n", argv); + exit(1); +} + +#define REQUIRE_EX(errval, ...) (typeof(__VA_ARGS__))( \ + (typeof(__VA_ARGS__))(require_v = (long long)(__VA_ARGS__)) != (typeof(__VA_ARGS__))errval \ + ? require_v \ + : (REQUIRE_TERMINATOR(STRINGIFY(__VA_ARGS__)), 0ll) \ +) + +#define REQUIRE(...) REQUIRE_EX(0ll, __VA_ARGS__) + +#endif -- cgit v1.2.3