Skip to content

Commit da2ebb1

Browse files
committed
[nrf fromlist] sys: util_macro: Add CASE_IF_ENABLED and CASE_IF_ENABLED_<ALL/ANY>
-Added macro CASE_IF_ENABLED to emit a case in a switch-statement if the given flag is define to 1. -Added macro CASE_IF_ENABLED_ALL to emit code if all flags are defined to 1, otherwise an empty token is emitted. -Added macro CASE_IF_ENABLED_ANY to emit a case code if any flags are defined to 1, otherwise an empty token is emitted. -Added unit tests for CASE_IF_ENABLED, CASE_IF_ENABLED_ALL, CASE_IF_ENABLED_ANY These macros utilize the same strategy as the IF_ENABLED macro Signed-off-by: Frank Audun Kvamtrø <[email protected]> (cherry picked from commit 4ee6ef8708d0126afe9f990b505222e6529bc687)
1 parent 25a513c commit da2ebb1

File tree

3 files changed

+310
-0
lines changed

3 files changed

+310
-0
lines changed

include/zephyr/sys/util_internal.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,18 @@
376376
#define MACRO_MC_14(m, a, ...) UTIL_CAT(m(a), MACRO_MC_13(m, __VA_ARGS__,))
377377
#define MACRO_MC_15(m, a, ...) UTIL_CAT(m(a), MACRO_MC_14(m, __VA_ARGS__,))
378378

379+
/* Used by CASE_IF_ENABLED */
380+
#define Z_CASE_IF_ENABLED(_flag, _label, ...) \
381+
Z_CASE_IF_ENABLED_ALL((_flag), _label, __VA_ARGS__)
382+
383+
/* Used by CASE_IF_ENABLED_ALL */
384+
#define Z_CASE_IF_ENABLED_ALL(_flags, _label, ...) \
385+
Z_IF_ENABLED_ALL((case _label: { __VA_ARGS__ }), __DEBRACKET _flags)
386+
387+
/* Used by CASE_IF_ENABLED_ANY */
388+
#define Z_CASE_IF_ENABLED_ANY(_flags, _label, ...) \
389+
Z_IF_ENABLED_ANY((case _label: { __VA_ARGS__ }), __DEBRACKET _flags)
390+
379391
/* Used by Z_IS_EQ */
380392
#include "util_internal_is_eq.h"
381393

include/zephyr/sys/util_macro.h

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,167 @@ extern "C" {
803803
*/
804804
#define MACRO_MAP_CAT_N(N, ...) MACRO_MAP_CAT_N_(N, __VA_ARGS__)
805805

806+
/**
807+
* @brief Macro to emit a case in a switch-statement if the @p _flag is
808+
* defined to 1
809+
*
810+
* @note The content will only be emitted if a the configuration is
811+
* defined to 1, otherwise the whole case in the switch will
812+
* be expressed as an empty token. This means that the content will
813+
* only compiled and error-checked when the checked configurations yields
814+
* an emitted case in the switch-statement.
815+
*
816+
* Example:
817+
*
818+
* enum { CASE_FOO = 1 };
819+
*
820+
* switch(some_var) {
821+
* CASE_IF_ENABLED(CONFIG_FOO, CASE_FOO,
822+
* a++;
823+
* b++;
824+
* break;
825+
* )
826+
* default:
827+
* return -EIO;
828+
* }
829+
*
830+
* This will emit the following if @p CONFIG_FOO is defined to 1:
831+
*
832+
* switch (some_var) {
833+
* case CASE_FOO: {
834+
* a++;
835+
* b++;
836+
* break;
837+
* }
838+
* default:
839+
* return -EIO;
840+
* }
841+
*
842+
* Otherwise it will emit the following:
843+
*
844+
* switch (some_var) {
845+
* default:
846+
* return -EIO;
847+
* }
848+
*
849+
* @param _flag Configuration to check
850+
* @param _label Label to emit in switch-statement
851+
* @param ... Content of the case
852+
*
853+
* @return Case with label and content if @p _flag is enabled and set 1,
854+
* otherwise an empty token
855+
*/
856+
#define CASE_IF_ENABLED(_flag, _label, ...) \
857+
Z_CASE_IF_ENABLED(_flag, _label, __VA_ARGS__)
858+
859+
/**
860+
* @brief Macro to emit a case in a switch-statement if a list of @p _flags
861+
* are all defined to 1
862+
*
863+
* @note The content will only be emitted if all @p _flags are defined and
864+
* set to 1, otherwise the whole case in the switch will be expressed
865+
* as an empty token. This means that the content will only compiled and
866+
* error-checked when the checked configurations yields an emitted case
867+
* in the switch-statement.
868+
*
869+
* Example:
870+
*
871+
* enum { CASE_FOO = 1 };
872+
*
873+
* switch(some_var) {
874+
* CASE_IF_ENABLED(CONFIG_FOO, CONFIG_BAR, CASE_FOO,
875+
* a++;
876+
* b++;
877+
* break;
878+
* )
879+
* default:
880+
* return -EIO;
881+
* }
882+
*
883+
* Will emit the following if both @p CONFIG_FOO and @p CONFIG_BAR are defined
884+
* to 1:
885+
*
886+
* switch (some_var) {
887+
* case CASE_FOO: {
888+
* a++;
889+
* b++;
890+
* break;
891+
* }
892+
* default:
893+
* return -EIO;
894+
* }
895+
*
896+
* Otherwise it will emit the following:
897+
*
898+
* switch (some_var) {
899+
* default:
900+
* return -EIO;
901+
* }
902+
*
903+
* @param _flags Configurations to check; must be in parentheses
904+
* @param _label Label to emit in switch-statement
905+
* @param ... Content of the case
906+
*
907+
* @return Case with label and content if all @p _flags are enabled and set 1,
908+
* otherwise an empty token
909+
*/
910+
#define CASE_IF_ENABLED_ALL(_flags, _label, ...) \
911+
Z_CASE_IF_ENABLED_ALL(_flags, _label, __VA_ARGS__)
912+
913+
/**
914+
* @brief Macro to emit a case in a switch-statement if any @p _flags are
915+
* defined to 1
916+
*
917+
* @note The content will only be emitted if any @p _flags are defined to 1,
918+
* otherwise the whole case in the switch will be expressed as an
919+
* empty token. This means that the content will only compiled and
920+
* error-checked when the checked configurations yields an emitted case in
921+
* the switch-statement.
922+
*
923+
* Example:
924+
*
925+
* enum { CASE_FOO = 1 };
926+
*
927+
* switch(some_var) {
928+
* CASE_IF_ENABLED_ANY((CONFIG_FOO, CONFIG_BAR), CASE_FOO,
929+
* a++;
930+
* b++;
931+
* break;
932+
* )
933+
* default:
934+
* return -EIO;
935+
* }
936+
*
937+
* This will emit the following if any of the configurations @p CONFIG_FOO,
938+
* @p CONFIG_BAR are defined to 1:
939+
*
940+
* switch (some_var) {
941+
* case CASE_FOO: {
942+
* a++;
943+
* b++;
944+
* break;
945+
* }
946+
* default:
947+
* return -EIO;
948+
* }
949+
*
950+
* Otherwise it will emit the following:
951+
*
952+
* switch (som_var) {
953+
* default:
954+
* return -EIO;
955+
* }
956+
*
957+
* @param _flags Configurations to check; must be in parentheses
958+
* @param _label Label to emit in switch-statement
959+
* @param ... Content of the case
960+
*
961+
* @return Case with label and content if any @p _flags are enabled and set 1,
962+
* otherwise an empty token
963+
*/
964+
#define CASE_IF_ENABLED_ANY(_flags, _label, ...) \
965+
Z_CASE_IF_ENABLED_ANY(_flags, _label, __VA_ARGS__)
966+
806967
/**
807968
* @}
808969
*/

tests/unit/util/main.c

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,143 @@ ZTEST(util, test_IF_ENABLED_ANY) {
377377
#undef TEST_FLAG_D
378378
}
379379

380+
ZTEST(util, test_CASE_IF_ENABLED) {
381+
#define TEST_FLAG_A 1
382+
#define TEST_FLAG_B 0
383+
#define TEST_LABEL_SUCCESS 1
384+
#define TEST_LABEL_FAILURE 2
385+
386+
int a = TEST_LABEL_SUCCESS;
387+
388+
switch (a) {
389+
CASE_IF_ENABLED(TEST_FLAG_A, TEST_LABEL_SUCCESS,
390+
break;
391+
)
392+
default:
393+
zassert_false(true, "CASE_IF_ENABLED not emitted (default reached)");
394+
break;
395+
}
396+
397+
a = TEST_LABEL_FAILURE;
398+
switch (a) {
399+
CASE_IF_ENABLED(TEST_FLAG_B, TEST_LABEL_FAILURE,
400+
zassert_false(true, "CASE_IF_ENABLED emitted (invalid case)");
401+
break;
402+
)
403+
default:
404+
break;
405+
}
406+
407+
zassert_true(true, "");
408+
409+
#undef TEST_FLAG_A
410+
#undef TEST_FLAG_B
411+
#undef TEST_LABEL_SUCCESS
412+
#undef TEST_LABEL_FAILURE
413+
}
414+
415+
ZTEST(util, test_CASE_IF_ENABLED_ALL) {
416+
#define TEST_FLAG_A 1
417+
#define TEST_FLAG_B 1
418+
#define TEST_FLAG_C 0
419+
#define TEST_FLAG_D 0
420+
#define TEST_LABEL_SUCCESS 1
421+
#define TEST_LABEL_FAILURE 2
422+
423+
int a = TEST_LABEL_SUCCESS;
424+
425+
switch (a) {
426+
CASE_IF_ENABLED_ALL((TEST_FLAG_A, TEST_FLAG_B), TEST_LABEL_SUCCESS,
427+
break;
428+
)
429+
default:
430+
zassert_false(true,
431+
"CASE_IF_ENABLED_ALL not emitted (all valid)");
432+
break;
433+
}
434+
435+
a = TEST_LABEL_FAILURE;
436+
switch (a) {
437+
CASE_IF_ENABLED_ALL((TEST_FLAG_A, TEST_FLAG_C), TEST_LABEL_FAILURE,
438+
zassert_false(true,
439+
"CASE_IF_ENABLED_ALL should not emit (one invalid)");
440+
break;
441+
)
442+
default:
443+
break;
444+
}
445+
446+
a = TEST_LABEL_FAILURE;
447+
switch (a) {
448+
CASE_IF_ENABLED_ALL((TEST_FLAG_C, TEST_FLAG_D), TEST_LABEL_FAILURE,
449+
zassert_false(true, "CASE_IF_ENABLED_ALL should not emit");
450+
break;
451+
)
452+
default:
453+
break;
454+
}
455+
456+
zassert_true(true, "");
457+
458+
#undef TEST_FLAG_A
459+
#undef TEST_FLAG_B
460+
#undef TEST_FLAG_C
461+
#undef TEST_FLAG_D
462+
#undef TEST_LABEL_SUCCESS
463+
#undef TEST_LABEL_FAILURE
464+
}
465+
466+
ZTEST(util, test_CASE_IF_ENABLED_ANY) {
467+
468+
#define TEST_FLAG_A 1
469+
#define TEST_FLAG_B 1
470+
#define TEST_FLAG_C 0
471+
#define TEST_FLAG_D 0
472+
#define TEST_LABEL_SUCCESS 1
473+
#define TEST_LABEL_FAILURE 2
474+
475+
int a = TEST_LABEL_SUCCESS;
476+
477+
switch (a) {
478+
CASE_IF_ENABLED_ANY((TEST_FLAG_A, TEST_FLAG_B), TEST_LABEL_SUCCESS,
479+
break;
480+
)
481+
default:
482+
zassert_false(true, "CASE_IF_ENABLED_ANY not emitted (all valid)");
483+
break;
484+
}
485+
486+
a = TEST_LABEL_SUCCESS;
487+
switch (a) {
488+
CASE_IF_ENABLED_ANY((TEST_FLAG_A, TEST_FLAG_C), TEST_LABEL_SUCCESS,
489+
break;
490+
)
491+
default:
492+
zassert_false(true, "CASE_IF_ENABLED_ANY not emitted (one valid)");
493+
break;
494+
}
495+
496+
a = TEST_LABEL_FAILURE;
497+
switch (a) {
498+
CASE_IF_ENABLED_ANY((TEST_FLAG_C, TEST_FLAG_D),
499+
TEST_LABEL_FAILURE,
500+
zassert_false(true, "CASE_IF_ENABLED_ANY should not emit");
501+
break;
502+
)
503+
default:
504+
break;
505+
}
506+
507+
zassert_true(true, "");
508+
509+
#undef TEST_FLAG_A
510+
#undef TEST_FLAG_B
511+
#undef TEST_FLAG_C
512+
#undef TEST_FLAG_D
513+
#undef TEST_LABEL_SUCCESS
514+
#undef TEST_LABEL_FAILURE
515+
}
516+
380517
ZTEST(util, test_LISTIFY) {
381518
int ab0 = 1;
382519
int ab1 = 1;

0 commit comments

Comments
 (0)