pw_tokenizer: Support tokenizing __func__
- In C++, take an array reference for PW_TOKENIZE_STRING, so that
literals or arrays may be tokenized, but not const char*.
- Use std::to_array to copy the original string to the tokenized section
so that character arrays may be used.
- Add tests for tokenizing __func__ and __PRETTY_FUNCTION__ in C++.
Change-Id: I7a9e997d862a2eccad464e9113ce0cf5fc96697b
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/16962
Reviewed-by: Keir Mierle <keir@google.com>
Reviewed-by: Paul Mathieu <paulmathieu@google.com>
Commit-Queue: Wyatt Hepler <hepler@google.com>
diff --git a/pw_tokenizer/tokenize_test.cc b/pw_tokenizer/tokenize_test.cc
index bc552bc..cd96681 100644
--- a/pw_tokenizer/tokenize_test.cc
+++ b/pw_tokenizer/tokenize_test.cc
@@ -32,7 +32,7 @@
// configuration.
template <size_t kSize>
constexpr uint32_t TestHash(const char (&string)[kSize]) {
- constexpr unsigned kTestHashLength = 48;
+ constexpr unsigned kTestHashLength = 64;
static_assert(kTestHashLength <= PW_TOKENIZER_CFG_HASH_LENGTH);
static_assert(kSize <= kTestHashLength + 1);
return PwTokenizer65599FixedLengthHash(std::string_view(string, kSize - 1),
@@ -51,22 +51,60 @@
kData...};
}
-TEST(TokenizeStringLiteral, EmptyString_IsZero) {
+TEST(TokenizeString, EmptyString_IsZero) {
constexpr pw_TokenizerStringToken token = PW_TOKENIZE_STRING("");
EXPECT_EQ(0u, token);
}
-TEST(TokenizeStringLiteral, String_MatchesHash) {
+TEST(TokenizeString, String_MatchesHash) {
constexpr uint32_t token = PW_TOKENIZE_STRING("[:-)");
EXPECT_EQ(TestHash("[:-)"), token);
}
constexpr uint32_t kGlobalToken = PW_TOKENIZE_STRING(">:-[]");
-TEST(TokenizeStringLiteral, GlobalVariable_MatchesHash) {
+TEST(TokenizeString, GlobalVariable_MatchesHash) {
EXPECT_EQ(TestHash(">:-[]"), kGlobalToken);
}
+struct TokenizedWithinClass {
+ static constexpr uint32_t kThisToken = PW_TOKENIZE_STRING("???");
+};
+
+static_assert(TestHash("???") == TokenizedWithinClass::kThisToken);
+
+TEST(TokenizeString, ClassMember_MatchesHash) {
+ EXPECT_EQ(TestHash("???"), TokenizedWithinClass().kThisToken);
+}
+
+// Use a function with a shorter name to test tokenizing __func__ and
+// __PRETTY_FUNCTION__.
+//
+// WARNING: This function might cause errors for compilers other than GCC and
+// clang. It relies on two GCC/clang extensions:
+//
+// 1 - The __PRETTY_FUNCTION__ C++ function name variable.
+// 2 - __func__ as a static constexpr array instead of static const. See
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66639 for background.
+//
+void TestName() {
+ constexpr uint32_t function_hash = PW_TOKENIZE_STRING(__func__);
+ EXPECT_EQ(pw::tokenizer::TestHash(__func__), function_hash);
+
+ // Check the non-standard __PRETTY_FUNCTION__ name.
+ constexpr uint32_t pretty_function = PW_TOKENIZE_STRING(__PRETTY_FUNCTION__);
+ EXPECT_EQ(pw::tokenizer::TestHash(__PRETTY_FUNCTION__), pretty_function);
+}
+
+TEST(TokenizeString, FunctionName) { TestName(); }
+
+TEST(TokenizeString, Array) {
+ constexpr char array[] = "won-won-won-wonderful";
+
+ const uint32_t array_hash = PW_TOKENIZE_STRING(array);
+ EXPECT_EQ(TestHash(array), array_hash);
+}
+
// Verify that we can tokenize multiple strings from one source line.
#define THREE_FOR_ONE(first, second, third) \
[[maybe_unused]] constexpr uint32_t token_1 = \
@@ -76,7 +114,7 @@
[[maybe_unused]] constexpr uint32_t token_3 = \
PW_TOKENIZE_STRING_DOMAIN("ignored", third);
-TEST(TokenizeStringLiteral, MultipleTokenizationsInOneMacroExpansion) {
+TEST(TokenizeString, MultipleTokenizationsInOneMacroExpansion) {
// This verifies that we can safely tokenize multiple times in a single macro
// expansion. This can be useful when for example a name and description are
// both tokenized after being passed into a macro.
@@ -240,6 +278,16 @@
EXPECT_EQ(std::memcmp(empty.data(), buffer_, empty.size()), 0);
}
+TEST_F(TokenizeToBuffer, Array) {
+ static constexpr char array[] = "1234";
+ size_t message_size = 4;
+ PW_TOKENIZE_TO_BUFFER(buffer_, &message_size, array);
+
+ constexpr std::array<uint8_t, 4> result = ExpectedData<>("1234");
+ ASSERT_EQ(result.size(), message_size);
+ EXPECT_EQ(std::memcmp(result.data(), buffer_, result.size()), 0);
+}
+
TEST_F(TokenizeToBuffer, NullptrString_EncodesNull) {
char* string = nullptr;
size_t message_size = 9;