• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // clang-format off
97 #define PW_MACRO_ARG_COUNT(...)                      \
98   _PW_MACRO_ARG_COUNT_IMPL(__VA_ARGS__,              \
99                      64, 63, 62, 61, 60, 59, 58, 57, \
100                      56, 55, 54, 53, 52, 51, 50, 49, \
101                      48, 47, 46, 45, 44, 43, 42, 41, \
102                      40, 39, 38, 37, 36, 35, 34, 33, \
103                      32, 31, 30, 29, 28, 27, 26, 25, \
104                      24, 23, 22, 21, 20, 19, 18, 17, \
105                      16, 15, 14, 13, 12, 11, 10,  9, \
106                       8,  7,  6,  5, 4,  3,  2,  PW_HAS_ARGS(__VA_ARGS__))
107 
108 #define _PW_MACRO_ARG_COUNT_IMPL(a64, a63, a62, a61, a60, a59, a58, a57, \
109                                  a56, a55, a54, a53, a52, a51, a50, a49, \
110                                  a48, a47, a46, a45, a44, a43, a42, a41, \
111                                  a40, a39, a38, a37, a36, a35, a34, a33, \
112                                  a32, a31, a30, a29, a28, a27, a26, a25, \
113                                  a24, a23, a22, a21, a20, a19, a18, a17, \
114                                  a16, a15, a14, a13, a12, a11, a10, a09, \
115                                  a08, a07, a06, a05, a04, a03, a02, a01, \
116                                  count, ...)                             \
117   count
118 
119 // clang-format on
120 
121 // Argument count for using with a C/C++ function or template parameter list.
122 // The difference from PW_MACRO_ARG_COUNT is that the last argument is not
123 // counted if it is empty. This makes it easier to drop the final comma when
124 // expanding to C/C++ code.
125 #define PW_FUNCTION_ARG_COUNT(...) \
126   _PW_FUNCTION_ARG_COUNT(PW_LAST_ARG(__VA_ARGS__), __VA_ARGS__)
127 
128 #define _PW_FUNCTION_ARG_COUNT(last_arg, ...) \
129   _PW_PASTE2(_PW_FUNCTION_ARG_COUNT_, PW_EMPTY_ARGS(last_arg))(__VA_ARGS__)
130 
131 #define _PW_FUNCTION_ARG_COUNT_0 PW_MACRO_ARG_COUNT
132 #define _PW_FUNCTION_ARG_COUNT_1(...) \
133   PW_MACRO_ARG_COUNT(PW_DROP_LAST_ARG(__VA_ARGS__))
134 
135 // Evaluates to the last argument in the provided arguments.
136 #define PW_LAST_ARG(...) \
137   _PW_PASTE2(_PW_LAST_ARG_, PW_MACRO_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__)
138 
139 // Evaluates to the provided arguments, excluding the final argument.
140 #define PW_DROP_LAST_ARG(...) \
141   _PW_PASTE2(_PW_DROP_LAST_ARG_, PW_MACRO_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__)
142 
143 // Evaluates to the arguments, excluding the final argument if it is empty.
144 #define PW_DROP_LAST_ARG_IF_EMPTY(...)                                       \
145   _PW_IF(                                                                    \
146       PW_EMPTY_ARGS(PW_LAST_ARG(__VA_ARGS__)), PW_DROP_LAST_ARG, _PW_EXPAND) \
147   (__VA_ARGS__)
148 
149 // Expands to 1 if one or more arguments are provided, 0 otherwise.
150 #define PW_HAS_ARGS(...) PW_NOT(PW_EMPTY_ARGS(__VA_ARGS__))
151 
152 #if PW_VA_OPT_SUPPORTED()
153 
154 // Expands to 0 if one or more arguments are provided, 1 otherwise.
155 #define PW_EMPTY_ARGS(...) _PW_EMPTY_ARGS_##__VA_OPT__(0)
156 #define _PW_EMPTY_ARGS_ 1
157 #define _PW_EMPTY_ARGS_0 0
158 
159 #else
160 
161 // If __VA_OPT__ is not available, use a complicated fallback mechanism. This
162 // approach is from Jens Gustedt's blog:
163 //   https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
164 //
165 // Normally, with a standard-compliant C preprocessor, it's impossible to tell
166 // whether a variadic macro was called with no arguments or with one argument.
167 // A macro invoked with no arguments is actually passed one empty argument.
168 //
169 // This macro works by checking for the presence of a comma in four situations.
170 // These situations give the following information about __VA_ARGS__:
171 //
172 //   1. It is two or more variadic arguments.
173 //   2. It expands to one argument surrounded by parentheses.
174 //   3. It is a function-like macro that produces a comma when invoked.
175 //   4. It does not interfere with calling a macro when placed between it and
176 //      parentheses.
177 //
178 // If a comma is not present in 1, 2, 3, but is present in 4, then __VA_ARGS__
179 // is empty. For this case (0001), and only this case, a corresponding macro
180 // that expands to a comma is defined. The presence of this comma determines
181 // whether any arguments were passed in.
182 #define PW_EMPTY_ARGS(...)                                             \
183   _PW_HAS_NO_ARGS(_PW_HAS_COMMA(__VA_ARGS__),                          \
184                   _PW_HAS_COMMA(_PW_MAKE_COMMA_IF_CALLED __VA_ARGS__), \
185                   _PW_HAS_COMMA(__VA_ARGS__()),                        \
186                   _PW_HAS_COMMA(_PW_MAKE_COMMA_IF_CALLED __VA_ARGS__()))
187 
188 // clang-format off
189 #define _PW_HAS_COMMA(...)                                           \
190   _PW_MACRO_ARG_COUNT_IMPL(__VA_ARGS__,                              \
191                      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
192                      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
193                      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
194                      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
195 // clang-format on
196 
197 #define _PW_HAS_NO_ARGS(a1, a2, a3, a4) \
198   _PW_HAS_COMMA(_PW_PASTE_RESULTS(a1, a2, a3, a4))
199 #define _PW_PASTE_RESULTS(a1, a2, a3, a4) _PW_HAS_COMMA_CASE_##a1##a2##a3##a4
200 #define _PW_HAS_COMMA_CASE_0001 ,
201 #define _PW_MAKE_COMMA_IF_CALLED(...) ,
202 
203 #endif  // PW_VA_OPT_SUPPORTED()
204