Annotation of embedaddon/bird2/lib/macro.h, revision 1.1
1.1 ! misho 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
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>