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