sys/util.h: add UTIL_OR and UTIL_AND

These are short-circuiting utility helpers that can save typing
in situations where avoiding evaluation of the not-taken branch
skips invalid expressions.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This commit is contained in:
Martí Bolívar 2020-03-24 16:22:33 -07:00 committed by Carles Cufí
commit 1edc84f526
2 changed files with 50 additions and 0 deletions

View file

@ -711,6 +711,21 @@ u8_t u8_to_dec(char *buf, u8_t buflen, u8_t value);
#define UTIL_IF(c) UTIL_IIF(UTIL_BOOL(c)) #define UTIL_IF(c) UTIL_IIF(UTIL_BOOL(c))
/*
* These are like || and &&, but they do evaluation and
* short-circuiting at preprocessor time instead of runtime.
*
* UTIL_OR(foo, bar) is sometimes a replacement for (foo || bar)
* when "bar" is an expression that would cause a build
* error when "foo" is true.
*
* UTIL_AND(foo, bar) is sometimes a replacement for (foo && bar)
* when "bar" is an expression that would cause a build
* error when "foo" is false.
*/
#define UTIL_OR(a, b) COND_CODE_1(UTIL_BOOL(a), (a), (b))
#define UTIL_AND(a, b) COND_CODE_1(UTIL_BOOL(a), (b), (0))
#define UTIL_EAT(...) #define UTIL_EAT(...)
#define UTIL_EXPAND(...) __VA_ARGS__ #define UTIL_EXPAND(...) __VA_ARGS__
#define UTIL_WHEN(c) UTIL_IF(c)(UTIL_EXPAND, UTIL_EAT) #define UTIL_WHEN(c) UTIL_IF(c)(UTIL_EXPAND, UTIL_EAT)

View file

@ -110,6 +110,39 @@ void test_COND_CODE_0(void)
zassert_true((y3 == 1), NULL); zassert_true((y3 == 1), NULL);
} }
#undef ZERO
#undef SEVEN
#undef A_BUILD_ERROR
#define ZERO 0
#define SEVEN 7
#define A_BUILD_ERROR (this would be a build error if you used || or &&)
void test_UTIL_OR(void)
{
zassert_equal(UTIL_OR(SEVEN, A_BUILD_ERROR), 7, NULL);
zassert_equal(UTIL_OR(7, 0), 7, NULL);
zassert_equal(UTIL_OR(SEVEN, ZERO), 7, NULL);
zassert_equal(UTIL_OR(0, 7), 7, NULL);
zassert_equal(UTIL_OR(ZERO, SEVEN), 7, NULL);
zassert_equal(UTIL_OR(0, 0), 0, NULL);
zassert_equal(UTIL_OR(ZERO, ZERO), 0, NULL);
}
void test_UTIL_AND(void)
{
zassert_equal(UTIL_AND(ZERO, A_BUILD_ERROR), 0, NULL);
zassert_equal(UTIL_AND(7, 0), 0, NULL);
zassert_equal(UTIL_AND(SEVEN, ZERO), 0, NULL);
zassert_equal(UTIL_AND(0, 7), 0, NULL);
zassert_equal(UTIL_AND(ZERO, SEVEN), 0, NULL);
zassert_equal(UTIL_AND(0, 0), 0, NULL);
zassert_equal(UTIL_AND(ZERO, ZERO), 0, NULL);
zassert_equal(UTIL_AND(7, 7), 7, NULL);
zassert_equal(UTIL_AND(7, SEVEN), 7, NULL);
zassert_equal(UTIL_AND(SEVEN, 7), 7, NULL);
zassert_equal(UTIL_AND(SEVEN, SEVEN), 7, NULL);
}
void test_IF_ENABLED(void) void test_IF_ENABLED(void)
{ {
#define test_IF_ENABLED_FLAG_A 1 #define test_IF_ENABLED_FLAG_A 1
@ -190,6 +223,8 @@ void test_main(void)
ztest_unit_test(test_u8_to_dec), ztest_unit_test(test_u8_to_dec),
ztest_unit_test(test_COND_CODE_1), ztest_unit_test(test_COND_CODE_1),
ztest_unit_test(test_COND_CODE_0), ztest_unit_test(test_COND_CODE_0),
ztest_unit_test(test_UTIL_OR),
ztest_unit_test(test_UTIL_AND),
ztest_unit_test(test_IF_ENABLED), ztest_unit_test(test_IF_ENABLED),
ztest_unit_test(test_UTIL_LISTIFY), ztest_unit_test(test_UTIL_LISTIFY),
ztest_unit_test(test_MACRO_MAP_CAT), ztest_unit_test(test_MACRO_MAP_CAT),