blob: afb20e998ede5f4ddab91a877f5cd1856320b4ae (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
#ifndef REQUIRE_H
#define REQUIRE_H
#include <chad/experimental/bits.h>
/* 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(__VA_ARGS__)
#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
|