sys: util: improve IS_EMPTY() implementation
The current implementation relies on preprocessor concatenation to work. This makes it incompatible with any content which expansion is not a valid preprocessor token such as strings, pointers, etc. and therefore limits its usefulness. Replace it with an implementation that can cope with all cases. Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
parent
e710f5acb1
commit
e3144ca68a
3 changed files with 23 additions and 14 deletions
|
@ -67,9 +67,23 @@
|
||||||
#define __DEBRACKET(...) __VA_ARGS__
|
#define __DEBRACKET(...) __VA_ARGS__
|
||||||
|
|
||||||
/* Used by IS_EMPTY() */
|
/* Used by IS_EMPTY() */
|
||||||
#define Z_IS_EMPTY_(...) Z_IS_EMPTY__(__VA_ARGS__)
|
/* reference: https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ */
|
||||||
#define Z_IS_EMPTY__(a, ...) Z_IS_EMPTY___(_ZZ##a##ZZ0, __VA_ARGS__)
|
#define Z_HAS_COMMA(...) \
|
||||||
#define Z_IS_EMPTY___(...) GET_ARG_N(3, __VA_ARGS__)
|
NUM_VA_ARGS_LESS_1_IMPL(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, \
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
|
||||||
|
#define Z_TRIGGER_PARENTHESIS_(...) ,
|
||||||
|
#define Z_IS_EMPTY_(...) \
|
||||||
|
Z_IS_EMPTY__( \
|
||||||
|
Z_HAS_COMMA(__VA_ARGS__), \
|
||||||
|
Z_HAS_COMMA(Z_TRIGGER_PARENTHESIS_ __VA_ARGS__), \
|
||||||
|
Z_HAS_COMMA(__VA_ARGS__ (/*empty*/)), \
|
||||||
|
Z_HAS_COMMA(Z_TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/)))
|
||||||
|
#define Z_CAT5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
|
||||||
|
#define Z_IS_EMPTY__(_0, _1, _2, _3) \
|
||||||
|
Z_HAS_COMMA(Z_CAT5(Z_IS_EMPTY_CASE_, _0, _1, _2, _3))
|
||||||
|
#define Z_IS_EMPTY_CASE_0001 ,
|
||||||
|
|
||||||
/* Used by LIST_DROP_EMPTY() */
|
/* Used by LIST_DROP_EMPTY() */
|
||||||
/* Adding ',' after each element would add empty element at the end of
|
/* Adding ',' after each element would add empty element at the end of
|
||||||
|
|
|
@ -210,15 +210,6 @@ extern "C" {
|
||||||
* This macro may be used with COND_CODE_1() and COND_CODE_0() while
|
* This macro may be used with COND_CODE_1() and COND_CODE_0() while
|
||||||
* processing <tt>__VA_ARGS__</tt> to avoid processing empty arguments.
|
* processing <tt>__VA_ARGS__</tt> to avoid processing empty arguments.
|
||||||
*
|
*
|
||||||
* Note that this macro is intended to check macro names that evaluate
|
|
||||||
* to replacement lists being empty or containing numbers or macro name
|
|
||||||
* like tokens.
|
|
||||||
*
|
|
||||||
* @note Not all arguments are accepted by this macro and compilation will fail
|
|
||||||
* if argument cannot be concatenated with literal constant. That will
|
|
||||||
* happen if argument does not start with letter or number. Example
|
|
||||||
* arguments that will fail during compilation: .arg, (arg), "arg", {arg}.
|
|
||||||
*
|
|
||||||
* Example:
|
* Example:
|
||||||
*
|
*
|
||||||
* #define EMPTY
|
* #define EMPTY
|
||||||
|
@ -234,9 +225,9 @@ extern "C" {
|
||||||
* In above examples, the invocations of IS_EMPTY(...) return @p true,
|
* In above examples, the invocations of IS_EMPTY(...) return @p true,
|
||||||
* @p false, and @p true; @p some_conditional_code is included.
|
* @p false, and @p true; @p some_conditional_code is included.
|
||||||
*
|
*
|
||||||
* @param a macro to check for emptiness
|
* @param ... macro to check for emptiness (may be <tt>__VA_ARGS__</tt>)
|
||||||
*/
|
*/
|
||||||
#define IS_EMPTY(a) Z_IS_EMPTY_(a, 1, 0,)
|
#define IS_EMPTY(...) Z_IS_EMPTY_(__VA_ARGS__)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Remove empty arguments from list.
|
* @brief Remove empty arguments from list.
|
||||||
|
|
|
@ -354,6 +354,10 @@ static void test_IS_EMPTY(void)
|
||||||
"Expected to be empty");
|
"Expected to be empty");
|
||||||
zassert_false(IS_EMPTY(test_IS_EMPTY_NOT_EMPTY),
|
zassert_false(IS_EMPTY(test_IS_EMPTY_NOT_EMPTY),
|
||||||
"Expected to be non-empty");
|
"Expected to be non-empty");
|
||||||
|
zassert_false(IS_EMPTY("string"),
|
||||||
|
"Expected to be non-empty");
|
||||||
|
zassert_false(IS_EMPTY(&test_IS_EMPTY),
|
||||||
|
"Expected to be non-empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_LIST_DROP_EMPTY(void)
|
static void test_LIST_DROP_EMPTY(void)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue