1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2016 Intel Corporation. All rights reserved.
4  *
5  * Author: Michal Jerzy Wierzbicki <michalx.wierzbicki@intel.com>
6  */
7 
8 /* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY */
9 
10 #ifdef __SOF_TRACE_PREPROC_H__
11 /* Macros defined in this file are only helpers for the macros that are
12  * defined in header file containing "namespace"
13  *     __SOF_TRACE_PREPROC_H__ .
14  * This combination of #ifdef and #ifndef should sufficently narrow
15  * the "include-ability" of this dependent header file.
16  * If you wish to use macros from this file directly, be *V E R Y* careful!
17  * HIC SUNT DRACONES
18  */
19 #ifndef __SOF_TRACE_PREPROC_PRIVATE_H__
20 #define __SOF_TRACE_PREPROC_PRIVATE_H__
21 
22 /* Include
23  * #define _META_DEC_0   0
24  * #define _META_DEC_1   1
25  * #define _META_DEC_2   1
26  * #define _META_DEC_3   2
27  * ...
28  * #define _META_DEC_N   N-1
29  */
30 #include <sof/trace/preproc-private-dec.h>
31 /* Include
32  * #define _META_INC_0   1
33  * #define _META_INC_1   2
34  * ...
35  * #define _META_INC_N-1 N
36  * #define _META_INC_N   N
37  */
38 #include <sof/trace/preproc-private-inc.h>
39 
40 /* count number of var args - during preprocesing
41  * works for predefined number of args
42  * META_COUNT_VARAGS_BEFORE_COMPILE(A,B,C,D) evaluates to 4
43  */
44 #define _META_PP_NARG_BEFORE_COMPILE_(...) \
45 	_META_PP_ARG_N(__VA_ARGS__)
46 
47 #define _META_PP_ARG_N(\
48 	_1,   _2,  _3,  _4,  _5,  _6,  _7,  _8,  _9, _10, \
49 	_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
50 	_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
51 	_31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
52 	_41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
53 	_51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
54 	_61, _62, _63, N, ...) N
55 
56 #define _META_PP_RSEQ_N() \
57 	63, 62, 61, 60, \
58 	59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \
59 	49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \
60 	39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \
61 	29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \
62 	19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
63 	 9,  8,  7,  6,  5,  4,  3,  2,  1,  0
64 
65 /* treat x as string while forcing x expansion beforehand */
66 #define _META_QUOTE(x) #x
67 
68 /* concat x and y while forcing x and y expansion beforehand */
69 #define _META_CONCAT_BASE(x, y) x##y
70 
71 /* discard first x-1 args in vararg and return the xth arg */
72 #define _META_GET_ARG_1(arg1, ...) arg1
73 #define _META_GET_ARG_2(arg1, arg2, ...) arg2
74 /* TODO: GET_ARG version for arbitrary x>2 should be possible using
75  * META_RECURSE(META_REPEAT
76  */
77 
78 #define _META_NO_ARGS(...) 0
79 
80 /* _META_IS_PROBE(...) evaluates to 0 when __VA_ARGS__ is single token
81  * _META_IS_PROBE(PROBE()) evaulates to 1, because it is equivalent to
82  * _META_GET_ARG_2(~, 1, 0)
83  * ~ is no special value, it is just a meaningless placeholder,
84  * it could be something else if that thing would also have no meaning
85  * but be a valid C
86  */
87 #define _META_IS_PROBE(...) _META_GET_ARG_2(__VA_ARGS__, 0)
88 #define _META_PROBE() ~, 1
89 
90 /* _META_NOT_0 evaluates to '~, 1'
91  * _META_NOT_1 evaluates to '_META_NOT_1' (because it is not a macro)
92  * _META_IS_PROBE(_META_NOT_0) evaluates to 1, because it is equivalent to
93  * _META_GET_ARG_2(~, 1, 0)
94  * _META_IS_PROBE(_NOT_1)      evaluates to 0, because it is equivalent to
95  * _META_GET_ARG_2(_NOT_1, 0)
96  *
97  * notice, that any x!=0 would also result in 0
98  * e.x. META_NOT(123) evaluates to 0
99  */
100 #define _META_NOT_0 _META_PROBE()
101 
102 /* indirection forces condition to be "cast" to 0 1
103  * then for 0 discard first (), and for 1 discard second ()
104  * so  META_IF_ELSE(0)(a)(b) expands to b,
105  * and META_IF_ELSE(1)(a)(b) expands to a
106  */
107 #define _META_IF_ELSE(condition) META_CONCAT(_META_IF_, condition)
108 
109 #define _META_IF_1(...) __VA_ARGS__ _META_IF_1_ELSE
110 #define _META_IF_0(...)             _META_IF_0_ELSE
111 
112 #define _META_IF_1_ELSE(...)
113 #define _META_IF_0_ELSE(...) __VA_ARGS__
114 
115 #define _META_IIF(condition) META_CONCAT(_META_IIF_, condition)
116 #define _META_IIF_0(x, ...) __VA_ARGS__
117 #define _META_IIF_1(x, ...) x
118 
119 /* primitive recursion */
120 #define _META_REQRS_8(...)    _META_REQRS_4(  _META_REQRS_4  (__VA_ARGS__))
121 #define _META_REQRS_4(...)    _META_REQRS_2(  _META_REQRS_2  (__VA_ARGS__))
122 #define _META_REQRS_2(...)    _META_REQRS_1(  _META_REQRS_1  (__VA_ARGS__))
123 #define _META_REQRS_1(...) __VA_ARGS__
124 
125 /* Delay macro m expansion depth times
126  * IT IS CRUCIAL FOR NO #define _META_EMPTY macro to exist!!!
127  * _META_DEFER_N(depth) will work for any depth valid in META_REPEAT
128  * (which is confined only by META_DEC).
129  * _META_DEFER_N will NOT work inside META_REPEAT, because
130  * _META_DEFER_N uses META_REPEAT as seen below.
131  * In order for META_REPEAT to work (which also requires DEFER functionality)
132  * a duplicate, implicit _META_DEFER_2(m) has to be defined.
133  * It is because how the c preprocesor works.
134  */
135 #define _META_EMPTY()
136 
137 /* These two will expand to:
138  * _META_EMPTY _META_EMPTY ... _META_EMPTY
139  * () () ... ()
140  * Why '_META_EMPTY() _META_EMPTY' instead of '_META_EMPTY'?
141  * Using simply '_META_EMPTY' would produce
142  * _META_EMPTY_META_EMPTY_META_EMPTY
143  * and adding _META_EMPTY() introduces a " "(space) token.
144  */
145 #define _META_EMPTY_GEN(i, rest) _META_EMPTY() _META_EMPTY
146 #define _META_PAREN_GEN(i, rest) ()
147 /* You cannot use here META_RECURSE
148  * and must instead use _META_REQRS_{NUMBER}.
149  * If META_RECURSE was used, things like
150  * META_RECURSE(MAP_AGGREGATE
151 * would break.
152  */
153 #define _META_DEFER_N(depth) \
154 	META_RECURSE_N(8, META_REPEAT(depth, _META_EMPTY_GEN, ~)) \
155 	META_RECURSE_N(8, META_REPEAT(depth, _META_PAREN_GEN, ~))
156 
157 /* Special, implicit defer implementation for META_REPEAT to work */
158 #define _META_DEFER_2(m) m _META_EMPTY _META_EMPTY () ()
159 
160 /* helpers for consuming every single arg from __VA_ARGS__ */
161 // expand and discard
162 #define _META_EAT(...)
163 // force expansion, reverse of META_DEFER
164 #define _META_EXPAND(...) __VA_ARGS__
165 #define _META_WHEN(c) META_IF(c)(_META_EXPAND, _META_EAT)
166 
167 /* while(count--!=0) do
168  * uses DEC so count == N can only work if all following exist
169  * DEC_0, DEC_1, ..., DEC_N-1, DEC_N
170  */
171 #define _META_REPEAT_INDIRECT() META_REPEAT
172 
173 /* map every group of arg_count arguments onto function m
174  * i.e. arg_count=2;m=ADD;args=1,2,3,4,5,6,7...
175  * results in ADD(1,2) ADD(3,4) ADD(5,6) and so on
176  * MAP##N must exist for arg_count == N to work
177  */
178 #define _META_MAP() META_MAP
179 
180 /* implements MAP(1, m, ...) */
181 #define _META_MAP_1(m, arg1, ...)\
182 	m(arg1)\
183 	_META_DEFER_2(_META_MAP_BODY_TMP)()(1, m, __VA_ARGS__)
184 
185 /* implements MAP(2, m, ...) */
186 #define _META_MAP_2(m, arg1, arg2, ...)\
187 	m(arg1, arg2)\
188 	_META_DEFER_2(_META_MAP_BODY_TMP)()(2, m, __VA_ARGS__)
189 
190 /* implements MAP(3, m, ...) */
191 #define _META_MAP_3(m, arg1, arg2, arg3, ...)\
192 	m(arg1, arg2, arg3)\
193 	_META_DEFER_2(_META_MAP_BODY_TMP)()(3, m, __VA_ARGS__)
194 
195 /* used by macro MAP, don't use on its own */
196 #define _META_MAP_BODY(arg_count, m, ...)\
197 	META_IF_ELSE(META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__))(\
198 		META_CONCAT(_META_MAP_, arg_count)(m, __VA_ARGS__) \
199 	)()
200 #define _META_MAP_BODY_TMP() _META_MAP_BODY
201 
202 /* map aggregator and every group of arg_count arguments onto function m
203  * i.e. aggr=x;arg_count=1;m=ADD;args=1,2,3,4,5,6,7...
204  * results in x = ... ADD(7,ADD(6,ADD(5,ADD(4,ADD(3,ADD(2,ADD(1,x))))))) ...
205  * MAP##N must exist for arg_count == N to work
206  */
207 #define _META_MAP_AGGREGATE() META_MAP_AGGREGATE
208 
209 /* implements MAP_AGGREGATE(1, m, ...) */
210 #define _META_MAP_AGGREGATE_1(m, aggr, arg1, ...)\
211 	_META_MAP_AGGREGATE_BODY(1, m, m(aggr, arg1), __VA_ARGS__)
212 
213 /* implements MAP_AGGREGATE(2, m, ...) */
214 #define _META_MAP_AGGREGATE_2(m, aggr, arg1, arg2, ...)\
215 	_META_MAP_AGGREGATE_BODY(2, m, m(aggr, arg1, arg2), __VA_ARGS__)
216 
217 /* used by macro MAP_AGGREGATE, don't use on its own */
218 #define _META_MAP_AGGREGATE_BODY(arg_count, m, aggr, ...)\
219 	META_IF_ELSE(META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__))(\
220 		_META_DEFER_2(_META_MAP_AGGREGATE)()\
221 			(arg_count, m, aggr, __VA_ARGS__)\
222 	)(aggr)
223 
224 /* META_CONCAT with parametrised delimeter between concatenised tokens
225  * META_CONCAT_SEQ_DELIM_(A,B,C,D) tokenizes as A_B_C_D
226  */
227 #define _META_CONCAT_DELIM(delim, x, y) META_CONCAT(META_CONCAT(x, delim),y)
228 #define _META_CONCAT_DELIM_(x, y) _META_CONCAT_DELIM(_, x, y)
229 
230 /* UNUSED private macros */
231 #define _META_VOID(x) (void)(x)
232 #define _META_VOID2(x, y) x; _META_VOID(y)
233 
234 #endif /* __SOF_TRACE_PREPROC_PRIVATE_H__ */
235 #else
236 	#error \
237 		Illegal use of header file: \
238 		can only be included from context of \
239 		__INCLUDE_MACRO_METAPROGRAMMING__
240 #endif /* __SOF_TRACE_PREPROC_H__ */
241