aboutsummaryrefslogtreecommitdiff
path: root/pw_tokenizer/public/pw_tokenizer/tokenize.h
diff options
context:
space:
mode:
Diffstat (limited to 'pw_tokenizer/public/pw_tokenizer/tokenize.h')
-rw-r--r--pw_tokenizer/public/pw_tokenizer/tokenize.h95
1 files changed, 71 insertions, 24 deletions
diff --git a/pw_tokenizer/public/pw_tokenizer/tokenize.h b/pw_tokenizer/public/pw_tokenizer/tokenize.h
index 6b8e62c57..aa8efd888 100644
--- a/pw_tokenizer/public/pw_tokenizer/tokenize.h
+++ b/pw_tokenizer/public/pw_tokenizer/tokenize.h
@@ -75,7 +75,7 @@ typedef uint32_t pw_tokenizer_Token;
}()
/// Tokenizes a string literal in a standalone statement using the specified
-/// @rstref{domain <module-pw_tokenizer-domains>}. C and C++ compatible.
+/// @rstref{domain<module-pw_tokenizer-domains>}. C and C++ compatible.
#define PW_TOKENIZE_STRING_DOMAIN(domain, string_literal) \
PW_TOKENIZE_STRING_MASK(domain, UINT32_MAX, string_literal)
@@ -111,7 +111,7 @@ typedef uint32_t pw_tokenizer_Token;
}()
#define _PW_TOKENIZER_MASK_TOKEN(mask, string_literal) \
- ((pw_tokenizer_Token)(mask)&PW_TOKENIZER_STRING_TOKEN(string_literal))
+ ((pw_tokenizer_Token)(mask) & PW_TOKENIZER_STRING_TOKEN(string_literal))
/// Encodes a tokenized string and arguments to the provided buffer. The size of
/// the buffer is passed via a pointer to a `size_t`. After encoding is
@@ -159,23 +159,56 @@ typedef uint32_t pw_tokenizer_Token;
/// Same as @c_macro{PW_TOKENIZE_TO_BUFFER_DOMAIN}, but applies a
/// @rstref{bit mask <module-pw_tokenizer-masks>} to the token.
-#define PW_TOKENIZE_TO_BUFFER_MASK( \
- domain, mask, buffer, buffer_size_pointer, format, ...) \
- do { \
- PW_TOKENIZE_FORMAT_STRING(domain, mask, format, __VA_ARGS__); \
- _pw_tokenizer_ToBuffer(buffer, \
- buffer_size_pointer, \
- _pw_tokenizer_token, \
- PW_TOKENIZER_ARG_TYPES(__VA_ARGS__) \
- PW_COMMA_ARGS(__VA_ARGS__)); \
+#define PW_TOKENIZE_TO_BUFFER_MASK( \
+ domain, mask, buffer, buffer_size_pointer, format, ...) \
+ do { \
+ PW_TOKENIZE_FORMAT_STRING(domain, mask, format, __VA_ARGS__); \
+ _pw_tokenizer_ToBuffer(buffer, \
+ buffer_size_pointer, \
+ PW_TOKENIZER_REPLACE_FORMAT_STRING(__VA_ARGS__)); \
} while (0)
+/// @brief Low-level macro for calling functions that handle tokenized strings.
+///
+/// Functions that work with tokenized format strings must take the following
+/// arguments:
+///
+/// - The 32-bit token (@cpp_type{pw_tokenizer_Token})
+/// - The 32- or 64-bit argument types (@cpp_type{pw_tokenizer_ArgTypes})
+/// - Variadic arguments, if any
+///
+/// This macro expands to those arguments. Custom tokenization macros should use
+/// this macro to pass these arguments to a function or other macro.
+///
+/** @code{cpp}
+ * EncodeMyTokenizedString(uint32_t token,
+ * pw_tokenier_ArgTypes arg_types,
+ * ...);
+ *
+ * #define CUSTOM_TOKENIZATION_MACRO(format, ...) \
+ * PW_TOKENIZE_FORMAT_STRING(domain, mask, format, __VA_ARGS__); \
+ * EncodeMyTokenizedString(PW_TOKENIZER_REPLACE_FORMAT_STRING(__VA_ARGS__))
+ * @endcode
+ */
+#define PW_TOKENIZER_REPLACE_FORMAT_STRING(...) \
+ _PW_TOKENIZER_REPLACE_FORMAT_STRING(PW_EMPTY_ARGS(__VA_ARGS__), __VA_ARGS__)
+
+#define _PW_TOKENIZER_REPLACE_FORMAT_STRING(empty_args, ...) \
+ _PW_CONCAT_2(_PW_TOKENIZER_REPLACE_FORMAT_STRING_, empty_args)(__VA_ARGS__)
+
+#define _PW_TOKENIZER_REPLACE_FORMAT_STRING_1() _pw_tokenizer_token, 0u
+#define _PW_TOKENIZER_REPLACE_FORMAT_STRING_0(...) \
+ _pw_tokenizer_token, PW_TOKENIZER_ARG_TYPES(__VA_ARGS__), __VA_ARGS__
+
/// Converts a series of arguments to a compact format that replaces the format
/// string literal. Evaluates to a `pw_tokenizer_ArgTypes` value.
///
/// Depending on the size of `pw_tokenizer_ArgTypes`, the bottom 4 or 6 bits
/// store the number of arguments and the remaining bits store the types, two
/// bits per type. The arguments are not evaluated; only their types are used.
+///
+/// In general, @c_macro{PW_TOKENIZER_ARG_TYPES} should not be used directly.
+/// Instead, use @c_macro{PW_TOKENIZER_REPLACE_FORMAT_STRING}.
#define PW_TOKENIZER_ARG_TYPES(...) \
PW_DELEGATE_BY_ARG_COUNT(_PW_TOKENIZER_TYPES_, __VA_ARGS__)
@@ -204,25 +237,40 @@ PW_EXTERN_C_END
/// since the same variable is used in every invocation.
///
/// The tokenized string uses the specified @rstref{tokenization domain
-/// <module-pw_tokenizer-domains>}. Use `PW_TOKENIZER_DEFAULT_DOMAIN` for the
+/// <module-pw_tokenizer-domains>}. Use `PW_TOKENIZER_DEFAULT_DOMAIN` for the
/// default. The token also may be masked; use `UINT32_MAX` to keep all bits.
///
-/// This macro checks that the printf-style format string matches the arguments,
-/// stores the format string in a special section, and calculates the string's
-/// token at compile time.
+/// This macro checks that the printf-style format string matches the arguments
+/// and that no more than @c_macro{PW_TOKENIZER_MAX_SUPPORTED_ARGS} are
+/// provided. It then stores the format string in a special section, and
+/// calculates the string's token at compile time.
// clang-format off
-#define PW_TOKENIZE_FORMAT_STRING(domain, mask, format, ...) \
- if (0) { /* Do not execute to prevent double evaluation of the arguments. */ \
- pw_tokenizer_CheckFormatString(format PW_COMMA_ARGS(__VA_ARGS__)); \
- } \
- \
- /* Check that the macro is invoked with a supported number of arguments. */ \
+#define PW_TOKENIZE_FORMAT_STRING(domain, mask, format, ...) \
static_assert( \
PW_FUNCTION_ARG_COUNT(__VA_ARGS__) <= PW_TOKENIZER_MAX_SUPPORTED_ARGS, \
"Tokenized strings cannot have more than " \
PW_STRINGIFY(PW_TOKENIZER_MAX_SUPPORTED_ARGS) " arguments; " \
PW_STRINGIFY(PW_FUNCTION_ARG_COUNT(__VA_ARGS__)) \
" arguments were used for " #format " (" #__VA_ARGS__ ")"); \
+ PW_TOKENIZE_FORMAT_STRING_ANY_ARG_COUNT(domain, mask, format, __VA_ARGS__)
+// clang-format on
+
+/// Equivalent to `PW_TOKENIZE_FORMAT_STRING`, but supports any number of
+/// arguments.
+///
+/// This is a low-level macro that should rarely be used directly. It is
+/// intended for situations when @cpp_type{pw_tokenizer_ArgTypes} is not used.
+/// There are two situations where @cpp_type{pw_tokenizer_ArgTypes} is
+/// unnecessary:
+///
+/// - The exact format string argument types and count are fixed.
+/// - The format string supports a variable number of arguments of only one
+/// type. In this case, @c_macro{PW_FUNCTION_ARG_COUNT} may be used to pass
+/// the argument count to the function.
+#define PW_TOKENIZE_FORMAT_STRING_ANY_ARG_COUNT(domain, mask, format, ...) \
+ if (0) { /* Do not execute to prevent double evaluation of the arguments. */ \
+ pw_tokenizer_CheckFormatString(format PW_COMMA_ARGS(__VA_ARGS__)); \
+ } \
\
/* Tokenize the string to a pw_tokenizer_Token at compile time. */ \
static _PW_TOKENIZER_CONST pw_tokenizer_Token _pw_tokenizer_token = \
@@ -230,8 +278,6 @@ PW_EXTERN_C_END
\
_PW_TOKENIZER_RECORD_ORIGINAL_STRING(_pw_tokenizer_token, domain, format)
-// clang-format on
-
// Creates unique names to use for tokenized string entries and linker sections.
#define _PW_TOKENIZER_UNIQUE(prefix) PW_CONCAT(prefix, __LINE__, _, __COUNTER__)
@@ -255,9 +301,10 @@ using Token = ::pw_tokenizer_Token;
#else
#define _PW_TOKENIZER_CONST const
+#define _PW_ALIGNAS(alignment) __attribute__((aligned(alignment)))
#define _PW_TOKENIZER_RECORD_ORIGINAL_STRING(token, domain, string) \
- _Alignas(1) static const _PW_TOKENIZER_STRING_ENTRY(token, domain, string)
+ _PW_ALIGNAS(1) static const _PW_TOKENIZER_STRING_ENTRY(token, domain, string)
#endif // __cplusplus