mirror of https://github.com/n64decomp/007.git
737 lines
22 KiB
C
737 lines
22 KiB
C
/**
|
|
* This header file contains a library of advanced C Pre-Processor (CPP) macros
|
|
* which implement various useful functions, such as iteration, in the
|
|
* pre-processor.
|
|
*/
|
|
#ifndef CPPLIB_H
|
|
#define CPPLIB_H
|
|
|
|
/*#define EXPAND_EXAMPLES */
|
|
|
|
/**
|
|
* Macros which expand to common values
|
|
*/
|
|
|
|
#define EMPTY()
|
|
#define COMMA() ,
|
|
#define COMMA_IF(cond) COMMA_IF_I(cond)
|
|
#define COMMA_IF_I(cond) IF_ELSE(cond)(COMMA)(EMPTY)()
|
|
#define LPAREN() (
|
|
#define RPAREN() )
|
|
#define PLUS() +
|
|
#define ZERO() 0
|
|
#define ONE() 1
|
|
#define STR(n) #n
|
|
|
|
#ifdef __sgi
|
|
# define EXPAND(a) a
|
|
# define EAT(x)
|
|
#else
|
|
# define EXPAND(...) __VA_ARGS__
|
|
# define EAT(x, ...) __VA_ARGS__
|
|
#endif
|
|
|
|
|
|
/**
|
|
* Force the pre-processor to expand the macro a large number of times. Usage:
|
|
*
|
|
* EVAL(expression)
|
|
*
|
|
* This is useful when you have a macro which evaluates to a valid macro
|
|
* expression which is not subsequently expanded in the same pass. A contrived,
|
|
* but easy to understand, example of such a macro follows. Note that though
|
|
* this example is contrived, this behaviour is abused to implement bounded
|
|
* recursion in macros such as FOR.
|
|
*
|
|
* #define A(x) x+1
|
|
* #define EMPTY
|
|
* #define NOT_QUITE_RIGHT(x) A EMPTY (x)
|
|
* NOT_QUITE_RIGHT(999)
|
|
*
|
|
* Here's what happens inside the C preprocessor:
|
|
*
|
|
* 1. It sees a macro "NOT_QUITE_RIGHT" and performs a single macro expansion
|
|
* pass on its arguments. Since the argument is "999" and this isn't a macro,
|
|
* this is a boring step resulting in no change.
|
|
* 2. The NOT_QUITE_RIGHT macro is substituted for its definition giving "A
|
|
* EMPTY() (x)".
|
|
* 3. The expander moves from left-to-right trying to expand the macro:
|
|
* The first token, A, cannot be expanded since there are no brackets
|
|
* immediately following it. The second token EMPTY(), however, can be
|
|
* expanded (recursively in this manner) and is replaced with "".
|
|
* 4. Expansion continues from the start of the substituted test (which in this
|
|
* case is just empty), and sees "(999)" but since no macro name is present,
|
|
* nothing is done. This results in a final expansion of "A (999)".
|
|
*
|
|
* Unfortunately, this doesn't quite meet expectations since you may expect that
|
|
* "A (999)" would have been expanded into "999+1". Unfortunately this requires
|
|
* a second expansion pass but luckily we can force the macro processor to make
|
|
* more passes by abusing the first step of macro expansion: the preprocessor
|
|
* expands arguments in their own pass. If we define a macro which does nothing
|
|
* except produce its arguments e.g.:
|
|
*
|
|
* #define PASS_THROUGH(...) __VA_ARGS__
|
|
*
|
|
* We can now do "PASS_THROUGH(NOT_QUITE_RIGHT(999))" causing "NOT_QUITE_RIGHT"
|
|
* to be expanded to "A (999)", as described above, when the arguments are
|
|
* expanded. Now when the body of PASS_THROUGH is expanded, "A (999)" gets
|
|
* expanded to "999+1".
|
|
*
|
|
* The EVAL defined below is essentially equivalent to a large nesting of
|
|
* "PASS_THROUGH(PASS_THROUGH(PASS_THROUGH(..." which results in the
|
|
* preprocessor making a large number of expansion passes over the given
|
|
* expression.
|
|
*/
|
|
#define EVAL(a) EVAL512(EVAL256(EVAL128(EVAL64(EVAL32(EVAL16(EVAL8(EVAL4(EVAL2(EVAL1(a))))))))))
|
|
#define EVAL512(a) EVAL256(EVAL128(EVAL64(EVAL32(EVAL16(EVAL8(EVAL4(EVAL2(EVAL1(a)))))))))
|
|
#define EVAL256(a) EVAL128(EVAL64(EVAL32(EVAL16(EVAL8(EVAL4(EVAL2(EVAL1(a))))))))
|
|
#define EVAL128(a) EVAL64(EVAL32(EVAL16(EVAL8(EVAL4(EVAL2(EVAL1(a)))))))
|
|
#define EVAL64(a) EVAL32(EVAL16(EVAL8(EVAL4(EVAL2(EVAL1(a))))))
|
|
#define EVAL32(a) EVAL16(EVAL8(EVAL4(EVAL2(EVAL1(a)))))
|
|
#define EVAL16(a) EVAL8(EVAL4(EVAL2(EVAL1(a))))
|
|
#define EVAL8(a) EVAL4(EVAL2(EVAL1(a)))
|
|
#define EVAL4(a) EVAL2(EVAL1(a))
|
|
#define EVAL2(a) EVAL1(a)
|
|
#ifdef __sgi
|
|
# define EVAL1(VA) IF_VA(EXPAND(DEFER(IS_PAREN)(VA)))(DEFER(EXPAND_ARGS_STACK)) VA
|
|
#else
|
|
# define EVAL1(...) __VA_ARGS__
|
|
#endif
|
|
|
|
/**
|
|
* Causes a function-style macro to require an additional pass to be expanded.
|
|
* This is useful, for example, when trying to implement recursion since the
|
|
* recursive step must not be expanded in a single pass as the pre-processor
|
|
* will catch it and prevent it.
|
|
*
|
|
* Usage:
|
|
*
|
|
* DEFER(IN_NEXT_PASS)(args, to, the, macro)
|
|
*
|
|
* Blocking a Second time can be done with DEFER2
|
|
*
|
|
* Usage:
|
|
*
|
|
* DEFER2(IN_NEXT_NEXT_PASS)(args, to, the, macro)
|
|
*/
|
|
|
|
/**
|
|
* As with DEFER1 except here n additional passes are required for DEFERn.
|
|
*
|
|
* The mechanism is analogous.
|
|
*/
|
|
#define DEFERA1024(a) DEFERA512(DEFERA512(a))
|
|
#define DEFERA512(a) DEFERA256(DEFERA256(a))
|
|
#define DEFERA256(a) DEFERA128(DEFERA128(a))
|
|
#define DEFERA128(a) DEFERA64(DEFERA64(a))
|
|
#define DEFERA64(a) DEFERA32(DEFERA32(a))
|
|
#define DEFERA32(a) DEFERA16(DEFERA16(a))
|
|
#define DEFERA16(a) DEFERA8(DEFERA8(a))
|
|
#define DEFERA8(a) DEFERA4(DEFERA4(a))
|
|
#define DEFERA4(a) DEFERA2(DEFERA2(a))
|
|
#define DEFERA2(a) DEFERA1(DEFERA1(a))
|
|
#define DEFERA1(a) EMPTY a
|
|
#define DEFERB1024(a) DEFERB512(DEFERB512(a))
|
|
#define DEFERB512(a) DEFERB256(DEFERB256(a))
|
|
#define DEFERB256(a) DEFERB128(DEFERB128(a))
|
|
#define DEFERB128(a) DEFERB64(DEFERB64(a))
|
|
#define DEFERB64(a) DEFERB32(DEFERB32(a))
|
|
#define DEFERB32(a) DEFERB16(DEFERB16(a))
|
|
#define DEFERB16(a) DEFERB8(DEFERB8(a))
|
|
#define DEFERB8(a) DEFERB4(DEFERB4(a))
|
|
#define DEFERB4(a) DEFERB2(DEFERB2(a))
|
|
#define DEFERB2(a) DEFERB1(DEFERB1(a))
|
|
#define DEFERB1(a) () a
|
|
|
|
#define DEFER1024(id) id DEFERA1024() DEFERB1024()
|
|
#define DEFER512(id) id DEFERA512() DEFERB512()
|
|
#define DEFER256(id) id DEFERA256() DEFERB256()
|
|
#define DEFER128(id) id DEFERA128() DEFERB128()
|
|
#define DEFER64(id) id DEFERA64() DEFERB64()
|
|
#define DEFER32(id) id DEFERA32() DEFERB32()
|
|
#define DEFER16(id) id DEFERA16() DEFERB16()
|
|
#define DEFER8(id) id DEFERA8() DEFERB8()
|
|
#define DEFER4(id) id DEFERA4() DEFERB4()
|
|
#define DEFER3(id) id DEFERA1() DEFERA2() DEFERB2() DEFERB1()
|
|
#define DEFER2(id) id DEFERA2() DEFERB2()
|
|
#define DEFER1(id) id DEFERA1() DEFERB1()
|
|
#define DEFER(id) id DEFERA1() DEFERB1()
|
|
|
|
#define INC(x) CAT(INC_, x)
|
|
#define INC_0 1
|
|
#define INC_1 2
|
|
#define INC_2 3
|
|
#define INC_3 4
|
|
#define INC_4 5
|
|
#define INC_5 6
|
|
#define INC_6 7
|
|
#define INC_7 8
|
|
#define INC_8 9
|
|
#define INC_9 0
|
|
|
|
#define DEC(x) CAT(DEC_, x)
|
|
#define DEC_0 (1/0)
|
|
#define DEC_1 0
|
|
#define DEC_2 1
|
|
#define DEC_3 2
|
|
#define DEC_4 3
|
|
#define DEC_5 4
|
|
#define DEC_6 5
|
|
#define DEC_7 6
|
|
#define DEC_8 7
|
|
#define DEC_9 8
|
|
|
|
/**
|
|
* Indirection around the standard ## concatenation operator. This simply
|
|
* ensures that the arguments are expanded (once) before concatenation.
|
|
* @param a, b
|
|
* @return Concantinated Token
|
|
*/
|
|
#define CAT(a, b) PRIMITIVECAT(a, b)
|
|
#define PRIMITIVECAT(a, b) a##b
|
|
|
|
#ifdef __sgi
|
|
/**
|
|
* Get the first argument and ignore the rest.
|
|
*/
|
|
#define FIRST_PRE_VA(a) a
|
|
#else
|
|
/**
|
|
* Get the first argument and ignore the rest.
|
|
*/
|
|
# define FIRST_PRE_VA(a,...) a
|
|
#endif
|
|
|
|
#ifdef __sgi
|
|
/**
|
|
* Get the second argument and ignore the rest.
|
|
*/
|
|
# define SECOND_PRE_VA(a, b) b
|
|
#else
|
|
/**
|
|
* Get the second argument and ignore the rest.
|
|
*/
|
|
# define SECOND_PRE_VA(a, b,...) b
|
|
#endif
|
|
|
|
/**
|
|
* Expects a single input (not containing commas). Returns 1 if the input is
|
|
* PROBE() and otherwise returns 0.
|
|
*
|
|
* This can be useful as the basis of a NOT function.
|
|
*
|
|
* This macro abuses the fact that PROBE() contains a comma while other valid
|
|
* inputs must not.
|
|
*/
|
|
#ifdef __sgi
|
|
# define IS_PROBE(a) SECOND_PRE_VA(a, 0)
|
|
# define PROBE() ~, 1
|
|
#else
|
|
# define IS_PROBE(...) SECOND_PRE_VA(__VA_ARGS__,0)
|
|
# define PROBE(...) ~, 1, __VA_ARGS__
|
|
#endif
|
|
|
|
/**
|
|
* Detect Parenthesis
|
|
* @return TRUE/FALSE
|
|
*/
|
|
|
|
#ifdef __sgi
|
|
# define IS_PAREN(x) IS_PROBE(IS_PAREN_PROBE x)
|
|
# define IS_PAREN_PROBE(A) PROBE(~)
|
|
#else
|
|
# define IS_PAREN(...) IS_PROBE(IS_PAREN_PROBE __VA_ARGS__)
|
|
# define IS_PAREN_PROBE(...) PROBE(~) __VA_ARGS__
|
|
#endif
|
|
|
|
#ifdef EXPAND_EXAMPLES
|
|
//IS PAREN
|
|
IS_PAREN((S)) // IS...((s)) Expands to 1
|
|
IS_PAREN(xxx) // IS...(xxx) Expands to 0
|
|
#endif
|
|
|
|
/**
|
|
* Detects if arg or macro is defined as nothing.
|
|
*/
|
|
#define IS_EMPTY(x) _IS_EMPTY(x)
|
|
#define _IS_EMPTY(x) IS_PROBE(CAT(_IS_EMPTY, _##x##_))
|
|
#define _IS_EMPTY__ PROBE(~) /*NULL*/
|
|
|
|
/**
|
|
* Detects if arg or macro is a Bool (1 or 0).
|
|
* Use _IS_BOOL to prevent first expansion (TRUE/FALSE macro)
|
|
* @return TRUE/FALSE
|
|
*/
|
|
#define IS_BOOL(x) _IS_BOOL(x)
|
|
#define _IS_BOOL(x) IS_PROBE(CAT(_IS_BOOL, _##x##_))
|
|
#define _IS_BOOL_TRUE_ PROBE(~)
|
|
#define _IS_BOOL_FALSE_ PROBE(~)
|
|
#define _IS_BOOL_1_ PROBE(~)
|
|
#define _IS_BOOL_0_ PROBE(~)
|
|
|
|
/**
|
|
* Macro version of "defined" however its limited to 1/0/nothing. Any other value
|
|
* is indistuiguishable from a random name
|
|
* Certain pre-defined definitions can be "NOTDEFINED" eg THIS.
|
|
* so checking IF(DEFINED(THIS)) is asking if THIS is NOT defined
|
|
* @return TRUE/FALSE
|
|
*/
|
|
#define DEFINED(x) _DEFINED(x)
|
|
#define _DEFINED(x) IS_PROBE(CAT(_DEFINED, _##x##_))
|
|
#define _DEFINED_0_ PROBE(~)
|
|
#define _DEFINED_1_ PROBE(~)
|
|
#define _DEFINED__ PROBE(~)
|
|
|
|
/*The following names are NOT defined and need to be regarded as NOTDEFINED */
|
|
#define _DEFINED_THIS_ PROBE(~)
|
|
#define _DEFINED_SETUPSUBROUTINES(ID) PROBE(~),
|
|
|
|
/**
|
|
* Logical negation. 0 or nothing is defined as false and everything else as
|
|
* true.
|
|
*
|
|
* When 0, _NOT_0 will be found which evaluates to the PROBE. When 1 (or any
|
|
* other value) is given, an appropriately named macro won't be found and the
|
|
* concatenated string will be produced. IS_PROBE then simply checks to see if
|
|
* the PROBE was returned, cleanly converting the argument into a 1 or 0.
|
|
* @return TRUE/FALSE
|
|
*/
|
|
#define NOT(x) _NOT(x)
|
|
#define _NOT(x) IS_PROBE(CAT(_NOT, _##x##_))
|
|
#define _NOT_0_ PROBE(~)
|
|
#define _NOT__ PROBE(~) /*NULL*/
|
|
|
|
|
|
#ifdef EXPAND_EXAMPLES
|
|
//NOT
|
|
NOT(1) // not 1
|
|
NOT(0) // not 0
|
|
NOT() // not
|
|
NOT(NOT(IS_PAREN(()))) // not !1
|
|
NOT(NOT(0)) // not !0
|
|
NOT(NOT()) // not !
|
|
#endif
|
|
|
|
/**
|
|
* Macro version of C's famous "cast to bool" operator (i.e. !!) which takes
|
|
* anything and casts it to 0 if it is 0 and 1 otherwise.
|
|
* @return TRUE/FALSE
|
|
*/
|
|
#define BOOL(x) NOT(NOT(x))
|
|
|
|
/* this little anoying block may look out of place, but it needs to be right here */
|
|
|
|
/**
|
|
If Statement (Non-Expanding)
|
|
@param c: If True, output the contents of parenthises else output nothing.
|
|
*/
|
|
#define IF_VA(c) _IF_VA(BOOL(c))
|
|
#define _IF_VA(c) CAT(_IF_VA_, c)
|
|
#define _IF_VA_1(a) a
|
|
#define _IF_VA_0(a)
|
|
|
|
/**
|
|
* _VA_ARGS_ for c89
|
|
* Allows up to 32 Args on the stack
|
|
*/
|
|
#define EXPAND_ARGS_STACK(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,ERROR) \
|
|
IF_VA(NOT(IS_EMPTY(A)))/*
|
|
*/(/*
|
|
*/A /*
|
|
*/IF_VA(NOT(IS_EMPTY(B)))/*
|
|
*/(/*
|
|
*/COMMA() B /*
|
|
*/IF_VA(NOT(IS_EMPTY(C)))/*
|
|
*/(/*
|
|
*/COMMA() C /*
|
|
*/IF_VA(NOT(IS_EMPTY(D)))/*
|
|
*/(/*
|
|
*/COMMA() D /*
|
|
*/IF_VA(NOT(IS_EMPTY(E)))/*
|
|
*/(/*
|
|
*/COMMA() E/*
|
|
*/IF_VA(NOT(IS_EMPTY(F)))/*
|
|
*/(/*
|
|
*/COMMA() F /*
|
|
*/IF_VA(NOT(IS_EMPTY(G)))/*
|
|
*/(/*
|
|
*/COMMA() G /*
|
|
*/IF_VA(NOT(IS_EMPTY(H)))/*
|
|
*/(/*
|
|
*/COMMA() H /*
|
|
*/IF_VA(NOT(IS_EMPTY(I)))/*
|
|
*/(/*
|
|
*/COMMA() I /*
|
|
*/IF_VA(NOT(IS_EMPTY(J)))/*
|
|
*/(/*
|
|
*/COMMA() J /*
|
|
*/IF_VA(NOT(IS_EMPTY(K)))/*
|
|
*/(/*
|
|
*/COMMA() K /*
|
|
*/IF_VA(NOT(IS_EMPTY(L)))/*
|
|
*/(/*
|
|
*/COMMA() L /*
|
|
*/IF_VA(NOT(IS_EMPTY(M)))/*
|
|
*/(/*
|
|
*/COMMA() M /*
|
|
*/IF_VA(NOT(IS_EMPTY(N)))/*
|
|
*/(/*
|
|
*/COMMA() N /*
|
|
*/IF_VA(NOT(IS_EMPTY(O)))/*
|
|
*/(/*
|
|
*/COMMA() O /*
|
|
*/IF_VA(NOT(IS_EMPTY(P)))/*
|
|
*/(/*
|
|
*/COMMA() P /*
|
|
*/IF_VA(NOT(IS_EMPTY(Q)))/*
|
|
*/(/*
|
|
*/COMMA() Q /*
|
|
*/IF_VA(NOT(IS_EMPTY(R)))/*
|
|
*/(/*
|
|
*/COMMA() R /*
|
|
*/IF_VA(NOT(IS_EMPTY(S)))/*
|
|
*/(/*
|
|
*/COMMA() S /*
|
|
*/IF_VA(NOT(IS_EMPTY(T)))/*
|
|
*/(/*
|
|
*/COMMA() T /*
|
|
*/IF_VA(NOT(IS_EMPTY(U)))/*
|
|
*/(/*
|
|
*/COMMA() U /*
|
|
*/IF_VA(NOT(IS_EMPTY(V)))/*
|
|
*/(/*
|
|
*/COMMA() V /*
|
|
*/IF_VA(NOT(IS_EMPTY(W)))/*
|
|
*/(/*
|
|
*/COMMA() W /*
|
|
*/IF_VA(NOT(IS_EMPTY(X)))/*
|
|
*/(/*
|
|
*/COMMA() X /*
|
|
*/IF_VA(NOT(IS_EMPTY(Y)))/*
|
|
*/(/*
|
|
*/COMMA() Y /*
|
|
*/IF_VA(NOT(IS_EMPTY(Z)))/*
|
|
*/(/*
|
|
*/COMMA() Z /*
|
|
*/IF_VA(NOT(IS_EMPTY(AA)))/*
|
|
*/(/*
|
|
*/COMMA() AA /*
|
|
*/IF_VA(NOT(IS_EMPTY(AB)))/*
|
|
*/(/*
|
|
*/COMMA() AB /*
|
|
*/IF_VA(NOT(IS_EMPTY(AC)))/*
|
|
*/(/*
|
|
*/COMMA() AC /*
|
|
*/IF_VA(NOT(IS_EMPTY(AD)))/*
|
|
*/(/*
|
|
*/COMMA() AD /*
|
|
*/IF_VA(NOT(IS_EMPTY(AE)))/*
|
|
*/(/*
|
|
*/COMMA() AE /*
|
|
*/IF_VA(NOT(IS_EMPTY(AF)))/*
|
|
*/(/*
|
|
*/COMMA() AF /*
|
|
*/IF_VA(NOT(IS_EMPTY(ERROR)))/*
|
|
*/(/*
|
|
*/COMMA() undefinedlocal = 1/0 "_VA_ARGS Stack full"/*
|
|
*/)/*
|
|
*/) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )
|
|
/**
|
|
* Push/Pop VA Args arrays
|
|
*/
|
|
|
|
#ifdef __sgi
|
|
# define POP_ARG(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF) /*
|
|
*/(IF_VA(IS_PAREN(A))(_POP_ARG A) /*
|
|
ELSE*/IF_VA(NOT(IS_PAREN(A)))(EXPAND_ARGS_STACK(B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF)))
|
|
# define _POP_ARG(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA, AB, AC, AD, AE, AF) EXPAND_ARGS_STACK(B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA, AB, AC, AD, AE, AF)
|
|
#else
|
|
# define POP_ARG(A, ...) (IF_VA(IS_PAREN(A))(_POP_ARG A) IF_VA(NOT(IS_PAREN(A))) (_POP_ARG(A, __VA_ARGS__))
|
|
# define _POP_ARG(A, ...) __VA_ARGS__
|
|
#endif
|
|
# define PUSH_ARG(A,B)(A, TRY_EXPAND(B))
|
|
|
|
/**
|
|
* TRY Expand If Array
|
|
*/
|
|
#define TRY_EXPAND(c) _TRY_EXPAND(IS_PAREN(c))(c)
|
|
#define _TRY_EXPAND(c) CAT(__TRY_EXPAND_, c)
|
|
#ifdef __sgi
|
|
# define __TRY_EXPAND_1(a) EXPAND_ARGS_STACK a
|
|
#else
|
|
# define __TRY_EXPAND_1(A) __TRY_EXPAND_11 A
|
|
# define __TRY_EXPAND_11(...) __VA_ARGS__
|
|
#endif
|
|
#define __TRY_EXPAND_0(a) a
|
|
|
|
|
|
#ifdef __sgi
|
|
/**
|
|
* Get the first argument and ignore the rest.
|
|
*/
|
|
# define FIRST(a) EXPAND(DEFER(FIRST_PRE_VA)(TRY_EXPAND(a)))
|
|
/**
|
|
* Get the second argument and ignore the rest.
|
|
*/
|
|
# define SECOND(a, b) EXPAND(DEFER(SECOND_PRE_VA)(TRY_EXPAND(a), b))
|
|
|
|
#else
|
|
/**
|
|
* Get the first argument and ignore the rest.
|
|
*/
|
|
# define FIRST(A,...) EXPAND(DEFER(FIRST_PRE_VA)(TRY_EXPAND(a)))
|
|
/**
|
|
* Get the second argument and ignore the rest.
|
|
*/
|
|
# define SECOND(a, b,...) EXPAND(DEFER(SECOND_PRE_VA)(TRY_EXPAND(a), b))
|
|
#endif
|
|
|
|
|
|
#ifdef EXPAND_EXAMPLES
|
|
// POP ARG (THIS, IS, a, TEST, hy)
|
|
POP_ARG(THIS, IS, a, TEST, hy)
|
|
// push arg test (this, is, a, test, with, a , is, so, is, a, test, with, a , is, so, is, a, test, with, a , is, so, is, a, test, with, a , is, so)
|
|
PUSH_ARG(test, (this, is, a, test, with, a2 , is2, so, is3, a3, test2, with2, a3 , is4, so4, is5, a4, test3, with3, a6 , is6, so5, is7, a7, test4, with5, a8 , is8, so8))
|
|
#endif
|
|
|
|
/**
|
|
* Logical OR. Simply performs a lookup.
|
|
*/
|
|
#define OR(a, b) CAT(CAT(_OR_, a), b)
|
|
#define _OR_00 0
|
|
#define _OR_01 1
|
|
#define _OR_10 1
|
|
#define _OR_11 1
|
|
/**
|
|
* Logical XOR. Simply performs a lookup.
|
|
*/
|
|
#define XOR(a, b) CAT(CAT(_XOR_, a), b)
|
|
#define _XOR_00 0
|
|
#define _XOR_01 1
|
|
#define _XOR_10 1
|
|
#define _XOR_11 0
|
|
/**
|
|
* Logical AND. Simply performs a lookup.
|
|
*/
|
|
#define AND_CPPLIB(a, b) CAT(CAT(_AND_CPPLIB_, a), b)
|
|
#define _AND_CPPLIB_00 0
|
|
#define _AND_CPPLIB_01 0
|
|
#define _AND_CPPLIB_10 0
|
|
#define _AND_CPPLIB_11 1
|
|
|
|
/**
|
|
* Macro if statement.
|
|
* Usage:
|
|
* IF(condition) \
|
|
* ( \
|
|
* expansion when true \
|
|
* )
|
|
* @param condition
|
|
* @return TRUE/FALSE
|
|
*/
|
|
#define IF(c) _IF(BOOL(c))
|
|
#define _IF(c) CAT(_IF_, c)
|
|
#define _IF_1(a) TRY_EXPAND(a)
|
|
#define _IF_0(a)
|
|
|
|
/**
|
|
* Macro if/else statement.
|
|
* Usage:
|
|
*
|
|
* IF_ELSE(condition)
|
|
* ((
|
|
* expansion when true
|
|
* ))
|
|
* ((
|
|
* expansion when false
|
|
* ))
|
|
* @param condition
|
|
* @return TRUE/FALSE
|
|
*/
|
|
#define IF_ELSE(c) _IF(CAT(E, BOOL(c)))
|
|
#define _IF_E1(a) TRY_EXPAND(a) _IF_1_ELSE
|
|
#define _IF_E0(a) _IF_0_ELSE
|
|
#define _IF_1_ELSE(a)
|
|
#define _IF_0_ELSE(a) TRY_EXPAND(a)
|
|
|
|
|
|
#ifdef EXPAND_EXAMPLES
|
|
//if else 220
|
|
IF_ELSE(220)((it was, non - zero))(it was zero) // Expands to "it was, non Zero"
|
|
//if 06
|
|
IF(06)(NONZERO)
|
|
#endif
|
|
|
|
#if 0
|
|
/*
|
|
* When
|
|
*/
|
|
#define WHEN(c) IF(c)(EVAL1)(EAT)
|
|
#endif
|
|
/**
|
|
* Macro which checks if it has any arguments. Returns '0' if there are no
|
|
* arguments, '1' otherwise.
|
|
* Limitation: HAS_ARGS(,1,2,3) returns 0 -- this check essentially only checks
|
|
* that the first argument exists.
|
|
* @return TRUE/FALSE
|
|
*/
|
|
#ifdef __sgi
|
|
# define HAS_ARGS(a) BOOL(EXPAND(_END_OF_ARGUMENTS_ FIRST(a)()))
|
|
#else
|
|
# define HAS_ARGS(...) BOOL(FIRST(__VA_ARGS__))
|
|
#endif
|
|
#define _END_OF_ARGUMENTS_() 0
|
|
|
|
/*
|
|
for_each(v.begin(), v.end(), [](int &number)
|
|
{
|
|
number++;
|
|
});
|
|
*/
|
|
/**
|
|
* foreach macro
|
|
* @param
|
|
*/
|
|
#define foreach(var, collection) for (var = *collection; var; var++)
|
|
|
|
#ifdef EXPAND_EXAMPLES
|
|
//do I have args?
|
|
//yes
|
|
HAS_ARGS(a, b, c)
|
|
HAS_ARGS((a, b, c))
|
|
//no
|
|
HAS_ARGS()
|
|
HAS_ARGS(())
|
|
HAS_ARGS(( ())) //this one has too many parens
|
|
#endif
|
|
#if 0
|
|
# define test() Im expanded
|
|
DEFER8(test)() EVAL1(EVAL4(DEFER4(test)()))
|
|
|
|
# define RECURSE(X) FIRST X DEFER(_RECURSE)()(POP_ARG X)
|
|
# define _RECURSE() RECURSE
|
|
// RECURSE
|
|
EVAL16(RECURSE((this, is, a, test, WITH, MANY, ARGS)))
|
|
#endif
|
|
#ifdef __sgi
|
|
#define COUNTPARAMS(X) \
|
|
IF_ELSE(IS_PAREN(X)) /*
|
|
*/( /*
|
|
*/EVAL8(COUNTPARAMS_INNER(X, 0)) /*
|
|
*/) /*
|
|
*/( /*
|
|
*/0() /*
|
|
*/)
|
|
#define COUNTPARAMS_INNER(X, COUNT) \
|
|
IF_ELSE(HAS_ARGS(X))/*
|
|
*/( /*
|
|
*/DEFER3(_COUNTPARMS)()(POP_ARG(X), INC(COUNT))/*
|
|
*/) /*
|
|
*/( /*
|
|
*/COUNT /*
|
|
*/)
|
|
# define _COUNTPARMS() COUNTPARAMS_INNER
|
|
#else
|
|
# define ELEVENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, ...) a11
|
|
# define COUNTPARAMS(...) IF_ELSE(IS_PAREN(__VA_ARGS__))(_COUNTPARAMS __VA_ARGS__)(ELEVENTH_ARGUMENT(dummy, ##__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
|
|
# define _COUNTPARAMS(...) ELEVENTH_ARGUMENT(dummy, ##__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
|
#endif
|
|
|
|
#ifdef EXPAND_EXAMPLES
|
|
// COUNTPARAMS - IT WORKS!!!, THIS WILL BE GREAT FOR AI
|
|
//0
|
|
COUNTPARAMS(())
|
|
//1
|
|
COUNTPARAMS((A))
|
|
// 2
|
|
COUNTPARAMS((A, B))
|
|
// 3
|
|
COUNTPARAMS((A, B, C))
|
|
// 4
|
|
COUNTPARAMS((A, B, C, D))
|
|
// 5
|
|
COUNTPARAMS((A, B, C, D, E))
|
|
// 6
|
|
COUNTPARAMS((A, B, C, D, E, F))
|
|
// 7
|
|
COUNTPARAMS((A, B, C, D, E, F, G))
|
|
// 8
|
|
COUNTPARAMS((A, B, C, D, E, F, G, H))
|
|
// 9
|
|
COUNTPARAMS((A, B, C, D, E, F, G, H, I))
|
|
|
|
#endif
|
|
#if 0
|
|
#define LIST_TO_TUPLE(list) \
|
|
IF_ELSE(IS_PAREN(list))\
|
|
(\
|
|
EVAL16((LIST_TO_TUPLE_INNER(SECOND list, FIRST list)))\
|
|
)\
|
|
(\
|
|
list\
|
|
)
|
|
|
|
#define LIST_TO_TUPLE_INNER(list, listb) \
|
|
IF_ELSE(HAS_ARGS(list)) \
|
|
(\
|
|
EXPAND(DEFER4(_LIST_TO_TUPLE_INNER)()(TRY_EXPAND((POP_ARG list)), PUSH_ARG(FIRST list, listb)))\
|
|
)\
|
|
(\
|
|
0 listb\
|
|
)
|
|
#define _LIST_TO_TUPLE_INNER() LIST_TO_TUPLE_INNER
|
|
// list to tuple
|
|
LIST_TO_TUPLE((this, (is, (a, (li8st, (lots, (of, (test, (another, )))))))))
|
|
//SINGLE
|
|
LIST_TO_TUPLE((this,(is)))
|
|
|
|
#endif
|
|
|
|
#define REPEAT(count, macro, a) \
|
|
IF_ELSE(DEC(count)) \
|
|
(DEFER3(REPEAT_INDIRECT)()(DEC(count), macro, a))( \
|
|
/* Do nothing, just terminate */) DEFER(macro)(DEC(count), a)
|
|
|
|
#define REPEAT_INDIRECT() REPEAT
|
|
#ifdef EXPAND_EXAMPLES
|
|
// An example of repeat 9
|
|
# define M(i, _) i
|
|
EVAL16(REPEAT(9, M, ~)) // 0 1 2 3 4 5 6 7 8
|
|
#endif
|
|
|
|
#define WHILE(pred, op, a) \
|
|
IF(pred(a)) \
|
|
(DEFER2(WHILE_INDIRECT)()(pred, op, op(a)), POP_ARG a)
|
|
#define WHILE_INDIRECT() WHILE
|
|
|
|
/**
|
|
* Macro map/list comprehension. Usage:
|
|
*
|
|
* MAP(op, sep, ...)
|
|
*
|
|
* Produces a 'sep()'-separated list of the result of op(arg) for each arg.
|
|
*
|
|
* Example Usage:
|
|
*
|
|
* #define MAKE_HAPPY(x) happy_##x
|
|
* #define COMMA() ,
|
|
* MAP(MAKE_HAPPY, COMMA, 1,2,3)
|
|
*
|
|
* Which expands to:
|
|
*
|
|
* happy_1 , happy_2 , happy_3
|
|
*/
|
|
#define MAP(op, sep, a) \
|
|
IF_ELSE(HAS_ARGS a) \
|
|
(EVAL(MAP_INNER(op, sep, a)))(/* Do nothing, just terminate */)
|
|
#define MAP_INNER(op, sep, a) \
|
|
DEFER(op) \
|
|
(FIRST a) IF_ELSE(DEFER(HAS_ARGS) POP_ARG a)(EXPAND EMSPTY()( \
|
|
sep() OBSTRUCT(_MAP_INNER)()(op, sep, EXPAND(POP_ARG a))))( \
|
|
/* Do nothing, just terminate */)
|
|
#define _MAP_INNER() MAP_INNER
|
|
|
|
/*MAP(MAKE_HAPPY, COMMA, (1,2,3,A))*/
|
|
#endif
|
|
|