Skip to content

Commit

Permalink
pw_tokenizer: Encoding buffer sizing helper
Browse files Browse the repository at this point in the history
pw::tokenizer::MinEncodingBufferSizeBytes() calculates the minimum
buffer size guaranteed to be able to encode a tokenized message with the
specified arguments.

Change-Id: I72ed3f5e31d8c707ec4500357d4b684a5c210024
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/107393
Commit-Queue: Auto-Submit <[email protected]>
Pigweed-Auto-Submit: Wyatt Hepler <[email protected]>
Reviewed-by: Alexei Frolov <[email protected]>
  • Loading branch information
255 authored and CQ Bot Account committed Mar 6, 2023
1 parent ed3638c commit f02e284
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 4 deletions.
9 changes: 9 additions & 0 deletions pw_tokenizer/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,15 @@ pw_cc_fuzz_test(
],
)

pw_cc_test(
name = "encode_args_test",
srcs = ["encode_args_test.cc"],
deps = [
":pw_tokenizer",
"//pw_unit_test",
],
)

pw_cc_test(
name = "hash_test",
srcs = [
Expand Down
6 changes: 6 additions & 0 deletions pw_tokenizer/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ pw_test_group("tests") {
":decode_test",
":detokenize_fuzzer",
":detokenize_test",
":encode_args_test",
":hash_test",
":simple_tokenize_test",
":token_database_fuzzer",
Expand Down Expand Up @@ -226,6 +227,11 @@ pw_test("detokenize_test") {
enable_if = pw_build_EXECUTABLE_TARGET_TYPE != "arduino_executable"
}

pw_test("encode_args_test") {
sources = [ "encode_args_test.cc" ]
deps = [ ":pw_tokenizer" ]
}

pw_test("hash_test") {
sources = [
"hash_test.cc",
Expand Down
10 changes: 10 additions & 0 deletions pw_tokenizer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,16 @@ pw_add_test(pw_tokenizer.detokenize_test
pw_tokenizer
)

pw_add_test(pw_tokenizer.encode_args_test
SOURCES
encode_args_test.cc
PRIVATE_DEPS
pw_tokenizer
GROUPS
modules
pw_tokenizer
)

pw_add_test(pw_tokenizer.hash_test
SOURCES
hash_test.cc
Expand Down
4 changes: 4 additions & 0 deletions pw_tokenizer/docs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@ Arguments are encoded as follows:
arguments short or avoid encoding them as strings (e.g. encode an enum as an
integer instead of a string). See also `Tokenized strings as %s arguments`_.

Buffer sizing helper
--------------------
.. doxygenfunction:: pw::tokenizer::MinEncodingBufferSizeBytes

Encoding command line utility
-----------------------------
The ``pw_tokenizer.encode`` command line tool can be used to encode tokenized
Expand Down
42 changes: 42 additions & 0 deletions pw_tokenizer/encode_args_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2022 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

#include "pw_tokenizer/encode_args.h"

#include "gtest/gtest.h"

namespace pw {
namespace tokenizer {

static_assert(MinEncodingBufferSizeBytes<>() == 4);
static_assert(MinEncodingBufferSizeBytes<bool>() == 4 + 2);
static_assert(MinEncodingBufferSizeBytes<char>() == 4 + 2);
static_assert(MinEncodingBufferSizeBytes<short>() == 4 + 3);
static_assert(MinEncodingBufferSizeBytes<int>() == 4 + 5);
static_assert(MinEncodingBufferSizeBytes<long long>() == 4 + 10);
static_assert(MinEncodingBufferSizeBytes<float>() == 4 + 4);
static_assert(MinEncodingBufferSizeBytes<double>() == 4 + 4);
static_assert(MinEncodingBufferSizeBytes<const char*>() == 4 + 1);
static_assert(MinEncodingBufferSizeBytes<void*>() == 4 + 5 ||
MinEncodingBufferSizeBytes<void*>() == 4 + 10);

static_assert(MinEncodingBufferSizeBytes<int, double>() == 4 + 5 + 4);
static_assert(MinEncodingBufferSizeBytes<int, int, const char*>() ==
4 + 5 + 5 + 1);
static_assert(
MinEncodingBufferSizeBytes<const char*, long long, int, short>() ==
4 + 1 + 10 + 5 + 3);

} // namespace tokenizer
} // namespace pw
47 changes: 43 additions & 4 deletions pw_tokenizer/public/pw_tokenizer/encode_args.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,52 @@

#include <cstring>

#include "pw_polyfill/standard.h"
#include "pw_span/span.h"
#include "pw_tokenizer/config.h"
#include "pw_tokenizer/tokenize.h"

namespace pw {
namespace tokenizer {
namespace pw::tokenizer {
namespace internal {

// Returns the maximum encoded size of an argument of the specified type.
template <typename T>
constexpr size_t ArgEncodedSizeBytes() {
constexpr pw_tokenizer_ArgTypes kType = VarargsType<T>();
if constexpr (kType == PW_TOKENIZER_ARG_TYPE_DOUBLE) {
return sizeof(float);
} else if constexpr (kType == PW_TOKENIZER_ARG_TYPE_STRING) {
return 1; // Size of the length byte only
} else if constexpr (kType == PW_TOKENIZER_ARG_TYPE_INT64) {
return 10; // Max size of a varint-encoded 64-bit integer
} else if constexpr (kType == PW_TOKENIZER_ARG_TYPE_INT) {
return sizeof(T) + 1; // Max size of zig-zag varint integer <= 32-bits
} else {
static_assert(sizeof(T) != sizeof(T), "Unsupported argument type");
}
}

} // namespace internal

/// Calculates the minimum buffer size to allocate that is guaranteed to support
/// encoding the specified arguments.
///
/// The contents of strings are NOT included in this total. The string's
/// length/status byte is guaranteed to fit, but the string contents may be
/// truncated. Encoding is considered to succeed as long as the string's
/// length/status byte is written, even if the actual string is truncated.
///
/// Examples:
///
/// - Message with no arguments:
/// `MinEncodingBufferSizeBytes() == 4`
/// - Message with an int argument
/// `MinEncodingBufferSizeBytes<int>() == 9 (4 + 5)`
template <typename... ArgTypes>
constexpr size_t MinEncodingBufferSizeBytes() {
return (sizeof(pw_tokenizer_Token) + ... +
internal::ArgEncodedSizeBytes<ArgTypes>());
}

/// Encodes a tokenized string's arguments to a buffer. The
/// @cpp_type{pw_tokenizer_ArgTypes} parameter specifies the argument types, in
Expand Down Expand Up @@ -97,8 +137,7 @@ class EncodedMessage {
size_t size_;
};

} // namespace tokenizer
} // namespace pw
} // namespace pw::tokenizer

#endif // PW_CXX_STANDARD_IS_SUPPORTED(17)

Expand Down

0 comments on commit f02e284

Please sign in to comment.