xref: /aosp_15_r20/external/pigweed/pw_preprocessor/public/pw_preprocessor/arguments.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 // Macros for working with arguments to function-like macros.
16 #pragma once
17 
18 #include "pw_preprocessor/boolean.h"
19 #include "pw_preprocessor/compiler.h"
20 #include "pw_preprocessor/internal/arg_count_impl.h"
21 
22 // Expands to a comma followed by __VA_ARGS__, if __VA_ARGS__ is non-empty.
23 // Otherwise, expands to nothing. If the final argument is empty, it is omitted.
24 // This is useful when passing __VA_ARGS__ to a variadic function or template
25 // parameter list, since it removes the extra comma when no arguments are
26 // provided. PW_COMMA_ARGS must NOT be used when invoking a macro from another
27 // macro.
28 //
29 // This is a more flexible, standard-compliant version of ##__VA_ARGS__. Unlike
30 // ##__VA_ARGS__, this can be used to eliminate an unwanted comma when
31 // __VA_ARGS__ expands to an empty argument because an outer macro was called
32 // with __VA_ARGS__ instead of ##__VA_ARGS__. Also, since PW_COMMA_ARGS drops
33 // the last argument if it is empty, both MY_MACRO(1, 2) and MY_MACRO(1, 2, )
34 // can work correctly.
35 //
36 // PW_COMMA_ARGS must NOT be used to conditionally include a comma when invoking
37 // a macro from another macro. PW_COMMA_ARGS only functions correctly when the
38 // macro expands to C or C++ code! Using it with intermediate macros can result
39 // in out-of-order parameters. When invoking one macro from another, simply pass
40 // __VA_ARGS__. Only the final macro that expands to C/C++ code should use
41 // PW_COMMA_ARGS.
42 //
43 // For example, the following does NOT work:
44 /*
45      #define MY_MACRO(fmt, ...) \
46          NESTED_MACRO(fmt PW_COMMA_ARGS(__VA_ARGS__))  // BAD! Do not do this!
47 */
48 // Instead, only use PW_COMMA_ARGS when the macro expands to C/C++ code:
49 /*
50      #define MY_MACRO(fmt, ...) \
51          NESTED_MACRO(fmt, __VA_ARGS__)  // Pass __VA_ARGS__ to nested macros
52 
53      #define NESTED_MACRO(fmt, ...) \
54          printf(fmt PW_COMMA_ARGS(__VA_ARGS__))  // PW_COMMA_ARGS is OK here
55 */
56 #define PW_COMMA_ARGS(...)                                       \
57   _PW_IF(PW_EMPTY_ARGS(__VA_ARGS__), _PW_EXPAND, _PW_COMMA_ARGS) \
58   (PW_DROP_LAST_ARG_IF_EMPTY(__VA_ARGS__))
59 
60 #define _PW_COMMA_ARGS(...) , __VA_ARGS__
61 
62 // Allows calling a different function-like macros based on the number of
63 // arguments. For example:
64 //
65 //   #define ARG_PRINT(...)  PW_DELEGATE_BY_ARG_COUNT(_ARG_PRINT, __VA_ARGS__)
66 //   #define _ARG_PRINT1(a)        LOG_INFO("1 arg: %s", a)
67 //   #define _ARG_PRINT2(a, b)     LOG_INFO("2 args: %s, %s", a, b)
68 //   #define _ARG_PRINT3(a, b, c)  LOG_INFO("3 args: %s, %s, %s", a, b, c)
69 //
70 // This can the be called from C/C++ code:
71 //
72 //    ARG_PRINT("a");            // Outputs: 1 arg: a
73 //    ARG_PRINT("a", "b");       // Outputs: 2 args: a, b
74 //    ARG_PRINT("a", "b", "c");  // Outputs: 3 args: a, b, c
75 //
76 #define PW_DELEGATE_BY_ARG_COUNT(function, ...)                 \
77   _PW_DELEGATE_BY_ARG_COUNT(                                    \
78       _PW_PASTE2(function, PW_FUNCTION_ARG_COUNT(__VA_ARGS__)), \
79       PW_DROP_LAST_ARG_IF_EMPTY(__VA_ARGS__))
80 
81 #define _PW_DELEGATE_BY_ARG_COUNT(function, ...) function(__VA_ARGS__)
82 
83 // PW_MACRO_ARG_COUNT counts the number of arguments it was called with. It
84 // evalulates to an integer literal in the range 0 to 64. Counting more than 64
85 // arguments is not currently supported.
86 //
87 // PW_MACRO_ARG_COUNT is most commonly used to count __VA_ARGS__ in a variadic
88 // macro. For example, the following code counts the number of arguments passed
89 // to a logging macro:
90 //
91 /*   #define LOG_INFO(format, ...) {                                   \
92          static const int kArgCount = PW_MACRO_ARG_COUNT(__VA_ARGS__); \
93          SendLog(kArgCount, format, ##__VA_ARGS__);                    \
94        }
95 */
96 // The macro argument lists were generated with a Python script:
97 /*
98 COUNT = 256
99 
100 for i in range(COUNT, 0, -1):
101     if i % 8 == 0:
102         print('\ \n', end='')
103     print(f"{i:3}, ", end='')
104 
105 for i in range(COUNT, 0, -1):
106     if i % 8 == 0:
107         print('\ \n', end='')
108     print(f"a{i:03}, ", end='')
109 */
110 // clang-format off
111 #define PW_MACRO_ARG_COUNT(...)               \
112   _PW_MACRO_ARG_COUNT_IMPL(__VA_ARGS__,       \
113       256, 255, 254, 253, 252, 251, 250, 249, \
114       248, 247, 246, 245, 244, 243, 242, 241, \
115       240, 239, 238, 237, 236, 235, 234, 233, \
116       232, 231, 230, 229, 228, 227, 226, 225, \
117       224, 223, 222, 221, 220, 219, 218, 217, \
118       216, 215, 214, 213, 212, 211, 210, 209, \
119       208, 207, 206, 205, 204, 203, 202, 201, \
120       200, 199, 198, 197, 196, 195, 194, 193, \
121       192, 191, 190, 189, 188, 187, 186, 185, \
122       184, 183, 182, 181, 180, 179, 178, 177, \
123       176, 175, 174, 173, 172, 171, 170, 169, \
124       168, 167, 166, 165, 164, 163, 162, 161, \
125       160, 159, 158, 157, 156, 155, 154, 153, \
126       152, 151, 150, 149, 148, 147, 146, 145, \
127       144, 143, 142, 141, 140, 139, 138, 137, \
128       136, 135, 134, 133, 132, 131, 130, 129, \
129       128, 127, 126, 125, 124, 123, 122, 121, \
130       120, 119, 118, 117, 116, 115, 114, 113, \
131       112, 111, 110, 109, 108, 107, 106, 105, \
132       104, 103, 102, 101, 100,  99,  98,  97, \
133        96,  95,  94,  93,  92,  91,  90,  89, \
134        88,  87,  86,  85,  84,  83,  82,  81, \
135        80,  79,  78,  77,  76,  75,  74,  73, \
136        72,  71,  70,  69,  68,  67,  66,  65, \
137        64,  63,  62,  61,  60,  59,  58,  57, \
138        56,  55,  54,  53,  52,  51,  50,  49, \
139        48,  47,  46,  45,  44,  43,  42,  41, \
140        40,  39,  38,  37,  36,  35,  34,  33, \
141        32,  31,  30,  29,  28,  27,  26,  25, \
142        24,  23,  22,  21,  20,  19,  18,  17, \
143        16,  15,  14,  13,  12,  11,  10,   9, \
144         8,   7,   6,   5,   4,   3,   2, PW_HAS_ARGS(__VA_ARGS__))
145 
146 
147 #define _PW_MACRO_ARG_COUNT_IMPL(                   \
148     a256, a255, a254, a253, a252, a251, a250, a249, \
149     a248, a247, a246, a245, a244, a243, a242, a241, \
150     a240, a239, a238, a237, a236, a235, a234, a233, \
151     a232, a231, a230, a229, a228, a227, a226, a225, \
152     a224, a223, a222, a221, a220, a219, a218, a217, \
153     a216, a215, a214, a213, a212, a211, a210, a209, \
154     a208, a207, a206, a205, a204, a203, a202, a201, \
155     a200, a199, a198, a197, a196, a195, a194, a193, \
156     a192, a191, a190, a189, a188, a187, a186, a185, \
157     a184, a183, a182, a181, a180, a179, a178, a177, \
158     a176, a175, a174, a173, a172, a171, a170, a169, \
159     a168, a167, a166, a165, a164, a163, a162, a161, \
160     a160, a159, a158, a157, a156, a155, a154, a153, \
161     a152, a151, a150, a149, a148, a147, a146, a145, \
162     a144, a143, a142, a141, a140, a139, a138, a137, \
163     a136, a135, a134, a133, a132, a131, a130, a129, \
164     a128, a127, a126, a125, a124, a123, a122, a121, \
165     a120, a119, a118, a117, a116, a115, a114, a113, \
166     a112, a111, a110, a109, a108, a107, a106, a105, \
167     a104, a103, a102, a101, a100, a099, a098, a097, \
168     a096, a095, a094, a093, a092, a091, a090, a089, \
169     a088, a087, a086, a085, a084, a083, a082, a081, \
170     a080, a079, a078, a077, a076, a075, a074, a073, \
171     a072, a071, a070, a069, a068, a067, a066, a065, \
172     a064, a063, a062, a061, a060, a059, a058, a057, \
173     a056, a055, a054, a053, a052, a051, a050, a049, \
174     a048, a047, a046, a045, a044, a043, a042, a041, \
175     a040, a039, a038, a037, a036, a035, a034, a033, \
176     a032, a031, a030, a029, a028, a027, a026, a025, \
177     a024, a023, a022, a021, a020, a019, a018, a017, \
178     a016, a015, a014, a013, a012, a011, a010, a009, \
179     a008, a007, a006, a005, a004, a003, a002, a001, \
180     count, ...)                                     \
181   count
182 
183 // clang-format on
184 
185 // Argument count for using with a C/C++ function or template parameter list.
186 // The difference from PW_MACRO_ARG_COUNT is that the last argument is not
187 // counted if it is empty. This makes it easier to drop the final comma when
188 // expanding to C/C++ code.
189 #define PW_FUNCTION_ARG_COUNT(...) \
190   _PW_FUNCTION_ARG_COUNT(PW_LAST_ARG(__VA_ARGS__), __VA_ARGS__)
191 
192 #define _PW_FUNCTION_ARG_COUNT(last_arg, ...) \
193   _PW_PASTE2(_PW_FUNCTION_ARG_COUNT_, PW_EMPTY_ARGS(last_arg))(__VA_ARGS__)
194 
195 #define _PW_FUNCTION_ARG_COUNT_0 PW_MACRO_ARG_COUNT
196 #define _PW_FUNCTION_ARG_COUNT_1(...) \
197   PW_MACRO_ARG_COUNT(PW_DROP_LAST_ARG(__VA_ARGS__))
198 
199 // Evaluates to the last argument in the provided arguments.
200 #define PW_LAST_ARG(...) \
201   _PW_PASTE2(_PW_LAST_ARG_, PW_MACRO_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__)
202 
203 // Evaluates to the provided arguments, excluding the final argument.
204 #define PW_DROP_LAST_ARG(...) \
205   _PW_PASTE2(_PW_DROP_LAST_ARG_, PW_MACRO_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__)
206 
207 // Evaluates to the arguments, excluding the final argument if it is empty.
208 #define PW_DROP_LAST_ARG_IF_EMPTY(...)                                       \
209   _PW_IF(                                                                    \
210       PW_EMPTY_ARGS(PW_LAST_ARG(__VA_ARGS__)), PW_DROP_LAST_ARG, _PW_EXPAND) \
211   (__VA_ARGS__)
212 
213 // Expands to 1 if one or more arguments are provided, 0 otherwise.
214 #define PW_HAS_ARGS(...) PW_NOT(PW_EMPTY_ARGS(__VA_ARGS__))
215 
216 #if PW_VA_OPT_SUPPORTED()
217 
218 // Expands to 0 if one or more arguments are provided, 1 otherwise.
219 #define PW_EMPTY_ARGS(...) _PW_EMPTY_ARGS_##__VA_OPT__(0)
220 #define _PW_EMPTY_ARGS_ 1
221 #define _PW_EMPTY_ARGS_0 0
222 
223 #else
224 
225 // If __VA_OPT__ is not available, use a complicated fallback mechanism. This
226 // approach is from Jens Gustedt's blog:
227 //   https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
228 //
229 // Normally, with a standard-compliant C preprocessor, it's impossible to tell
230 // whether a variadic macro was called with no arguments or with one argument.
231 // A macro invoked with no arguments is actually passed one empty argument.
232 //
233 // This macro works by checking for the presence of a comma in four situations.
234 // These situations give the following information about __VA_ARGS__:
235 //
236 //   1. It is two or more variadic arguments.
237 //   2. It expands to one argument surrounded by parentheses.
238 //   3. It is a function-like macro that produces a comma when invoked.
239 //   4. It does not interfere with calling a macro when placed between it and
240 //      parentheses.
241 //
242 // If a comma is not present in 1, 2, 3, but is present in 4, then __VA_ARGS__
243 // is empty. For this case (0001), and only this case, a corresponding macro
244 // that expands to a comma is defined. The presence of this comma determines
245 // whether any arguments were passed in.
246 #define PW_EMPTY_ARGS(...)                                             \
247   _PW_HAS_NO_ARGS(_PW_HAS_COMMA(__VA_ARGS__),                          \
248                   _PW_HAS_COMMA(_PW_MAKE_COMMA_IF_CALLED __VA_ARGS__), \
249                   _PW_HAS_COMMA(__VA_ARGS__()),                        \
250                   _PW_HAS_COMMA(_PW_MAKE_COMMA_IF_CALLED __VA_ARGS__()))
251 
252 // clang-format off
253 #define _PW_HAS_COMMA(...)                                           \
254   _PW_MACRO_ARG_COUNT_IMPL(__VA_ARGS__,                              \
255   /*  16 */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
256   /*  32 */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
257   /*  48 */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
258   /*  64 */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
259   /*     */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
260   /*     */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
261   /*     */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
262   /* 128 */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
263   /*     */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
264   /*     */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
265   /*     */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
266   /* 196 */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
267   /*     */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
268   /*     */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
269   /*     */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
270   /* 256 */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
271 // clang-format on
272 
273 #define _PW_HAS_NO_ARGS(a1, a2, a3, a4) \
274   _PW_HAS_COMMA(_PW_PASTE_RESULTS(a1, a2, a3, a4))
275 #define _PW_PASTE_RESULTS(a1, a2, a3, a4) _PW_HAS_COMMA_CASE_##a1##a2##a3##a4
276 #define _PW_HAS_COMMA_CASE_0001 ,
277 #define _PW_MAKE_COMMA_IF_CALLED(...) ,
278 
279 #endif  // PW_VA_OPT_SUPPORTED()
280