-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathapplyxn-generator.py
120 lines (105 loc) · 4.9 KB
/
applyxn-generator.py
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import sys
from functools import partial
applyxn_head = '''
#ifndef APPLYXN_H
#define APPLYXN_H
/**
This code auto-generated by `applyxn.py` written by Elad Nachmias.
APPLYXn basically receives a macro name and a variable number of items, then applies the macro on each item one-by-one.
APPLYXn optionally receives additional arguments to pass to the applied macro.
Synopsis: APPLYXn(MACRO_NAME, (AdditionalArgument(s)[, ...]), item_1, ..., item_n)
In each application of MACRO_NAME(..) it gets: MACRO_NAME(T,N,additional arg(s)[, ...], ITEM), where:
`T` is the total number of items that APPLYXn got;
`N` is the number of the current item;
additional args are passed (if given to `APPLYXn(..)`)
(you can pass to APPLYXn none, single, or more than one additional args,
in the last case you should wrap them in parentheses,
they'll be automatically stripped-off when sending the args to the MACRO_NAME macro,
as will be shown in the following example);
`ITEM` is the N-th item passed to `APPLYXn` (after the additional arguments).
EXAMPLE:
#define A(T,N,AdditionalArgs,item) \\
C(T,N,AdditionalArgs,item);
APPLYXn(A, (1,2,3), 'a', 'b', 'c', 'd', 'e', 'f')
// Expands to:
// C(6,1,1,2,3,'a'); C(6,2,1,2,3,'b'); C(6,3,1,2,3,'c'); C(6,4,1,2,3,'d'); C(6,5,1,2,3,'e'); C(6,6,1,2,3,'f');
APPLYXn(A, (), 'a', 'b', 'c', 'd', 'e', 'f')
// Expands to:
// C(6,1,,'a'); C(6,2,,'b'); C(6,3,,'c'); C(6,4,,'d'); C(6,5,,'e'); C(6,6,,'f');
APPLYXn(A, 1, 'a', 'b', 'c', 'd', 'e', 'f')
// Expands to:
// C(6,1,1,'a'); C(6,2,1,'b'); C(6,3,1,'c'); C(6,4,1,'d'); C(6,5,1,'e'); C(6,6,1,'f');
APPLYXn(A, , 'a', 'b', 'c', 'd', 'e', 'f')
// Expands to:
// C(6,1,,'a'); C(6,2,,'b'); C(6,3,,'c'); C(6,4,,'d'); C(6,5,,'e'); C(6,6,,'f');
**/
#define _Args(...) __VA_ARGS__
#define STRIP_PARENS(X) X
#define PASS_PARAMETERS(X) STRIP_PARENS( _Args X )
/* Macro logics to determine whether to STRIP_PARENS() for the additional arg or not.
So that additional args could be: pass one, omitted, pass many inside parens. example:
APPLYXn(TEST, (1,2,3), 'a', 'b', 'c', 'd', 'e', 'f');
APPLYXn(TEST, (), 'a', 'b', 'c', 'd', 'e', 'f');
APPLYXn(TEST, 1, 'a', 'b', 'c', 'd', 'e', 'f');
APPLYXn(TEST, , 'a', 'b', 'c', 'd', 'e', 'f');
*/
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define PROBE(x) x, 1,
#define IS_PAREN(x) CHECK(IS_PAREN_PROBE x)
#define IS_PAREN_PROBE(...) PROBE(~)
#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define PASS_PARAMS(X) IIF(IS_PAREN(X))(PASS_PARAMETERS(X),X)
#define PP_NARG(...) PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \\
_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, \\
_61,_62,_63,N,...) N
#define PP_RSEQ_N() \\
63,62,61,60, \\
59,58,57,56,55,54,53,52,51,50, \\
49,48,47,46,45,44,43,42,41,40, \\
39,38,37,36,35,34,33,32,31,30, \\
29,28,27,26,25,24,23,22,21,20, \\
19,18,17,16,15,14,13,12,11,10, \\
9,8,7,6,5,4,3,2,1,0
/* need extra level to force extra eval */
#define Paste(a,b) a ## b
#define XPASTE(a,b) Paste(a,b)\n\n\n'''
def generate_applyxn(max_nargs=64, depth=1, out_file=sys.stdout):
fprint = partial(print, file=out_file, end='')
fprint(applyxn_head)
for depth in range(depth):
str_depth = '_'*depth
for cur_nargs in range(1, max_nargs+1):
fprint('#define APPLYX{str_depth}{nargs}(X, AdditionalArgs, {args}) \\\n'.format(
str_depth=str_depth,
nargs=cur_nargs,
args=', '.join(('a'+str(i) for i in range(1, cur_nargs+1)))
))
fprint(' ')
for i in range(1, cur_nargs + 1):
if i > 1 and (i-1) % 3 == 0:
fprint('\\\n ')
fprint('X({total_nargs}, {cur_arg_num}, PASS_PARAMS(AdditionalArgs), a{cur_arg_num}) '.format(
total_nargs=cur_nargs,
cur_arg_num=i
))
fprint('\n')
fprint('#define APPLYX_AUX{str_depth}(X,AdditionalArgs,APPLYXM, ...) APPLYXM(X,AdditionalArgs,__VA_ARGS__)\n'
.format(str_depth=str_depth))
fprint('#define APPLYX{str_depth}n(X,AdditionalArgs,...) APPLYX_AUX{str_depth}(X,AdditionalArgs,XPASTE(APPLYX{str_depth}, PP_NARG(__VA_ARGS__)), __VA_ARGS__)\n'
.format(str_depth=str_depth))
fprint('\n\n')
fprint('#endif /* APPLYXN_H */\n')
if __name__ == '__main__':
with open('applyxn.h', 'w') as applyxn_h_file:
generate_applyxn(64, 10, out_file=applyxn_h_file)