• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
50 namespace tokenizer {
51 namespace internal {
52 
53 static_assert(sizeof(_pw_tokenizer_EntryHeader) == 4 * sizeof(uint32_t));
54 
55 // The C++ tokenzied string entry supports both string literals and char arrays,
56 // such as __func__.
57 template <uint32_t kDomainSize, uint32_t kStringSize>
PW_PACKED(class)58 PW_PACKED(class)
59 Entry {
60  public:
61   constexpr Entry(uint32_t token,
62                   const char(&domain)[kDomainSize],
63                   const char(&string)[kStringSize])
64       : header_{.magic = _PW_TOKENIZER_ENTRY_MAGIC,
65                 .token = token,
66                 .domain_length = kDomainSize,
67                 .string_length = kStringSize},
68         domain_(containers::to_array(domain)),
69         string_(containers::to_array(string)) {}
70 
71  private:
72   static_assert(kStringSize > 0u && kDomainSize > 0u,
73                 "The string and domain must have at least a null terminator");
74 
75   _pw_tokenizer_EntryHeader header_;
76   std::array<char, kDomainSize> domain_;
77   std::array<char, kStringSize> string_;
78 };
79 
80 // Use this MakeEntry function so that the type doesn't have to be specified in
81 // the macro. Specifying the type causes problems when the tokenization macro is
82 // used as an argument to another macro because it requires template arguments,
83 // which the preprocessor misinterprets as macro arguments.
84 template <uint32_t kDomainSize, uint32_t kStringSize>
MakeEntry(uint32_t token,const char (& domain)[kDomainSize],const char (& string)[kStringSize])85 constexpr Entry<kDomainSize, kStringSize> MakeEntry(
86     uint32_t token,
87     const char (&domain)[kDomainSize],
88     const char (&string)[kStringSize]) {
89   return {token, domain, string};
90 }
91 
92 }  // namespace internal
93 }  // namespace tokenizer
94 }  // namespace pw
95 
96 #else  // In C, define a struct inline with appropriately-sized string members.
97 
98 #define _PW_TOKENIZER_STRING_ENTRY(                   \
99     calculated_token, domain_literal, string_literal) \
100   PW_PACKED(struct) {                                 \
101     _pw_tokenizer_EntryHeader header;                 \
102     char domain[sizeof(domain_literal)];              \
103     char string[sizeof(string_literal)];              \
104   }                                                   \
105   _PW_TOKENIZER_UNIQUE(_pw_tokenizer_string_entry_)   \
106   _PW_TOKENIZER_SECTION = {                           \
107       {                                               \
108           .magic = _PW_TOKENIZER_ENTRY_MAGIC,         \
109           .token = calculated_token,                  \
110           .domain_length = sizeof(domain_literal),    \
111           .string_length = sizeof(string_literal),    \
112       },                                              \
113       domain_literal,                                 \
114       string_literal,                                 \
115   }
116 
117 #endif  // __cplusplus
118 
119 // In C++17, use a constexpr function to calculate the hash.
120 #if defined(__cpp_constexpr) && __cpp_constexpr >= 201304L && \
121     defined(__cpp_inline_variables)
122 
123 #include "pw_tokenizer/hash.h"
124 
125 #define PW_TOKENIZER_STRING_TOKEN(format) ::pw::tokenizer::Hash(format)
126 
127 #else  // In C or older C++ code, use the hashing macro.
128 
129 #if PW_TOKENIZER_CFG_C_HASH_LENGTH == 80
130 
131 #include "pw_tokenizer/internal/pw_tokenizer_65599_fixed_length_80_hash_macro.h"
132 #define PW_TOKENIZER_STRING_TOKEN PW_TOKENIZER_65599_FIXED_LENGTH_80_HASH
133 
134 #elif PW_TOKENIZER_CFG_C_HASH_LENGTH == 96
135 
136 #include "pw_tokenizer/internal/pw_tokenizer_65599_fixed_length_96_hash_macro.h"
137 #define PW_TOKENIZER_STRING_TOKEN PW_TOKENIZER_65599_FIXED_LENGTH_96_HASH
138 
139 #elif PW_TOKENIZER_CFG_C_HASH_LENGTH == 128
140 
141 #include "pw_tokenizer/internal/pw_tokenizer_65599_fixed_length_128_hash_macro.h"
142 #define PW_TOKENIZER_STRING_TOKEN PW_TOKENIZER_65599_FIXED_LENGTH_128_HASH
143 
144 #elif PW_TOKENIZER_CFG_C_HASH_LENGTH == 256
145 
146 #include "pw_tokenizer/internal/pw_tokenizer_65599_fixed_length_256_hash_macro.h"
147 #define PW_TOKENIZER_STRING_TOKEN PW_TOKENIZER_65599_FIXED_LENGTH_256_HASH
148 
149 #else  // unsupported hash length
150 
151 // Only hash lengths for which there is a corresponding macro header
152 // (pw_tokenizer/internal/mash_macro_#.h) are supported. Additional macros may
153 // be generated with the generate_hash_macro.py function. New macro headers must
154 // be added to this file.
155 #error "Unsupported value for PW_TOKENIZER_CFG_C_HASH_LENGTH"
156 
157 // Define a placeholder macro to give clearer compilation errors.
158 #define PW_TOKENIZER_STRING_TOKEN(unused) 0u
159 
160 #endif  // PW_TOKENIZER_CFG_C_HASH_LENGTH
161 
162 #endif  // __cpp_constexpr >= 201304L && defined(__cpp_inline_variables)
163