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/internal/arg_count_impl.h" 20 21 // Expands to a comma followed by __VA_ARGS__, if __VA_ARGS__ is non-empty. 22 // Otherwise, expands to nothing. If the final argument is empty, it is omitted. 23 // This is useful when passing __VA_ARGS__ to a variadic function or template 24 // parameter list, since it removes the extra comma when no arguments are 25 // provided. PW_COMMA_ARGS must NOT be used when invoking a macro from another 26 // macro. 27 // 28 // This is a more flexible, standard-compliant version of ##__VA_ARGS__. Unlike 29 // ##__VA_ARGS__, this can be used to eliminate an unwanted comma when 30 // __VA_ARGS__ expands to an empty argument because an outer macro was called 31 // with __VA_ARGS__ instead of ##__VA_ARGS__. Also, since PW_COMMA_ARGS drops 32 // the last argument if it is empty, both MY_MACRO(1, 2) and MY_MACRO(1, 2, ) 33 // can work correctly. 34 // 35 // PW_COMMA_ARGS must NOT be used to conditionally include a comma when invoking 36 // a macro from another macro. PW_COMMA_ARGS only functions correctly when the 37 // macro expands to C or C++ code! Using it with intermediate macros can result 38 // in out-of-order parameters. When invoking one macro from another, simply pass 39 // __VA_ARGS__. Only the final macro that expands to C/C++ code should use 40 // PW_COMMA_ARGS. 41 // 42 // For example, the following does NOT work: 43 /* 44 #define MY_MACRO(fmt, ...) \ 45 NESTED_MACRO(fmt PW_COMMA_ARGS(__VA_ARGS__)) // BAD! Do not do this! 46 */ 47 // Instead, only use PW_COMMA_ARGS when the macro expands to C/C++ code: 48 /* 49 #define MY_MACRO(fmt, ...) \ 50 NESTED_MACRO(fmt, __VA_ARGS__) // Pass __VA_ARGS__ to nested macros 51 52 #define NESTED_MACRO(fmt, ...) \ 53 printf(fmt PW_COMMA_ARGS(__VA_ARGS__)) // PW_COMMA_ARGS is OK here 54 */ 55 #define PW_COMMA_ARGS(...) \ 56 _PW_IF(PW_EMPTY_ARGS(__VA_ARGS__), _PW_EXPAND, _PW_COMMA_ARGS) \ 57 (PW_DROP_LAST_ARG_IF_EMPTY(__VA_ARGS__)) 58 59 #define _PW_COMMA_ARGS(...) , __VA_ARGS__ 60 61 // Allows calling a different function-like macros based on the number of 62 // arguments. For example: 63 // 64 // #define ARG_PRINT(...) PW_DELEGATE_BY_ARG_COUNT(_ARG_PRINT, __VA_ARGS__) 65 // #define _ARG_PRINT1(a) LOG_INFO("1 arg: %s", a) 66 // #define _ARG_PRINT2(a, b) LOG_INFO("2 args: %s, %s", a, b) 67 // #define _ARG_PRINT3(a, b, c) LOG_INFO("3 args: %s, %s, %s", a, b, c) 68 // 69 // This can the be called from C/C++ code: 70 // 71 // ARG_PRINT("a"); // Outputs: 1 arg: a 72 // ARG_PRINT("a", "b"); // Outputs: 2 args: a, b 73 // ARG_PRINT("a", "b", "c"); // Outputs: 3 args: a, b, c 74 // 75 #define PW_DELEGATE_BY_ARG_COUNT(function, ...) \ 76 _PW_DELEGATE_BY_ARG_COUNT( \ 77 _PW_PASTE2(function, PW_FUNCTION_ARG_COUNT(__VA_ARGS__)), \ 78 PW_DROP_LAST_ARG_IF_EMPTY(__VA_ARGS__)) 79 80 #define _PW_DELEGATE_BY_ARG_COUNT(function, ...) function(__VA_ARGS__) 81 82 // PW_MACRO_ARG_COUNT counts the number of arguments it was called with. It 83 // evalulates to an integer literal in the range 0 to 64. Counting more than 64 84 // arguments is not currently supported. 85 // 86 // PW_MACRO_ARG_COUNT is most commonly used to count __VA_ARGS__ in a variadic 87 // macro. For example, the following code counts the number of arguments passed 88 // to a logging macro: 89 // 90 /* #define LOG_INFO(format, ...) { \ 91 static const int kArgCount = PW_MACRO_ARG_COUNT(__VA_ARGS__); \ 92 SendLog(kArgCount, format, ##__VA_ARGS__); \ 93 } 94 */ 95 // clang-format off 96 #define PW_MACRO_ARG_COUNT(...) \ 97 _PW_MACRO_ARG_COUNT_IMPL(__VA_ARGS__, \ 98 64, 63, 62, 61, 60, 59, 58, 57, \ 99 56, 55, 54, 53, 52, 51, 50, 49, \ 100 48, 47, 46, 45, 44, 43, 42, 41, \ 101 40, 39, 38, 37, 36, 35, 34, 33, \ 102 32, 31, 30, 29, 28, 27, 26, 25, \ 103 24, 23, 22, 21, 20, 19, 18, 17, \ 104 16, 15, 14, 13, 12, 11, 10, 9, \ 105 8, 7, 6, 5, 4, 3, 2, PW_HAS_ARGS(__VA_ARGS__)) 106 // clang-format on 107 108 // Argument count for using with a C/C++ function or template parameter list. 109 // The difference from PW_MACRO_ARG_COUNT is that the last argument is not 110 // counted if it is empty. This makes it easier to drop the final comma when 111 // expanding to C/C++ code. 112 #define PW_FUNCTION_ARG_COUNT(...) \ 113 _PW_FUNCTION_ARG_COUNT(PW_LAST_ARG(__VA_ARGS__), __VA_ARGS__) 114 115 #define _PW_FUNCTION_ARG_COUNT(last_arg, ...) \ 116 _PW_PASTE2(_PW_FUNCTION_ARG_COUNT_, PW_EMPTY_ARGS(last_arg))(__VA_ARGS__) 117 118 #define _PW_FUNCTION_ARG_COUNT_0 PW_MACRO_ARG_COUNT 119 #define _PW_FUNCTION_ARG_COUNT_1(...) \ 120 PW_MACRO_ARG_COUNT(PW_DROP_LAST_ARG(__VA_ARGS__)) 121 122 // Evaluates to the last argument in the provided arguments. 123 #define PW_LAST_ARG(...) \ 124 _PW_PASTE2(_PW_LAST_ARG_, PW_MACRO_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__) 125 126 // Evaluates to the provided arguments, excluding the final argument. 127 #define PW_DROP_LAST_ARG(...) \ 128 _PW_PASTE2(_PW_DROP_LAST_ARG_, PW_MACRO_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__) 129 130 // Evaluates to the arguments, excluding the final argument if it is empty. 131 #define PW_DROP_LAST_ARG_IF_EMPTY(...) \ 132 _PW_IF( \ 133 PW_EMPTY_ARGS(PW_LAST_ARG(__VA_ARGS__)), PW_DROP_LAST_ARG, _PW_EXPAND) \ 134 (__VA_ARGS__) 135 136 // Expands to 1 if one or more arguments are provided, 0 otherwise. 137 #define PW_HAS_ARGS(...) PW_NOT(PW_EMPTY_ARGS(__VA_ARGS__)) 138 139 // Expands to 0 if one or more arguments are provided, 1 otherwise. This 140 // approach is from Jens Gustedt's blog: 141 // https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ 142 // 143 // Normally, with a standard-compliant C preprocessor, it's impossible to tell 144 // whether a variadic macro was called with no arguments or with one argument. 145 // A macro invoked with no arguments is actually passed one empty argument. 146 // 147 // This macro works by checking for the presence of a comma in four situations. 148 // These situations give the following information about __VA_ARGS__: 149 // 150 // 1. It is two or more variadic arguments. 151 // 2. It expands to one argument surrounded by parentheses. 152 // 3. It is a function-like macro that produces a comma when invoked. 153 // 4. It does not interfere with calling a macro when placed between it and 154 // parentheses. 155 // 156 // If a comma is not present in 1, 2, 3, but is present in 4, then __VA_ARGS__ 157 // is empty. For this case (0001), and only this case, a corresponding macro 158 // that expands to a comma is defined. The presence of this comma determines 159 // whether any arguments were passed in. 160 // 161 // C++20 introduces __VA_OPT__, which would greatly simplify this macro. 162 #define PW_EMPTY_ARGS(...) \ 163 _PW_HAS_NO_ARGS(_PW_HAS_COMMA(__VA_ARGS__), \ 164 _PW_HAS_COMMA(_PW_MAKE_COMMA_IF_CALLED __VA_ARGS__), \ 165 _PW_HAS_COMMA(__VA_ARGS__()), \ 166 _PW_HAS_COMMA(_PW_MAKE_COMMA_IF_CALLED __VA_ARGS__())) 167 168 // clang-format off 169 170 #define _PW_HAS_COMMA(...) \ 171 _PW_MACRO_ARG_COUNT_IMPL(__VA_ARGS__, \ 172 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 173 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 174 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 175 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) 176 177 #define _PW_MACRO_ARG_COUNT_IMPL(a64, a63, a62, a61, a60, a59, a58, a57, \ 178 a56, a55, a54, a53, a52, a51, a50, a49, \ 179 a48, a47, a46, a45, a44, a43, a42, a41, \ 180 a40, a39, a38, a37, a36, a35, a34, a33, \ 181 a32, a31, a30, a29, a28, a27, a26, a25, \ 182 a24, a23, a22, a21, a20, a19, a18, a17, \ 183 a16, a15, a14, a13, a12, a11, a10, a09, \ 184 a08, a07, a06, a05, a04, a03, a02, a01, \ 185 count, ...) \ 186 count 187 188 // clang-format on 189 190 #define _PW_HAS_NO_ARGS(a1, a2, a3, a4) \ 191 _PW_HAS_COMMA(_PW_PASTE_RESULTS(a1, a2, a3, a4)) 192 #define _PW_PASTE_RESULTS(a1, a2, a3, a4) _PW_HAS_COMMA_CASE_##a1##a2##a3##a4 193 #define _PW_HAS_COMMA_CASE_0001 , 194 #define _PW_MAKE_COMMA_IF_CALLED(...) , 195