blob: a56dad91c4bbd892570dcfb34ef2adf22646ed16 [file] [log] [blame]
Austin Schuh272c6132020-11-14 16:37:52 -08001 /*
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002 * Copyright 2014 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// independent from idl_parser, since this code is not needed for most clients
18
Austin Schuh272c6132020-11-14 16:37:52 -080019#include <unordered_set>
20
Austin Schuhe89fa2d2019-08-14 20:24:23 -070021#include "flatbuffers/code_generators.h"
22#include "flatbuffers/flatbuffers.h"
Austin Schuh272c6132020-11-14 16:37:52 -080023#include "flatbuffers/flatc.h"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070024#include "flatbuffers/idl.h"
25#include "flatbuffers/util.h"
26
Austin Schuhe89fa2d2019-08-14 20:24:23 -070027namespace flatbuffers {
28
Austin Schuhe89fa2d2019-08-14 20:24:23 -070029// Make numerical literal with type-suffix.
30// This function is only needed for C++! Other languages do not need it.
31static inline std::string NumToStringCpp(std::string val, BaseType type) {
32 // Avoid issues with -2147483648, -9223372036854775808.
33 switch (type) {
34 case BASE_TYPE_INT:
35 return (val != "-2147483648") ? val : ("(-2147483647 - 1)");
36 case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL");
37 case BASE_TYPE_LONG:
38 if (val == "-9223372036854775808")
39 return "(-9223372036854775807LL - 1LL)";
40 else
41 return (val == "0") ? val : (val + "LL");
42 default: return val;
43 }
44}
45
Austin Schuh272c6132020-11-14 16:37:52 -080046static std::string GenIncludeGuard(const std::string &file_name,
47 const Namespace &name_space,
48 const std::string &postfix = "") {
49 // Generate include guard.
50 std::string guard = file_name;
51 // Remove any non-alpha-numeric characters that may appear in a filename.
52 struct IsAlnum {
53 bool operator()(char c) const { return !is_alnum(c); }
54 };
55 guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
56 guard.end());
57 guard = "FLATBUFFERS_GENERATED_" + guard;
58 guard += "_";
59 // For further uniqueness, also add the namespace.
60 for (auto it = name_space.components.begin();
61 it != name_space.components.end(); ++it) {
62 guard += *it + "_";
63 }
64 // Anything extra to add to the guard?
65 if (!postfix.empty()) { guard += postfix + "_"; }
66 guard += "H_";
67 std::transform(guard.begin(), guard.end(), guard.begin(), CharToUpper);
68 return guard;
Austin Schuhe89fa2d2019-08-14 20:24:23 -070069}
70
71namespace cpp {
Austin Schuh272c6132020-11-14 16:37:52 -080072
73enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
74
75// Define a style of 'struct' constructor if it has 'Array' fields.
76enum GenArrayArgMode {
77 kArrayArgModeNone, // don't generate initialization args
78 kArrayArgModeSpanStatic, // generate flatbuffers::span<T,N>
79};
80
81// Extension of IDLOptions for cpp-generator.
82struct IDLOptionsCpp : public IDLOptions {
83 // All fields start with 'g_' prefix to distinguish from the base IDLOptions.
84 CppStandard g_cpp_std; // Base version of C++ standard.
85 bool g_only_fixed_enums; // Generate underlaying type for all enums.
86
87 IDLOptionsCpp(const IDLOptions &opts)
88 : IDLOptions(opts), g_cpp_std(CPP_STD_11), g_only_fixed_enums(true) {}
89};
90
Austin Schuhe89fa2d2019-08-14 20:24:23 -070091class CppGenerator : public BaseGenerator {
92 public:
93 CppGenerator(const Parser &parser, const std::string &path,
Austin Schuh272c6132020-11-14 16:37:52 -080094 const std::string &file_name, IDLOptionsCpp opts)
95 : BaseGenerator(parser, path, file_name, "", "::", "h"),
Austin Schuhe89fa2d2019-08-14 20:24:23 -070096 cur_name_space_(nullptr),
Austin Schuh272c6132020-11-14 16:37:52 -080097 opts_(opts),
Austin Schuhe89fa2d2019-08-14 20:24:23 -070098 float_const_gen_("std::numeric_limits<double>::",
99 "std::numeric_limits<float>::", "quiet_NaN()",
100 "infinity()") {
101 static const char *const keywords[] = {
102 "alignas",
103 "alignof",
104 "and",
105 "and_eq",
106 "asm",
107 "atomic_cancel",
108 "atomic_commit",
109 "atomic_noexcept",
110 "auto",
111 "bitand",
112 "bitor",
113 "bool",
114 "break",
115 "case",
116 "catch",
117 "char",
118 "char16_t",
119 "char32_t",
120 "class",
121 "compl",
122 "concept",
123 "const",
124 "constexpr",
125 "const_cast",
126 "continue",
127 "co_await",
128 "co_return",
129 "co_yield",
130 "decltype",
131 "default",
132 "delete",
133 "do",
134 "double",
135 "dynamic_cast",
136 "else",
137 "enum",
138 "explicit",
139 "export",
140 "extern",
141 "false",
142 "float",
143 "for",
144 "friend",
145 "goto",
146 "if",
147 "import",
148 "inline",
149 "int",
150 "long",
151 "module",
152 "mutable",
153 "namespace",
154 "new",
155 "noexcept",
156 "not",
157 "not_eq",
158 "nullptr",
159 "operator",
160 "or",
161 "or_eq",
162 "private",
163 "protected",
164 "public",
165 "register",
166 "reinterpret_cast",
167 "requires",
168 "return",
169 "short",
170 "signed",
171 "sizeof",
172 "static",
173 "static_assert",
174 "static_cast",
175 "struct",
176 "switch",
177 "synchronized",
178 "template",
179 "this",
180 "thread_local",
181 "throw",
182 "true",
183 "try",
184 "typedef",
185 "typeid",
186 "typename",
187 "union",
188 "unsigned",
189 "using",
190 "virtual",
191 "void",
192 "volatile",
193 "wchar_t",
194 "while",
195 "xor",
196 "xor_eq",
197 nullptr,
198 };
199 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
200 }
201
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700202 void GenIncludeDependencies() {
203 int num_includes = 0;
Austin Schuh272c6132020-11-14 16:37:52 -0800204 if (opts_.generate_object_based_api) {
205 for (auto it = parser_.native_included_files_.begin();
206 it != parser_.native_included_files_.end(); ++it) {
207 code_ += "#include \"" + *it + "\"";
208 num_includes++;
209 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700210 }
211 for (auto it = parser_.included_files_.begin();
212 it != parser_.included_files_.end(); ++it) {
213 if (it->second.empty()) continue;
214 auto noext = flatbuffers::StripExtension(it->second);
215 auto basename = flatbuffers::StripPath(noext);
Austin Schuh272c6132020-11-14 16:37:52 -0800216 auto includeName =
217 GeneratedFileName(opts_.include_prefix,
218 opts_.keep_include_path ? noext : basename, opts_);
219 code_ += "#include \"" + includeName + "\"";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700220 num_includes++;
221 }
222 if (num_includes) code_ += "";
223 }
224
225 void GenExtraIncludes() {
Austin Schuh272c6132020-11-14 16:37:52 -0800226 for (std::size_t i = 0; i < opts_.cpp_includes.size(); ++i) {
227 code_ += "#include \"" + opts_.cpp_includes[i] + "\"";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700228 }
Austin Schuh272c6132020-11-14 16:37:52 -0800229 if (!opts_.cpp_includes.empty()) { code_ += ""; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700230 }
231
232 std::string EscapeKeyword(const std::string &name) const {
233 return keywords_.find(name) == keywords_.end() ? name : name + "_";
234 }
235
236 std::string Name(const Definition &def) const {
237 return EscapeKeyword(def.name);
238 }
239
240 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
241
Austin Schuh272c6132020-11-14 16:37:52 -0800242 bool generate_bfbs_embed() {
243 code_.Clear();
244 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
245
246 // If we don't have a root struct definition,
247 if (!parser_.root_struct_def_) {
248 // put a comment in the output why there is no code generated.
249 code_ += "// Binary schema not generated, no root struct found";
250 } else {
251 auto &struct_def = *parser_.root_struct_def_;
252 const auto include_guard =
253 GenIncludeGuard(file_name_, *struct_def.defined_namespace, "bfbs");
254
255 code_ += "#ifndef " + include_guard;
256 code_ += "#define " + include_guard;
257 code_ += "";
258 if (parser_.opts.gen_nullable) {
259 code_ += "#pragma clang system_header\n\n";
260 }
261
262 SetNameSpace(struct_def.defined_namespace);
263 auto name = Name(struct_def);
264 code_.SetValue("STRUCT_NAME", name);
265
266 // Create code to return the binary schema data.
267 auto binary_schema_hex_text =
268 BufferToHexText(parser_.builder_.GetBufferPointer(),
269 parser_.builder_.GetSize(), 105, " ", "");
270
271 code_ += "struct {{STRUCT_NAME}}BinarySchema {";
272 code_ += " static const uint8_t *data() {";
273 code_ += " // Buffer containing the binary schema.";
274 code_ += " static const uint8_t bfbsData[" +
275 NumToString(parser_.builder_.GetSize()) + "] = {";
276 code_ += binary_schema_hex_text;
277 code_ += " };";
278 code_ += " return bfbsData;";
279 code_ += " }";
280 code_ += " static size_t size() {";
281 code_ += " return " + NumToString(parser_.builder_.GetSize()) + ";";
282 code_ += " }";
283 code_ += " const uint8_t *begin() {";
284 code_ += " return data();";
285 code_ += " }";
286 code_ += " const uint8_t *end() {";
287 code_ += " return data() + size();";
288 code_ += " }";
289 code_ += "};";
290 code_ += "";
291
292 if (cur_name_space_) SetNameSpace(nullptr);
293
294 // Close the include guard.
295 code_ += "#endif // " + include_guard;
296 }
297
298 // We are just adding "_bfbs" to the generated filename.
299 const auto file_path =
300 GeneratedFileName(path_, file_name_ + "_bfbs", opts_);
301 const auto final_code = code_.ToString();
302
303 return SaveFile(file_path.c_str(), final_code, false);
304 }
305
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700306 // Iterate through all definitions we haven't generate code for (enums,
307 // structs, and tables) and output them to a single file.
308 bool generate() {
309 code_.Clear();
310 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
311
Austin Schuh272c6132020-11-14 16:37:52 -0800312 const auto include_guard =
313 GenIncludeGuard(file_name_, *parser_.current_namespace_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700314 code_ += "#ifndef " + include_guard;
315 code_ += "#define " + include_guard;
316 code_ += "";
317
Austin Schuh272c6132020-11-14 16:37:52 -0800318 if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700319
320 code_ += "#include \"flatbuffers/flatbuffers.h\"";
321 if (parser_.uses_flexbuffers_) {
322 code_ += "#include \"flatbuffers/flexbuffers.h\"";
323 }
324 code_ += "";
325
Austin Schuh272c6132020-11-14 16:37:52 -0800326 if (opts_.include_dependence_headers) { GenIncludeDependencies(); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700327 GenExtraIncludes();
328
329 FLATBUFFERS_ASSERT(!cur_name_space_);
330
331 // Generate forward declarations for all structs/tables, since they may
332 // have circular references.
333 for (auto it = parser_.structs_.vec.begin();
334 it != parser_.structs_.vec.end(); ++it) {
335 const auto &struct_def = **it;
336 if (!struct_def.generated) {
337 SetNameSpace(struct_def.defined_namespace);
338 code_ += "struct " + Name(struct_def) + ";";
Austin Schuh272c6132020-11-14 16:37:52 -0800339 if (!struct_def.fixed) {
340 code_ += "struct " + Name(struct_def) + "Builder;";
341 }
342 if (opts_.generate_object_based_api) {
343 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700344 if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; }
345 }
346 code_ += "";
347 }
348 }
349
350 // Generate forward declarations for all equal operators
Austin Schuh272c6132020-11-14 16:37:52 -0800351 if (opts_.generate_object_based_api && opts_.gen_compare) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700352 for (auto it = parser_.structs_.vec.begin();
353 it != parser_.structs_.vec.end(); ++it) {
354 const auto &struct_def = **it;
355 if (!struct_def.generated) {
356 SetNameSpace(struct_def.defined_namespace);
Austin Schuh272c6132020-11-14 16:37:52 -0800357 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700358 code_ += "bool operator==(const " + nativeName + " &lhs, const " +
359 nativeName + " &rhs);";
360 code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
Austin Schuh272c6132020-11-14 16:37:52 -0800361 nativeName + " &rhs);";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700362 }
363 }
364 code_ += "";
365 }
366
367 // Generate preablmle code for mini reflection.
Austin Schuh272c6132020-11-14 16:37:52 -0800368 if (opts_.mini_reflect != IDLOptions::kNone) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700369 // To break cyclic dependencies, first pre-declare all tables/structs.
370 for (auto it = parser_.structs_.vec.begin();
371 it != parser_.structs_.vec.end(); ++it) {
372 const auto &struct_def = **it;
373 if (!struct_def.generated) {
374 SetNameSpace(struct_def.defined_namespace);
375 GenMiniReflectPre(&struct_def);
376 }
377 }
378 }
379
380 // Generate code for all the enum declarations.
381 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
382 ++it) {
383 const auto &enum_def = **it;
384 if (!enum_def.generated) {
385 SetNameSpace(enum_def.defined_namespace);
386 GenEnum(enum_def);
387 }
388 }
389
390 // Generate code for all structs, then all tables.
391 for (auto it = parser_.structs_.vec.begin();
392 it != parser_.structs_.vec.end(); ++it) {
393 const auto &struct_def = **it;
394 if (struct_def.fixed && !struct_def.generated) {
395 SetNameSpace(struct_def.defined_namespace);
396 GenStruct(struct_def);
397 }
398 }
399 for (auto it = parser_.structs_.vec.begin();
400 it != parser_.structs_.vec.end(); ++it) {
401 const auto &struct_def = **it;
402 if (!struct_def.fixed && !struct_def.generated) {
403 SetNameSpace(struct_def.defined_namespace);
404 GenTable(struct_def);
405 }
406 }
407 for (auto it = parser_.structs_.vec.begin();
408 it != parser_.structs_.vec.end(); ++it) {
409 const auto &struct_def = **it;
410 if (!struct_def.fixed && !struct_def.generated) {
411 SetNameSpace(struct_def.defined_namespace);
412 GenTablePost(struct_def);
413 }
414 }
415
416 // Generate code for union verifiers.
417 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
418 ++it) {
419 const auto &enum_def = **it;
420 if (enum_def.is_union && !enum_def.generated) {
421 SetNameSpace(enum_def.defined_namespace);
422 GenUnionPost(enum_def);
423 }
424 }
425
426 // Generate code for mini reflection.
Austin Schuh272c6132020-11-14 16:37:52 -0800427 if (opts_.mini_reflect != IDLOptions::kNone) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700428 // Then the unions/enums that may refer to them.
429 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
430 ++it) {
431 const auto &enum_def = **it;
432 if (!enum_def.generated) {
433 SetNameSpace(enum_def.defined_namespace);
434 GenMiniReflect(nullptr, &enum_def);
435 }
436 }
437 // Then the full tables/structs.
438 for (auto it = parser_.structs_.vec.begin();
439 it != parser_.structs_.vec.end(); ++it) {
440 const auto &struct_def = **it;
441 if (!struct_def.generated) {
442 SetNameSpace(struct_def.defined_namespace);
443 GenMiniReflect(&struct_def, nullptr);
444 }
445 }
446 }
447
448 // Generate convenient global helper functions:
449 if (parser_.root_struct_def_) {
450 auto &struct_def = *parser_.root_struct_def_;
451 SetNameSpace(struct_def.defined_namespace);
452 auto name = Name(struct_def);
453 auto qualified_name = cur_name_space_->GetFullyQualifiedName(name);
454 auto cpp_name = TranslateNameSpace(qualified_name);
455
456 code_.SetValue("STRUCT_NAME", name);
457 code_.SetValue("CPP_NAME", cpp_name);
458 code_.SetValue("NULLABLE_EXT", NullableExtension());
459
460 // The root datatype accessor:
461 code_ += "inline \\";
462 code_ +=
463 "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void "
464 "*buf) {";
465 code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
466 code_ += "}";
467 code_ += "";
468
469 code_ += "inline \\";
470 code_ +=
471 "const {{CPP_NAME}} "
472 "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void "
473 "*buf) {";
474 code_ += " return flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}>(buf);";
475 code_ += "}";
476 code_ += "";
477
Austin Schuh272c6132020-11-14 16:37:52 -0800478 if (opts_.mutable_buffer) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700479 code_ += "inline \\";
480 code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
481 code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
482 code_ += "}";
483 code_ += "";
484 }
485
486 if (parser_.file_identifier_.length()) {
487 // Return the identifier
488 code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
489 code_ += " return \"" + parser_.file_identifier_ + "\";";
490 code_ += "}";
491 code_ += "";
492
493 // Check if a buffer has the identifier.
494 code_ += "inline \\";
495 code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
496 code_ += " return flatbuffers::BufferHasIdentifier(";
497 code_ += " buf, {{STRUCT_NAME}}Identifier());";
498 code_ += "}";
499 code_ += "";
500 }
501
502 // The root verifier.
503 if (parser_.file_identifier_.length()) {
504 code_.SetValue("ID", name + "Identifier()");
505 } else {
506 code_.SetValue("ID", "nullptr");
507 }
508
509 code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
510 code_ += " flatbuffers::Verifier &verifier) {";
511 code_ += " return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
512 code_ += "}";
513 code_ += "";
514
515 code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer(";
516 code_ += " flatbuffers::Verifier &verifier) {";
517 code_ +=
518 " return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});";
519 code_ += "}";
520 code_ += "";
521
522 if (parser_.file_extension_.length()) {
523 // Return the extension
524 code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
525 code_ += " return \"" + parser_.file_extension_ + "\";";
526 code_ += "}";
527 code_ += "";
528 }
529
530 // Finish a buffer with a given root object:
531 code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
532 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
533 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
534 if (parser_.file_identifier_.length())
535 code_ += " fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
536 else
537 code_ += " fbb.Finish(root);";
538 code_ += "}";
539 code_ += "";
540
541 code_ += "inline void FinishSizePrefixed{{STRUCT_NAME}}Buffer(";
542 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
543 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
544 if (parser_.file_identifier_.length())
545 code_ += " fbb.FinishSizePrefixed(root, {{STRUCT_NAME}}Identifier());";
546 else
547 code_ += " fbb.FinishSizePrefixed(root);";
548 code_ += "}";
549 code_ += "";
550
Austin Schuh272c6132020-11-14 16:37:52 -0800551 if (opts_.generate_object_based_api) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700552 // A convenient root unpack function.
553 auto native_name =
Austin Schuh272c6132020-11-14 16:37:52 -0800554 NativeName(WrapInNameSpace(struct_def), &struct_def, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700555 code_.SetValue("UNPACK_RETURN",
556 GenTypeNativePtr(native_name, nullptr, false));
557 code_.SetValue("UNPACK_TYPE",
558 GenTypeNativePtr(native_name, nullptr, true));
559
560 code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
561 code_ += " const void *buf,";
562 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
563 code_ += " return {{UNPACK_TYPE}}\\";
564 code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
565 code_ += "}";
566 code_ += "";
567
568 code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}(";
569 code_ += " const void *buf,";
570 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
571 code_ += " return {{UNPACK_TYPE}}\\";
572 code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));";
573 code_ += "}";
574 code_ += "";
575 }
576 }
577
578 if (cur_name_space_) SetNameSpace(nullptr);
579
580 // Close the include guard.
581 code_ += "#endif // " + include_guard;
582
Austin Schuh272c6132020-11-14 16:37:52 -0800583 const auto file_path = GeneratedFileName(path_, file_name_, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700584 const auto final_code = code_.ToString();
Austin Schuh272c6132020-11-14 16:37:52 -0800585
586 // Save the file and optionally generate the binary schema code.
587 return SaveFile(file_path.c_str(), final_code, false) &&
588 (!parser_.opts.binary_schema_gen_embed || generate_bfbs_embed());
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700589 }
590
591 private:
592 CodeWriter code_;
593
594 std::unordered_set<std::string> keywords_;
595
596 // This tracks the current namespace so we can insert namespace declarations.
597 const Namespace *cur_name_space_;
598
Austin Schuh272c6132020-11-14 16:37:52 -0800599 const IDLOptionsCpp opts_;
600 const TypedFloatConstantGenerator float_const_gen_;
601
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700602 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
603
604 // Translates a qualified name in flatbuffer text format to the same name in
605 // the equivalent C++ namespace.
606 static std::string TranslateNameSpace(const std::string &qualified_name) {
607 std::string cpp_qualified_name = qualified_name;
608 size_t start_pos = 0;
609 while ((start_pos = cpp_qualified_name.find('.', start_pos)) !=
610 std::string::npos) {
611 cpp_qualified_name.replace(start_pos, 1, "::");
612 }
613 return cpp_qualified_name;
614 }
615
Austin Schuh272c6132020-11-14 16:37:52 -0800616 bool TypeHasKey(const Type &type) {
617 if (type.base_type != BASE_TYPE_STRUCT) { return false; }
618 for (auto it = type.struct_def->fields.vec.begin();
619 it != type.struct_def->fields.vec.end(); ++it) {
620 const auto &field = **it;
621 if (field.key) { return true; }
622 }
623 return false;
624 }
625
626 bool VectorElementUserFacing(const Type &type) const {
627 return opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums &&
628 IsEnum(type);
629 }
630
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700631 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
632 std::string text;
633 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
634 code_ += text + "\\";
635 }
636
637 // Return a C++ type from the table in idl.h
638 std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
639 // clang-format off
640 static const char *const ctypename[] = {
Austin Schuh272c6132020-11-14 16:37:52 -0800641 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
642 #CTYPE,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700643 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
Austin Schuh272c6132020-11-14 16:37:52 -0800644 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700645 };
646 // clang-format on
647 if (user_facing_type) {
648 if (type.enum_def) return WrapInNameSpace(*type.enum_def);
649 if (type.base_type == BASE_TYPE_BOOL) return "bool";
650 }
651 return ctypename[type.base_type];
652 }
653
654 // Return a C++ pointer type, specialized to the actual struct/table types,
655 // and vector element types.
656 std::string GenTypePointer(const Type &type) const {
657 switch (type.base_type) {
658 case BASE_TYPE_STRING: {
659 return "flatbuffers::String";
660 }
661 case BASE_TYPE_VECTOR: {
Austin Schuh272c6132020-11-14 16:37:52 -0800662 const auto type_name = GenTypeWire(
663 type.VectorType(), "", VectorElementUserFacing(type.VectorType()));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700664 return "flatbuffers::Vector<" + type_name + ">";
665 }
666 case BASE_TYPE_STRUCT: {
667 return WrapInNameSpace(*type.struct_def);
668 }
669 case BASE_TYPE_UNION:
Austin Schuh272c6132020-11-14 16:37:52 -0800670 // fall through
671 default: {
672 return "void";
673 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700674 }
675 }
676
677 // Return a C++ type for any type (scalar/pointer) specifically for
678 // building a flatbuffer.
679 std::string GenTypeWire(const Type &type, const char *postfix,
680 bool user_facing_type) const {
681 if (IsScalar(type.base_type)) {
682 return GenTypeBasic(type, user_facing_type) + postfix;
683 } else if (IsStruct(type)) {
684 return "const " + GenTypePointer(type) + " *";
685 } else {
686 return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix;
687 }
688 }
689
690 // Return a C++ type for any type (scalar/pointer) that reflects its
691 // serialized size.
692 std::string GenTypeSize(const Type &type) const {
693 if (IsScalar(type.base_type)) {
694 return GenTypeBasic(type, false);
695 } else if (IsStruct(type)) {
696 return GenTypePointer(type);
697 } else {
698 return "flatbuffers::uoffset_t";
699 }
700 }
701
702 std::string NullableExtension() {
Austin Schuh272c6132020-11-14 16:37:52 -0800703 return opts_.gen_nullable ? " _Nullable " : "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700704 }
705
706 static std::string NativeName(const std::string &name, const StructDef *sd,
707 const IDLOptions &opts) {
708 return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix
709 : name;
710 }
711
712 const std::string &PtrType(const FieldDef *field) {
713 auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
Austin Schuh272c6132020-11-14 16:37:52 -0800714 return attr ? attr->constant : opts_.cpp_object_api_pointer_type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700715 }
716
717 const std::string NativeString(const FieldDef *field) {
718 auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
Austin Schuh272c6132020-11-14 16:37:52 -0800719 auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700720 if (ret.empty()) { return "std::string"; }
721 return ret;
722 }
723
724 bool FlexibleStringConstructor(const FieldDef *field) {
725 auto attr = field
726 ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr)
727 : false;
Austin Schuh272c6132020-11-14 16:37:52 -0800728 auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700729 return ret && NativeString(field) !=
730 "std::string"; // Only for custom string types.
731 }
732
733 std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
734 bool is_constructor) {
735 auto &ptr_type = PtrType(field);
736 if (ptr_type != "naked") {
737 return (ptr_type != "default_ptr_type"
738 ? ptr_type
Austin Schuh272c6132020-11-14 16:37:52 -0800739 : opts_.cpp_object_api_pointer_type) +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700740 "<" + type + ">";
741 } else if (is_constructor) {
742 return "";
743 } else {
744 return type + " *";
745 }
746 }
747
748 std::string GenPtrGet(const FieldDef &field) {
749 auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get");
750 if (cpp_ptr_type_get) return cpp_ptr_type_get->constant;
751 auto &ptr_type = PtrType(&field);
752 return ptr_type == "naked" ? "" : ".get()";
753 }
754
Austin Schuh272c6132020-11-14 16:37:52 -0800755 std::string GenOptionalNull() { return "flatbuffers::nullopt"; }
756
757 std::string GenOptionalDecl(const Type &type) {
758 return "flatbuffers::Optional<" + GenTypeBasic(type, true) + ">";
759 }
760
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700761 std::string GenTypeNative(const Type &type, bool invector,
762 const FieldDef &field) {
763 switch (type.base_type) {
764 case BASE_TYPE_STRING: {
765 return NativeString(&field);
766 }
767 case BASE_TYPE_VECTOR: {
768 const auto type_name = GenTypeNative(type.VectorType(), true, field);
769 if (type.struct_def &&
770 type.struct_def->attributes.Lookup("native_custom_alloc")) {
771 auto native_custom_alloc =
772 type.struct_def->attributes.Lookup("native_custom_alloc");
773 return "std::vector<" + type_name + "," +
774 native_custom_alloc->constant + "<" + type_name + ">>";
775 } else
776 return "std::vector<" + type_name + ">";
777 }
778 case BASE_TYPE_STRUCT: {
779 auto type_name = WrapInNameSpace(*type.struct_def);
780 if (IsStruct(type)) {
781 auto native_type = type.struct_def->attributes.Lookup("native_type");
782 if (native_type) { type_name = native_type->constant; }
783 if (invector || field.native_inline) {
784 return type_name;
785 } else {
786 return GenTypeNativePtr(type_name, &field, false);
787 }
788 } else {
Austin Schuh272c6132020-11-14 16:37:52 -0800789 return GenTypeNativePtr(NativeName(type_name, type.struct_def, opts_),
790 &field, false);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700791 }
792 }
793 case BASE_TYPE_UNION: {
Austin Schuh272c6132020-11-14 16:37:52 -0800794 auto type_name = WrapInNameSpace(*type.enum_def);
795 return type_name + "Union";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700796 }
Austin Schuh272c6132020-11-14 16:37:52 -0800797 default: {
798 return field.IsScalarOptional() ? GenOptionalDecl(type)
799 : GenTypeBasic(type, true);
800 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700801 }
802 }
803
804 // Return a C++ type for any type (scalar/pointer) specifically for
805 // using a flatbuffer.
806 std::string GenTypeGet(const Type &type, const char *afterbasic,
807 const char *beforeptr, const char *afterptr,
808 bool user_facing_type) {
809 if (IsScalar(type.base_type)) {
810 return GenTypeBasic(type, user_facing_type) + afterbasic;
811 } else if (IsArray(type)) {
812 auto element_type = type.VectorType();
Austin Schuh272c6132020-11-14 16:37:52 -0800813 // Check if enum arrays are used in C++ without specifying --scoped-enums
814 if (IsEnum(element_type) && !opts_.g_only_fixed_enums) {
815 LogCompilerError(
816 "--scoped-enums must be enabled to use enum arrays in C++");
817 FLATBUFFERS_ASSERT(true);
818 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700819 return beforeptr +
820 (IsScalar(element_type.base_type)
821 ? GenTypeBasic(element_type, user_facing_type)
822 : GenTypePointer(element_type)) +
823 afterptr;
824 } else {
825 return beforeptr + GenTypePointer(type) + afterptr;
826 }
827 }
828
Austin Schuh272c6132020-11-14 16:37:52 -0800829 std::string GenTypeSpan(const Type &type, bool immutable, size_t extent) {
830 // Generate "flatbuffers::span<const U, extent>".
831 FLATBUFFERS_ASSERT(IsSeries(type) && "unexpected type");
832 auto element_type = type.VectorType();
833 std::string text = "flatbuffers::span<";
834 text += immutable ? "const " : "";
835 if (IsScalar(element_type.base_type)) {
836 text += GenTypeBasic(element_type, IsEnum(element_type));
837 } else {
838 switch (element_type.base_type) {
839 case BASE_TYPE_STRING: {
840 text += "char";
841 break;
842 }
843 case BASE_TYPE_STRUCT: {
844 FLATBUFFERS_ASSERT(type.struct_def);
845 text += WrapInNameSpace(*type.struct_def);
846 break;
847 }
848 default:
849 FLATBUFFERS_ASSERT(false && "unexpected element's type");
850 break;
851 }
852 }
853 if (extent != flatbuffers::dynamic_extent) {
854 text += ", ";
855 text += NumToString(extent);
856 }
857 text += "> ";
858 return text;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700859 }
860
861 std::string GenEnumValDecl(const EnumDef &enum_def,
862 const std::string &enum_val) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800863 return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700864 }
865
866 std::string GetEnumValUse(const EnumDef &enum_def,
867 const EnumVal &enum_val) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800868 if (opts_.scoped_enums) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700869 return Name(enum_def) + "::" + Name(enum_val);
Austin Schuh272c6132020-11-14 16:37:52 -0800870 } else if (opts_.prefixed_enums) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700871 return Name(enum_def) + "_" + Name(enum_val);
872 } else {
873 return Name(enum_val);
874 }
875 }
876
877 std::string StripUnionType(const std::string &name) {
878 return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
879 }
880
881 std::string GetUnionElement(const EnumVal &ev, bool wrap, bool actual_type,
882 bool native_type = false) {
883 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
884 auto name = actual_type ? ev.union_type.struct_def->name : Name(ev);
885 return wrap ? WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
886 name)
887 : name;
Austin Schuh272c6132020-11-14 16:37:52 -0800888 } else if (IsString(ev.union_type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700889 return actual_type ? (native_type ? "std::string" : "flatbuffers::String")
890 : Name(ev);
891 } else {
892 FLATBUFFERS_ASSERT(false);
893 return Name(ev);
894 }
895 }
896
897 std::string UnionVerifySignature(const EnumDef &enum_def) {
898 return "bool Verify" + Name(enum_def) +
899 "(flatbuffers::Verifier &verifier, const void *obj, " +
900 Name(enum_def) + " type)";
901 }
902
903 std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
904 return "bool Verify" + Name(enum_def) + "Vector" +
905 "(flatbuffers::Verifier &verifier, " +
906 "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
907 "const flatbuffers::Vector<uint8_t> *types)";
908 }
909
910 std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) {
911 return (inclass ? "static " : "") + std::string("void *") +
912 (inclass ? "" : Name(enum_def) + "Union::") +
913 "UnPack(const void *obj, " + Name(enum_def) +
914 " type, const flatbuffers::resolver_function_t *resolver)";
915 }
916
917 std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
918 return "flatbuffers::Offset<void> " +
919 (inclass ? "" : Name(enum_def) + "Union::") +
920 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
921 "const flatbuffers::rehasher_function_t *_rehasher" +
922 (inclass ? " = nullptr" : "") + ") const";
923 }
924
925 std::string TableCreateSignature(const StructDef &struct_def, bool predecl,
926 const IDLOptions &opts) {
927 return "flatbuffers::Offset<" + Name(struct_def) + "> Create" +
928 Name(struct_def) + "(flatbuffers::FlatBufferBuilder &_fbb, const " +
929 NativeName(Name(struct_def), &struct_def, opts) +
930 " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
931 (predecl ? " = nullptr" : "") + ")";
932 }
933
934 std::string TablePackSignature(const StructDef &struct_def, bool inclass,
935 const IDLOptions &opts) {
936 return std::string(inclass ? "static " : "") + "flatbuffers::Offset<" +
937 Name(struct_def) + "> " + (inclass ? "" : Name(struct_def) + "::") +
938 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + "const " +
939 NativeName(Name(struct_def), &struct_def, opts) + "* _o, " +
940 "const flatbuffers::rehasher_function_t *_rehasher" +
941 (inclass ? " = nullptr" : "") + ")";
942 }
943
944 std::string TableUnPackSignature(const StructDef &struct_def, bool inclass,
945 const IDLOptions &opts) {
946 return NativeName(Name(struct_def), &struct_def, opts) + " *" +
947 (inclass ? "" : Name(struct_def) + "::") +
948 "UnPack(const flatbuffers::resolver_function_t *_resolver" +
949 (inclass ? " = nullptr" : "") + ") const";
950 }
951
952 std::string TableUnPackToSignature(const StructDef &struct_def, bool inclass,
953 const IDLOptions &opts) {
954 return "void " + (inclass ? "" : Name(struct_def) + "::") + "UnPackTo(" +
955 NativeName(Name(struct_def), &struct_def, opts) + " *" +
956 "_o, const flatbuffers::resolver_function_t *_resolver" +
957 (inclass ? " = nullptr" : "") + ") const";
958 }
959
960 void GenMiniReflectPre(const StructDef *struct_def) {
961 code_.SetValue("NAME", struct_def->name);
962 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable();";
963 code_ += "";
964 }
965
966 void GenMiniReflect(const StructDef *struct_def, const EnumDef *enum_def) {
967 code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
968 code_.SetValue("SEQ_TYPE",
969 struct_def ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
970 : (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
971 auto num_fields =
972 struct_def ? struct_def->fields.vec.size() : enum_def->size();
973 code_.SetValue("NUM_FIELDS", NumToString(num_fields));
974 std::vector<std::string> names;
975 std::vector<Type> types;
976
977 if (struct_def) {
978 for (auto it = struct_def->fields.vec.begin();
979 it != struct_def->fields.vec.end(); ++it) {
980 const auto &field = **it;
981 names.push_back(Name(field));
982 types.push_back(field.value.type);
983 }
984 } else {
985 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
986 ++it) {
987 const auto &ev = **it;
988 names.push_back(Name(ev));
989 types.push_back(enum_def->is_union ? ev.union_type
990 : Type(enum_def->underlying_type));
991 }
992 }
993 std::string ts;
994 std::vector<std::string> type_refs;
Austin Schuh272c6132020-11-14 16:37:52 -0800995 std::vector<uint16_t> array_sizes;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700996 for (auto it = types.begin(); it != types.end(); ++it) {
997 auto &type = *it;
998 if (!ts.empty()) ts += ",\n ";
Austin Schuh272c6132020-11-14 16:37:52 -0800999 auto is_vector = IsVector(type);
1000 auto is_array = IsArray(type);
1001 auto bt = is_vector || is_array ? type.element : type.base_type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001002 auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
1003 ? bt - BASE_TYPE_UTYPE + ET_UTYPE
1004 : ET_SEQUENCE;
1005 int ref_idx = -1;
1006 std::string ref_name =
1007 type.struct_def
1008 ? WrapInNameSpace(*type.struct_def)
1009 : type.enum_def ? WrapInNameSpace(*type.enum_def) : "";
1010 if (!ref_name.empty()) {
1011 auto rit = type_refs.begin();
1012 for (; rit != type_refs.end(); ++rit) {
1013 if (*rit == ref_name) {
1014 ref_idx = static_cast<int>(rit - type_refs.begin());
1015 break;
1016 }
1017 }
1018 if (rit == type_refs.end()) {
1019 ref_idx = static_cast<int>(type_refs.size());
1020 type_refs.push_back(ref_name);
1021 }
1022 }
Austin Schuh272c6132020-11-14 16:37:52 -08001023 if (is_array) { array_sizes.push_back(type.fixed_length); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001024 ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
Austin Schuh272c6132020-11-14 16:37:52 -08001025 NumToString(is_vector || is_array) + ", " + NumToString(ref_idx) +
1026 " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001027 }
1028 std::string rs;
1029 for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
1030 if (!rs.empty()) rs += ",\n ";
1031 rs += *it + "TypeTable";
1032 }
Austin Schuh272c6132020-11-14 16:37:52 -08001033 std::string as;
1034 for (auto it = array_sizes.begin(); it != array_sizes.end(); ++it) {
1035 as += NumToString(*it);
1036 as += ", ";
1037 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001038 std::string ns;
1039 for (auto it = names.begin(); it != names.end(); ++it) {
1040 if (!ns.empty()) ns += ",\n ";
1041 ns += "\"" + *it + "\"";
1042 }
1043 std::string vs;
1044 const auto consecutive_enum_from_zero =
1045 enum_def && enum_def->MinValue()->IsZero() &&
1046 ((enum_def->size() - 1) == enum_def->Distance());
1047 if (enum_def && !consecutive_enum_from_zero) {
1048 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
1049 ++it) {
1050 const auto &ev = **it;
1051 if (!vs.empty()) vs += ", ";
1052 vs += NumToStringCpp(enum_def->ToString(ev),
1053 enum_def->underlying_type.base_type);
1054 }
1055 } else if (struct_def && struct_def->fixed) {
1056 for (auto it = struct_def->fields.vec.begin();
1057 it != struct_def->fields.vec.end(); ++it) {
1058 const auto &field = **it;
1059 vs += NumToString(field.value.offset);
1060 vs += ", ";
1061 }
1062 vs += NumToString(struct_def->bytesize);
1063 }
1064 code_.SetValue("TYPES", ts);
1065 code_.SetValue("REFS", rs);
Austin Schuh272c6132020-11-14 16:37:52 -08001066 code_.SetValue("ARRAYSIZES", as);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001067 code_.SetValue("NAMES", ns);
1068 code_.SetValue("VALUES", vs);
1069 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable() {";
1070 if (num_fields) {
1071 code_ += " static const flatbuffers::TypeCode type_codes[] = {";
1072 code_ += " {{TYPES}}";
1073 code_ += " };";
1074 }
1075 if (!type_refs.empty()) {
1076 code_ += " static const flatbuffers::TypeFunction type_refs[] = {";
1077 code_ += " {{REFS}}";
1078 code_ += " };";
1079 }
Austin Schuh272c6132020-11-14 16:37:52 -08001080 if (!as.empty()) {
1081 code_ += " static const int16_t array_sizes[] = { {{ARRAYSIZES}} };";
1082 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001083 if (!vs.empty()) {
1084 // Problem with uint64_t values greater than 9223372036854775807ULL.
1085 code_ += " static const int64_t values[] = { {{VALUES}} };";
1086 }
1087 auto has_names =
Austin Schuh272c6132020-11-14 16:37:52 -08001088 num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001089 if (has_names) {
1090 code_ += " static const char * const names[] = {";
1091 code_ += " {{NAMES}}";
1092 code_ += " };";
1093 }
1094 code_ += " static const flatbuffers::TypeTable tt = {";
1095 code_ += std::string(" flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
1096 (num_fields ? "type_codes, " : "nullptr, ") +
1097 (!type_refs.empty() ? "type_refs, " : "nullptr, ") +
Austin Schuh272c6132020-11-14 16:37:52 -08001098 (!as.empty() ? "array_sizes, " : "nullptr, ") +
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001099 (!vs.empty() ? "values, " : "nullptr, ") +
1100 (has_names ? "names" : "nullptr");
1101 code_ += " };";
1102 code_ += " return &tt;";
1103 code_ += "}";
1104 code_ += "";
1105 }
1106
1107 // Generate an enum declaration,
1108 // an enum string lookup table,
1109 // and an enum array of values
1110
1111 void GenEnum(const EnumDef &enum_def) {
1112 code_.SetValue("ENUM_NAME", Name(enum_def));
1113 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
1114
1115 GenComment(enum_def.doc_comment);
Austin Schuh272c6132020-11-14 16:37:52 -08001116 code_ +=
1117 (opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\";
1118 if (opts_.g_only_fixed_enums) { code_ += " : {{BASE_TYPE}}\\"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001119 code_ += " {";
1120
1121 code_.SetValue("SEP", ",");
1122 auto add_sep = false;
1123 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1124 const auto &ev = **it;
1125 if (add_sep) code_ += "{{SEP}}";
1126 GenComment(ev.doc_comment, " ");
1127 code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev)));
1128 code_.SetValue("VALUE",
1129 NumToStringCpp(enum_def.ToString(ev),
1130 enum_def.underlying_type.base_type));
1131 code_ += " {{KEY}} = {{VALUE}}\\";
1132 add_sep = true;
1133 }
1134 const EnumVal *minv = enum_def.MinValue();
1135 const EnumVal *maxv = enum_def.MaxValue();
1136
Austin Schuh272c6132020-11-14 16:37:52 -08001137 if (opts_.scoped_enums || opts_.prefixed_enums) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001138 FLATBUFFERS_ASSERT(minv && maxv);
1139
1140 code_.SetValue("SEP", ",\n");
1141 if (enum_def.attributes.Lookup("bit_flags")) {
1142 code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
1143 code_.SetValue("VALUE", "0");
1144 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1145
1146 code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
1147 code_.SetValue("VALUE",
1148 NumToStringCpp(enum_def.AllFlags(),
1149 enum_def.underlying_type.base_type));
1150 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1151 } else { // MIN & MAX are useless for bit_flags
1152 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN"));
Austin Schuh272c6132020-11-14 16:37:52 -08001153 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*minv)));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001154 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1155
1156 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX"));
Austin Schuh272c6132020-11-14 16:37:52 -08001157 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*maxv)));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001158 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1159 }
1160 }
1161 code_ += "";
1162 code_ += "};";
1163
Austin Schuh272c6132020-11-14 16:37:52 -08001164 if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001165 code_ +=
1166 "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
1167 }
1168 code_ += "";
1169
1170 // Generate an array of all enumeration values
1171 auto num_fields = NumToString(enum_def.size());
1172 code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
1173 num_fields + "] {";
1174 code_ += " static const {{ENUM_NAME}} values[] = {";
1175 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1176 const auto &ev = **it;
1177 auto value = GetEnumValUse(enum_def, ev);
1178 auto suffix = *it != enum_def.Vals().back() ? "," : "";
1179 code_ += " " + value + suffix;
1180 }
1181 code_ += " };";
1182 code_ += " return values;";
1183 code_ += "}";
1184 code_ += "";
1185
1186 // Generate a generate string table for enum values.
1187 // Problem is, if values are very sparse that could generate really big
1188 // tables. Ideally in that case we generate a map lookup instead, but for
1189 // the moment we simply don't output a table at all.
1190 auto range = enum_def.Distance();
1191 // Average distance between values above which we consider a table
1192 // "too sparse". Change at will.
1193 static const uint64_t kMaxSparseness = 5;
1194 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
1195 code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
1196 code_ += " static const char * const names[" +
1197 NumToString(range + 1 + 1) + "] = {";
1198
1199 auto val = enum_def.Vals().front();
1200 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1201 ++it) {
1202 auto ev = *it;
1203 for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
1204 code_ += " \"\",";
1205 }
1206 val = ev;
1207 code_ += " \"" + Name(*ev) + "\",";
1208 }
1209 code_ += " nullptr";
1210 code_ += " };";
1211
1212 code_ += " return names;";
1213 code_ += "}";
1214 code_ += "";
1215
1216 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1217
Austin Schuh272c6132020-11-14 16:37:52 -08001218 code_ += " if (flatbuffers::IsOutRange(e, " +
1219 GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " +
1220 GetEnumValUse(enum_def, *enum_def.MaxValue()) +
1221 ")) return \"\";";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001222
1223 code_ += " const size_t index = static_cast<size_t>(e)\\";
1224 if (enum_def.MinValue()->IsNonZero()) {
1225 auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
1226 code_ += " - static_cast<size_t>(" + vals + ")\\";
1227 }
1228 code_ += ";";
1229
1230 code_ += " return EnumNames{{ENUM_NAME}}()[index];";
1231 code_ += "}";
1232 code_ += "";
1233 } else {
1234 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1235
1236 code_ += " switch (e) {";
1237
1238 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1239 ++it) {
1240 const auto &ev = **it;
1241 code_ += " case " + GetEnumValUse(enum_def, ev) + ": return \"" +
1242 Name(ev) + "\";";
1243 }
1244
1245 code_ += " default: return \"\";";
1246 code_ += " }";
1247
1248 code_ += "}";
1249 code_ += "";
1250 }
1251
1252 // Generate type traits for unions to map from a type to union enum value.
1253 if (enum_def.is_union && !enum_def.uses_multiple_type_instances) {
1254 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1255 ++it) {
1256 const auto &ev = **it;
1257
1258 if (it == enum_def.Vals().begin()) {
1259 code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
1260 } else {
1261 auto name = GetUnionElement(ev, true, true);
1262 code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
1263 }
1264
1265 auto value = GetEnumValUse(enum_def, ev);
1266 code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
1267 code_ += "};";
1268 code_ += "";
1269 }
1270 }
1271
Austin Schuh272c6132020-11-14 16:37:52 -08001272 if (opts_.generate_object_based_api && enum_def.is_union) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001273 // Generate a union type
1274 code_.SetValue("NAME", Name(enum_def));
1275 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1276 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1277
1278 code_ += "struct {{NAME}}Union {";
1279 code_ += " {{NAME}} type;";
1280 code_ += " void *value;";
1281 code_ += "";
1282 code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
1283 code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
1284 code_ += " type({{NONE}}), value(nullptr)";
1285 code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
Austin Schuh272c6132020-11-14 16:37:52 -08001286 code_ += " {{NAME}}Union(const {{NAME}}Union &);";
1287 code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001288 code_ +=
1289 " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, "
1290 "t.value); return *this; }";
1291 code_ +=
1292 " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
1293 code_ +=
1294 " { std::swap(type, u.type); std::swap(value, u.value); return "
1295 "*this; }";
1296 code_ += " ~{{NAME}}Union() { Reset(); }";
1297 code_ += "";
1298 code_ += " void Reset();";
1299 code_ += "";
1300 if (!enum_def.uses_multiple_type_instances) {
1301 code_ += "#ifndef FLATBUFFERS_CPP98_STL";
1302 code_ += " template <typename T>";
1303 code_ += " void Set(T&& val) {";
1304 code_ += " using RT = typename std::remove_reference<T>::type;";
1305 code_ += " Reset();";
Austin Schuh272c6132020-11-14 16:37:52 -08001306 code_ +=
1307 " type = {{NAME}}Traits<typename RT::TableType>::enum_value;";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001308 code_ += " if (type != {{NONE}}) {";
1309 code_ += " value = new RT(std::forward<T>(val));";
1310 code_ += " }";
1311 code_ += " }";
1312 code_ += "#endif // FLATBUFFERS_CPP98_STL";
1313 code_ += "";
1314 }
1315 code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
1316 code_ += " " + UnionPackSignature(enum_def, true) + ";";
1317 code_ += "";
1318
1319 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1320 ++it) {
1321 const auto &ev = **it;
1322 if (ev.IsZero()) { continue; }
1323
1324 const auto native_type =
1325 NativeName(GetUnionElement(ev, true, true, true),
Austin Schuh272c6132020-11-14 16:37:52 -08001326 ev.union_type.struct_def, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001327 code_.SetValue("NATIVE_TYPE", native_type);
1328 code_.SetValue("NATIVE_NAME", Name(ev));
1329 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1330
1331 code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
1332 code_ += " return type == {{NATIVE_ID}} ?";
1333 code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
1334 code_ += " }";
1335
1336 code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {";
1337 code_ += " return type == {{NATIVE_ID}} ?";
1338 code_ +=
1339 " reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;";
1340 code_ += " }";
1341 }
1342 code_ += "};";
1343 code_ += "";
1344
Austin Schuh272c6132020-11-14 16:37:52 -08001345 if (opts_.gen_compare) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001346 code_ += "";
1347 code_ +=
1348 "inline bool operator==(const {{NAME}}Union &lhs, const "
1349 "{{NAME}}Union &rhs) {";
1350 code_ += " if (lhs.type != rhs.type) return false;";
1351 code_ += " switch (lhs.type) {";
1352
1353 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1354 ++it) {
1355 const auto &ev = **it;
1356 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1357 if (ev.IsNonZero()) {
1358 const auto native_type =
1359 NativeName(GetUnionElement(ev, true, true, true),
Austin Schuh272c6132020-11-14 16:37:52 -08001360 ev.union_type.struct_def, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001361 code_.SetValue("NATIVE_TYPE", native_type);
1362 code_ += " case {{NATIVE_ID}}: {";
1363 code_ +=
1364 " return *(reinterpret_cast<const {{NATIVE_TYPE}} "
1365 "*>(lhs.value)) ==";
1366 code_ +=
1367 " *(reinterpret_cast<const {{NATIVE_TYPE}} "
1368 "*>(rhs.value));";
1369 code_ += " }";
1370 } else {
1371 code_ += " case {{NATIVE_ID}}: {";
1372 code_ += " return true;"; // "NONE" enum value.
1373 code_ += " }";
1374 }
1375 }
1376 code_ += " default: {";
1377 code_ += " return false;";
1378 code_ += " }";
1379 code_ += " }";
1380 code_ += "}";
1381
1382 code_ += "";
1383 code_ +=
1384 "inline bool operator!=(const {{NAME}}Union &lhs, const "
1385 "{{NAME}}Union &rhs) {";
1386 code_ += " return !(lhs == rhs);";
1387 code_ += "}";
1388 code_ += "";
1389 }
1390 }
1391
1392 if (enum_def.is_union) {
1393 code_ += UnionVerifySignature(enum_def) + ";";
1394 code_ += UnionVectorVerifySignature(enum_def) + ";";
1395 code_ += "";
1396 }
1397 }
1398
1399 void GenUnionPost(const EnumDef &enum_def) {
1400 // Generate a verifier function for this union that can be called by the
1401 // table verifier functions. It uses a switch case to select a specific
1402 // verifier function to call, this should be safe even if the union type
1403 // has been corrupted, since the verifiers will simply fail when called
1404 // on the wrong type.
1405 code_.SetValue("ENUM_NAME", Name(enum_def));
1406
1407 code_ += "inline " + UnionVerifySignature(enum_def) + " {";
1408 code_ += " switch (type) {";
1409 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1410 const auto &ev = **it;
1411 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1412
1413 if (ev.IsNonZero()) {
1414 code_.SetValue("TYPE", GetUnionElement(ev, true, true));
1415 code_ += " case {{LABEL}}: {";
1416 auto getptr =
1417 " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1418 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1419 if (ev.union_type.struct_def->fixed) {
Austin Schuh272c6132020-11-14 16:37:52 -08001420 code_ +=
1421 " return verifier.Verify<{{TYPE}}>(static_cast<const "
1422 "uint8_t *>(obj), 0);";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001423 } else {
1424 code_ += getptr;
1425 code_ += " return verifier.VerifyTable(ptr);";
1426 }
Austin Schuh272c6132020-11-14 16:37:52 -08001427 } else if (IsString(ev.union_type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001428 code_ += getptr;
1429 code_ += " return verifier.VerifyString(ptr);";
1430 } else {
1431 FLATBUFFERS_ASSERT(false);
1432 }
1433 code_ += " }";
1434 } else {
1435 code_ += " case {{LABEL}}: {";
1436 code_ += " return true;"; // "NONE" enum value.
1437 code_ += " }";
1438 }
1439 }
Austin Schuh272c6132020-11-14 16:37:52 -08001440 code_ += " default: return true;"; // unknown values are OK.
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001441 code_ += " }";
1442 code_ += "}";
1443 code_ += "";
1444
1445 code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
1446 code_ += " if (!values || !types) return !values && !types;";
1447 code_ += " if (values->size() != types->size()) return false;";
1448 code_ += " for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
1449 code_ += " if (!Verify" + Name(enum_def) + "(";
1450 code_ += " verifier, values->Get(i), types->GetEnum<" +
1451 Name(enum_def) + ">(i))) {";
1452 code_ += " return false;";
1453 code_ += " }";
1454 code_ += " }";
1455 code_ += " return true;";
1456 code_ += "}";
1457 code_ += "";
1458
Austin Schuh272c6132020-11-14 16:37:52 -08001459 if (opts_.generate_object_based_api) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001460 // Generate union Unpack() and Pack() functions.
1461 code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
1462 code_ += " switch (type) {";
1463 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1464 ++it) {
1465 const auto &ev = **it;
1466 if (ev.IsZero()) { continue; }
1467
1468 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1469 code_.SetValue("TYPE", GetUnionElement(ev, true, true));
1470 code_ += " case {{LABEL}}: {";
1471 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1472 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1473 if (ev.union_type.struct_def->fixed) {
1474 code_ += " return new " +
1475 WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
1476 } else {
1477 code_ += " return ptr->UnPack(resolver);";
1478 }
Austin Schuh272c6132020-11-14 16:37:52 -08001479 } else if (IsString(ev.union_type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001480 code_ += " return new std::string(ptr->c_str(), ptr->size());";
1481 } else {
1482 FLATBUFFERS_ASSERT(false);
1483 }
1484 code_ += " }";
1485 }
1486 code_ += " default: return nullptr;";
1487 code_ += " }";
1488 code_ += "}";
1489 code_ += "";
1490
1491 code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
1492 code_ += " switch (type) {";
1493 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1494 ++it) {
1495 auto &ev = **it;
1496 if (ev.IsZero()) { continue; }
1497
1498 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
Austin Schuh272c6132020-11-14 16:37:52 -08001499 code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
1500 ev.union_type.struct_def, opts_));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001501 code_.SetValue("NAME", GetUnionElement(ev, false, true));
1502 code_ += " case {{LABEL}}: {";
1503 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
1504 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1505 if (ev.union_type.struct_def->fixed) {
1506 code_ += " return _fbb.CreateStruct(*ptr).Union();";
1507 } else {
1508 code_ +=
1509 " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
1510 }
Austin Schuh272c6132020-11-14 16:37:52 -08001511 } else if (IsString(ev.union_type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001512 code_ += " return _fbb.CreateString(*ptr).Union();";
1513 } else {
1514 FLATBUFFERS_ASSERT(false);
1515 }
1516 code_ += " }";
1517 }
1518 code_ += " default: return 0;";
1519 code_ += " }";
1520 code_ += "}";
1521 code_ += "";
1522
1523 // Union copy constructor
1524 code_ +=
1525 "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
Austin Schuh272c6132020-11-14 16:37:52 -08001526 "{{ENUM_NAME}}Union &u) : type(u.type), value(nullptr) {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001527 code_ += " switch (type) {";
1528 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1529 ++it) {
1530 const auto &ev = **it;
1531 if (ev.IsZero()) { continue; }
1532 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
Austin Schuh272c6132020-11-14 16:37:52 -08001533 code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
1534 ev.union_type.struct_def, opts_));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001535 code_ += " case {{LABEL}}: {";
1536 bool copyable = true;
1537 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1538 // Don't generate code to copy if table is not copyable.
1539 // TODO(wvo): make tables copyable instead.
1540 for (auto fit = ev.union_type.struct_def->fields.vec.begin();
1541 fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
1542 const auto &field = **fit;
1543 if (!field.deprecated && field.value.type.struct_def &&
1544 !field.native_inline) {
1545 copyable = false;
1546 break;
1547 }
1548 }
1549 }
1550 if (copyable) {
1551 code_ +=
1552 " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
1553 "(u.value));";
1554 } else {
1555 code_ +=
1556 " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable.";
1557 }
1558 code_ += " break;";
1559 code_ += " }";
1560 }
1561 code_ += " default:";
1562 code_ += " break;";
1563 code_ += " }";
1564 code_ += "}";
1565 code_ += "";
1566
1567 // Union Reset() function.
1568 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1569 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1570
1571 code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
1572 code_ += " switch (type) {";
1573 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1574 ++it) {
1575 const auto &ev = **it;
1576 if (ev.IsZero()) { continue; }
1577 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
Austin Schuh272c6132020-11-14 16:37:52 -08001578 code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
1579 ev.union_type.struct_def, opts_));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001580 code_ += " case {{LABEL}}: {";
1581 code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
1582 code_ += " delete ptr;";
1583 code_ += " break;";
1584 code_ += " }";
1585 }
1586 code_ += " default: break;";
1587 code_ += " }";
1588 code_ += " value = nullptr;";
1589 code_ += " type = {{NONE}};";
1590 code_ += "}";
1591 code_ += "";
1592 }
1593 }
1594
1595 // Generates a value with optionally a cast applied if the field has a
1596 // different underlying type from its interface type (currently only the
1597 // case for enums. "from" specify the direction, true meaning from the
1598 // underlying type to the interface type.
1599 std::string GenUnderlyingCast(const FieldDef &field, bool from,
1600 const std::string &val) {
1601 if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
1602 return val + " != 0";
1603 } else if ((field.value.type.enum_def &&
1604 IsScalar(field.value.type.base_type)) ||
1605 field.value.type.base_type == BASE_TYPE_BOOL) {
1606 return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
1607 val + ")";
1608 } else {
1609 return val;
1610 }
1611 }
1612
1613 std::string GenFieldOffsetName(const FieldDef &field) {
1614 std::string uname = Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001615 std::transform(uname.begin(), uname.end(), uname.begin(), CharToUpper);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001616 return "VT_" + uname;
1617 }
1618
1619 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1620 const std::string &name) {
Austin Schuh272c6132020-11-14 16:37:52 -08001621 if (!opts_.generate_name_strings) { return; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001622 auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
1623 code_.SetValue("NAME", fullname);
1624 code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
1625 code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
1626 code_ += " return \"{{NAME}}\";";
1627 code_ += " }";
1628 }
1629
1630 std::string GenDefaultConstant(const FieldDef &field) {
1631 if (IsFloat(field.value.type.base_type))
1632 return float_const_gen_.GenFloatConstant(field);
1633 else
1634 return NumToStringCpp(field.value.constant, field.value.type.base_type);
1635 }
1636
1637 std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
Austin Schuh272c6132020-11-14 16:37:52 -08001638 const auto &type = field.value.type;
1639 if (field.IsScalarOptional()) {
1640 return GenOptionalNull();
1641 } else if (type.enum_def && IsScalar(type.base_type)) {
1642 auto ev = type.enum_def->FindByValue(field.value.constant);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001643 if (ev) {
Austin Schuh272c6132020-11-14 16:37:52 -08001644 return WrapInNameSpace(type.enum_def->defined_namespace,
1645 GetEnumValUse(*type.enum_def, *ev));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001646 } else {
1647 return GenUnderlyingCast(
Austin Schuh272c6132020-11-14 16:37:52 -08001648 field, true, NumToStringCpp(field.value.constant, type.base_type));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001649 }
Austin Schuh272c6132020-11-14 16:37:52 -08001650 } else if (type.base_type == BASE_TYPE_BOOL) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001651 return field.value.constant == "0" ? "false" : "true";
1652 } else if (field.attributes.Lookup("cpp_type")) {
1653 if (is_ctor) {
1654 if (PtrType(&field) == "naked") {
1655 return "nullptr";
1656 } else {
1657 return "";
1658 }
1659 } else {
1660 return "0";
1661 }
1662 } else {
1663 return GenDefaultConstant(field);
1664 }
1665 }
1666
1667 void GenParam(const FieldDef &field, bool direct, const char *prefix) {
1668 code_.SetValue("PRE", prefix);
1669 code_.SetValue("PARAM_NAME", Name(field));
Austin Schuh272c6132020-11-14 16:37:52 -08001670 if (direct && IsString(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001671 code_.SetValue("PARAM_TYPE", "const char *");
1672 code_.SetValue("PARAM_VALUE", "nullptr");
Austin Schuh272c6132020-11-14 16:37:52 -08001673 } else if (direct && IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001674 const auto vtype = field.value.type.VectorType();
1675 std::string type;
1676 if (IsStruct(vtype)) {
1677 type = WrapInNameSpace(*vtype.struct_def);
1678 } else {
Austin Schuh272c6132020-11-14 16:37:52 -08001679 type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001680 }
Austin Schuh272c6132020-11-14 16:37:52 -08001681 if (TypeHasKey(vtype)) {
1682 code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
1683 } else {
1684 code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
1685 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001686 code_.SetValue("PARAM_VALUE", "nullptr");
1687 } else {
Austin Schuh272c6132020-11-14 16:37:52 -08001688 const auto &type = field.value.type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001689 code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
Austin Schuh272c6132020-11-14 16:37:52 -08001690 if (field.IsScalarOptional())
1691 code_.SetValue("PARAM_TYPE", GenOptionalDecl(type) + " ");
1692 else
1693 code_.SetValue("PARAM_TYPE", GenTypeWire(type, " ", true));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001694 }
1695 code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
1696 }
1697
1698 // Generate a member, including a default value for scalars and raw pointers.
1699 void GenMember(const FieldDef &field) {
1700 if (!field.deprecated && // Deprecated fields won't be accessible.
1701 field.value.type.base_type != BASE_TYPE_UTYPE &&
1702 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1703 field.value.type.element != BASE_TYPE_UTYPE)) {
1704 auto type = GenTypeNative(field.value.type, false, field);
1705 auto cpp_type = field.attributes.Lookup("cpp_type");
1706 auto full_type =
1707 (cpp_type
Austin Schuh272c6132020-11-14 16:37:52 -08001708 ? (IsVector(field.value.type)
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001709 ? "std::vector<" +
1710 GenTypeNativePtr(cpp_type->constant, &field,
1711 false) +
1712 "> "
1713 : GenTypeNativePtr(cpp_type->constant, &field, false))
1714 : type + " ");
Austin Schuh272c6132020-11-14 16:37:52 -08001715 // Generate default member initializers for >= C++11.
1716 std::string field_di = "";
1717 if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
1718 field_di = "{}";
1719 auto native_default = field.attributes.Lookup("native_default");
1720 // Scalar types get parsed defaults, raw pointers get nullptrs.
1721 if (IsScalar(field.value.type.base_type)) {
1722 field_di =
1723 " = " + (native_default ? std::string(native_default->constant)
1724 : GetDefaultScalarValue(field, true));
1725 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1726 if (IsStruct(field.value.type) && native_default) {
1727 field_di = " = " + native_default->constant;
1728 }
1729 }
1730 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001731 code_.SetValue("FIELD_TYPE", full_type);
1732 code_.SetValue("FIELD_NAME", Name(field));
Austin Schuh272c6132020-11-14 16:37:52 -08001733 code_.SetValue("FIELD_DI", field_di);
1734 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}{{FIELD_DI}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001735 }
1736 }
1737
1738 // Generate the default constructor for this struct. Properly initialize all
1739 // scalar members with default values.
1740 void GenDefaultConstructor(const StructDef &struct_def) {
Austin Schuh272c6132020-11-14 16:37:52 -08001741 code_.SetValue("NATIVE_NAME",
1742 NativeName(Name(struct_def), &struct_def, opts_));
1743 // In >= C++11, default member initializers are generated.
1744 if (opts_.g_cpp_std >= cpp::CPP_STD_11) { return; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001745 std::string initializer_list;
1746 for (auto it = struct_def.fields.vec.begin();
1747 it != struct_def.fields.vec.end(); ++it) {
1748 const auto &field = **it;
1749 if (!field.deprecated && // Deprecated fields won't be accessible.
1750 field.value.type.base_type != BASE_TYPE_UTYPE) {
1751 auto cpp_type = field.attributes.Lookup("cpp_type");
1752 auto native_default = field.attributes.Lookup("native_default");
1753 // Scalar types get parsed defaults, raw pointers get nullptrs.
1754 if (IsScalar(field.value.type.base_type)) {
1755 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1756 initializer_list += Name(field);
1757 initializer_list +=
1758 "(" +
1759 (native_default ? std::string(native_default->constant)
1760 : GetDefaultScalarValue(field, true)) +
1761 ")";
1762 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1763 if (IsStruct(field.value.type)) {
1764 if (native_default) {
1765 if (!initializer_list.empty()) {
1766 initializer_list += ",\n ";
1767 }
1768 initializer_list +=
1769 Name(field) + "(" + native_default->constant + ")";
1770 }
1771 }
1772 } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) {
1773 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1774 initializer_list += Name(field) + "(0)";
1775 }
1776 }
1777 }
1778 if (!initializer_list.empty()) {
1779 initializer_list = "\n : " + initializer_list;
1780 }
1781
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001782 code_.SetValue("INIT_LIST", initializer_list);
1783
1784 code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
1785 code_ += " }";
1786 }
1787
1788 void GenCompareOperator(const StructDef &struct_def,
1789 std::string accessSuffix = "") {
1790 std::string compare_op;
1791 for (auto it = struct_def.fields.vec.begin();
1792 it != struct_def.fields.vec.end(); ++it) {
1793 const auto &field = **it;
1794 if (!field.deprecated && // Deprecated fields won't be accessible.
1795 field.value.type.base_type != BASE_TYPE_UTYPE &&
1796 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1797 field.value.type.element != BASE_TYPE_UTYPE)) {
1798 if (!compare_op.empty()) { compare_op += " &&\n "; }
1799 auto accessor = Name(field) + accessSuffix;
1800 compare_op += "(lhs." + accessor + " == rhs." + accessor + ")";
1801 }
1802 }
1803
1804 std::string cmp_lhs;
1805 std::string cmp_rhs;
1806 if (compare_op.empty()) {
1807 cmp_lhs = "";
1808 cmp_rhs = "";
1809 compare_op = " return true;";
1810 } else {
1811 cmp_lhs = "lhs";
1812 cmp_rhs = "rhs";
1813 compare_op = " return\n " + compare_op + ";";
1814 }
1815
1816 code_.SetValue("CMP_OP", compare_op);
1817 code_.SetValue("CMP_LHS", cmp_lhs);
1818 code_.SetValue("CMP_RHS", cmp_rhs);
1819 code_ += "";
1820 code_ +=
1821 "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
1822 "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
1823 code_ += "{{CMP_OP}}";
1824 code_ += "}";
1825
1826 code_ += "";
1827 code_ +=
1828 "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
1829 "{{NATIVE_NAME}} &rhs) {";
1830 code_ += " return !(lhs == rhs);";
1831 code_ += "}";
1832 code_ += "";
1833 }
1834
1835 void GenOperatorNewDelete(const StructDef &struct_def) {
1836 if (auto native_custom_alloc =
1837 struct_def.attributes.Lookup("native_custom_alloc")) {
1838 code_ += " inline void *operator new (std::size_t count) {";
1839 code_ += " return " + native_custom_alloc->constant +
1840 "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
1841 code_ += " }";
1842 code_ += " inline void operator delete (void *ptr) {";
1843 code_ += " return " + native_custom_alloc->constant +
1844 "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
1845 "ptr),1);";
1846 code_ += " }";
1847 }
1848 }
1849
1850 void GenNativeTable(const StructDef &struct_def) {
Austin Schuh272c6132020-11-14 16:37:52 -08001851 const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001852 code_.SetValue("STRUCT_NAME", Name(struct_def));
1853 code_.SetValue("NATIVE_NAME", native_name);
1854
1855 // Generate a C++ object that can hold an unpacked version of this table.
1856 code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
1857 code_ += " typedef {{STRUCT_NAME}} TableType;";
1858 GenFullyQualifiedNameGetter(struct_def, native_name);
1859 for (auto it = struct_def.fields.vec.begin();
1860 it != struct_def.fields.vec.end(); ++it) {
1861 GenMember(**it);
1862 }
1863 GenOperatorNewDelete(struct_def);
1864 GenDefaultConstructor(struct_def);
1865 code_ += "};";
Austin Schuh272c6132020-11-14 16:37:52 -08001866 if (opts_.gen_compare) GenCompareOperator(struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001867 code_ += "";
1868 }
1869
1870 // Generate the code to call the appropriate Verify function(s) for a field.
1871 void GenVerifyCall(const FieldDef &field, const char *prefix) {
1872 code_.SetValue("PRE", prefix);
1873 code_.SetValue("NAME", Name(field));
1874 code_.SetValue("REQUIRED", field.required ? "Required" : "");
1875 code_.SetValue("SIZE", GenTypeSize(field.value.type));
1876 code_.SetValue("OFFSET", GenFieldOffsetName(field));
1877 if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
1878 code_ +=
1879 "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
1880 } else {
1881 code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
1882 }
1883
1884 switch (field.value.type.base_type) {
1885 case BASE_TYPE_UNION: {
1886 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1887 code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
1888 code_ +=
1889 "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
1890 "{{NAME}}{{SUFFIX}}())\\";
1891 break;
1892 }
1893 case BASE_TYPE_STRUCT: {
1894 if (!field.value.type.struct_def->fixed) {
1895 code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
1896 }
1897 break;
1898 }
1899 case BASE_TYPE_STRING: {
1900 code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
1901 break;
1902 }
1903 case BASE_TYPE_VECTOR: {
1904 code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
1905
1906 switch (field.value.type.element) {
1907 case BASE_TYPE_STRING: {
1908 code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
1909 break;
1910 }
1911 case BASE_TYPE_STRUCT: {
1912 if (!field.value.type.struct_def->fixed) {
1913 code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
1914 }
1915 break;
1916 }
1917 case BASE_TYPE_UNION: {
1918 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1919 code_ +=
1920 "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
1921 "{{NAME}}_type())\\";
1922 break;
1923 }
1924 default: break;
1925 }
1926 break;
1927 }
Austin Schuh272c6132020-11-14 16:37:52 -08001928 default: {
1929 break;
1930 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001931 }
1932 }
1933
1934 // Generate CompareWithValue method for a key field.
1935 void GenKeyFieldMethods(const FieldDef &field) {
1936 FLATBUFFERS_ASSERT(field.key);
Austin Schuh272c6132020-11-14 16:37:52 -08001937 const bool is_string = (IsString(field.value.type));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001938
1939 code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
1940 if (is_string) {
1941 // use operator< of flatbuffers::String
1942 code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
1943 } else {
1944 code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
1945 }
1946 code_ += " }";
1947
1948 if (is_string) {
1949 code_ += " int KeyCompareWithValue(const char *val) const {";
1950 code_ += " return strcmp({{FIELD_NAME}}()->c_str(), val);";
1951 code_ += " }";
1952 } else {
1953 FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
1954 auto type = GenTypeBasic(field.value.type, false);
Austin Schuh272c6132020-11-14 16:37:52 -08001955 if (opts_.scoped_enums && field.value.type.enum_def &&
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001956 IsScalar(field.value.type.base_type)) {
1957 type = GenTypeGet(field.value.type, " ", "const ", " *", true);
1958 }
1959 // Returns {field<val: -1, field==val: 0, field>val: +1}.
1960 code_.SetValue("KEY_TYPE", type);
1961 code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {";
1962 code_ +=
1963 " return static_cast<int>({{FIELD_NAME}}() > val) - "
1964 "static_cast<int>({{FIELD_NAME}}() < val);";
1965 code_ += " }";
1966 }
1967 }
1968
Austin Schuh272c6132020-11-14 16:37:52 -08001969 void GenTableUnionAsGetters(const FieldDef &field) {
1970 const auto &type = field.value.type;
1971 auto u = type.enum_def;
1972
1973 if (!type.enum_def->uses_multiple_type_instances)
1974 code_ +=
1975 " template<typename T> "
1976 "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
1977
1978 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
1979 auto &ev = **u_it;
1980 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1981 auto full_struct_name = GetUnionElement(ev, true, true);
1982
1983 // @TODO: Mby make this decisions more universal? How?
1984 code_.SetValue("U_GET_TYPE",
1985 EscapeKeyword(field.name + UnionTypeFieldSuffix()));
1986 code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace,
1987 GetEnumValUse(*u, ev)));
1988 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
1989 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
1990 code_.SetValue("U_NULLABLE", NullableExtension());
1991
1992 // `const Type *union_name_asType() const` accessor.
1993 code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
1994 code_ +=
1995 " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
1996 "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
1997 ": nullptr;";
1998 code_ += " }";
1999 }
2000 }
2001
2002 void GenTableFieldGetter(const FieldDef &field) {
2003 const auto &type = field.value.type;
2004 const auto offset_str = GenFieldOffsetName(field);
2005
2006 GenComment(field.doc_comment, " ");
2007 // Call a different accessor for pointers, that indirects.
2008 if (false == field.IsScalarOptional()) {
2009 const bool is_scalar = IsScalar(type.base_type);
2010 std::string accessor;
2011 if (is_scalar)
2012 accessor = "GetField<";
2013 else if (IsStruct(type))
2014 accessor = "GetStruct<";
2015 else
2016 accessor = "GetPointer<";
2017 auto offset_type = GenTypeGet(type, "", "const ", " *", false);
2018 auto call = accessor + offset_type + ">(" + offset_str;
2019 // Default value as second arg for non-pointer types.
2020 if (is_scalar) { call += ", " + GenDefaultConstant(field); }
2021 call += ")";
2022
2023 std::string afterptr = " *" + NullableExtension();
2024 code_.SetValue("FIELD_TYPE",
2025 GenTypeGet(type, " ", "const ", afterptr.c_str(), true));
2026 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
2027 code_.SetValue("NULLABLE_EXT", NullableExtension());
2028 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
2029 code_ += " return {{FIELD_VALUE}};";
2030 code_ += " }";
2031 } else {
2032 auto wire_type = GenTypeBasic(type, false);
2033 auto face_type = GenTypeBasic(type, true);
2034 auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
2035 offset_str + ")";
2036 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2037 code_ += " {{FIELD_TYPE}} {{FIELD_NAME}}() const {";
2038 code_ += " return " + opt_value + ";";
2039 code_ += " }";
2040 }
2041
2042 if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); }
2043 }
2044
2045 void GenTableFieldSetter(const FieldDef &field) {
2046 const auto &type = field.value.type;
2047 const bool is_scalar = IsScalar(type.base_type);
2048 if (is_scalar && IsUnion(type))
2049 return; // changing of a union's type is forbidden
2050
2051 auto offset_str = GenFieldOffsetName(field);
2052 if (is_scalar) {
2053 const auto wire_type = GenTypeWire(type, "", false);
2054 code_.SetValue("SET_FN", "SetField<" + wire_type + ">");
2055 code_.SetValue("OFFSET_NAME", offset_str);
2056 code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true));
2057 code_.SetValue("FIELD_VALUE",
2058 GenUnderlyingCast(field, false, "_" + Name(field)));
2059
2060 code_ +=
2061 " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
2062 "_{{FIELD_NAME}}) {";
2063 if (false == field.IsScalarOptional()) {
2064 code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
2065 code_ +=
2066 " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
2067 "{{DEFAULT_VALUE}});";
2068 } else {
2069 code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
2070 }
2071 code_ += " }";
2072 } else {
2073 auto postptr = " *" + NullableExtension();
2074 auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
2075 std::string accessor = IsStruct(type) ? "GetStruct<" : "GetPointer<";
2076 auto underlying = accessor + wire_type + ">(" + offset_str + ")";
2077 code_.SetValue("FIELD_TYPE", wire_type);
2078 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
2079
2080 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
2081 code_ += " return {{FIELD_VALUE}};";
2082 code_ += " }";
2083 }
2084 }
2085
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002086 // Generate an accessor struct, builder structs & function for a table.
2087 void GenTable(const StructDef &struct_def) {
Austin Schuh272c6132020-11-14 16:37:52 -08002088 if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002089
2090 // Generate an accessor struct, with methods of the form:
2091 // type name() const { return GetField<type>(offset, defaultval); }
2092 GenComment(struct_def.doc_comment);
2093
2094 code_.SetValue("STRUCT_NAME", Name(struct_def));
2095 code_ +=
2096 "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
2097 " : private flatbuffers::Table {";
Austin Schuh272c6132020-11-14 16:37:52 -08002098 if (opts_.generate_object_based_api) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002099 code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
2100 }
Austin Schuh272c6132020-11-14 16:37:52 -08002101 code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
2102 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
2103 if (opts_.mini_reflect != IDLOptions::kNone) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002104 code_ +=
2105 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
2106 code_ += " return {{STRUCT_NAME}}TypeTable();";
2107 code_ += " }";
2108 }
2109
2110 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
2111
2112 // Generate field id constants.
2113 if (struct_def.fields.vec.size() > 0) {
2114 // We need to add a trailing comma to all elements except the last one as
2115 // older versions of gcc complain about this.
2116 code_.SetValue("SEP", "");
2117 code_ +=
2118 " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
2119 for (auto it = struct_def.fields.vec.begin();
2120 it != struct_def.fields.vec.end(); ++it) {
2121 const auto &field = **it;
2122 if (field.deprecated) {
2123 // Deprecated fields won't be accessible.
2124 continue;
2125 }
2126
2127 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2128 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
2129 code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
2130 code_.SetValue("SEP", ",\n");
2131 }
2132 code_ += "";
2133 code_ += " };";
2134 }
2135
2136 // Generate the accessors.
2137 for (auto it = struct_def.fields.vec.begin();
2138 it != struct_def.fields.vec.end(); ++it) {
2139 const auto &field = **it;
2140 if (field.deprecated) {
2141 // Deprecated fields won't be accessible.
2142 continue;
2143 }
2144
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002145 code_.SetValue("FIELD_NAME", Name(field));
Austin Schuh272c6132020-11-14 16:37:52 -08002146 GenTableFieldGetter(field);
2147 if (opts_.mutable_buffer) { GenTableFieldSetter(field); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002148
2149 auto nested = field.attributes.Lookup("nested_flatbuffer");
2150 if (nested) {
2151 std::string qualified_name = nested->constant;
2152 auto nested_root = parser_.LookupStruct(nested->constant);
2153 if (nested_root == nullptr) {
2154 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
2155 nested->constant);
2156 nested_root = parser_.LookupStruct(qualified_name);
2157 }
2158 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
2159 (void)nested_root;
2160 code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
2161
2162 code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
2163 code_ +=
2164 " return "
2165 "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());";
2166 code_ += " }";
2167 }
2168
2169 if (field.flexbuffer) {
2170 code_ +=
2171 " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
2172 " const {";
2173 // Both Data() and size() are const-methods, therefore call order
2174 // doesn't matter.
2175 code_ +=
2176 " return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), "
2177 "{{FIELD_NAME}}()->size());";
2178 code_ += " }";
2179 }
2180
2181 // Generate a comparison function for this field if it is a key.
2182 if (field.key) { GenKeyFieldMethods(field); }
2183 }
2184
2185 // Generate a verifier function that can check a buffer from an untrusted
2186 // source will never cause reads outside the buffer.
2187 code_ += " bool Verify(flatbuffers::Verifier &verifier) const {";
2188 code_ += " return VerifyTableStart(verifier)\\";
2189 for (auto it = struct_def.fields.vec.begin();
2190 it != struct_def.fields.vec.end(); ++it) {
2191 const auto &field = **it;
2192 if (field.deprecated) { continue; }
2193 GenVerifyCall(field, " &&\n ");
2194 }
2195
2196 code_ += " &&\n verifier.EndTable();";
2197 code_ += " }";
2198
Austin Schuh272c6132020-11-14 16:37:52 -08002199 if (opts_.generate_object_based_api) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002200 // Generate the UnPack() pre declaration.
Austin Schuh272c6132020-11-14 16:37:52 -08002201 code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";";
2202 code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";";
2203 code_ += " " + TablePackSignature(struct_def, true, opts_) + ";";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002204 }
2205
2206 code_ += "};"; // End of table.
2207 code_ += "";
2208
2209 // Explicit specializations for union accessors
2210 for (auto it = struct_def.fields.vec.begin();
2211 it != struct_def.fields.vec.end(); ++it) {
2212 const auto &field = **it;
2213 if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
2214 continue;
2215 }
2216
2217 auto u = field.value.type.enum_def;
2218 if (u->uses_multiple_type_instances) continue;
2219
2220 code_.SetValue("FIELD_NAME", Name(field));
2221
2222 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2223 auto &ev = **u_it;
2224 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
2225
2226 auto full_struct_name = GetUnionElement(ev, true, true);
2227
2228 code_.SetValue(
2229 "U_ELEMENT_TYPE",
2230 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
2231 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2232 code_.SetValue("U_ELEMENT_NAME", full_struct_name);
2233 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2234
2235 // `template<> const T *union_name_as<T>() const` accessor.
2236 code_ +=
2237 "template<> "
2238 "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
2239 "<{{U_ELEMENT_NAME}}>() const {";
2240 code_ += " return {{U_FIELD_NAME}}();";
2241 code_ += "}";
2242 code_ += "";
2243 }
2244 }
2245
2246 GenBuilders(struct_def);
2247
Austin Schuh272c6132020-11-14 16:37:52 -08002248 if (opts_.generate_object_based_api) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002249 // Generate a pre-declaration for a CreateX method that works with an
2250 // unpacked C++ object.
Austin Schuh272c6132020-11-14 16:37:52 -08002251 code_ += TableCreateSignature(struct_def, true, opts_) + ";";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002252 code_ += "";
2253 }
2254 }
2255
Austin Schuh272c6132020-11-14 16:37:52 -08002256 // Generate code to force vector alignment. Return empty string for vector
2257 // that doesn't need alignment code.
2258 std::string GenVectorForceAlign(const FieldDef &field,
2259 const std::string &field_size) {
2260 FLATBUFFERS_ASSERT(IsVector(field.value.type));
2261 // Get the value of the force_align attribute.
2262 const auto *force_align = field.attributes.Lookup("force_align");
2263 const int align = force_align ? atoi(force_align->constant.c_str()) : 1;
2264 // Generate code to do force_align for the vector.
2265 if (align > 1) {
2266 const auto vtype = field.value.type.VectorType();
2267 const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def)
2268 : GenTypeWire(vtype, "", false);
2269 return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type +
2270 "), " + std::to_string(static_cast<long long>(align)) + ");";
2271 }
2272 return "";
2273 }
2274
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002275 void GenBuilders(const StructDef &struct_def) {
2276 code_.SetValue("STRUCT_NAME", Name(struct_def));
2277
2278 // Generate a builder struct:
2279 code_ += "struct {{STRUCT_NAME}}Builder {";
Austin Schuh272c6132020-11-14 16:37:52 -08002280 code_ += " typedef {{STRUCT_NAME}} Table;";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002281 code_ += " flatbuffers::FlatBufferBuilder &fbb_;";
2282 code_ += " flatbuffers::uoffset_t start_;";
2283
2284 bool has_string_or_vector_fields = false;
2285 for (auto it = struct_def.fields.vec.begin();
2286 it != struct_def.fields.vec.end(); ++it) {
2287 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -08002288 if (field.deprecated) continue;
2289 const bool is_scalar = IsScalar(field.value.type.base_type);
2290 const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
2291 const bool is_string = IsString(field.value.type);
2292 const bool is_vector = IsVector(field.value.type);
2293 if (is_string || is_vector) { has_string_or_vector_fields = true; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002294
Austin Schuh272c6132020-11-14 16:37:52 -08002295 std::string offset = GenFieldOffsetName(field);
2296 std::string name = GenUnderlyingCast(field, false, Name(field));
2297 std::string value = is_default_scalar ? GenDefaultConstant(field) : "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002298
Austin Schuh272c6132020-11-14 16:37:52 -08002299 // Generate accessor functions of the form:
2300 // void add_name(type name) {
2301 // fbb_.AddElement<type>(offset, name, default);
2302 // }
2303 code_.SetValue("FIELD_NAME", Name(field));
2304 code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
2305 code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
2306 code_.SetValue("ADD_NAME", name);
2307 code_.SetValue("ADD_VALUE", value);
2308 if (is_scalar) {
2309 const auto type = GenTypeWire(field.value.type, "", false);
2310 code_.SetValue("ADD_FN", "AddElement<" + type + ">");
2311 } else if (IsStruct(field.value.type)) {
2312 code_.SetValue("ADD_FN", "AddStruct");
2313 } else {
2314 code_.SetValue("ADD_FN", "AddOffset");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002315 }
Austin Schuh272c6132020-11-14 16:37:52 -08002316
2317 code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
2318 code_ += " fbb_.{{ADD_FN}}(\\";
2319 if (is_default_scalar) {
2320 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
2321 } else {
2322 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
2323 }
2324 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002325 }
2326
2327 // Builder constructor
2328 code_ +=
2329 " explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder "
2330 "&_fbb)";
2331 code_ += " : fbb_(_fbb) {";
2332 code_ += " start_ = fbb_.StartTable();";
2333 code_ += " }";
2334
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002335 // Finish() function.
2336 code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
2337 code_ += " const auto end = fbb_.EndTable(start_);";
2338 code_ += " auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
2339
2340 for (auto it = struct_def.fields.vec.begin();
2341 it != struct_def.fields.vec.end(); ++it) {
2342 const auto &field = **it;
2343 if (!field.deprecated && field.required) {
2344 code_.SetValue("FIELD_NAME", Name(field));
2345 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2346 code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
2347 }
2348 }
2349 code_ += " return o;";
2350 code_ += " }";
2351 code_ += "};";
2352 code_ += "";
2353
2354 // Generate a convenient CreateX function that uses the above builder
2355 // to create a table in one go.
2356 code_ +=
2357 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2358 "Create{{STRUCT_NAME}}(";
2359 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2360 for (auto it = struct_def.fields.vec.begin();
2361 it != struct_def.fields.vec.end(); ++it) {
2362 const auto &field = **it;
2363 if (!field.deprecated) { GenParam(field, false, ",\n "); }
2364 }
2365 code_ += ") {";
2366
2367 code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);";
2368 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
2369 size; size /= 2) {
2370 for (auto it = struct_def.fields.vec.rbegin();
2371 it != struct_def.fields.vec.rend(); ++it) {
2372 const auto &field = **it;
2373 if (!field.deprecated && (!struct_def.sortbysize ||
2374 size == SizeOf(field.value.type.base_type))) {
2375 code_.SetValue("FIELD_NAME", Name(field));
Austin Schuh272c6132020-11-14 16:37:52 -08002376 if (field.IsScalarOptional()) {
2377 code_ +=
2378 " if({{FIELD_NAME}}) { "
2379 "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }";
2380 } else {
2381 code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
2382 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002383 }
2384 }
2385 }
2386 code_ += " return builder_.Finish();";
2387 code_ += "}";
2388 code_ += "";
2389
Austin Schuh272c6132020-11-14 16:37:52 -08002390 // Definition for type traits for this table type. This allows querying var-
2391 // ious compile-time traits of the table.
2392 if (opts_.g_cpp_std >= cpp::CPP_STD_17) {
2393 code_ += "struct {{STRUCT_NAME}}::Traits {";
2394 code_ += " using type = {{STRUCT_NAME}};";
2395 code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
2396 code_ += "};";
2397 code_ += "";
2398 }
2399
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002400 // Generate a CreateXDirect function with vector types as parameters
Austin Schuh272c6132020-11-14 16:37:52 -08002401 if (opts_.cpp_direct_copy && has_string_or_vector_fields) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002402 code_ +=
2403 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2404 "Create{{STRUCT_NAME}}Direct(";
2405 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2406 for (auto it = struct_def.fields.vec.begin();
2407 it != struct_def.fields.vec.end(); ++it) {
2408 const auto &field = **it;
2409 if (!field.deprecated) { GenParam(field, true, ",\n "); }
2410 }
2411 // Need to call "Create" with the struct namespace.
2412 const auto qualified_create_name =
2413 struct_def.defined_namespace->GetFullyQualifiedName("Create");
2414 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2415 code_ += ") {";
2416 for (auto it = struct_def.fields.vec.begin();
2417 it != struct_def.fields.vec.end(); ++it) {
2418 const auto &field = **it;
2419 if (!field.deprecated) {
2420 code_.SetValue("FIELD_NAME", Name(field));
Austin Schuh272c6132020-11-14 16:37:52 -08002421 if (IsString(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002422 if (!field.shared) {
2423 code_.SetValue("CREATE_STRING", "CreateString");
2424 } else {
2425 code_.SetValue("CREATE_STRING", "CreateSharedString");
2426 }
2427 code_ +=
2428 " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
2429 "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
Austin Schuh272c6132020-11-14 16:37:52 -08002430 } else if (IsVector(field.value.type)) {
2431 const std::string force_align_code =
2432 GenVectorForceAlign(field, Name(field) + "->size()");
2433 if (!force_align_code.empty()) {
2434 code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }";
2435 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002436 code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
2437 const auto vtype = field.value.type.VectorType();
Austin Schuh272c6132020-11-14 16:37:52 -08002438 const auto has_key = TypeHasKey(vtype);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002439 if (IsStruct(vtype)) {
2440 const auto type = WrapInNameSpace(*vtype.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08002441 code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<"
2442 : "_fbb.CreateVectorOfStructs<") +
2443 type + ">\\";
2444 } else if (has_key) {
2445 const auto type = WrapInNameSpace(*vtype.struct_def);
2446 code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002447 } else {
Austin Schuh272c6132020-11-14 16:37:52 -08002448 const auto type =
2449 GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002450 code_ += "_fbb.CreateVector<" + type + ">\\";
2451 }
Austin Schuh272c6132020-11-14 16:37:52 -08002452 code_ +=
2453 has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002454 }
2455 }
2456 }
2457 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2458 code_ += " _fbb\\";
2459 for (auto it = struct_def.fields.vec.begin();
2460 it != struct_def.fields.vec.end(); ++it) {
2461 const auto &field = **it;
2462 if (!field.deprecated) {
2463 code_.SetValue("FIELD_NAME", Name(field));
2464 code_ += ",\n {{FIELD_NAME}}\\";
Austin Schuh272c6132020-11-14 16:37:52 -08002465 if (IsString(field.value.type) ||
2466 IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002467 code_ += "__\\";
2468 }
2469 }
2470 }
2471 code_ += ");";
2472 code_ += "}";
2473 code_ += "";
2474 }
2475 }
2476
2477 std::string GenUnionUnpackVal(const FieldDef &afield,
2478 const char *vec_elem_access,
2479 const char *vec_type_access) {
Austin Schuh272c6132020-11-14 16:37:52 -08002480 auto type_name = WrapInNameSpace(*afield.value.type.enum_def);
2481 return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " +
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002482 EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
2483 vec_type_access + ", _resolver)";
2484 }
2485
2486 std::string GenUnpackVal(const Type &type, const std::string &val,
2487 bool invector, const FieldDef &afield) {
2488 switch (type.base_type) {
2489 case BASE_TYPE_STRING: {
2490 if (FlexibleStringConstructor(&afield)) {
2491 return NativeString(&afield) + "(" + val + "->c_str(), " + val +
2492 "->size())";
2493 } else {
2494 return val + "->str()";
2495 }
2496 }
2497 case BASE_TYPE_STRUCT: {
2498 const auto name = WrapInNameSpace(*type.struct_def);
2499 if (IsStruct(type)) {
2500 auto native_type = type.struct_def->attributes.Lookup("native_type");
2501 if (native_type) {
2502 return "flatbuffers::UnPack(*" + val + ")";
2503 } else if (invector || afield.native_inline) {
2504 return "*" + val;
2505 } else {
2506 const auto ptype = GenTypeNativePtr(name, &afield, true);
2507 return ptype + "(new " + name + "(*" + val + "))";
2508 }
2509 } else {
2510 const auto ptype = GenTypeNativePtr(
Austin Schuh272c6132020-11-14 16:37:52 -08002511 NativeName(name, type.struct_def, opts_), &afield, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002512 return ptype + "(" + val + "->UnPack(_resolver))";
2513 }
2514 }
2515 case BASE_TYPE_UNION: {
2516 return GenUnionUnpackVal(
2517 afield, invector ? "->Get(_i)" : "",
2518 invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
2519 : "");
2520 }
2521 default: {
2522 return val;
2523 break;
2524 }
2525 }
2526 }
2527
2528 std::string GenUnpackFieldStatement(const FieldDef &field,
2529 const FieldDef *union_field) {
2530 std::string code;
2531 switch (field.value.type.base_type) {
2532 case BASE_TYPE_VECTOR: {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002533 auto name = Name(field);
2534 if (field.value.type.element == BASE_TYPE_UTYPE) {
2535 name = StripUnionType(Name(field));
2536 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002537 code += "{ _o->" + name + ".resize(_e->size()); ";
Austin Schuh272c6132020-11-14 16:37:52 -08002538 if (!field.value.type.enum_def && !IsBool(field.value.type.element) &&
2539 IsOneByte(field.value.type.element)) {
2540 // For vectors of bytes, std::copy is used to improve performance.
2541 // This doesn't work for:
2542 // - enum types because they have to be explicitly static_cast.
2543 // - vectors of bool, since they are a template specialization.
2544 // - multiple-byte types due to endianness.
2545 code +=
2546 "std::copy(_e->begin(), _e->end(), _o->" + name + ".begin()); }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002547 } else {
Austin Schuh272c6132020-11-14 16:37:52 -08002548 std::string indexing;
2549 if (field.value.type.enum_def) {
2550 indexing += "static_cast<" +
2551 WrapInNameSpace(*field.value.type.enum_def) + ">(";
2552 }
2553 indexing += "_e->Get(_i)";
2554 if (field.value.type.enum_def) {
2555 indexing += ")";
2556 }
2557 if (field.value.type.element == BASE_TYPE_BOOL) {
2558 indexing += " != 0";
2559 }
2560 // Generate code that pushes data from _e to _o in the form:
2561 // for (uoffset_t i = 0; i < _e->size(); ++i) {
2562 // _o->field.push_back(_e->Get(_i));
2563 // }
2564 auto access =
2565 field.value.type.element == BASE_TYPE_UTYPE
2566 ? ".type"
2567 : (field.value.type.element == BASE_TYPE_UNION ? ".value"
2568 : "");
2569
2570 code += "for (flatbuffers::uoffset_t _i = 0;";
2571 code += " _i < _e->size(); _i++) { ";
2572 auto cpp_type = field.attributes.Lookup("cpp_type");
2573 if (cpp_type) {
2574 // Generate code that resolves the cpp pointer type, of the form:
2575 // if (resolver)
2576 // (*resolver)(&_o->field, (hash_value_t)(_e));
2577 // else
2578 // _o->field = nullptr;
2579 code += "//vector resolver, " + PtrType(&field) + "\n";
2580 code += "if (_resolver) ";
2581 code += "(*_resolver)";
2582 code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" +
2583 access + "), ";
2584 code +=
2585 "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
2586 if (PtrType(&field) == "naked") {
2587 code += " else ";
2588 code += "_o->" + name + "[_i]" + access + " = nullptr";
2589 } else {
2590 // code += " else ";
2591 // code += "_o->" + name + "[_i]" + access + " = " +
2592 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2593 code += "/* else do nothing */";
2594 }
2595 } else {
2596 code += "_o->" + name + "[_i]" + access + " = ";
2597 code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
2598 field);
2599 }
2600 code += "; } }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002601 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002602 break;
2603 }
2604 case BASE_TYPE_UTYPE: {
2605 FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
2606 BASE_TYPE_UNION);
2607 // Generate code that sets the union type, of the form:
2608 // _o->field.type = _e;
2609 code += "_o->" + union_field->name + ".type = _e;";
2610 break;
2611 }
2612 case BASE_TYPE_UNION: {
2613 // Generate code that sets the union value, of the form:
2614 // _o->field.value = Union::Unpack(_e, field_type(), resolver);
2615 code += "_o->" + Name(field) + ".value = ";
2616 code += GenUnionUnpackVal(field, "", "");
2617 code += ";";
2618 break;
2619 }
2620 default: {
2621 auto cpp_type = field.attributes.Lookup("cpp_type");
2622 if (cpp_type) {
2623 // Generate code that resolves the cpp pointer type, of the form:
2624 // if (resolver)
2625 // (*resolver)(&_o->field, (hash_value_t)(_e));
2626 // else
2627 // _o->field = nullptr;
2628 code += "//scalar resolver, " + PtrType(&field) + " \n";
2629 code += "if (_resolver) ";
2630 code += "(*_resolver)";
2631 code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
2632 code += "static_cast<flatbuffers::hash_value_t>(_e));";
2633 if (PtrType(&field) == "naked") {
2634 code += " else ";
2635 code += "_o->" + Name(field) + " = nullptr;";
2636 } else {
2637 // code += " else ";
2638 // code += "_o->" + Name(field) + " = " +
2639 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2640 code += "/* else do nothing */;";
2641 }
2642 } else {
2643 // Generate code for assigning the value, of the form:
2644 // _o->field = value;
2645 code += "_o->" + Name(field) + " = ";
2646 code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
2647 }
2648 break;
2649 }
2650 }
2651 return code;
2652 }
2653
2654 std::string GenCreateParam(const FieldDef &field) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002655 std::string value = "_o->";
2656 if (field.value.type.base_type == BASE_TYPE_UTYPE) {
2657 value += StripUnionType(Name(field));
2658 value += ".type";
2659 } else {
2660 value += Name(field);
2661 }
2662 if (field.value.type.base_type != BASE_TYPE_VECTOR &&
2663 field.attributes.Lookup("cpp_type")) {
2664 auto type = GenTypeBasic(field.value.type, false);
2665 value =
2666 "_rehasher ? "
2667 "static_cast<" +
2668 type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
2669 }
2670
2671 std::string code;
2672 switch (field.value.type.base_type) {
2673 // String fields are of the form:
2674 // _fbb.CreateString(_o->field)
2675 // or
2676 // _fbb.CreateSharedString(_o->field)
2677 case BASE_TYPE_STRING: {
2678 if (!field.shared) {
2679 code += "_fbb.CreateString(";
2680 } else {
2681 code += "_fbb.CreateSharedString(";
2682 }
2683 code += value;
2684 code.push_back(')');
2685
2686 // For optional fields, check to see if there actually is any data
2687 // in _o->field before attempting to access it. If there isn't,
Austin Schuh272c6132020-11-14 16:37:52 -08002688 // depending on set_empty_strings_to_null either set it to 0 or an empty
2689 // string.
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002690 if (!field.required) {
Austin Schuh272c6132020-11-14 16:37:52 -08002691 auto empty_value = opts_.set_empty_strings_to_null
2692 ? "0"
2693 : "_fbb.CreateSharedString(\"\")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002694 code = value + ".empty() ? " + empty_value + " : " + code;
2695 }
2696 break;
2697 }
Austin Schuh272c6132020-11-14 16:37:52 -08002698 // Vector fields come in several flavours, of the forms:
2699 // _fbb.CreateVector(_o->field);
2700 // _fbb.CreateVector((const utype*)_o->field.data(),
2701 // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field)
2702 // _fbb.CreateVectorOfStructs(_o->field)
2703 // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
2704 // return CreateT(_fbb, _o->Get(i), rehasher);
2705 // });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002706 case BASE_TYPE_VECTOR: {
2707 auto vector_type = field.value.type.VectorType();
2708 switch (vector_type.base_type) {
2709 case BASE_TYPE_STRING: {
2710 if (NativeString(&field) == "std::string") {
2711 code += "_fbb.CreateVectorOfStrings(" + value + ")";
2712 } else {
2713 // Use by-function serialization to emulate
2714 // CreateVectorOfStrings(); this works also with non-std strings.
2715 code +=
2716 "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>"
2717 " ";
2718 code += "(" + value + ".size(), ";
2719 code += "[](size_t i, _VectorArgs *__va) { ";
2720 code +=
2721 "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
2722 code += " }, &_va )";
2723 }
2724 break;
2725 }
2726 case BASE_TYPE_STRUCT: {
2727 if (IsStruct(vector_type)) {
2728 auto native_type =
2729 field.value.type.struct_def->attributes.Lookup("native_type");
2730 if (native_type) {
2731 code += "_fbb.CreateVectorOfNativeStructs<";
2732 code += WrapInNameSpace(*vector_type.struct_def) + ">";
2733 } else {
2734 code += "_fbb.CreateVectorOfStructs";
2735 }
2736 code += "(" + value + ")";
2737 } else {
2738 code += "_fbb.CreateVector<flatbuffers::Offset<";
2739 code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
2740 code += "(" + value + ".size(), ";
2741 code += "[](size_t i, _VectorArgs *__va) { ";
2742 code += "return Create" + vector_type.struct_def->name;
2743 code += "(*__va->__fbb, __va->_" + value + "[i]" +
2744 GenPtrGet(field) + ", ";
2745 code += "__va->__rehasher); }, &_va )";
2746 }
2747 break;
2748 }
2749 case BASE_TYPE_BOOL: {
2750 code += "_fbb.CreateVector(" + value + ")";
2751 break;
2752 }
2753 case BASE_TYPE_UNION: {
2754 code +=
2755 "_fbb.CreateVector<flatbuffers::"
2756 "Offset<void>>(" +
2757 value +
2758 ".size(), [](size_t i, _VectorArgs *__va) { "
2759 "return __va->_" +
2760 value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
2761 break;
2762 }
2763 case BASE_TYPE_UTYPE: {
2764 value = StripUnionType(value);
2765 code += "_fbb.CreateVector<uint8_t>(" + value +
2766 ".size(), [](size_t i, _VectorArgs *__va) { "
2767 "return static_cast<uint8_t>(__va->_" +
2768 value + "[i].type); }, &_va)";
2769 break;
2770 }
2771 default: {
Austin Schuh272c6132020-11-14 16:37:52 -08002772 if (field.value.type.enum_def &&
2773 !VectorElementUserFacing(vector_type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002774 // For enumerations, we need to get access to the array data for
2775 // the underlying storage type (eg. uint8_t).
2776 const auto basetype = GenTypeBasic(
2777 field.value.type.enum_def->underlying_type, false);
2778 code += "_fbb.CreateVectorScalarCast<" + basetype +
2779 ">(flatbuffers::data(" + value + "), " + value +
2780 ".size())";
2781 } else if (field.attributes.Lookup("cpp_type")) {
2782 auto type = GenTypeBasic(vector_type, false);
2783 code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
2784 code += "[](size_t i, _VectorArgs *__va) { ";
2785 code += "return __va->__rehasher ? ";
2786 code += "static_cast<" + type + ">((*__va->__rehasher)";
2787 code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
2788 code += "; }, &_va )";
2789 } else {
2790 code += "_fbb.CreateVector(" + value + ")";
2791 }
2792 break;
2793 }
2794 }
2795
Austin Schuh272c6132020-11-14 16:37:52 -08002796 // If set_empty_vectors_to_null option is enabled, for optional fields,
2797 // check to see if there actually is any data in _o->field before
2798 // attempting to access it.
2799 if (opts_.set_empty_vectors_to_null && !field.required) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002800 code = value + ".size() ? " + code + " : 0";
2801 }
2802 break;
2803 }
2804 case BASE_TYPE_UNION: {
2805 // _o->field.Pack(_fbb);
2806 code += value + ".Pack(_fbb)";
2807 break;
2808 }
2809 case BASE_TYPE_STRUCT: {
2810 if (IsStruct(field.value.type)) {
2811 auto native_type =
2812 field.value.type.struct_def->attributes.Lookup("native_type");
2813 if (native_type) {
2814 code += "flatbuffers::Pack(" + value + ")";
2815 } else if (field.native_inline) {
2816 code += "&" + value;
2817 } else {
2818 code += value + " ? " + value + GenPtrGet(field) + " : 0";
2819 }
2820 } else {
2821 // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
2822 const auto type = field.value.type.struct_def->name;
2823 code += value + " ? Create" + type;
2824 code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
2825 code += " : 0";
2826 }
2827 break;
2828 }
2829 default: {
2830 code += value;
2831 break;
2832 }
2833 }
2834 return code;
2835 }
2836
2837 // Generate code for tables that needs to come after the regular definition.
2838 void GenTablePost(const StructDef &struct_def) {
2839 code_.SetValue("STRUCT_NAME", Name(struct_def));
2840 code_.SetValue("NATIVE_NAME",
Austin Schuh272c6132020-11-14 16:37:52 -08002841 NativeName(Name(struct_def), &struct_def, opts_));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002842
Austin Schuh272c6132020-11-14 16:37:52 -08002843 if (opts_.generate_object_based_api) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002844 // Generate the X::UnPack() method.
Austin Schuh272c6132020-11-14 16:37:52 -08002845 code_ +=
2846 "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
2847
2848 if (opts_.g_cpp_std == cpp::CPP_STD_X0) {
2849 auto native_name =
2850 NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts);
2851 code_.SetValue("POINTER_TYPE",
2852 GenTypeNativePtr(native_name, nullptr, false));
2853 code_ +=
2854 " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
2855 } else if (opts_.g_cpp_std == cpp::CPP_STD_11) {
2856 code_ +=
2857 " auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new "
2858 "{{NATIVE_NAME}}());";
2859 } else {
2860 code_ += " auto _o = std::make_unique<{{NATIVE_NAME}}>();";
2861 }
2862 code_ += " UnPackTo(_o.get(), _resolver);";
2863 code_ += " return _o.release();";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002864 code_ += "}";
2865 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08002866 code_ +=
2867 "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002868 code_ += " (void)_o;";
2869 code_ += " (void)_resolver;";
2870
2871 for (auto it = struct_def.fields.vec.begin();
2872 it != struct_def.fields.vec.end(); ++it) {
2873 const auto &field = **it;
2874 if (field.deprecated) { continue; }
2875
2876 // Assign a value from |this| to |_o|. Values from |this| are stored
2877 // in a variable |_e| by calling this->field_type(). The value is then
2878 // assigned to |_o| using the GenUnpackFieldStatement.
2879 const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
2880 const auto statement =
2881 GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
2882
2883 code_.SetValue("FIELD_NAME", Name(field));
2884 auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
2885 auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
Austin Schuh272c6132020-11-14 16:37:52 -08002886 auto postfix = " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002887 code_ += std::string(prefix) + check + statement + postfix;
2888 }
2889 code_ += "}";
2890 code_ += "";
2891
2892 // Generate the X::Pack member function that simply calls the global
2893 // CreateX function.
Austin Schuh272c6132020-11-14 16:37:52 -08002894 code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002895 code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
2896 code_ += "}";
2897 code_ += "";
2898
2899 // Generate a CreateX method that works with an unpacked C++ object.
Austin Schuh272c6132020-11-14 16:37:52 -08002900 code_ +=
2901 "inline " + TableCreateSignature(struct_def, false, opts_) + " {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002902 code_ += " (void)_rehasher;";
2903 code_ += " (void)_o;";
2904
2905 code_ +=
2906 " struct _VectorArgs "
2907 "{ flatbuffers::FlatBufferBuilder *__fbb; "
2908 "const " +
Austin Schuh272c6132020-11-14 16:37:52 -08002909 NativeName(Name(struct_def), &struct_def, opts_) +
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002910 "* __o; "
2911 "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
2912 "&_fbb, _o, _rehasher}; (void)_va;";
2913
2914 for (auto it = struct_def.fields.vec.begin();
2915 it != struct_def.fields.vec.end(); ++it) {
2916 auto &field = **it;
2917 if (field.deprecated) { continue; }
Austin Schuh272c6132020-11-14 16:37:52 -08002918 if (IsVector(field.value.type)) {
2919 const std::string force_align_code =
2920 GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
2921 if (!force_align_code.empty()) { code_ += " " + force_align_code; }
2922 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002923 code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
2924 }
2925 // Need to call "Create" with the struct namespace.
2926 const auto qualified_create_name =
2927 struct_def.defined_namespace->GetFullyQualifiedName("Create");
2928 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2929
2930 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2931 code_ += " _fbb\\";
2932 for (auto it = struct_def.fields.vec.begin();
2933 it != struct_def.fields.vec.end(); ++it) {
2934 auto &field = **it;
2935 if (field.deprecated) { continue; }
2936
2937 bool pass_by_address = false;
2938 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
2939 if (IsStruct(field.value.type)) {
2940 auto native_type =
2941 field.value.type.struct_def->attributes.Lookup("native_type");
2942 if (native_type) { pass_by_address = true; }
2943 }
2944 }
2945
2946 // Call the CreateX function using values from |_o|.
2947 if (pass_by_address) {
2948 code_ += ",\n &_" + Name(field) + "\\";
2949 } else {
2950 code_ += ",\n _" + Name(field) + "\\";
2951 }
2952 }
2953 code_ += ");";
2954 code_ += "}";
2955 code_ += "";
2956 }
2957 }
2958
2959 static void GenPadding(
2960 const FieldDef &field, std::string *code_ptr, int *id,
2961 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
2962 if (field.padding) {
2963 for (int i = 0; i < 4; i++) {
2964 if (static_cast<int>(field.padding) & (1 << i)) {
2965 f((1 << i) * 8, code_ptr, id);
2966 }
2967 }
2968 FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
2969 }
2970 }
2971
2972 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
2973 *code_ptr += " int" + NumToString(bits) + "_t padding" +
2974 NumToString((*id)++) + "__;";
2975 }
2976
2977 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
2978 (void)bits;
Austin Schuh272c6132020-11-14 16:37:52 -08002979 if (!code_ptr->empty()) *code_ptr += ",\n ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002980 *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
2981 }
2982
2983 static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
2984 (void)bits;
Austin Schuh272c6132020-11-14 16:37:52 -08002985 if (!code_ptr->empty()) *code_ptr += '\n';
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002986 *code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
2987 }
2988
Austin Schuh272c6132020-11-14 16:37:52 -08002989 void GenStructDefaultConstructor(const StructDef &struct_def) {
2990 std::string init_list;
2991 std::string body;
2992 bool first_in_init_list = true;
2993 int padding_initializer_id = 0;
2994 int padding_body_id = 0;
2995 for (auto it = struct_def.fields.vec.begin();
2996 it != struct_def.fields.vec.end(); ++it) {
2997 const auto field = *it;
2998 const auto field_name = field->name + "_";
2999
3000 if (first_in_init_list) {
3001 first_in_init_list = false;
3002 } else {
3003 init_list += ",";
3004 init_list += "\n ";
3005 }
3006
3007 init_list += field_name;
3008 if (IsStruct(field->value.type) || IsArray(field->value.type)) {
3009 // this is either default initialization of struct
3010 // or
3011 // implicit initialization of array
3012 // for each object in array it:
3013 // * sets it as zeros for POD types (integral, floating point, etc)
3014 // * calls default constructor for classes/structs
3015 init_list += "()";
3016 } else {
3017 init_list += "(0)";
3018 }
3019 if (field->padding) {
3020 GenPadding(*field, &init_list, &padding_initializer_id,
3021 PaddingInitializer);
3022 GenPadding(*field, &body, &padding_body_id, PaddingNoop);
3023 }
3024 }
3025
3026 if (init_list.empty()) {
3027 code_ += " {{STRUCT_NAME}}()";
3028 code_ += " {}";
3029 } else {
3030 code_.SetValue("INIT_LIST", init_list);
3031 code_ += " {{STRUCT_NAME}}()";
3032 code_ += " : {{INIT_LIST}} {";
3033 if (!body.empty()) { code_ += body; }
3034 code_ += " }";
3035 }
3036 }
3037
3038 void GenStructConstructor(const StructDef &struct_def,
3039 GenArrayArgMode array_mode) {
3040 std::string arg_list;
3041 std::string init_list;
3042 int padding_id = 0;
3043 auto first = struct_def.fields.vec.begin();
3044 // skip arrays if generate ctor without array assignment
3045 const auto init_arrays = (array_mode != kArrayArgModeNone);
3046 for (auto it = struct_def.fields.vec.begin();
3047 it != struct_def.fields.vec.end(); ++it) {
3048 const auto &field = **it;
3049 const auto &type = field.value.type;
3050 const auto is_array = IsArray(type);
3051 const auto arg_name = "_" + Name(field);
3052 if (!is_array || init_arrays) {
3053 if (it != first && !arg_list.empty()) { arg_list += ", "; }
3054 arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true)
3055 : GenTypeSpan(type, true, type.fixed_length);
3056 arg_list += arg_name;
3057 }
3058 // skip an array with initialization from span
3059 if (false == (is_array && init_arrays)) {
3060 if (it != first && !init_list.empty()) { init_list += ",\n "; }
3061 init_list += Name(field) + "_";
3062 if (IsScalar(type.base_type)) {
3063 auto scalar_type = GenUnderlyingCast(field, false, arg_name);
3064 init_list += "(flatbuffers::EndianScalar(" + scalar_type + "))";
3065 } else {
3066 FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type));
3067 if (!is_array)
3068 init_list += "(" + arg_name + ")";
3069 else
3070 init_list += "()";
3071 }
3072 }
3073 if (field.padding)
3074 GenPadding(field, &init_list, &padding_id, PaddingInitializer);
3075 }
3076
3077 if (!arg_list.empty()) {
3078 code_.SetValue("ARG_LIST", arg_list);
3079 code_.SetValue("INIT_LIST", init_list);
3080 if (!init_list.empty()) {
3081 code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
3082 code_ += " : {{INIT_LIST}} {";
3083 } else {
3084 code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
3085 }
3086 padding_id = 0;
3087 for (auto it = struct_def.fields.vec.begin();
3088 it != struct_def.fields.vec.end(); ++it) {
3089 const auto &field = **it;
3090 const auto &type = field.value.type;
3091 if (IsArray(type) && init_arrays) {
3092 const auto &element_type = type.VectorType();
3093 const auto is_enum = IsEnum(element_type);
3094 FLATBUFFERS_ASSERT(
3095 (IsScalar(element_type.base_type) || IsStruct(element_type)) &&
3096 "invalid declaration");
3097 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3098 std::string get_array =
3099 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3100 const auto field_name = Name(field) + "_";
3101 const auto arg_name = "_" + Name(field);
3102 code_ += " flatbuffers::" + get_array + "(" + field_name +
3103 ").CopyFromSpan(" + arg_name + ");";
3104 }
3105 if (field.padding) {
3106 std::string padding;
3107 GenPadding(field, &padding, &padding_id, PaddingNoop);
3108 code_ += padding;
3109 }
3110 }
3111 code_ += " }";
3112 }
3113 }
3114
3115 void GenArrayAccessor(const Type &type, bool mutable_accessor) {
3116 FLATBUFFERS_ASSERT(IsArray(type));
3117 const auto is_enum = IsEnum(type.VectorType());
3118 // The Array<bool,N> is a tricky case, like std::vector<bool>.
3119 // It requires a specialization of Array class.
3120 // Generate Array<uint8_t> for Array<bool>.
3121 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3122 std::string ret_type = "flatbuffers::Array<" + face_type + ", " +
3123 NumToString(type.fixed_length) + ">";
3124 if (mutable_accessor)
3125 code_ += " " + ret_type + " *mutable_{{FIELD_NAME}}() {";
3126 else
3127 code_ += " const " + ret_type + " *{{FIELD_NAME}}() const {";
3128
3129 std::string get_array =
3130 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3131 code_ += " return &flatbuffers::" + get_array + "({{FIELD_VALUE}});";
3132 code_ += " }";
3133 }
3134
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003135 // Generate an accessor struct with constructor for a flatbuffers struct.
3136 void GenStruct(const StructDef &struct_def) {
3137 // Generate an accessor struct, with private variables of the form:
3138 // type name_;
3139 // Generates manual padding and alignment.
3140 // Variables are private because they contain little endian data on all
3141 // platforms.
3142 GenComment(struct_def.doc_comment);
3143 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
3144 code_.SetValue("STRUCT_NAME", Name(struct_def));
3145
3146 code_ +=
3147 "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
3148 "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
3149 code_ += " private:";
3150
3151 int padding_id = 0;
3152 for (auto it = struct_def.fields.vec.begin();
3153 it != struct_def.fields.vec.end(); ++it) {
3154 const auto &field = **it;
3155 const auto &field_type = field.value.type;
3156 code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
3157 code_.SetValue("FIELD_NAME", Name(field));
3158 code_.SetValue("ARRAY",
3159 IsArray(field_type)
3160 ? "[" + NumToString(field_type.fixed_length) + "]"
3161 : "");
3162 code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
3163
3164 if (field.padding) {
3165 std::string padding;
3166 GenPadding(field, &padding, &padding_id, PaddingDefinition);
3167 code_ += padding;
3168 }
3169 }
3170
3171 // Generate GetFullyQualifiedName
3172 code_ += "";
3173 code_ += " public:";
3174
3175 // Make TypeTable accessible via the generated struct.
Austin Schuh272c6132020-11-14 16:37:52 -08003176 if (opts_.mini_reflect != IDLOptions::kNone) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003177 code_ +=
3178 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
3179 code_ += " return {{STRUCT_NAME}}TypeTable();";
3180 code_ += " }";
3181 }
3182
3183 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
3184
3185 // Generate a default constructor.
Austin Schuh272c6132020-11-14 16:37:52 -08003186 GenStructDefaultConstructor(struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003187
3188 // Generate a constructor that takes all fields as arguments,
Austin Schuh272c6132020-11-14 16:37:52 -08003189 // excluding arrays.
3190 GenStructConstructor(struct_def, kArrayArgModeNone);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003191
Austin Schuh272c6132020-11-14 16:37:52 -08003192 auto arrays_num = std::count_if(struct_def.fields.vec.begin(),
3193 struct_def.fields.vec.end(),
3194 [](const flatbuffers::FieldDef *fd) {
3195 return IsArray(fd->value.type);
3196 });
3197 if (arrays_num > 0) {
3198 GenStructConstructor(struct_def, kArrayArgModeSpanStatic);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003199 }
3200
3201 // Generate accessor methods of the form:
3202 // type name() const { return flatbuffers::EndianScalar(name_); }
3203 for (auto it = struct_def.fields.vec.begin();
3204 it != struct_def.fields.vec.end(); ++it) {
3205 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -08003206 const auto &type = field.value.type;
3207 const auto is_scalar = IsScalar(type.base_type);
3208 const auto is_array = IsArray(type);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003209
Austin Schuh272c6132020-11-14 16:37:52 -08003210 const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ",
3211 is_array ? "" : " &", true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003212 auto member = Name(field) + "_";
3213 auto value =
3214 is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
3215
3216 code_.SetValue("FIELD_NAME", Name(field));
3217 code_.SetValue("FIELD_TYPE", field_type);
3218 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
3219
3220 GenComment(field.doc_comment, " ");
3221
3222 // Generate a const accessor function.
Austin Schuh272c6132020-11-14 16:37:52 -08003223 if (is_array) {
3224 GenArrayAccessor(type, false);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003225 } else {
3226 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
3227 code_ += " return {{FIELD_VALUE}};";
3228 code_ += " }";
3229 }
3230
3231 // Generate a mutable accessor function.
Austin Schuh272c6132020-11-14 16:37:52 -08003232 if (opts_.mutable_buffer) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003233 auto mut_field_type =
Austin Schuh272c6132020-11-14 16:37:52 -08003234 GenTypeGet(type, " ", "", is_array ? "" : " &", true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003235 code_.SetValue("FIELD_TYPE", mut_field_type);
3236 if (is_scalar) {
Austin Schuh272c6132020-11-14 16:37:52 -08003237 code_.SetValue("ARG", GenTypeBasic(type, true));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003238 code_.SetValue("FIELD_VALUE",
3239 GenUnderlyingCast(field, false, "_" + Name(field)));
3240
3241 code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
3242 code_ +=
3243 " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
3244 "{{FIELD_VALUE}});";
3245 code_ += " }";
Austin Schuh272c6132020-11-14 16:37:52 -08003246 } else if (is_array) {
3247 GenArrayAccessor(type, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003248 } else {
3249 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
3250 code_ += " return {{FIELD_VALUE}};";
3251 code_ += " }";
3252 }
3253 }
3254
3255 // Generate a comparison function for this field if it is a key.
3256 if (field.key) { GenKeyFieldMethods(field); }
3257 }
3258 code_.SetValue("NATIVE_NAME", Name(struct_def));
3259 GenOperatorNewDelete(struct_def);
3260 code_ += "};";
3261
3262 code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
3263 code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
Austin Schuh272c6132020-11-14 16:37:52 -08003264 if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003265 code_ += "";
3266 }
3267
3268 // Set up the correct namespace. Only open a namespace if the existing one is
3269 // different (closing/opening only what is necessary).
3270 //
3271 // The file must start and end with an empty (or null) namespace so that
3272 // namespaces are properly opened and closed.
3273 void SetNameSpace(const Namespace *ns) {
3274 if (cur_name_space_ == ns) { return; }
3275
3276 // Compute the size of the longest common namespace prefix.
3277 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
3278 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
3279 // and common_prefix_size = 2
3280 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
3281 size_t new_size = ns ? ns->components.size() : 0;
3282
3283 size_t common_prefix_size = 0;
3284 while (common_prefix_size < old_size && common_prefix_size < new_size &&
3285 ns->components[common_prefix_size] ==
3286 cur_name_space_->components[common_prefix_size]) {
3287 common_prefix_size++;
3288 }
3289
3290 // Close cur_name_space in reverse order to reach the common prefix.
3291 // In the previous example, D then C are closed.
3292 for (size_t j = old_size; j > common_prefix_size; --j) {
3293 code_ += "} // namespace " + cur_name_space_->components[j - 1];
3294 }
3295 if (old_size != common_prefix_size) { code_ += ""; }
3296
3297 // open namespace parts to reach the ns namespace
3298 // in the previous example, E, then F, then G are opened
3299 for (auto j = common_prefix_size; j != new_size; ++j) {
3300 code_ += "namespace " + ns->components[j] + " {";
3301 }
3302 if (new_size != common_prefix_size) { code_ += ""; }
3303
3304 cur_name_space_ = ns;
3305 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003306};
3307
3308} // namespace cpp
3309
3310bool GenerateCPP(const Parser &parser, const std::string &path,
3311 const std::string &file_name) {
Austin Schuh272c6132020-11-14 16:37:52 -08003312 cpp::IDLOptionsCpp opts(parser.opts);
3313 // The '--cpp_std' argument could be extended (like ASAN):
3314 // Example: "flatc --cpp_std c++17:option1:option2".
3315 auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++0X";
3316 std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), CharToUpper);
3317 if (cpp_std == "C++0X") {
3318 opts.g_cpp_std = cpp::CPP_STD_X0;
3319 opts.g_only_fixed_enums = false;
3320 } else if (cpp_std == "C++11") {
3321 // Use the standard C++11 code generator.
3322 opts.g_cpp_std = cpp::CPP_STD_11;
3323 opts.g_only_fixed_enums = true;
3324 } else if (cpp_std == "C++17") {
3325 opts.g_cpp_std = cpp::CPP_STD_17;
3326 // With c++17 generate strong enums only.
3327 opts.scoped_enums = true;
3328 // By default, prefixed_enums==true, reset it.
3329 opts.prefixed_enums = false;
3330 } else {
3331 LogCompilerError("Unknown value of the '--cpp-std' switch: " +
3332 opts.cpp_std);
3333 return false;
3334 }
3335 // The opts.scoped_enums has priority.
3336 opts.g_only_fixed_enums |= opts.scoped_enums;
3337
3338 cpp::CppGenerator generator(parser, path, file_name, opts);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003339 return generator.generate();
3340}
3341
3342std::string CPPMakeRule(const Parser &parser, const std::string &path,
3343 const std::string &file_name) {
3344 const auto filebase =
3345 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
Austin Schuh272c6132020-11-14 16:37:52 -08003346 cpp::CppGenerator geneartor(parser, path, file_name, parser.opts);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003347 const auto included_files = parser.GetIncludedFilesRecursive(file_name);
Austin Schuh272c6132020-11-14 16:37:52 -08003348 std::string make_rule =
3349 geneartor.GeneratedFileName(path, filebase, parser.opts) + ": ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003350 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
3351 make_rule += " " + *it;
3352 }
3353 return make_rule;
3354}
3355
3356} // namespace flatbuffers