]> git.ipfire.org Git - thirdparty/bird.git/blame - lib/macro.h
Filter: Fix function comparison
[thirdparty/bird.git] / lib / macro.h
CommitLineData
90609253
JMM
1/*
2 * BIRD Macro Tricks
3 *
4 * (c) 2018 Jan Maria Matejka <mq@jmq.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 *
8 * Contains useful but dirty macro tricks:
9 * MACRO_CONCAT(a, b) -> concatenates a##b
10 * MACRO_BOOL(x) -> convert 0 to 0, anything else to 1
11 * MACRO_IFELSE(b)(true-branch)(false-branch)
12 * -> b shall be 0 or 1; expands to the appropriate branch
13 * MACRO_ISEMPTY(...) -> 1 for empty argument list, 0 otherwise
14 * MACRO_FOREACH(func, ...)
15 * -> calling FOREACH(func, a, b, c, d) expands to
16 * func(a) func(b) func(c) func(d)
17 * MACRO_RPACK(func, terminator, ...)
18 * -> packs the list into recursive calls:
19 * func(func(func(func(terminator, a), b), c), d)
20 */
21
22#ifndef _BIRD_MACRO_H_
23#define _BIRD_MACRO_H_
24
25/* What to do with args */
26#define MACRO_DROP(...)
27#define MACRO_UNPAREN(...) __VA_ARGS__
28#define MACRO_SEP(a, b, sep) a sep b
29
30/* Aliases for some special chars */
31#define MACRO_COMMA ,
32#define MACRO_LPAREN (
33#define MACRO_RPAREN )
34#define MACRO_LPAREN_() (
35#define MACRO_RPAREN_() )
36
37/* Multiple expansion trick */
38#define MACRO_EXPAND0(...) __VA_ARGS__
39#define MACRO_EXPAND1(...) MACRO_EXPAND0(MACRO_EXPAND0(__VA_ARGS__))
40#define MACRO_EXPAND2(...) MACRO_EXPAND1(MACRO_EXPAND1(__VA_ARGS__))
41#define MACRO_EXPAND3(...) MACRO_EXPAND2(MACRO_EXPAND2(__VA_ARGS__))
42#define MACRO_EXPAND(...) MACRO_EXPAND3(MACRO_EXPAND3(__VA_ARGS__))
43
44/* Deferring expansion in the expansion trick */
45#define MACRO_EMPTY()
46#define MACRO_DEFER(t) t MACRO_EMPTY()
47#define MACRO_DEFER2(t) t MACRO_EMPTY MACRO_EMPTY()()
48#define MACRO_DEFER3(t) t MACRO_EMPTY MACRO_EMPTY MACRO_EMPTY()()()
49
50/* Token concatenation */
51#define MACRO_CONCAT(prefix, ...) prefix##__VA_ARGS__
52#define MACRO_CONCAT_AFTER(...) MACRO_CONCAT(__VA_ARGS__)
53
54/* Get first or second argument only */
55#define MACRO_FIRST(a, ...) a
56#define MACRO_SECOND(a, b, ...) b
57#define MACRO_SECOND_OR_ZERO(...) MACRO_SECOND(__VA_ARGS__, 0,)
58
59/* Macro Boolean auxiliary macros */
60#define MACRO_BOOL_CHECK_0 ~, 1
61#define MACRO_BOOL_NEG(x) MACRO_SECOND_OR_ZERO(MACRO_CONCAT(MACRO_BOOL_CHECK_, x))
62
63#define MACRO_BOOL_NOT_0 1
64#define MACRO_BOOL_NOT_1 0
65
66/* Macro Boolean negation */
67#define MACRO_NOT(x) MACRO_CONCAT(MACRO_BOOL_NOT_, x)
68
69/* Convert anything to bool (anything -> 1, 0 -> 0) */
70#define MACRO_BOOL(x) MACRO_NOT(MACRO_BOOL_NEG(x))
71
72/*
73 * Macro If/Else condition
74 * Usage: MACRO_IFELSE(condition)(true-branch)(false-branch)
75 * Expands to true-branch if condition is true, otherwise to false-branch.
76 */
77#define MACRO_IFELSE(b) MACRO_CONCAT(MACRO_IFELSE_, b)
78#define MACRO_IFELSE_0(...) MACRO_UNPAREN
79#define MACRO_IFELSE_1(...) __VA_ARGS__ MACRO_DROP
80
81/* Auxiliary macros for MACRO_FOREACH */
82#define MACRO_ISLAST(...) MACRO_BOOL_NEG(MACRO_FIRST(MACRO_ISLAST_CHECK __VA_ARGS__)())
83#define MACRO_ISLAST_CHECK() 0
84
85#define MACRO_FOREACH_EXPAND(call, a, ...) MACRO_IFELSE(MACRO_ISLAST(__VA_ARGS__))(call(a))(call(a) MACRO_DEFER2(MACRO_FOREACH_PAREN)()(call, __VA_ARGS__))
86#define MACRO_FOREACH_PAREN() MACRO_FOREACH_EXPAND
87
88#define MACRO_RPACK_EXPAND(call, terminator, a, ...) MACRO_IFELSE(MACRO_ISLAST(__VA_ARGS__))(call(terminator, a))(call(MACRO_DEFER2(MACRO_RPACK_PAREN)()(call, terminator, __VA_ARGS__), a))
89#define MACRO_RPACK_PAREN() MACRO_RPACK_EXPAND
90/*
91 * Call the first argument for each following:
92 * MACRO_FOREACH(func, a, b, c, d) expands to func(a) func(b) func(c) func(d).
93 * It supports also macros as func.
94 */
95#define MACRO_FOREACH(call, ...) MACRO_EXPAND(MACRO_FOREACH_EXPAND(call, __VA_ARGS__))
96#define MACRO_RPACK(call, terminator, ...) MACRO_EXPAND(MACRO_RPACK_EXPAND(call, terminator, __VA_ARGS__))
97
98#endif