From d5cbaa5c04f678f7ecbd63845922266b955c1de9 Mon Sep 17 00:00:00 2001 From: Wyatt Hepler Date: Mon, 27 Feb 2023 17:59:19 +0000 Subject: [PATCH] pw_tokenizer: Make EncodedMessage a template Allow users of the pw::tokenizer::EncodedMessage class to specify their own size, but default to the configured value. Change-Id: I182b9c2f1c1de8173151195ab5a64a054220806f Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/129190 Reviewed-by: Keir Mierle Commit-Queue: Auto-Submit Pigweed-Auto-Submit: Wyatt Hepler --- docs/BUILD.gn | 1 + pw_log_tokenized/compatibility.cc | 2 +- pw_log_tokenized/log_tokenized.cc | 2 +- pw_tokenizer/docs.rst | 34 +++++--- .../public/pw_tokenizer/encode_args.h | 82 +++++++++---------- 5 files changed, 68 insertions(+), 53 deletions(-) diff --git a/docs/BUILD.gn b/docs/BUILD.gn index 66dafbf818..aaa73c36a7 100644 --- a/docs/BUILD.gn +++ b/docs/BUILD.gn @@ -124,6 +124,7 @@ _doxygen_input_files = [ "$dir_pw_sync/public/pw_sync/timed_thread_notification.h", "$dir_pw_sync/public/pw_sync/virtual_basic_lockable.h", "$dir_pw_rpc/public/pw_rpc/internal/config.h", + "$dir_pw_tokenizer/public/pw_tokenizer/encode_args.h", ] pw_python_action("generate_doxygen") { diff --git a/pw_log_tokenized/compatibility.cc b/pw_log_tokenized/compatibility.cc index 6c1f00fae3..54060dbc7f 100644 --- a/pw_log_tokenized/compatibility.cc +++ b/pw_log_tokenized/compatibility.cc @@ -52,7 +52,7 @@ extern "C" void _pw_tokenizer_ToGlobalHandlerWithPayload( ...) { va_list args; va_start(args, types); - pw::tokenizer::EncodedMessage encoded_message(token, types, args); + pw::tokenizer::EncodedMessage<> encoded_message(token, types, args); va_end(args); pw_log_tokenized_HandleLog( diff --git a/pw_log_tokenized/log_tokenized.cc b/pw_log_tokenized/log_tokenized.cc index ea59221d30..25c00d90a3 100644 --- a/pw_log_tokenized/log_tokenized.cc +++ b/pw_log_tokenized/log_tokenized.cc @@ -26,7 +26,7 @@ extern "C" void _pw_log_tokenized_EncodeTokenizedLog( ...) { va_list args; va_start(args, types); - pw::tokenizer::EncodedMessage encoded_message(token, types, args); + pw::tokenizer::EncodedMessage<> encoded_message(token, types, args); va_end(args); pw_log_tokenized_HandleLog( diff --git a/pw_tokenizer/docs.rst b/pw_tokenizer/docs.rst index 4614ac4692..f276328864 100644 --- a/pw_tokenizer/docs.rst +++ b/pw_tokenizer/docs.rst @@ -281,7 +281,11 @@ special function variables like ``__func__``. Tokenize a message with arguments in a custom macro --------------------------------------------------- Projects can leverage the tokenization machinery in whichever way best suits -their needs. ``pw_tokenizer`` provides two low-level macros for projects to use +their needs. The most efficient way to use ``pw_tokenizer`` is to pass tokenized +data to a global handler function. A project's custom tokenization macro can +handle tokenized data in a function of their choosing. + +``pw_tokenizer`` provides two low-level macros for projects to use to create custom tokenization macros. .. c:macro:: PW_TOKENIZE_FORMAT_STRING(domain, mask, format_string, ...) @@ -297,12 +301,21 @@ to create custom tokenization macros. .. c:macro:: PW_TOKENIZER_ARG_TYPES(...) Converts a series of arguments to a compact format that replaces the format - string literal. + string literal. Evaluates to a ``pw_tokenizer_ArgTypes`` value. + +The outputs of these macros are typically passed to an encoding function. That +function encodes the token, argument types, and argument data to a buffer using +helpers provided by ``pw_tokenizer/encode_args.h``. + +.. doxygenfunction:: pw::tokenizer::EncodeArgs -The most efficient way to use ``pw_tokenizer`` is to pass tokenized data to a -global handler function. A project's custom tokenization macro can handle -tokenized data in a function of their choosing. The following example implements -a custom tokenization macro similar to :ref:`module-pw_log_tokenized`. +.. doxygenclass:: pw::tokenizer::EncodedMessage + :members: + +Example +^^^^^^^ +The following example implements a custom tokenization macro similar to +:ref:`module-pw_log_tokenized`. .. code-block:: cpp @@ -333,9 +346,10 @@ a custom tokenization macro similar to :ref:`module-pw_log_tokenized`. In this example, the ``EncodeTokenizedMessage`` function would handle encoding and processing the message. Encoding is done by the -``pw::tokenizer::EncodedMessage`` class or ``pw::tokenizer::EncodeArgs`` -function from ``pw_tokenizer/encode_args.h``. The encoded message can then be -transmitted or stored as needed. +:cpp:class:`pw::tokenizer::EncodedMessage` class or +:cpp:func:`pw::tokenizer::EncodeArgs` function from +``pw_tokenizer/encode_args.h``. The encoded message can then be transmitted or +stored as needed. .. code-block:: cpp @@ -351,7 +365,7 @@ transmitted or stored as needed. ...) { va_list args; va_start(args, types); - pw::tokenizer::EncodedMessage encoded_message(token, types, args); + pw::tokenizer::EncodedMessage<> encoded_message(token, types, args); va_end(args); HandleTokenizedMessage(metadata, encoded_message); diff --git a/pw_tokenizer/public/pw_tokenizer/encode_args.h b/pw_tokenizer/public/pw_tokenizer/encode_args.h index 65ab320fea..9fd2ffcc17 100644 --- a/pw_tokenizer/public/pw_tokenizer/encode_args.h +++ b/pw_tokenizer/public/pw_tokenizer/encode_args.h @@ -25,39 +25,39 @@ namespace pw { namespace tokenizer { -// Encodes a tokenized string's arguments to a buffer. The -// pw_tokenizer_ArgTypes parameter specifies the argument types, in place of a -// format string. -// -// Most tokenization implementations may use the EncodedMessage class below. +/// Encodes a tokenized string's arguments to a buffer. The +/// @cpp_type{pw_tokenizer_ArgTypes} parameter specifies the argument types, in +/// place of a format string. +/// +/// Most tokenization implementations should use the @cpp_class{EncodedMessage} +/// class. size_t EncodeArgs(pw_tokenizer_ArgTypes types, va_list args, span output); -// Encodes a tokenized message to a fixed size buffer. The size of the buffer is -// determined by the PW_TOKENIZER_CFG_ENCODING_BUFFER_SIZE_BYTES config macro. -// -// This class is used to encode tokenized messages passed in from the -// tokenization macros. The macros provided by pw_tokenizer use this class, and -// projects that elect to define their own versions of the tokenization macros -// should use it when possible. -// -// To use the pw::Tokenizer::EncodedMessage, construct it with the token, -// argument types, and va_list from the variadic arguments: -// -// void SendLogMessage(span log_data); -// -// extern "C" void TokenizeToSendLogMessage(pw_tokenizer_Token token, -// pw_tokenizer_ArgTypes types, -// ...) { -// va_list args; -// va_start(args, types); -// EncodedMessage encoded_message(token, types, args); -// va_end(args); -// -// SendLogMessage(encoded_message); // EncodedMessage converts to span -// } -// +/// Encodes a tokenized message to a fixed size buffer. By default, the buffer +/// size is set by the @c_macro{PW_TOKENIZER_CFG_ENCODING_BUFFER_SIZE_BYTES} +/// config macro. This class is used to encode tokenized messages passed in from +/// tokenization macros. +/// +/// To use `pw::tokenizer::EncodedMessage`, construct it with the token, +/// argument types, and `va_list` from the variadic arguments: +/// +/// @code{.cpp} +/// void SendLogMessage(span log_data); +/// +/// extern "C" void TokenizeToSendLogMessage(pw_tokenizer_Token token, +/// pw_tokenizer_ArgTypes types, +/// ...) { +/// va_list args; +/// va_start(args, types); +/// EncodedMessage encoded_message(token, types, args); +/// va_end(args); +/// +/// SendLogMessage(encoded_message); // EncodedMessage converts to span +/// } +/// @endcode +template class EncodedMessage { public: // Encodes a tokenized message to an internal buffer. @@ -65,30 +65,30 @@ class EncodedMessage { pw_tokenizer_ArgTypes types, va_list args) { std::memcpy(data_, &token, sizeof(token)); - args_size_ = + size_ = + sizeof(token) + EncodeArgs(types, args, span(data_).subspan(sizeof(token))); } - // The binary-encoded tokenized message. + /// The binary-encoded tokenized message. const std::byte* data() const { return data_; } - // Returns the data() as a pointer to uint8_t instead of std::byte. + /// Returns `data()` as a pointer to `uint8_t` instead of `std::byte`. const uint8_t* data_as_uint8() const { return reinterpret_cast(data()); } - // The size of the encoded tokenized message in bytes. - size_t size() const { return sizeof(pw_tokenizer_Token) + args_size_; } + /// The size of the encoded tokenized message in bytes. + size_t size() const { return size_; } private: - std::byte data_[PW_TOKENIZER_CFG_ENCODING_BUFFER_SIZE_BYTES]; - size_t args_size_; -}; + static_assert(kMaxSizeBytes >= sizeof(pw_tokenizer_Token), + "The encoding buffer must be at least large enough for a token " + "(4 bytes)"); -static_assert(PW_TOKENIZER_CFG_ENCODING_BUFFER_SIZE_BYTES >= - sizeof(pw_tokenizer_Token), - "PW_TOKENIZER_CFG_ENCODING_BUFFER_SIZE_BYTES must be at least " - "large enough for a token (4 bytes)"); + std::byte data_[kMaxSizeBytes]; + size_t size_; +}; } // namespace tokenizer } // namespace pw