xref: /aosp_15_r20/external/pigweed/pw_tokenizer/public/pw_tokenizer/internal/tokenize_string.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 // Selects the hash macro implementation to use. The implementation selected
16 // depends on the language (C or C++) and value of
17 // PW_TOKENIZER_CFG_C_HASH_LENGTH. The options are:
18 //
19 //   - C++ hash constexpr function, which works for any hash length
20 //   - C 80-character hash macro
21 //   - C 96-character hash macro
22 //   - C 128-character hash macro
23 //
24 // C hash macros for other lengths may be generated using generate_hash_macro.py
25 // and added to this file.
26 #pragma once
27 
28 #include <stdint.h>
29 
30 #define _PW_TOKENIZER_ENTRY_MAGIC 0xBAA98DEE
31 
32 // Tokenizer entries are stored sequentially in an ELF section. Each entry
33 // starts with a header comprised of a magic number, the token, and the domain
34 // and string lengths. The domain and tokenized string follow immediately after
35 // the header, with no padding or null terminators. Entries are NOT aligned
36 // within the section.
37 typedef struct {
38   uint32_t magic;          // must be _PW_TOKENIZER_ENTRY_MAGIC
39   uint32_t token;          // the token that represents this string.
40   uint32_t domain_length;  // domain string length
41   uint32_t string_length;  // tokenized string length
42 } _pw_tokenizer_EntryHeader;
43 
44 #ifdef __cplusplus
45 
46 #include "pw_containers/to_array.h"
47 #include "pw_preprocessor/compiler.h"
48 
49 namespace pw::tokenizer::internal {
50 
51 static_assert(sizeof(_pw_tokenizer_EntryHeader) == 4 * sizeof(uint32_t));
52 
53 // The C++ tokenzied string entry supports both string literals and char arrays,
54 // such as __func__.
55 template <uint32_t kDomainSize, uint32_t kStringSize>
PW_PACKED(class)56 PW_PACKED(class)
57 Entry {
58  public:
59   constexpr Entry(uint32_t token,
60                   const char(&domain)[kDomainSize],
61                   const char(&string)[kStringSize])
62       : header_{.magic = _PW_TOKENIZER_ENTRY_MAGIC,
63                 .token = token,
64                 .domain_length = kDomainSize,
65                 .string_length = kStringSize},
66         domain_(containers::to_array(domain)),
67         string_(containers::to_array(string)) {}
68 
69  private:
70   static_assert(kStringSize > 0u && kDomainSize > 0u,
71                 "The string and domain must have at least a null terminator");
72 
73   _pw_tokenizer_EntryHeader header_;
74   std::array<char, kDomainSize> domain_;
75   std::array<char, kStringSize> string_;
76 };
77 
78 // Use this MakeEntry function so that the type doesn't have to be specified in
79 // the macro. Specifying the type causes problems when the tokenization macro is
80 // used as an argument to another macro because it requires template arguments,
81 // which the preprocessor misinterprets as macro arguments.
82 template <uint32_t kDomainSize, uint32_t kStringSize>
MakeEntry(uint32_t token,const char (& domain)[kDomainSize],const char (& string)[kStringSize])83 constexpr Entry<kDomainSize, kStringSize> MakeEntry(
84     uint32_t token,
85     const char (&domain)[kDomainSize],
86     const char (&string)[kStringSize]) {
87   return {token, domain, string};
88 }
89 
90 }  // namespace pw::tokenizer::internal
91 
92 #else  // In C, define a struct inline with appropriately-sized string members.
93 
94 #define _PW_TOKENIZER_STRING_ENTRY(                   \
95     calculated_token, domain_literal, string_literal) \
96   PW_PACKED(struct) {                                 \
97     _pw_tokenizer_EntryHeader header;                 \
98     char domain[sizeof(domain_literal)];              \
99     char string[sizeof(string_literal)];              \
100   }                                                   \
101   _PW_TOKENIZER_UNIQUE(_pw_tokenizer_string_entry_)   \
102   _PW_TOKENIZER_SECTION = {                           \
103       {                                               \
104           .magic = _PW_TOKENIZER_ENTRY_MAGIC,         \
105           .token = calculated_token,                  \
106           .domain_length = sizeof(domain_literal),    \
107           .string_length = sizeof(string_literal),    \
108       },                                              \
109       domain_literal,                                 \
110       string_literal,                                 \
111   }
112 
113 #endif  // __cplusplus
114 
115 // In C++17, use a constexpr function to calculate the hash.
116 #if defined(__cpp_constexpr) && __cpp_constexpr >= 201304L && \
117     defined(__cpp_inline_variables)
118 
119 #include "pw_tokenizer/hash.h"
120 
121 #define PW_TOKENIZER_STRING_TOKEN(format) ::pw::tokenizer::Hash(format)
122 
123 #else  // In C or older C++ code, use the hashing macro.
124 
125 #if PW_TOKENIZER_CFG_C_HASH_LENGTH == 80
126 
127 #include "pw_tokenizer/internal/pw_tokenizer_65599_fixed_length_80_hash_macro.h"
128 #define PW_TOKENIZER_STRING_TOKEN PW_TOKENIZER_65599_FIXED_LENGTH_80_HASH
129 
130 #elif PW_TOKENIZER_CFG_C_HASH_LENGTH == 96
131 
132 #include "pw_tokenizer/internal/pw_tokenizer_65599_fixed_length_96_hash_macro.h"
133 #define PW_TOKENIZER_STRING_TOKEN PW_TOKENIZER_65599_FIXED_LENGTH_96_HASH
134 
135 #elif PW_TOKENIZER_CFG_C_HASH_LENGTH == 128
136 
137 #include "pw_tokenizer/internal/pw_tokenizer_65599_fixed_length_128_hash_macro.h"
138 #define PW_TOKENIZER_STRING_TOKEN PW_TOKENIZER_65599_FIXED_LENGTH_128_HASH
139 
140 #elif PW_TOKENIZER_CFG_C_HASH_LENGTH == 256
141 
142 #include "pw_tokenizer/internal/pw_tokenizer_65599_fixed_length_256_hash_macro.h"
143 #define PW_TOKENIZER_STRING_TOKEN PW_TOKENIZER_65599_FIXED_LENGTH_256_HASH
144 
145 #else  // unsupported hash length
146 
147 // Only hash lengths for which there is a corresponding macro header
148 // (pw_tokenizer/internal/mash_macro_#.h) are supported. Additional macros may
149 // be generated with the generate_hash_macro.py function. New macro headers must
150 // be added to this file.
151 #error "Unsupported value for PW_TOKENIZER_CFG_C_HASH_LENGTH"
152 
153 // Define a placeholder macro to give clearer compilation errors.
154 #define PW_TOKENIZER_STRING_TOKEN(unused) 0u
155 
156 #endif  // PW_TOKENIZER_CFG_C_HASH_LENGTH
157 
158 #endif  // __cpp_constexpr >= 201304L && defined(__cpp_inline_variables)
159