#pragma once // Code generated by muli-line pre-processor macros is hard to read after // pre-processing. // // When you want to check pre-processed code, e.g. for debugging or // to understand what's going on, do the following: // // 1) Add the compiler command line definition // -DKALEIDOSCOPE_ENABLE_MACRO_NEWLINE_SUBSTITUTION // This prevents the __NL__ macro being defined below. // 2) Generate the preprocessed code (it will contain a lot of __NL__ definitions). // 3) Open the pre-processed code in your favorite editor. // 3.1) Replace all __NL__ with newline characters. // In vim the command would be ':%s/__NL__/\r/g'. // 3.2) Autocorrect code-indenting to improve readability. This is necessary // as pre-processor macros remove all whitespaces at the beginning of lines. // With vim, the command gg=G helps (just type the characters one after // the other). // 4) Don't forget to remove the // -DKALEIDOSCOPE_ENABLE_MACRO_NEWLINE_SUBSTITUTION // from your compiler command line. Else the code won't compile. #ifndef KALEIDOSCOPE_ENABLE_MACRO_NEWLINE_SUBSTITUTION #define __NL__ #endif #define __NN__ // Some auxiliary macros // #define __STRINGIZE(S) #S #define STRINGIZE(S) __STRINGIZE(S) // Allow for the creation of verbose messages in static_asserts // #define VEROSE_STATIC_ASSERT_HEADER \ __NL__ "\n" \ __NL__ "\n***************************************************************" \ __NL__ "\n******************** READ THIS CAREFULLY! *********************" \ __NL__ "\n***************************************************************" \ __NL__ "\n" #define VERBOSE_STATIC_ASSERT_FOOTER \ __NL__ "\n" \ __NL__ "\n***************************************************************" \ __NL__ "\n***************************************************************" \ __NL__ "\n***************************************************************" \ __NL__ "\n" #define VERBOSE_FILE_INFO \ __NL__ "\nFile: " __FILE__ #define VERBOSE_LINE_INFO \ __NL__ "\nLine: " STRINGIZE(__LINE__) // The macro function RESTRICT_ARGS_COUNT can be used to generate more // verbose error messages when users supply an insuitable number of arguments // to a macro. // // For a macro it is used wherever one of the arguments A, B, C might // be used, e.g. // #if 0 // This is just so that A_MACRO is not actually defined #define A_MACRO(A, B, C, ...) \ (void)RESTRICT_ARGS_COUNT(0, 3, A_MACRO, ##__VA_ARGS__); \ int a = A; \ int b = B; \ int c = C; #endif // // Note that RESTRICT_ARGS_COUNT can also be invoked wherever one of the macro // arguments is used, e.g. // #if 0 // This is just so that B_MACRO is not actually defined #define B_MACRO(A, B, C, ...) int array[] = { A, B, RESTRICT_ARGS_COUNT(C, 3, B_MACRO, ##__VA_ARGS__) }; #endif // #define RESTRICT_ARGS_COUNT(B, \ NUM_EXPECTED_ARGS, \ ORIGINAL_MACRO, \ ...) \ __NN__ ( \ __NL__ []{ /* Here we are in the body of a dummy lambda function. \ __NN__ []{} is, BTW, the shortest way to write a lambda. \ __NN__ It is only used to hold the static_assert that cannot be \ __NN__ defined directly in the keymap initializer list. By using the \ __NN__ comma operator ((A, B) always evaluates to b), we ensure \ __NN__ that not the lambda but B is what ASSERT_ARGS_COUNT \ __NN__ finally evaluates to. \ __NN__ Please not that passing B through this macro is a must \ __NN__ as we need it for the comma operator to work. \ __NN__ */ \ __NN__ static_assert(sizeof(const char) == sizeof(#__VA_ARGS__ ), \ __NN__ /* sizeof(const char) == sizeof(#__VA_ARGS__ ) checks the quoted \ __NN__ list of additional arguments. If there are none, then the \ __NN__ length of #__VA_ARGS__ is a single char as it contains '\0'. \ __NN__ This check is not able to find the corner case of a single \ __NN__ superfluous comma at the end of the macro arguments as this \ __NN__ causes #__VA_ARGS__ being empty (only '\0'). \ __NN__ */ \ __NN__ VEROSE_STATIC_ASSERT_HEADER \ __NN__ \ __NN__ VERBOSE_FILE_INFO \ __NN__ VERBOSE_LINE_INFO \ __NL__ "\n" \ __NL__ "\nStrange arguments encountered in invocation of " #ORIGINAL_MACRO "." \ __NL__ "\n" \ __NL__ "\nPlease make sure to pass exactly " #NUM_EXPECTED_ARGS \ __NN__ " macro arguments to" \ __NL__ "\n" #ORIGINAL_MACRO ". Also make sure that there are no dangling" \ __NL__ "\ncommas at the end of the argument list." \ __NL__ "\n" \ __NL__ "\nThis is the superfluous part at the end of the macro" \ __NL__ "\narguments list: \'" #__VA_ARGS__ "\'" \ __NN__ \ __NN__ VERBOSE_STATIC_ASSERT_FOOTER \ __NL__ ); \ __NL__ \ __NL__ }, /* End of dummy lambda, the comma operator's A operand. */ \ __NL__ B /* The overall ASSERT_ARGS_COUNT evaluates to B. */ \ __NL__ )