1 | /* |
2 | * Copyright 2016 Google Inc. All rights reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #include "flatbuffers/code_generators.h" |
18 | #include <assert.h> |
19 | #include "flatbuffers/base.h" |
20 | #include "flatbuffers/util.h" |
21 | |
22 | #include <cmath> |
23 | |
24 | #if defined(_MSC_VER) |
25 | # pragma warning(push) |
26 | # pragma warning(disable : 4127) // C4127: conditional expression is constant |
27 | #endif |
28 | |
29 | namespace flatbuffers { |
30 | |
31 | void CodeWriter::operator+=(std::string text) { |
32 | while (true) { |
33 | auto begin = text.find("{{" ); |
34 | if (begin == std::string::npos) { break; } |
35 | |
36 | auto end = text.find("}}" ); |
37 | if (end == std::string::npos || end < begin) { break; } |
38 | |
39 | // Write all the text before the first {{ into the stream. |
40 | stream_.write(text.c_str(), begin); |
41 | |
42 | // The key is between the {{ and }}. |
43 | const std::string key = text.substr(begin + 2, end - begin - 2); |
44 | |
45 | // Find the value associated with the key. If it exists, write the |
46 | // value into the stream, otherwise write the key itself into the stream. |
47 | auto iter = value_map_.find(key); |
48 | if (iter != value_map_.end()) { |
49 | const std::string &value = iter->second; |
50 | stream_ << value; |
51 | } else { |
52 | FLATBUFFERS_ASSERT(false && "could not find key" ); |
53 | stream_ << key; |
54 | } |
55 | |
56 | // Update the text to everything after the }}. |
57 | text = text.substr(end + 2); |
58 | } |
59 | if (!text.empty() && string_back(text) == '\\') { |
60 | text.pop_back(); |
61 | stream_ << text; |
62 | } else { |
63 | stream_ << text << std::endl; |
64 | } |
65 | } |
66 | |
67 | const char *BaseGenerator::FlatBuffersGeneratedWarning() { |
68 | return "automatically generated by the FlatBuffers compiler," |
69 | " do not modify" ; |
70 | } |
71 | |
72 | std::string BaseGenerator::NamespaceDir(const Parser &parser, |
73 | const std::string &path, |
74 | const Namespace &ns) { |
75 | EnsureDirExists(path.c_str()); |
76 | if (parser.opts.one_file) return path; |
77 | std::string namespace_dir = path; // Either empty or ends in separator. |
78 | auto &namespaces = ns.components; |
79 | for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { |
80 | namespace_dir += *it + kPathSeparator; |
81 | EnsureDirExists(namespace_dir.c_str()); |
82 | } |
83 | return namespace_dir; |
84 | } |
85 | |
86 | std::string BaseGenerator::NamespaceDir(const Namespace &ns) const { |
87 | return BaseGenerator::NamespaceDir(parser_, path_, ns); |
88 | } |
89 | |
90 | std::string BaseGenerator::FullNamespace(const char *separator, |
91 | const Namespace &ns) { |
92 | std::string namespace_name; |
93 | auto &namespaces = ns.components; |
94 | for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { |
95 | if (namespace_name.length()) namespace_name += separator; |
96 | namespace_name += *it; |
97 | } |
98 | return namespace_name; |
99 | } |
100 | |
101 | std::string BaseGenerator::LastNamespacePart(const Namespace &ns) { |
102 | if (!ns.components.empty()) |
103 | return ns.components.back(); |
104 | else |
105 | return std::string("" ); |
106 | } |
107 | |
108 | // Ensure that a type is prefixed with its namespace whenever it is used |
109 | // outside of its namespace. |
110 | std::string BaseGenerator::WrapInNameSpace(const Namespace *ns, |
111 | const std::string &name) const { |
112 | if (CurrentNameSpace() == ns) return name; |
113 | std::string qualified_name = qualifying_start_; |
114 | for (auto it = ns->components.begin(); it != ns->components.end(); ++it) |
115 | qualified_name += *it + qualifying_separator_; |
116 | return qualified_name + name; |
117 | } |
118 | |
119 | std::string BaseGenerator::WrapInNameSpace(const Definition &def) const { |
120 | return WrapInNameSpace(def.defined_namespace, def.name); |
121 | } |
122 | |
123 | std::string BaseGenerator::GetNameSpace(const Definition &def) const { |
124 | const Namespace *ns = def.defined_namespace; |
125 | if (CurrentNameSpace() == ns) return "" ; |
126 | std::string qualified_name = qualifying_start_; |
127 | for (auto it = ns->components.begin(); it != ns->components.end(); ++it) { |
128 | qualified_name += *it; |
129 | if ((it + 1) != ns->components.end()) { |
130 | qualified_name += qualifying_separator_; |
131 | } |
132 | } |
133 | |
134 | return qualified_name; |
135 | } |
136 | |
137 | // Generate a documentation comment, if available. |
138 | void (const std::vector<std::string> &dc, std::string *code_ptr, |
139 | const CommentConfig *config, const char *prefix) { |
140 | if (dc.begin() == dc.end()) { |
141 | // Don't output empty comment blocks with 0 lines of comment content. |
142 | return; |
143 | } |
144 | |
145 | std::string &code = *code_ptr; |
146 | if (config != nullptr && config->first_line != nullptr) { |
147 | code += std::string(prefix) + std::string(config->first_line) + "\n" ; |
148 | } |
149 | std::string line_prefix = |
150 | std::string(prefix) + |
151 | ((config != nullptr && config->content_line_prefix != nullptr) |
152 | ? config->content_line_prefix |
153 | : "///" ); |
154 | for (auto it = dc.begin(); it != dc.end(); ++it) { |
155 | code += line_prefix + *it + "\n" ; |
156 | } |
157 | if (config != nullptr && config->last_line != nullptr) { |
158 | code += std::string(prefix) + std::string(config->last_line) + "\n" ; |
159 | } |
160 | } |
161 | |
162 | template<typename T> |
163 | std::string FloatConstantGenerator::GenFloatConstantImpl( |
164 | const FieldDef &field) const { |
165 | const auto &constant = field.value.constant; |
166 | T v; |
167 | auto done = StringToNumber(constant.c_str(), &v); |
168 | FLATBUFFERS_ASSERT(done); |
169 | if (done) { |
170 | #if (!defined(_MSC_VER) || (_MSC_VER >= 1800)) |
171 | if (std::isnan(v)) return NaN(v); |
172 | if (std::isinf(v)) return Inf(v); |
173 | #endif |
174 | return Value(v, constant); |
175 | } |
176 | return "#" ; // compile time error |
177 | } |
178 | |
179 | std::string FloatConstantGenerator::GenFloatConstant( |
180 | const FieldDef &field) const { |
181 | switch (field.value.type.base_type) { |
182 | case BASE_TYPE_FLOAT: return GenFloatConstantImpl<float>(field); |
183 | case BASE_TYPE_DOUBLE: return GenFloatConstantImpl<double>(field); |
184 | default: { |
185 | FLATBUFFERS_ASSERT(false); |
186 | return "INVALID_BASE_TYPE" ; |
187 | } |
188 | }; |
189 | } |
190 | |
191 | TypedFloatConstantGenerator::TypedFloatConstantGenerator( |
192 | const char *double_prefix, const char *single_prefix, |
193 | const char *nan_number, const char *pos_inf_number, |
194 | const char *neg_inf_number) |
195 | : double_prefix_(double_prefix), |
196 | single_prefix_(single_prefix), |
197 | nan_number_(nan_number), |
198 | pos_inf_number_(pos_inf_number), |
199 | neg_inf_number_(neg_inf_number) {} |
200 | |
201 | std::string TypedFloatConstantGenerator::MakeNaN( |
202 | const std::string &prefix) const { |
203 | return prefix + nan_number_; |
204 | } |
205 | std::string TypedFloatConstantGenerator::MakeInf( |
206 | bool neg, const std::string &prefix) const { |
207 | if (neg) |
208 | return !neg_inf_number_.empty() ? (prefix + neg_inf_number_) |
209 | : ("-" + prefix + pos_inf_number_); |
210 | else |
211 | return prefix + pos_inf_number_; |
212 | } |
213 | |
214 | std::string TypedFloatConstantGenerator::Value(double v, |
215 | const std::string &src) const { |
216 | (void)v; |
217 | return src; |
218 | } |
219 | |
220 | std::string TypedFloatConstantGenerator::Inf(double v) const { |
221 | return MakeInf(v < 0, double_prefix_); |
222 | } |
223 | |
224 | std::string TypedFloatConstantGenerator::NaN(double v) const { |
225 | (void)v; |
226 | return MakeNaN(double_prefix_); |
227 | } |
228 | |
229 | std::string TypedFloatConstantGenerator::Value(float v, |
230 | const std::string &src) const { |
231 | (void)v; |
232 | return src + "f" ; |
233 | } |
234 | |
235 | std::string TypedFloatConstantGenerator::Inf(float v) const { |
236 | return MakeInf(v < 0, single_prefix_); |
237 | } |
238 | |
239 | std::string TypedFloatConstantGenerator::NaN(float v) const { |
240 | (void)v; |
241 | return MakeNaN(single_prefix_); |
242 | } |
243 | |
244 | SimpleFloatConstantGenerator::SimpleFloatConstantGenerator( |
245 | const char *nan_number, const char *pos_inf_number, |
246 | const char *neg_inf_number) |
247 | : nan_number_(nan_number), |
248 | pos_inf_number_(pos_inf_number), |
249 | neg_inf_number_(neg_inf_number) {} |
250 | |
251 | std::string SimpleFloatConstantGenerator::Value(double v, |
252 | const std::string &src) const { |
253 | (void)v; |
254 | return src; |
255 | } |
256 | |
257 | std::string SimpleFloatConstantGenerator::Inf(double v) const { |
258 | return (v < 0) ? neg_inf_number_ : pos_inf_number_; |
259 | } |
260 | |
261 | std::string SimpleFloatConstantGenerator::NaN(double v) const { |
262 | (void)v; |
263 | return nan_number_; |
264 | } |
265 | |
266 | std::string SimpleFloatConstantGenerator::Value(float v, |
267 | const std::string &src) const { |
268 | return this->Value(static_cast<double>(v), src); |
269 | } |
270 | |
271 | std::string SimpleFloatConstantGenerator::Inf(float v) const { |
272 | return this->Inf(static_cast<double>(v)); |
273 | } |
274 | |
275 | std::string SimpleFloatConstantGenerator::NaN(float v) const { |
276 | return this->NaN(static_cast<double>(v)); |
277 | } |
278 | |
279 | } // namespace flatbuffers |
280 | |
281 | #if defined(_MSC_VER) |
282 | # pragma warning(pop) |
283 | #endif |
284 | |