Skip to content

Commit

Permalink
pw_tokenizer: Make EncodedMessage a template
Browse files Browse the repository at this point in the history
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 <keir@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
  • Loading branch information
255 authored and CQ Bot Account committed Feb 27, 2023
1 parent 87a65ef commit d5cbaa5
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 53 deletions.
1 change: 1 addition & 0 deletions docs/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand Down
2 changes: 1 addition & 1 deletion pw_log_tokenized/compatibility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion pw_log_tokenized/log_tokenized.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
34 changes: 24 additions & 10 deletions pw_tokenizer/docs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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, ...)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
82 changes: 41 additions & 41 deletions pw_tokenizer/public/pw_tokenizer/encode_args.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,70 +25,70 @@
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<std::byte> 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<std::byte> 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<std::byte> 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 <size_t kMaxSizeBytes = PW_TOKENIZER_CFG_ENCODING_BUFFER_SIZE_BYTES>
class EncodedMessage {
public:
// Encodes a tokenized message to an internal buffer.
EncodedMessage(pw_tokenizer_Token token,
pw_tokenizer_ArgTypes types,
va_list args) {
std::memcpy(data_, &token, sizeof(token));
args_size_ =
size_ =
sizeof(token) +
EncodeArgs(types, args, span<std::byte>(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<const uint8_t*>(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

0 comments on commit d5cbaa5

Please sign in to comment.