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