1 /*
2 * 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
19 #include "idl_gen_cpp.h"
20
21 #include <limits>
22 #include <memory>
23 #include <string>
24 #include <unordered_set>
25 #include <utility>
26
27 #include "flatbuffers/base.h"
28 #include "flatbuffers/code_generators.h"
29 #include "flatbuffers/flatbuffers.h"
30 #include "flatbuffers/flatc.h"
31 #include "flatbuffers/idl.h"
32 #include "flatbuffers/util.h"
33
34 namespace flatbuffers {
35
36 // Make numerical literal with type-suffix.
37 // This function is only needed for C++! Other languages do not need it.
NumToStringCpp(std::string val,BaseType type)38 static inline std::string NumToStringCpp(std::string val, BaseType type) {
39 // Avoid issues with -2147483648, -9223372036854775808.
40 switch (type) {
41 case BASE_TYPE_INT:
42 return (val != "-2147483648") ? val : ("(-2147483647 - 1)");
43 case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL");
44 case BASE_TYPE_LONG:
45 if (val == "-9223372036854775808")
46 return "(-9223372036854775807LL - 1LL)";
47 else
48 return (val == "0") ? val : (val + "LL");
49 default: return val;
50 }
51 }
52
GenIncludeGuard(const std::string & file_name,const Namespace & name_space,const std::string & postfix="")53 static std::string GenIncludeGuard(const std::string &file_name,
54 const Namespace &name_space,
55 const std::string &postfix = "") {
56 // Generate include guard.
57 std::string guard = file_name;
58 // Remove any non-alpha-numeric characters that may appear in a filename.
59 struct IsAlnum {
60 bool operator()(char c) const { return !is_alnum(c); }
61 };
62 guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
63 guard.end());
64 guard = "FLATBUFFERS_GENERATED_" + guard;
65 guard += "_";
66 // For further uniqueness, also add the namespace.
67 for (const std::string &component : name_space.components) {
68 guard += component + "_";
69 }
70 // Anything extra to add to the guard?
71 if (!postfix.empty()) { guard += postfix + "_"; }
72 guard += "H_";
73 std::transform(guard.begin(), guard.end(), guard.begin(), CharToUpper);
74 return guard;
75 }
76
IsVectorOfPointers(const FieldDef & field)77 static bool IsVectorOfPointers(const FieldDef &field) {
78 const auto &type = field.value.type;
79 const auto &vector_type = type.VectorType();
80 return IsVector(type) && vector_type.base_type == BASE_TYPE_STRUCT &&
81 !vector_type.struct_def->fixed && !field.native_inline;
82 }
83
IsPointer(const FieldDef & field)84 static bool IsPointer(const FieldDef &field) {
85 return field.value.type.base_type == BASE_TYPE_STRUCT &&
86 !IsStruct(field.value.type);
87 }
88
89 namespace cpp {
90
91 enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
92
93 // Define a style of 'struct' constructor if it has 'Array' fields.
94 enum GenArrayArgMode {
95 kArrayArgModeNone, // don't generate initialization args
96 kArrayArgModeSpanStatic, // generate ::flatbuffers::span<T,N>
97 };
98
99 // Extension of IDLOptions for cpp-generator.
100 struct IDLOptionsCpp : public IDLOptions {
101 // All fields start with 'g_' prefix to distinguish from the base IDLOptions.
102 CppStandard g_cpp_std; // Base version of C++ standard.
103 bool g_only_fixed_enums; // Generate underlaying type for all enums.
104
IDLOptionsCppflatbuffers::cpp::IDLOptionsCpp105 IDLOptionsCpp(const IDLOptions &opts)
106 : IDLOptions(opts), g_cpp_std(CPP_STD_11), g_only_fixed_enums(true) {}
107 };
108
109 // Iterates over all the fields of the object first by Offset type (Offset64
110 // before Offset32) and then by definition order.
ForAllFieldsOrderedByOffset(const StructDef & object,std::function<void (const FieldDef * field)> func)111 static void ForAllFieldsOrderedByOffset(
112 const StructDef &object, std::function<void(const FieldDef *field)> func) {
113 // Loop over all the fields and call the func on all offset64 fields.
114 for (const FieldDef *field_def : object.fields.vec) {
115 if (field_def->offset64) { func(field_def); }
116 }
117 // Loop over all the fields a second time and call the func on all offset
118 // fields.
119 for (const FieldDef *field_def : object.fields.vec) {
120 if (!field_def->offset64) { func(field_def); }
121 }
122 }
123
124 class CppGenerator : public BaseGenerator {
125 public:
CppGenerator(const Parser & parser,const std::string & path,const std::string & file_name,IDLOptionsCpp opts)126 CppGenerator(const Parser &parser, const std::string &path,
127 const std::string &file_name, IDLOptionsCpp opts)
128 : BaseGenerator(parser, path, file_name, "", "::", "h"),
129 cur_name_space_(nullptr),
130 opts_(opts),
131 float_const_gen_("std::numeric_limits<double>::",
132 "std::numeric_limits<float>::", "quiet_NaN()",
133 "infinity()") {
134 static const char *const keywords[] = {
135 "alignas",
136 "alignof",
137 "and",
138 "and_eq",
139 "asm",
140 "atomic_cancel",
141 "atomic_commit",
142 "atomic_noexcept",
143 "auto",
144 "bitand",
145 "bitor",
146 "bool",
147 "break",
148 "case",
149 "catch",
150 "char",
151 "char16_t",
152 "char32_t",
153 "class",
154 "compl",
155 "concept",
156 "const",
157 "constexpr",
158 "const_cast",
159 "continue",
160 "co_await",
161 "co_return",
162 "co_yield",
163 "decltype",
164 "default",
165 "delete",
166 "do",
167 "double",
168 "dynamic_cast",
169 "else",
170 "enum",
171 "explicit",
172 "export",
173 "extern",
174 "false",
175 "float",
176 "for",
177 "friend",
178 "goto",
179 "if",
180 "import",
181 "inline",
182 "int",
183 "long",
184 "module",
185 "mutable",
186 "namespace",
187 "new",
188 "noexcept",
189 "not",
190 "not_eq",
191 "nullptr",
192 "operator",
193 "or",
194 "or_eq",
195 "private",
196 "protected",
197 "public",
198 "register",
199 "reinterpret_cast",
200 "requires",
201 "return",
202 "short",
203 "signed",
204 "sizeof",
205 "static",
206 "static_assert",
207 "static_cast",
208 "struct",
209 "switch",
210 "synchronized",
211 "template",
212 "this",
213 "thread_local",
214 "throw",
215 "true",
216 "try",
217 "typedef",
218 "typeid",
219 "typename",
220 "union",
221 "unsigned",
222 "using",
223 "virtual",
224 "void",
225 "volatile",
226 "wchar_t",
227 "while",
228 "xor",
229 "xor_eq",
230 nullptr,
231 };
232 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
233 }
234
235 // Adds code to check that the included flatbuffers.h is of the same version
236 // as the generated code. This check currently looks for exact version match,
237 // as we would guarantee that they are compatible, but in theory a newer
238 // version of flatbuffers.h should work with a old code gen if we do proper
239 // backwards support.
GenFlatbuffersVersionCheck()240 void GenFlatbuffersVersionCheck() {
241 code_ +=
242 "// Ensure the included flatbuffers.h is the same version as when this "
243 "file was";
244 code_ += "// generated, otherwise it may not be compatible.";
245 code_ += "static_assert(FLATBUFFERS_VERSION_MAJOR == " +
246 std::to_string(FLATBUFFERS_VERSION_MAJOR) + " &&";
247 code_ += " FLATBUFFERS_VERSION_MINOR == " +
248 std::to_string(FLATBUFFERS_VERSION_MINOR) + " &&";
249 code_ += " FLATBUFFERS_VERSION_REVISION == " +
250 std::to_string(FLATBUFFERS_VERSION_REVISION) + ",";
251 code_ += " \"Non-compatible flatbuffers version included\");";
252 }
253
GenIncludeDependencies()254 void GenIncludeDependencies() {
255 if (opts_.generate_object_based_api) {
256 for (const std::string &native_included_file :
257 parser_.native_included_files_) {
258 code_ += "#include \"" + native_included_file + "\"";
259 }
260 }
261
262 // Get the directly included file of the file being parsed.
263 std::vector<IncludedFile> included_files(parser_.GetIncludedFiles());
264
265 // We are safe to sort them alphabetically, since there shouldn't be any
266 // interdependence between them.
267 std::stable_sort(included_files.begin(), included_files.end());
268
269 for (const IncludedFile &included_file : included_files) {
270 // Get the name of the included file as defined by the schema, and strip
271 // the .fbs extension.
272 const std::string name_without_ext =
273 StripExtension(included_file.schema_name);
274
275 // If we are told to keep the prefix of the included schema, leave it
276 // unchanged, otherwise strip the leading path off so just the "basename"
277 // of the include is retained.
278 const std::string basename =
279 opts_.keep_prefix ? name_without_ext : StripPath(name_without_ext);
280
281 code_ += "#include \"" +
282 GeneratedFileName(opts_.include_prefix, basename, opts_) + "\"";
283 }
284
285 if (!parser_.native_included_files_.empty() || !included_files.empty()) {
286 code_ += "";
287 }
288 }
289
MarkIf64BitBuilderIsNeeded()290 void MarkIf64BitBuilderIsNeeded() {
291 if (needs_64_bit_builder_) { return; }
292 for (auto t : parser_.structs_.vec) {
293 if (t == nullptr) continue;
294 for (auto f : t->fields.vec) {
295 if (f == nullptr) continue;
296 if (f->offset64) {
297 needs_64_bit_builder_ = true;
298 break;
299 }
300 }
301 }
302 }
303
GetBuilder()304 std::string GetBuilder() {
305 return std::string("::flatbuffers::FlatBufferBuilder") +
306 (needs_64_bit_builder_ ? "64" : "");
307 }
308
GenExtraIncludes()309 void GenExtraIncludes() {
310 for (const std::string &cpp_include : opts_.cpp_includes) {
311 code_ += "#include \"" + cpp_include + "\"";
312 }
313 if (!opts_.cpp_includes.empty()) { code_ += ""; }
314 }
315
GenEmbeddedIncludes()316 void GenEmbeddedIncludes() {
317 if (parser_.opts.binary_schema_gen_embed && parser_.root_struct_def_) {
318 const std::string file_path =
319 GeneratedFileName(opts_.include_prefix, file_name_ + "_bfbs", opts_);
320 code_ += "// For access to the binary schema that produced this file.";
321 code_ += "#include \"" + file_path + "\"";
322 code_ += "";
323 }
324 }
325
EscapeKeyword(const std::string & name) const326 std::string EscapeKeyword(const std::string &name) const {
327 return keywords_.find(name) == keywords_.end() ? name : name + "_";
328 }
329
Name(const FieldDef & field) const330 std::string Name(const FieldDef &field) const {
331 // the union type field suffix is immutable.
332 static size_t union_suffix_len = strlen(UnionTypeFieldSuffix());
333 const bool is_union_type = field.value.type.base_type == BASE_TYPE_UTYPE;
334 // early return if no case transformation required
335 if (opts_.cpp_object_api_field_case_style ==
336 IDLOptions::CaseStyle_Unchanged)
337 return EscapeKeyword(field.name);
338 std::string name = field.name;
339 // do not change the case style of the union type field suffix
340 if (is_union_type) {
341 FLATBUFFERS_ASSERT(name.length() > union_suffix_len);
342 name.erase(name.length() - union_suffix_len, union_suffix_len);
343 }
344 if (opts_.cpp_object_api_field_case_style == IDLOptions::CaseStyle_Upper)
345 name = ConvertCase(name, Case::kUpperCamel);
346 else if (opts_.cpp_object_api_field_case_style ==
347 IDLOptions::CaseStyle_Lower)
348 name = ConvertCase(name, Case::kLowerCamel);
349 // restore the union field type suffix
350 if (is_union_type) name.append(UnionTypeFieldSuffix(), union_suffix_len);
351 return EscapeKeyword(name);
352 }
353
Name(const Definition & def) const354 std::string Name(const Definition &def) const {
355 return EscapeKeyword(def.name);
356 }
357
Name(const EnumVal & ev) const358 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
359
generate_bfbs_embed()360 bool generate_bfbs_embed() {
361 code_.Clear();
362 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
363
364 // If we don't have a root struct definition,
365 if (!parser_.root_struct_def_) {
366 // put a comment in the output why there is no code generated.
367 code_ += "// Binary schema not generated, no root struct found";
368 } else {
369 auto &struct_def = *parser_.root_struct_def_;
370 const auto include_guard =
371 GenIncludeGuard(file_name_, *struct_def.defined_namespace, "bfbs");
372
373 code_ += "#ifndef " + include_guard;
374 code_ += "#define " + include_guard;
375 code_ += "";
376 if (parser_.opts.gen_nullable) {
377 code_ += "#pragma clang system_header\n\n";
378 }
379
380 code_ += "#include <cstddef>";
381 code_ += "#include <cstdint>";
382
383 SetNameSpace(struct_def.defined_namespace);
384 auto name = Name(struct_def);
385 code_.SetValue("STRUCT_NAME", name);
386
387 // Create code to return the binary schema data.
388 auto binary_schema_hex_text =
389 BufferToHexText(parser_.builder_.GetBufferPointer(),
390 parser_.builder_.GetSize(), 105, " ", "");
391
392 code_ += "struct {{STRUCT_NAME}}BinarySchema {";
393 code_ += " static const uint8_t *data() {";
394 code_ += " // Buffer containing the binary schema.";
395 code_ += " static const uint8_t bfbsData[" +
396 NumToString(parser_.builder_.GetSize()) + "] = {";
397 code_ += binary_schema_hex_text;
398 code_ += " };";
399 code_ += " return bfbsData;";
400 code_ += " }";
401 code_ += " static size_t size() {";
402 code_ += " return " + NumToString(parser_.builder_.GetSize()) + ";";
403 code_ += " }";
404 code_ += " const uint8_t *begin() {";
405 code_ += " return data();";
406 code_ += " }";
407 code_ += " const uint8_t *end() {";
408 code_ += " return data() + size();";
409 code_ += " }";
410 code_ += "};";
411 code_ += "";
412
413 if (cur_name_space_) SetNameSpace(nullptr);
414
415 // Close the include guard.
416 code_ += "#endif // " + include_guard;
417 }
418
419 // We are just adding "_bfbs" to the generated filename.
420 const auto file_path =
421 GeneratedFileName(path_, file_name_ + "_bfbs", opts_);
422 const auto final_code = code_.ToString();
423
424 return SaveFile(file_path.c_str(), final_code, false);
425 }
426
427 // Iterate through all definitions we haven't generate code for (enums,
428 // structs, and tables) and output them to a single file.
generate()429 bool generate() {
430 // Check if we require a 64-bit flatbuffer builder.
431 MarkIf64BitBuilderIsNeeded();
432
433 code_.Clear();
434 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
435
436 const auto include_guard =
437 GenIncludeGuard(file_name_, *parser_.current_namespace_);
438 code_ += "#ifndef " + include_guard;
439 code_ += "#define " + include_guard;
440 code_ += "";
441
442 if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; }
443
444 code_ += "#include \"flatbuffers/flatbuffers.h\"";
445 if (parser_.uses_flexbuffers_) {
446 code_ += "#include \"flatbuffers/flexbuffers.h\"";
447 code_ += "#include \"flatbuffers/flex_flat_util.h\"";
448 }
449 code_ += "";
450 GenFlatbuffersVersionCheck();
451 code_ += "";
452
453 if (opts_.include_dependence_headers) { GenIncludeDependencies(); }
454 GenExtraIncludes();
455 GenEmbeddedIncludes();
456
457 FLATBUFFERS_ASSERT(!cur_name_space_);
458
459 // Generate forward declarations for all structs/tables, since they may
460 // have circular references.
461 for (const auto &struct_def : parser_.structs_.vec) {
462 if (!struct_def->generated) {
463 SetNameSpace(struct_def->defined_namespace);
464 code_ += "struct " + Name(*struct_def) + ";";
465 if (!struct_def->fixed) {
466 code_ += "struct " + Name(*struct_def) + "Builder;";
467 }
468 if (opts_.generate_object_based_api) {
469 auto nativeName = NativeName(Name(*struct_def), struct_def, opts_);
470
471 // Check that nativeName doesn't collide the name of another struct.
472 for (const auto &other_struct_def : parser_.structs_.vec) {
473 if (other_struct_def == struct_def ||
474 other_struct_def->defined_namespace !=
475 struct_def->defined_namespace) {
476 continue;
477 }
478
479 auto other_name = Name(*other_struct_def);
480 if (nativeName == other_name) {
481 LogCompilerError("Generated Object API type for " +
482 Name(*struct_def) + " collides with " +
483 other_name);
484 FLATBUFFERS_ASSERT(true);
485 }
486 }
487
488 if (!struct_def->fixed) { code_ += "struct " + nativeName + ";"; }
489 }
490 code_ += "";
491 }
492 }
493
494 // Generate forward declarations for all equal operators
495 if (opts_.generate_object_based_api && opts_.gen_compare) {
496 for (const auto &struct_def : parser_.structs_.vec) {
497 if (!struct_def->generated) {
498 SetNameSpace(struct_def->defined_namespace);
499 auto nativeName = NativeName(Name(*struct_def), struct_def, opts_);
500 code_ += "bool operator==(const " + nativeName + " &lhs, const " +
501 nativeName + " &rhs);";
502 code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
503 nativeName + " &rhs);";
504 }
505 }
506 code_ += "";
507 }
508
509 // Generate preablmle code for mini reflection.
510 if (opts_.mini_reflect != IDLOptions::kNone) {
511 // To break cyclic dependencies, first pre-declare all tables/structs.
512 for (const auto &struct_def : parser_.structs_.vec) {
513 if (!struct_def->generated) {
514 SetNameSpace(struct_def->defined_namespace);
515 GenMiniReflectPre(struct_def);
516 }
517 }
518 }
519
520 // Generate code for all the enum declarations.
521 for (const auto &enum_def : parser_.enums_.vec) {
522 if (!enum_def->generated) {
523 SetNameSpace(enum_def->defined_namespace);
524 GenEnum(*enum_def);
525 }
526 }
527
528 // Generate code for all structs, then all tables.
529 for (const auto &struct_def : parser_.structs_.vec) {
530 if (struct_def->fixed && !struct_def->generated) {
531 SetNameSpace(struct_def->defined_namespace);
532 GenStruct(*struct_def);
533 }
534 }
535 for (const auto &struct_def : parser_.structs_.vec) {
536 if (!struct_def->fixed && !struct_def->generated) {
537 SetNameSpace(struct_def->defined_namespace);
538 GenTable(*struct_def);
539 }
540 }
541 for (const auto &struct_def : parser_.structs_.vec) {
542 if (!struct_def->fixed && !struct_def->generated) {
543 SetNameSpace(struct_def->defined_namespace);
544 GenTablePost(*struct_def);
545 }
546 }
547
548 // Generate code for union verifiers.
549 for (const auto &enum_def : parser_.enums_.vec) {
550 if (enum_def->is_union && !enum_def->generated) {
551 SetNameSpace(enum_def->defined_namespace);
552 GenUnionPost(*enum_def);
553 }
554 }
555
556 // Generate code for mini reflection.
557 if (opts_.mini_reflect != IDLOptions::kNone) {
558 // Then the unions/enums that may refer to them.
559 for (const auto &enum_def : parser_.enums_.vec) {
560 if (!enum_def->generated) {
561 SetNameSpace(enum_def->defined_namespace);
562 GenMiniReflect(nullptr, enum_def);
563 }
564 }
565 // Then the full tables/structs.
566 for (const auto &struct_def : parser_.structs_.vec) {
567 if (!struct_def->generated) {
568 SetNameSpace(struct_def->defined_namespace);
569 GenMiniReflect(struct_def, nullptr);
570 }
571 }
572 }
573
574 // Generate convenient global helper functions:
575 if (parser_.root_struct_def_) {
576 auto &struct_def = *parser_.root_struct_def_;
577 SetNameSpace(struct_def.defined_namespace);
578 auto name = Name(struct_def);
579 auto qualified_name = cur_name_space_->GetFullyQualifiedName(name);
580 auto cpp_name = TranslateNameSpace(qualified_name);
581
582 code_.SetValue("STRUCT_NAME", name);
583 code_.SetValue("CPP_NAME", cpp_name);
584 code_.SetValue("NULLABLE_EXT", NullableExtension());
585 code_.SetValue(
586 "SIZE_T", needs_64_bit_builder_ ? ",::flatbuffers::uoffset64_t" : "");
587
588 // The root datatype accessor:
589 code_ += "inline \\";
590 code_ +=
591 "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void "
592 "*buf) {";
593 code_ += " return ::flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
594 code_ += "}";
595 code_ += "";
596
597 code_ += "inline \\";
598 code_ +=
599 "const {{CPP_NAME}} "
600 "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void "
601 "*buf) {";
602 code_ +=
603 " return "
604 "::flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}{{SIZE_T}}>(buf);";
605 code_ += "}";
606 code_ += "";
607
608 if (opts_.mutable_buffer) {
609 code_ += "inline \\";
610 code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
611 code_ +=
612 " return ::flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
613 code_ += "}";
614 code_ += "";
615
616 code_ += "inline \\";
617 code_ +=
618 "{{CPP_NAME}} "
619 "*{{NULLABLE_EXT}}GetMutableSizePrefixed{{STRUCT_NAME}}(void "
620 "*buf) {";
621 code_ +=
622 " return "
623 "::flatbuffers::GetMutableSizePrefixedRoot<{{CPP_NAME}}{{SIZE_T}}>("
624 "buf);";
625 code_ += "}";
626 code_ += "";
627 }
628
629 if (parser_.file_identifier_.length()) {
630 // Return the identifier
631 code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
632 code_ += " return \"" + parser_.file_identifier_ + "\";";
633 code_ += "}";
634 code_ += "";
635
636 // Check if a buffer has the identifier.
637 code_ += "inline \\";
638 code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
639 code_ += " return ::flatbuffers::BufferHasIdentifier(";
640 code_ += " buf, {{STRUCT_NAME}}Identifier());";
641 code_ += "}";
642 code_ += "";
643
644 // Check if a size-prefixed buffer has the identifier.
645 code_ += "inline \\";
646 code_ +=
647 "bool SizePrefixed{{STRUCT_NAME}}BufferHasIdentifier(const void "
648 "*buf) {";
649 code_ += " return ::flatbuffers::BufferHasIdentifier(";
650 code_ += " buf, {{STRUCT_NAME}}Identifier(), true);";
651 code_ += "}";
652 code_ += "";
653 }
654
655 // The root verifier.
656 if (parser_.file_identifier_.length()) {
657 code_.SetValue("ID", name + "Identifier()");
658 } else {
659 code_.SetValue("ID", "nullptr");
660 }
661
662 code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
663 code_ += " ::flatbuffers::Verifier &verifier) {";
664 code_ += " return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
665 code_ += "}";
666 code_ += "";
667
668 code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer(";
669 code_ += " ::flatbuffers::Verifier &verifier) {";
670 code_ +=
671 " return "
672 "verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}{{SIZE_T}}>({{ID}});";
673 code_ += "}";
674 code_ += "";
675
676 if (parser_.file_extension_.length()) {
677 // Return the extension
678 code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
679 code_ += " return \"" + parser_.file_extension_ + "\";";
680 code_ += "}";
681 code_ += "";
682 }
683
684 // Finish a buffer with a given root object:
685 code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
686 code_ += " " + GetBuilder() + " &fbb,";
687 code_ += " ::flatbuffers::Offset<{{CPP_NAME}}> root) {";
688 if (parser_.file_identifier_.length())
689 code_ += " fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
690 else
691 code_ += " fbb.Finish(root);";
692 code_ += "}";
693 code_ += "";
694
695 code_ += "inline void FinishSizePrefixed{{STRUCT_NAME}}Buffer(";
696 code_ += " " + GetBuilder() + " &fbb,";
697 code_ += " ::flatbuffers::Offset<{{CPP_NAME}}> root) {";
698 if (parser_.file_identifier_.length())
699 code_ += " fbb.FinishSizePrefixed(root, {{STRUCT_NAME}}Identifier());";
700 else
701 code_ += " fbb.FinishSizePrefixed(root);";
702 code_ += "}";
703 code_ += "";
704
705 if (opts_.generate_object_based_api) {
706 // A convenient root unpack function.
707 auto native_name = WrapNativeNameInNameSpace(struct_def, opts_);
708 code_.SetValue("UNPACK_RETURN",
709 GenTypeNativePtr(native_name, nullptr, false));
710 code_.SetValue("UNPACK_TYPE",
711 GenTypeNativePtr(native_name, nullptr, true));
712
713 code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
714 code_ += " const void *buf,";
715 code_ +=
716 " const ::flatbuffers::resolver_function_t *res = nullptr) {";
717 code_ += " return {{UNPACK_TYPE}}\\";
718 code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
719 code_ += "}";
720 code_ += "";
721
722 code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}(";
723 code_ += " const void *buf,";
724 code_ +=
725 " const ::flatbuffers::resolver_function_t *res = nullptr) {";
726 code_ += " return {{UNPACK_TYPE}}\\";
727 code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));";
728 code_ += "}";
729 code_ += "";
730 }
731 }
732
733 if (cur_name_space_) SetNameSpace(nullptr);
734
735 // Close the include guard.
736 code_ += "#endif // " + include_guard;
737
738 const auto file_path = GeneratedFileName(path_, file_name_, opts_);
739 const auto final_code = code_.ToString();
740
741 // Save the file and optionally generate the binary schema code.
742 return SaveFile(file_path.c_str(), final_code, false) &&
743 (!parser_.opts.binary_schema_gen_embed || generate_bfbs_embed());
744 }
745
746 private:
747 CodeWriter code_;
748
749 std::unordered_set<std::string> keywords_;
750
751 // This tracks the current namespace so we can insert namespace declarations.
752 const Namespace *cur_name_space_;
753
754 const IDLOptionsCpp opts_;
755 const TypedFloatConstantGenerator float_const_gen_;
756 bool needs_64_bit_builder_ = false;
757
CurrentNameSpace() const758 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
759
760 // Translates a qualified name in flatbuffer text format to the same name in
761 // the equivalent C++ namespace.
TranslateNameSpace(const std::string & qualified_name)762 static std::string TranslateNameSpace(const std::string &qualified_name) {
763 std::string cpp_qualified_name = qualified_name;
764 size_t start_pos = 0;
765 while ((start_pos = cpp_qualified_name.find('.', start_pos)) !=
766 std::string::npos) {
767 cpp_qualified_name.replace(start_pos, 1, "::");
768 }
769 return cpp_qualified_name;
770 }
771
TypeHasKey(const Type & type)772 bool TypeHasKey(const Type &type) {
773 if (type.base_type != BASE_TYPE_STRUCT) { return false; }
774 for (auto &field : type.struct_def->fields.vec) {
775 if (field->key) { return true; }
776 }
777 return false;
778 }
779
VectorElementUserFacing(const Type & type) const780 bool VectorElementUserFacing(const Type &type) const {
781 return (opts_.scoped_enums && IsEnum(type)) ||
782 (opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums &&
783 IsEnum(type));
784 }
785
GenComment(const std::vector<std::string> & dc,const char * prefix="")786 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
787 std::string text;
788 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
789 code_ += text + "\\";
790 }
791
792 // Return a C++ type from the table in idl.h
GenTypeBasic(const Type & type,bool user_facing_type) const793 std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
794 if (user_facing_type) {
795 if (type.enum_def) return WrapInNameSpace(*type.enum_def);
796 if (type.base_type == BASE_TYPE_BOOL) return "bool";
797 }
798 // Get real underlying type for union type
799 auto base_type = type.base_type;
800 if (type.base_type == BASE_TYPE_UTYPE && type.enum_def != nullptr) {
801 base_type = type.enum_def->underlying_type.base_type;
802 }
803 return StringOf(base_type);
804 }
805
806 // Return a C++ pointer type, specialized to the actual struct/table types,
807 // and vector element types.
GenTypePointer(const Type & type) const808 std::string GenTypePointer(const Type &type) const {
809 switch (type.base_type) {
810 case BASE_TYPE_STRING: {
811 return "::flatbuffers::String";
812 }
813 case BASE_TYPE_VECTOR64:
814 case BASE_TYPE_VECTOR: {
815 const auto type_name = GenTypeWire(
816 type.VectorType(), "", VectorElementUserFacing(type.VectorType()));
817 return "::flatbuffers::Vector" +
818 std::string((type.base_type == BASE_TYPE_VECTOR64) ? "64<"
819 : "<") +
820 type_name + ">";
821 }
822 case BASE_TYPE_STRUCT: {
823 return WrapInNameSpace(*type.struct_def);
824 }
825 case BASE_TYPE_UNION:
826 // fall through
827 default: {
828 return "void";
829 }
830 }
831 }
832
833 // Return a C++ type for any type (scalar/pointer) specifically for
834 // building a flatbuffer.
GenTypeWire(const Type & type,const char * postfix,bool user_facing_type,bool _64_bit_offset=false) const835 std::string GenTypeWire(const Type &type, const char *postfix,
836 bool user_facing_type,
837 bool _64_bit_offset = false) const {
838 if (IsScalar(type.base_type)) {
839 return GenTypeBasic(type, user_facing_type) + postfix;
840 } else if (IsStruct(type)) {
841 return "const " + GenTypePointer(type) + " *";
842 } else {
843 return "::flatbuffers::Offset" + std::string(_64_bit_offset ? "64" : "") +
844 "<" + GenTypePointer(type) + ">" + postfix;
845 }
846 }
847
848 // Return a C++ type for any type (scalar/pointer) that reflects its
849 // serialized size.
GenTypeSize(const Type & type) const850 std::string GenTypeSize(const Type &type) const {
851 if (IsScalar(type.base_type)) {
852 return GenTypeBasic(type, false);
853 } else if (IsStruct(type)) {
854 return GenTypePointer(type);
855 } else {
856 return "::flatbuffers::uoffset_t";
857 }
858 }
859
NullableExtension()860 std::string NullableExtension() {
861 return opts_.gen_nullable ? " _Nullable " : "";
862 }
863
NativeName(const std::string & name,const StructDef * sd,const IDLOptions & opts)864 static std::string NativeName(const std::string &name, const StructDef *sd,
865 const IDLOptions &opts) {
866 return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix
867 : name;
868 }
869
WrapNativeNameInNameSpace(const StructDef & struct_def,const IDLOptions & opts)870 std::string WrapNativeNameInNameSpace(const StructDef &struct_def,
871 const IDLOptions &opts) {
872 return WrapInNameSpace(struct_def.defined_namespace,
873 NativeName(Name(struct_def), &struct_def, opts));
874 }
875
PtrType(const FieldDef * field)876 const std::string &PtrType(const FieldDef *field) {
877 auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
878 return attr ? attr->constant : opts_.cpp_object_api_pointer_type;
879 }
880
NativeString(const FieldDef * field)881 const std::string NativeString(const FieldDef *field) {
882 auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
883 auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type;
884 if (ret.empty()) { return "std::string"; }
885 return ret;
886 }
887
FlexibleStringConstructor(const FieldDef * field)888 bool FlexibleStringConstructor(const FieldDef *field) {
889 auto attr = field != nullptr &&
890 (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr);
891 auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor;
892 return ret && NativeString(field) !=
893 "std::string"; // Only for custom string types.
894 }
895
GenTypeNativePtr(const std::string & type,const FieldDef * field,bool is_constructor)896 std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
897 bool is_constructor) {
898 auto &ptr_type = PtrType(field);
899 if (ptr_type != "naked") {
900 return (ptr_type != "default_ptr_type"
901 ? ptr_type
902 : opts_.cpp_object_api_pointer_type) +
903 "<" + type + ">";
904 } else if (is_constructor) {
905 return "";
906 } else {
907 return type + " *";
908 }
909 }
910
GenPtrGet(const FieldDef & field)911 std::string GenPtrGet(const FieldDef &field) {
912 auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get");
913 if (cpp_ptr_type_get) return cpp_ptr_type_get->constant;
914 auto &ptr_type = PtrType(&field);
915 return ptr_type == "naked" ? "" : ".get()";
916 }
917
GenOptionalNull()918 std::string GenOptionalNull() { return "::flatbuffers::nullopt"; }
919
GenOptionalDecl(const Type & type)920 std::string GenOptionalDecl(const Type &type) {
921 return "::flatbuffers::Optional<" + GenTypeBasic(type, true) + ">";
922 }
923
GenTypeNative(const Type & type,bool invector,const FieldDef & field,bool forcopy=false)924 std::string GenTypeNative(const Type &type, bool invector,
925 const FieldDef &field, bool forcopy = false) {
926 switch (type.base_type) {
927 case BASE_TYPE_STRING: {
928 return NativeString(&field);
929 }
930 case BASE_TYPE_VECTOR64:
931 case BASE_TYPE_VECTOR: {
932 const auto type_name = GenTypeNative(type.VectorType(), true, field);
933 if (type.struct_def &&
934 type.struct_def->attributes.Lookup("native_custom_alloc")) {
935 auto native_custom_alloc =
936 type.struct_def->attributes.Lookup("native_custom_alloc");
937 return "std::vector<" + type_name + "," +
938 native_custom_alloc->constant + "<" + type_name + ">>";
939 } else {
940 return "std::vector<" + type_name + ">";
941 }
942 }
943 case BASE_TYPE_STRUCT: {
944 auto type_name = WrapInNameSpace(*type.struct_def);
945 if (IsStruct(type)) {
946 auto native_type = type.struct_def->attributes.Lookup("native_type");
947 if (native_type) { type_name = native_type->constant; }
948 if (invector || field.native_inline || forcopy) {
949 return type_name;
950 } else {
951 return GenTypeNativePtr(type_name, &field, false);
952 }
953 } else {
954 const auto nn = WrapNativeNameInNameSpace(*type.struct_def, opts_);
955 return (forcopy || field.native_inline)
956 ? nn
957 : GenTypeNativePtr(nn, &field, false);
958 }
959 }
960 case BASE_TYPE_UNION: {
961 auto type_name = WrapInNameSpace(*type.enum_def);
962 return type_name + "Union";
963 }
964 default: {
965 return field.IsScalarOptional() ? GenOptionalDecl(type)
966 : GenTypeBasic(type, true);
967 }
968 }
969 }
970
971 // Return a C++ type for any type (scalar/pointer) specifically for
972 // using a flatbuffer.
GenTypeGet(const Type & type,const char * afterbasic,const char * beforeptr,const char * afterptr,bool user_facing_type)973 std::string GenTypeGet(const Type &type, const char *afterbasic,
974 const char *beforeptr, const char *afterptr,
975 bool user_facing_type) {
976 if (IsScalar(type.base_type)) {
977 return GenTypeBasic(type, user_facing_type) + afterbasic;
978 } else if (IsArray(type)) {
979 auto element_type = type.VectorType();
980 // Check if enum arrays are used in C++ without specifying --scoped-enums
981 if (IsEnum(element_type) && !opts_.g_only_fixed_enums) {
982 LogCompilerError(
983 "--scoped-enums must be enabled to use enum arrays in C++");
984 FLATBUFFERS_ASSERT(true);
985 }
986 return beforeptr +
987 (IsScalar(element_type.base_type)
988 ? GenTypeBasic(element_type, user_facing_type)
989 : GenTypePointer(element_type)) +
990 afterptr;
991 } else {
992 return beforeptr + GenTypePointer(type) + afterptr;
993 }
994 }
995
GenTypeSpan(const Type & type,bool immutable,size_t extent)996 std::string GenTypeSpan(const Type &type, bool immutable, size_t extent) {
997 // Generate "::flatbuffers::span<const U, extent>".
998 FLATBUFFERS_ASSERT(IsSeries(type) && "unexpected type");
999 auto element_type = type.VectorType();
1000 std::string text = "::flatbuffers::span<";
1001 text += immutable ? "const " : "";
1002 if (IsScalar(element_type.base_type)) {
1003 text += GenTypeBasic(element_type, IsEnum(element_type));
1004 } else {
1005 switch (element_type.base_type) {
1006 case BASE_TYPE_STRING: {
1007 text += "char";
1008 break;
1009 }
1010 case BASE_TYPE_STRUCT: {
1011 FLATBUFFERS_ASSERT(type.struct_def);
1012 text += WrapInNameSpace(*type.struct_def);
1013 break;
1014 }
1015 default:
1016 FLATBUFFERS_ASSERT(false && "unexpected element's type");
1017 break;
1018 }
1019 }
1020 if (extent != dynamic_extent) {
1021 text += ", ";
1022 text += NumToString(extent);
1023 }
1024 text += "> ";
1025 return text;
1026 }
1027
GenEnumValDecl(const EnumDef & enum_def,const std::string & enum_val) const1028 std::string GenEnumValDecl(const EnumDef &enum_def,
1029 const std::string &enum_val) const {
1030 return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
1031 }
1032
GetEnumValUse(const EnumDef & enum_def,const EnumVal & enum_val) const1033 std::string GetEnumValUse(const EnumDef &enum_def,
1034 const EnumVal &enum_val) const {
1035 if (opts_.scoped_enums) {
1036 return Name(enum_def) + "::" + Name(enum_val);
1037 } else if (opts_.prefixed_enums) {
1038 return Name(enum_def) + "_" + Name(enum_val);
1039 } else {
1040 return Name(enum_val);
1041 }
1042 }
1043
StripUnionType(const std::string & name)1044 std::string StripUnionType(const std::string &name) {
1045 return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
1046 }
1047
GetUnionElement(const EnumVal & ev,bool native_type,const IDLOptions & opts)1048 std::string GetUnionElement(const EnumVal &ev, bool native_type,
1049 const IDLOptions &opts) {
1050 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1051 std::string name = ev.union_type.struct_def->name;
1052 if (native_type) {
1053 name = NativeName(std::move(name), ev.union_type.struct_def, opts);
1054 }
1055 return WrapInNameSpace(ev.union_type.struct_def->defined_namespace, name);
1056 } else if (IsString(ev.union_type)) {
1057 return native_type ? "std::string" : "::flatbuffers::String";
1058 } else {
1059 FLATBUFFERS_ASSERT(false);
1060 return Name(ev);
1061 }
1062 }
1063
UnionVerifySignature(const EnumDef & enum_def)1064 std::string UnionVerifySignature(const EnumDef &enum_def) {
1065 return "bool Verify" + Name(enum_def) +
1066 "(::flatbuffers::Verifier &verifier, const void *obj, " +
1067 Name(enum_def) + " type)";
1068 }
1069
UnionVectorVerifySignature(const EnumDef & enum_def)1070 std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
1071 const std::string name = Name(enum_def);
1072 const std::string &type =
1073 opts_.scoped_enums ? name
1074 : GenTypeBasic(enum_def.underlying_type, false);
1075 return "bool Verify" + name + "Vector" +
1076 "(::flatbuffers::Verifier &verifier, " +
1077 "const ::flatbuffers::Vector<::flatbuffers::Offset<void>> "
1078 "*values, " +
1079 "const ::flatbuffers::Vector<" + type + "> *types)";
1080 }
1081
UnionUnPackSignature(const EnumDef & enum_def,bool inclass)1082 std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) {
1083 return (inclass ? "static " : "") + std::string("void *") +
1084 (inclass ? "" : Name(enum_def) + "Union::") +
1085 "UnPack(const void *obj, " + Name(enum_def) +
1086 " type, const ::flatbuffers::resolver_function_t *resolver)";
1087 }
1088
UnionPackSignature(const EnumDef & enum_def,bool inclass)1089 std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
1090 return "::flatbuffers::Offset<void> " +
1091 (inclass ? "" : Name(enum_def) + "Union::") + "Pack(" +
1092 GetBuilder() + " &_fbb, " +
1093 "const ::flatbuffers::rehasher_function_t *_rehasher" +
1094 (inclass ? " = nullptr" : "") + ") const";
1095 }
1096
TableCreateSignature(const StructDef & struct_def,bool predecl,const IDLOptions & opts)1097 std::string TableCreateSignature(const StructDef &struct_def, bool predecl,
1098 const IDLOptions &opts) {
1099 return "::flatbuffers::Offset<" + Name(struct_def) + "> Create" +
1100 Name(struct_def) + "(" + GetBuilder() + " &_fbb, const " +
1101 NativeName(Name(struct_def), &struct_def, opts) +
1102 " *_o, const ::flatbuffers::rehasher_function_t *_rehasher" +
1103 (predecl ? " = nullptr" : "") + ")";
1104 }
1105
TablePackSignature(const StructDef & struct_def,bool inclass,const IDLOptions & opts)1106 std::string TablePackSignature(const StructDef &struct_def, bool inclass,
1107 const IDLOptions &opts) {
1108 return std::string(inclass ? "static " : "") + "::flatbuffers::Offset<" +
1109 Name(struct_def) + "> " + (inclass ? "" : Name(struct_def) + "::") +
1110 "Pack(" + GetBuilder() + " &_fbb, " + "const " +
1111 NativeName(Name(struct_def), &struct_def, opts) + "* _o, " +
1112 "const ::flatbuffers::rehasher_function_t *_rehasher" +
1113 (inclass ? " = nullptr" : "") + ")";
1114 }
1115
TableUnPackSignature(const StructDef & struct_def,bool inclass,const IDLOptions & opts)1116 std::string TableUnPackSignature(const StructDef &struct_def, bool inclass,
1117 const IDLOptions &opts) {
1118 return NativeName(Name(struct_def), &struct_def, opts) + " *" +
1119 (inclass ? "" : Name(struct_def) + "::") +
1120 "UnPack(const ::flatbuffers::resolver_function_t *_resolver" +
1121 (inclass ? " = nullptr" : "") + ") const";
1122 }
1123
TableUnPackToSignature(const StructDef & struct_def,bool inclass,const IDLOptions & opts)1124 std::string TableUnPackToSignature(const StructDef &struct_def, bool inclass,
1125 const IDLOptions &opts) {
1126 return "void " + (inclass ? "" : Name(struct_def) + "::") + "UnPackTo(" +
1127 NativeName(Name(struct_def), &struct_def, opts) + " *" +
1128 "_o, const ::flatbuffers::resolver_function_t *_resolver" +
1129 (inclass ? " = nullptr" : "") + ") const";
1130 }
1131
GenMiniReflectPre(const StructDef * struct_def)1132 void GenMiniReflectPre(const StructDef *struct_def) {
1133 code_.SetValue("NAME", struct_def->name);
1134 code_ += "inline const ::flatbuffers::TypeTable *{{NAME}}TypeTable();";
1135 code_ += "";
1136 }
1137
GenMiniReflect(const StructDef * struct_def,const EnumDef * enum_def)1138 void GenMiniReflect(const StructDef *struct_def, const EnumDef *enum_def) {
1139 code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
1140 code_.SetValue("SEQ_TYPE",
1141 struct_def ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
1142 : (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
1143 auto num_fields =
1144 struct_def ? struct_def->fields.vec.size() : enum_def->size();
1145 code_.SetValue("NUM_FIELDS", NumToString(num_fields));
1146 std::vector<std::string> names;
1147 std::vector<Type> types;
1148
1149 if (struct_def) {
1150 for (const auto &field : struct_def->fields.vec) {
1151 names.push_back(Name(*field));
1152 types.push_back(field->value.type);
1153 }
1154 } else {
1155 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
1156 ++it) {
1157 const auto &ev = **it;
1158 names.push_back(Name(ev));
1159 types.push_back(enum_def->is_union ? ev.union_type
1160 : Type(enum_def->underlying_type));
1161 }
1162 }
1163 std::string ts;
1164 std::vector<std::string> type_refs;
1165 std::vector<uint16_t> array_sizes;
1166 for (auto &type : types) {
1167 if (!ts.empty()) ts += ",\n ";
1168 auto is_vector = IsVector(type);
1169 auto is_array = IsArray(type);
1170 auto bt = is_vector || is_array ? type.element : type.base_type;
1171 auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
1172 ? bt - BASE_TYPE_UTYPE + ET_UTYPE
1173 : ET_SEQUENCE;
1174 int ref_idx = -1;
1175 std::string ref_name = type.struct_def ? WrapInNameSpace(*type.struct_def)
1176 : type.enum_def ? WrapInNameSpace(*type.enum_def)
1177 : "";
1178 if (!ref_name.empty()) {
1179 auto rit = type_refs.begin();
1180 for (; rit != type_refs.end(); ++rit) {
1181 if (*rit == ref_name) {
1182 ref_idx = static_cast<int>(rit - type_refs.begin());
1183 break;
1184 }
1185 }
1186 if (rit == type_refs.end()) {
1187 ref_idx = static_cast<int>(type_refs.size());
1188 type_refs.push_back(ref_name);
1189 }
1190 }
1191 if (is_array) { array_sizes.push_back(type.fixed_length); }
1192 ts += "{ ::flatbuffers::" + std::string(ElementaryTypeNames()[et]) +
1193 ", " + NumToString(is_vector || is_array) + ", " +
1194 NumToString(ref_idx) + " }";
1195 }
1196 std::string rs;
1197 for (auto &type_ref : type_refs) {
1198 if (!rs.empty()) rs += ",\n ";
1199 rs += type_ref + "TypeTable";
1200 }
1201 std::string as;
1202 for (auto &array_size : array_sizes) {
1203 as += NumToString(array_size);
1204 as += ", ";
1205 }
1206 std::string ns;
1207 for (auto &name : names) {
1208 if (!ns.empty()) ns += ",\n ";
1209 ns += "\"" + name + "\"";
1210 }
1211 std::string vs;
1212 const auto consecutive_enum_from_zero =
1213 enum_def && enum_def->MinValue()->IsZero() &&
1214 ((enum_def->size() - 1) == enum_def->Distance());
1215 if (enum_def && !consecutive_enum_from_zero) {
1216 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
1217 ++it) {
1218 const auto &ev = **it;
1219 if (!vs.empty()) vs += ", ";
1220 vs += NumToStringCpp(enum_def->ToString(ev),
1221 enum_def->underlying_type.base_type);
1222 }
1223 } else if (struct_def && struct_def->fixed) {
1224 for (const auto field : struct_def->fields.vec) {
1225 vs += NumToString(field->value.offset);
1226 vs += ", ";
1227 }
1228 vs += NumToString(struct_def->bytesize);
1229 }
1230 code_.SetValue("TYPES", ts);
1231 code_.SetValue("REFS", rs);
1232 code_.SetValue("ARRAYSIZES", as);
1233 code_.SetValue("NAMES", ns);
1234 code_.SetValue("VALUES", vs);
1235 code_ += "inline const ::flatbuffers::TypeTable *{{NAME}}TypeTable() {";
1236 if (num_fields) {
1237 code_ += " static const ::flatbuffers::TypeCode type_codes[] = {";
1238 code_ += " {{TYPES}}";
1239 code_ += " };";
1240 }
1241 if (!type_refs.empty()) {
1242 code_ += " static const ::flatbuffers::TypeFunction type_refs[] = {";
1243 code_ += " {{REFS}}";
1244 code_ += " };";
1245 }
1246 if (!as.empty()) {
1247 code_ += " static const int16_t array_sizes[] = { {{ARRAYSIZES}} };";
1248 }
1249 if (!vs.empty()) {
1250 // Problem with uint64_t values greater than 9223372036854775807ULL.
1251 code_ += " static const int64_t values[] = { {{VALUES}} };";
1252 }
1253 auto has_names =
1254 num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames;
1255 if (has_names) {
1256 code_ += " static const char * const names[] = {";
1257 code_ += " {{NAMES}}";
1258 code_ += " };";
1259 }
1260 code_ += " static const ::flatbuffers::TypeTable tt = {";
1261 code_ += std::string(" ::flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
1262 (num_fields ? "type_codes, " : "nullptr, ") +
1263 (!type_refs.empty() ? "type_refs, " : "nullptr, ") +
1264 (!as.empty() ? "array_sizes, " : "nullptr, ") +
1265 (!vs.empty() ? "values, " : "nullptr, ") +
1266 (has_names ? "names" : "nullptr");
1267 code_ += " };";
1268 code_ += " return &tt;";
1269 code_ += "}";
1270 code_ += "";
1271 }
1272
1273 // Generate an enum declaration,
1274 // an enum string lookup table,
1275 // and an enum array of values
1276
GenEnum(const EnumDef & enum_def)1277 void GenEnum(const EnumDef &enum_def) {
1278 code_.SetValue("ENUM_NAME", Name(enum_def));
1279 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
1280
1281 GenComment(enum_def.doc_comment);
1282 code_ +=
1283 (opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\";
1284 if (opts_.g_only_fixed_enums) { code_ += " : {{BASE_TYPE}}\\"; }
1285 code_ += " {";
1286
1287 code_.SetValue("SEP", ",");
1288 auto add_sep = false;
1289 for (const auto ev : enum_def.Vals()) {
1290 if (add_sep) code_ += "{{SEP}}";
1291 GenComment(ev->doc_comment, " ");
1292 code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(*ev)));
1293 code_.SetValue("VALUE",
1294 NumToStringCpp(enum_def.ToString(*ev),
1295 enum_def.underlying_type.base_type));
1296 code_ += " {{KEY}} = {{VALUE}}\\";
1297 add_sep = true;
1298 }
1299 if (opts_.cpp_minify_enums) {
1300 code_ += "";
1301 code_ += "};";
1302 return;
1303 }
1304 const EnumVal *minv = enum_def.MinValue();
1305 const EnumVal *maxv = enum_def.MaxValue();
1306
1307 if (opts_.scoped_enums || opts_.prefixed_enums) {
1308 FLATBUFFERS_ASSERT(minv && maxv);
1309
1310 code_.SetValue("SEP", ",\n");
1311
1312 // MIN & MAX are useless for bit_flags
1313 if (enum_def.attributes.Lookup("bit_flags")) {
1314 code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
1315 code_.SetValue("VALUE", "0");
1316 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1317
1318 code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
1319 code_.SetValue("VALUE",
1320 NumToStringCpp(enum_def.AllFlags(),
1321 enum_def.underlying_type.base_type));
1322 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1323 } else if (opts_.emit_min_max_enum_values) {
1324 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN"));
1325 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*minv)));
1326 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1327
1328 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX"));
1329 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*maxv)));
1330 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1331 }
1332 }
1333 code_ += "";
1334 code_ += "};";
1335
1336 if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
1337 code_ +=
1338 "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
1339 }
1340 code_ += "";
1341 GenEnumArray(enum_def);
1342 GenEnumStringTable(enum_def);
1343
1344 // Generate type traits for unions to map from a type to union enum value.
1345 if (enum_def.is_union && !enum_def.uses_multiple_type_instances) {
1346 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1347 ++it) {
1348 const auto &ev = **it;
1349
1350 if (it == enum_def.Vals().begin()) {
1351 code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
1352 } else {
1353 auto name = GetUnionElement(ev, false, opts_);
1354 code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
1355 }
1356
1357 auto value = GetEnumValUse(enum_def, ev);
1358 code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
1359 code_ += "};";
1360 code_ += "";
1361 }
1362 }
1363
1364 GenEnumObjectBasedAPI(enum_def);
1365
1366 if (enum_def.is_union) {
1367 code_ += UnionVerifySignature(enum_def) + ";";
1368 code_ += UnionVectorVerifySignature(enum_def) + ";";
1369 code_ += "";
1370 }
1371 }
1372
1373 // Generate a union type and a trait type for it.
GenEnumObjectBasedAPI(const EnumDef & enum_def)1374 void GenEnumObjectBasedAPI(const EnumDef &enum_def) {
1375 if (!(opts_.generate_object_based_api && enum_def.is_union)) { return; }
1376 code_.SetValue("NAME", Name(enum_def));
1377 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1378 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1379
1380 if (!enum_def.uses_multiple_type_instances) {
1381 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1382 ++it) {
1383 const auto &ev = **it;
1384
1385 if (it == enum_def.Vals().begin()) {
1386 code_ += "template<typename T> struct {{NAME}}UnionTraits {";
1387 } else {
1388 auto name = GetUnionElement(ev, true, opts_);
1389 code_ += "template<> struct {{NAME}}UnionTraits<" + name + "> {";
1390 }
1391
1392 auto value = GetEnumValUse(enum_def, ev);
1393 code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
1394 code_ += "};";
1395 code_ += "";
1396 }
1397 }
1398
1399 code_ += "struct {{NAME}}Union {";
1400 code_ += " {{NAME}} type;";
1401 code_ += " void *value;";
1402 code_ += "";
1403 code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
1404 code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
1405 code_ += " type({{NONE}}), value(nullptr)";
1406 code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
1407 code_ += " {{NAME}}Union(const {{NAME}}Union &);";
1408 code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)";
1409 code_ +=
1410 " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, "
1411 "t.value); return *this; }";
1412 code_ +=
1413 " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
1414 code_ +=
1415 " { std::swap(type, u.type); std::swap(value, u.value); return "
1416 "*this; }";
1417 code_ += " ~{{NAME}}Union() { Reset(); }";
1418 code_ += "";
1419 code_ += " void Reset();";
1420 code_ += "";
1421 if (!enum_def.uses_multiple_type_instances) {
1422 code_ += " template <typename T>";
1423 code_ += " void Set(T&& val) {";
1424 code_ += " typedef typename std::remove_reference<T>::type RT;";
1425 code_ += " Reset();";
1426 code_ += " type = {{NAME}}UnionTraits<RT>::enum_value;";
1427 code_ += " if (type != {{NONE}}) {";
1428 code_ += " value = new RT(std::forward<T>(val));";
1429 code_ += " }";
1430 code_ += " }";
1431 code_ += "";
1432 }
1433 code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
1434 code_ += " " + UnionPackSignature(enum_def, true) + ";";
1435 code_ += "";
1436
1437 for (const auto ev : enum_def.Vals()) {
1438 if (ev->IsZero()) { continue; }
1439
1440 const auto native_type = GetUnionElement(*ev, true, opts_);
1441 code_.SetValue("NATIVE_TYPE", native_type);
1442 code_.SetValue("NATIVE_NAME", Name(*ev));
1443 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, *ev));
1444
1445 code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
1446 code_ += " return type == {{NATIVE_ID}} ?";
1447 code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
1448 code_ += " }";
1449
1450 code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {";
1451 code_ += " return type == {{NATIVE_ID}} ?";
1452 code_ +=
1453 " reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;";
1454 code_ += " }";
1455 }
1456 code_ += "};";
1457 code_ += "";
1458
1459 GenEnumEquals(enum_def);
1460 }
1461
GenEnumEquals(const EnumDef & enum_def)1462 void GenEnumEquals(const EnumDef &enum_def) {
1463 if (opts_.gen_compare) {
1464 code_ += "";
1465 code_ +=
1466 "inline bool operator==(const {{NAME}}Union &lhs, const "
1467 "{{NAME}}Union &rhs) {";
1468 code_ += " if (lhs.type != rhs.type) return false;";
1469 code_ += " switch (lhs.type) {";
1470
1471 for (const auto &ev : enum_def.Vals()) {
1472 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, *ev));
1473 if (ev->IsNonZero()) {
1474 const auto native_type = GetUnionElement(*ev, true, opts_);
1475 code_.SetValue("NATIVE_TYPE", native_type);
1476 code_ += " case {{NATIVE_ID}}: {";
1477 code_ +=
1478 " return *(reinterpret_cast<const {{NATIVE_TYPE}} "
1479 "*>(lhs.value)) ==";
1480 code_ +=
1481 " *(reinterpret_cast<const {{NATIVE_TYPE}} "
1482 "*>(rhs.value));";
1483 code_ += " }";
1484 } else {
1485 code_ += " case {{NATIVE_ID}}: {";
1486 code_ += " return true;"; // "NONE" enum value.
1487 code_ += " }";
1488 }
1489 }
1490 code_ += " default: {";
1491 code_ += " return false;";
1492 code_ += " }";
1493 code_ += " }";
1494 code_ += "}";
1495
1496 code_ += "";
1497 code_ +=
1498 "inline bool operator!=(const {{NAME}}Union &lhs, const "
1499 "{{NAME}}Union &rhs) {";
1500 code_ += " return !(lhs == rhs);";
1501 code_ += "}";
1502 code_ += "";
1503 }
1504 }
1505
1506 // Generate an array of all enumeration values
GenEnumArray(const EnumDef & enum_def)1507 void GenEnumArray(const EnumDef &enum_def) {
1508 auto num_fields = NumToString(enum_def.size());
1509 code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
1510 num_fields + "] {";
1511 code_ += " static const {{ENUM_NAME}} values[] = {";
1512 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1513 const auto &ev = **it;
1514 auto value = GetEnumValUse(enum_def, ev);
1515 auto suffix = *it != enum_def.Vals().back() ? "," : "";
1516 code_ += " " + value + suffix;
1517 }
1518 code_ += " };";
1519 code_ += " return values;";
1520 code_ += "}";
1521 code_ += "";
1522 }
1523
1524 // Generate a string table for enum values.
1525 // Problem is, if values are very sparse that could generate huge tables.
1526 // Ideally in that case we generate a map lookup instead, but for the moment
1527 // we simply don't output a table at all.
GenEnumStringTable(const EnumDef & enum_def)1528 void GenEnumStringTable(const EnumDef &enum_def) {
1529 auto range = enum_def.Distance();
1530 // Average distance between values above which we consider a table
1531 // "too sparse". Change at will.
1532 static const uint64_t kMaxSparseness = 5;
1533 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
1534 code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
1535 code_ += " static const char * const names[" +
1536 NumToString(range + 1 + 1) + "] = {";
1537
1538 auto val = enum_def.Vals().front();
1539 for (const auto &enum_value : enum_def.Vals()) {
1540 for (auto k = enum_def.Distance(val, enum_value); k > 1; --k) {
1541 code_ += " \"\",";
1542 }
1543 val = enum_value;
1544 code_ += " \"" + Name(*enum_value) + "\",";
1545 }
1546 code_ += " nullptr";
1547 code_ += " };";
1548
1549 code_ += " return names;";
1550 code_ += "}";
1551 code_ += "";
1552
1553 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1554
1555 code_ += " if (::flatbuffers::IsOutRange(e, " +
1556 GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " +
1557 GetEnumValUse(enum_def, *enum_def.MaxValue()) +
1558 ")) return \"\";";
1559
1560 code_ += " const size_t index = static_cast<size_t>(e)\\";
1561 if (enum_def.MinValue()->IsNonZero()) {
1562 auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
1563 code_ += " - static_cast<size_t>(" + vals + ")\\";
1564 }
1565 code_ += ";";
1566
1567 code_ += " return EnumNames{{ENUM_NAME}}()[index];";
1568 code_ += "}";
1569 code_ += "";
1570 } else {
1571 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1572 code_ += " switch (e) {";
1573 for (const auto &ev : enum_def.Vals()) {
1574 code_ += " case " + GetEnumValUse(enum_def, *ev) + ": return \"" +
1575 Name(*ev) + "\";";
1576 }
1577 code_ += " default: return \"\";";
1578 code_ += " }";
1579 code_ += "}";
1580 code_ += "";
1581 }
1582 }
1583
GenUnionPost(const EnumDef & enum_def)1584 void GenUnionPost(const EnumDef &enum_def) {
1585 // Generate a verifier function for this union that can be called by the
1586 // table verifier functions. It uses a switch case to select a specific
1587 // verifier function to call, this should be safe even if the union type
1588 // has been corrupted, since the verifiers will simply fail when called
1589 // on the wrong type.
1590 code_.SetValue("ENUM_NAME", Name(enum_def));
1591
1592 code_ += "inline " + UnionVerifySignature(enum_def) + " {";
1593 code_ += " switch (type) {";
1594 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1595 const auto &ev = **it;
1596 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1597
1598 if (ev.IsNonZero()) {
1599 code_.SetValue("TYPE", GetUnionElement(ev, false, opts_));
1600 code_ += " case {{LABEL}}: {";
1601 auto getptr =
1602 " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1603 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1604 if (ev.union_type.struct_def->fixed) {
1605 code_.SetValue("ALIGN",
1606 NumToString(ev.union_type.struct_def->minalign));
1607 code_ +=
1608 " return verifier.VerifyField<{{TYPE}}>("
1609 "static_cast<const uint8_t *>(obj), 0, {{ALIGN}});";
1610 } else {
1611 code_ += getptr;
1612 code_ += " return verifier.VerifyTable(ptr);";
1613 }
1614 } else if (IsString(ev.union_type)) {
1615 code_ += getptr;
1616 code_ += " return verifier.VerifyString(ptr);";
1617 } else {
1618 FLATBUFFERS_ASSERT(false);
1619 }
1620 code_ += " }";
1621 } else {
1622 code_ += " case {{LABEL}}: {";
1623 code_ += " return true;"; // "NONE" enum value.
1624 code_ += " }";
1625 }
1626 }
1627 code_ += " default: return true;"; // unknown values are OK.
1628 code_ += " }";
1629 code_ += "}";
1630 code_ += "";
1631
1632 code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
1633 code_ += " if (!values || !types) return !values && !types;";
1634 code_ += " if (values->size() != types->size()) return false;";
1635 code_ +=
1636 " for (::flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
1637 code_ += " if (!Verify" + Name(enum_def) + "(";
1638 code_ += " verifier, values->Get(i), types->GetEnum<" +
1639 Name(enum_def) + ">(i))) {";
1640 code_ += " return false;";
1641 code_ += " }";
1642 code_ += " }";
1643 code_ += " return true;";
1644 code_ += "}";
1645 code_ += "";
1646
1647 if (opts_.generate_object_based_api) {
1648 // Generate union Unpack() and Pack() functions.
1649 code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
1650 code_ += " (void)resolver;";
1651 code_ += " switch (type) {";
1652 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1653 ++it) {
1654 const auto &ev = **it;
1655 if (ev.IsZero()) { continue; }
1656
1657 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1658 code_.SetValue("TYPE", GetUnionElement(ev, false, opts_));
1659 code_ += " case {{LABEL}}: {";
1660 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1661 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1662 if (ev.union_type.struct_def->fixed) {
1663 code_ += " return new " +
1664 WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
1665 } else {
1666 code_ += " return ptr->UnPack(resolver);";
1667 }
1668 } else if (IsString(ev.union_type)) {
1669 code_ += " return new std::string(ptr->c_str(), ptr->size());";
1670 } else {
1671 FLATBUFFERS_ASSERT(false);
1672 }
1673 code_ += " }";
1674 }
1675 code_ += " default: return nullptr;";
1676 code_ += " }";
1677 code_ += "}";
1678 code_ += "";
1679
1680 code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
1681 code_ += " (void)_rehasher;";
1682 code_ += " switch (type) {";
1683 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1684 ++it) {
1685 auto &ev = **it;
1686 if (ev.IsZero()) { continue; }
1687
1688 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1689 code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
1690 code_ += " case {{LABEL}}: {";
1691 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
1692 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1693 if (ev.union_type.struct_def->fixed) {
1694 code_ += " return _fbb.CreateStruct(*ptr).Union();";
1695 } else {
1696 code_.SetValue("NAME", ev.union_type.struct_def->name);
1697 code_ +=
1698 " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
1699 }
1700 } else if (IsString(ev.union_type)) {
1701 code_ += " return _fbb.CreateString(*ptr).Union();";
1702 } else {
1703 FLATBUFFERS_ASSERT(false);
1704 }
1705 code_ += " }";
1706 }
1707 code_ += " default: return 0;";
1708 code_ += " }";
1709 code_ += "}";
1710 code_ += "";
1711
1712 // Union copy constructor
1713 code_ +=
1714 "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
1715 "{{ENUM_NAME}}Union &u) : type(u.type), value(nullptr) {";
1716 code_ += " switch (type) {";
1717 for (const auto &ev : enum_def.Vals()) {
1718 if (ev->IsZero()) { continue; }
1719 code_.SetValue("LABEL", GetEnumValUse(enum_def, *ev));
1720 code_.SetValue("TYPE", GetUnionElement(*ev, true, opts_));
1721 code_ += " case {{LABEL}}: {";
1722 bool copyable = true;
1723 if (opts_.g_cpp_std < cpp::CPP_STD_11 &&
1724 ev->union_type.base_type == BASE_TYPE_STRUCT &&
1725 !ev->union_type.struct_def->fixed) {
1726 // Don't generate code to copy if table is not copyable.
1727 // TODO(wvo): make tables copyable instead.
1728 for (const auto &field : ev->union_type.struct_def->fields.vec) {
1729 if (!field->deprecated && field->value.type.struct_def &&
1730 !field->native_inline) {
1731 copyable = false;
1732 break;
1733 }
1734 }
1735 }
1736 if (copyable) {
1737 code_ +=
1738 " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
1739 "(u.value));";
1740 } else {
1741 code_ +=
1742 " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable.";
1743 }
1744 code_ += " break;";
1745 code_ += " }";
1746 }
1747 code_ += " default:";
1748 code_ += " break;";
1749 code_ += " }";
1750 code_ += "}";
1751 code_ += "";
1752
1753 // Union Reset() function.
1754 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1755 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1756
1757 code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
1758 code_ += " switch (type) {";
1759 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1760 ++it) {
1761 const auto &ev = **it;
1762 if (ev.IsZero()) { continue; }
1763 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1764 code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
1765 code_ += " case {{LABEL}}: {";
1766 code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
1767 code_ += " delete ptr;";
1768 code_ += " break;";
1769 code_ += " }";
1770 }
1771 code_ += " default: break;";
1772 code_ += " }";
1773 code_ += " value = nullptr;";
1774 code_ += " type = {{NONE}};";
1775 code_ += "}";
1776 code_ += "";
1777 }
1778 }
1779
1780 // Generates a value with optionally a cast applied if the field has a
1781 // different underlying type from its interface type (currently only the
1782 // case for enums. "from" specify the direction, true meaning from the
1783 // underlying type to the interface type.
GenUnderlyingCast(const FieldDef & field,bool from,const std::string & val)1784 std::string GenUnderlyingCast(const FieldDef &field, bool from,
1785 const std::string &val) {
1786 if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
1787 return val + " != 0";
1788 } else if ((field.value.type.enum_def &&
1789 IsScalar(field.value.type.base_type)) ||
1790 field.value.type.base_type == BASE_TYPE_BOOL) {
1791 return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
1792 val + ")";
1793 } else {
1794 return val;
1795 }
1796 }
1797
GenFieldOffsetName(const FieldDef & field)1798 std::string GenFieldOffsetName(const FieldDef &field) {
1799 std::string uname = Name(field);
1800 std::transform(uname.begin(), uname.end(), uname.begin(), CharToUpper);
1801 return "VT_" + uname;
1802 }
1803
GenFullyQualifiedNameGetter(const StructDef & struct_def,const std::string & name)1804 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1805 const std::string &name) {
1806 if (!opts_.generate_name_strings) { return; }
1807 auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
1808 code_.SetValue("NAME", fullname);
1809 code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR_CPP11");
1810 code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
1811 code_ += " return \"{{NAME}}\";";
1812 code_ += " }";
1813 }
1814
GenDefaultConstant(const FieldDef & field)1815 std::string GenDefaultConstant(const FieldDef &field) {
1816 if (IsFloat(field.value.type.base_type))
1817 return float_const_gen_.GenFloatConstant(field);
1818 else
1819 return NumToStringCpp(field.value.constant, field.value.type.base_type);
1820 }
1821
GetDefaultScalarValue(const FieldDef & field,bool is_ctor)1822 std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
1823 const auto &type = field.value.type;
1824 if (field.IsScalarOptional()) {
1825 return GenOptionalNull();
1826 } else if (type.enum_def && IsScalar(type.base_type)) {
1827 auto ev = type.enum_def->FindByValue(field.value.constant);
1828 if (ev) {
1829 return WrapInNameSpace(type.enum_def->defined_namespace,
1830 GetEnumValUse(*type.enum_def, *ev));
1831 } else {
1832 return GenUnderlyingCast(
1833 field, true, NumToStringCpp(field.value.constant, type.base_type));
1834 }
1835 } else if (type.base_type == BASE_TYPE_BOOL) {
1836 return field.value.constant == "0" ? "false" : "true";
1837 } else if (field.attributes.Lookup("cpp_type")) {
1838 if (is_ctor) {
1839 if (PtrType(&field) == "naked") {
1840 return "nullptr";
1841 } else {
1842 return "";
1843 }
1844 } else {
1845 return "0";
1846 }
1847 } else if (IsStruct(type) && (field.value.constant == "0")) {
1848 return "nullptr";
1849 } else {
1850 return GenDefaultConstant(field);
1851 }
1852 }
1853
GenParam(const FieldDef & field,bool direct,const char * prefix)1854 void GenParam(const FieldDef &field, bool direct, const char *prefix) {
1855 code_.SetValue("PRE", prefix);
1856 code_.SetValue("PARAM_NAME", Name(field));
1857 if (direct && IsString(field.value.type)) {
1858 code_.SetValue("PARAM_TYPE", "const char *");
1859 code_.SetValue("PARAM_VALUE", "nullptr");
1860 } else if (direct && IsVector(field.value.type)) {
1861 const auto vtype = field.value.type.VectorType();
1862 std::string type;
1863 if (IsStruct(vtype)) {
1864 type = WrapInNameSpace(*vtype.struct_def);
1865 } else {
1866 type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype),
1867 field.offset64);
1868 }
1869 if (TypeHasKey(vtype)) {
1870 code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
1871 } else {
1872 code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
1873 }
1874 code_.SetValue("PARAM_VALUE", "nullptr");
1875 } else {
1876 const auto &type = field.value.type;
1877 code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
1878 if (field.IsScalarOptional())
1879 code_.SetValue("PARAM_TYPE", GenOptionalDecl(type) + " ");
1880 else
1881 code_.SetValue("PARAM_TYPE",
1882 GenTypeWire(type, " ", true, field.offset64));
1883 }
1884 code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
1885 }
1886
1887 // Generate a member, including a default value for scalars and raw pointers.
GenMember(const FieldDef & field)1888 void GenMember(const FieldDef &field) {
1889 if (!field.deprecated && // Deprecated fields won't be accessible.
1890 field.value.type.base_type != BASE_TYPE_UTYPE &&
1891 (!IsVector(field.value.type) ||
1892 field.value.type.element != BASE_TYPE_UTYPE)) {
1893 auto type = GenTypeNative(field.value.type, false, field);
1894 auto cpp_type = field.attributes.Lookup("cpp_type");
1895 const std::string &full_type =
1896 (cpp_type
1897 ? (IsVector(field.value.type)
1898 ? "std::vector<" +
1899 GenTypeNativePtr(cpp_type->constant, &field,
1900 false) +
1901 "> "
1902 : GenTypeNativePtr(cpp_type->constant, &field, false))
1903 : type + " ");
1904 // Generate default member initializers for >= C++11.
1905 std::string field_di;
1906 if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
1907 field_di = "{}";
1908 auto native_default = field.attributes.Lookup("native_default");
1909 // Scalar types get parsed defaults, raw pointers get nullptrs.
1910 if (IsScalar(field.value.type.base_type)) {
1911 field_di =
1912 " = " + (native_default ? std::string(native_default->constant)
1913 : GetDefaultScalarValue(field, true));
1914 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1915 if (IsStruct(field.value.type) && native_default) {
1916 field_di = " = " + native_default->constant;
1917 }
1918 }
1919 }
1920 code_.SetValue("FIELD_TYPE", full_type);
1921 code_.SetValue("FIELD_NAME", Name(field));
1922 code_.SetValue("FIELD_DI", field_di);
1923 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}{{FIELD_DI}};";
1924 }
1925 }
1926
1927 // Returns true if `struct_def` needs a copy constructor and assignment
1928 // operator because it has one or more table members, struct members with a
1929 // custom cpp_type and non-naked pointer type, or vector members of those.
NeedsCopyCtorAssignOp(const StructDef & struct_def)1930 bool NeedsCopyCtorAssignOp(const StructDef &struct_def) {
1931 for (const auto &field : struct_def.fields.vec) {
1932 const auto &type = field->value.type;
1933 if (field->deprecated) continue;
1934 if (type.base_type == BASE_TYPE_STRUCT) {
1935 const auto cpp_type = field->attributes.Lookup("cpp_type");
1936 const auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type");
1937 const bool is_ptr = !(IsStruct(type) && field->native_inline) ||
1938 (cpp_type && cpp_ptr_type->constant != "naked");
1939 if (is_ptr) { return true; }
1940 } else if (IsVector(type)) {
1941 const auto vec_type = type.VectorType();
1942 if (vec_type.base_type == BASE_TYPE_UTYPE) continue;
1943 const auto cpp_type = field->attributes.Lookup("cpp_type");
1944 const auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type");
1945 const bool is_ptr = IsVectorOfPointers(*field) ||
1946 (cpp_type && cpp_ptr_type->constant != "naked");
1947 if (is_ptr) { return true; }
1948 }
1949 }
1950 return false;
1951 }
1952
1953 // Generate the default constructor for this struct. Properly initialize all
1954 // scalar members with default values.
GenDefaultConstructor(const StructDef & struct_def)1955 void GenDefaultConstructor(const StructDef &struct_def) {
1956 code_.SetValue("NATIVE_NAME",
1957 NativeName(Name(struct_def), &struct_def, opts_));
1958 // In >= C++11, default member initializers are generated. To allow for
1959 // aggregate initialization, do not emit a default constructor at all, with
1960 // the exception of types that need a copy/move ctors and assignment
1961 // operators.
1962 if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
1963 if (NeedsCopyCtorAssignOp(struct_def)) {
1964 code_ += " {{NATIVE_NAME}}() = default;";
1965 }
1966 return;
1967 }
1968 std::string initializer_list;
1969 for (auto it = struct_def.fields.vec.begin();
1970 it != struct_def.fields.vec.end(); ++it) {
1971 const auto &field = **it;
1972 if (!field.deprecated && // Deprecated fields won't be accessible.
1973 field.value.type.base_type != BASE_TYPE_UTYPE) {
1974 auto cpp_type = field.attributes.Lookup("cpp_type");
1975 auto native_default = field.attributes.Lookup("native_default");
1976 // Scalar types get parsed defaults, raw pointers get nullptrs.
1977 if (IsScalar(field.value.type.base_type)) {
1978 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1979 initializer_list += Name(field);
1980 initializer_list +=
1981 "(" +
1982 (native_default ? std::string(native_default->constant)
1983 : GetDefaultScalarValue(field, true)) +
1984 ")";
1985 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1986 if (IsStruct(field.value.type)) {
1987 if (native_default) {
1988 if (!initializer_list.empty()) {
1989 initializer_list += ",\n ";
1990 }
1991 initializer_list +=
1992 Name(field) + "(" + native_default->constant + ")";
1993 }
1994 }
1995 } else if (cpp_type && !IsVector(field.value.type)) {
1996 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1997 initializer_list += Name(field) + "(0)";
1998 }
1999 }
2000 }
2001 if (!initializer_list.empty()) {
2002 initializer_list = "\n : " + initializer_list;
2003 }
2004
2005 code_.SetValue("INIT_LIST", initializer_list);
2006
2007 code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
2008 code_ += " }";
2009 }
2010
2011 // Generate the >= C++11 copy/move constructor and assignment operator
2012 // declarations if required. Tables that are default-copyable do not get
2013 // user-provided copy/move constructors and assignment operators so they
2014 // remain aggregates.
GenCopyMoveCtorAndAssigOpDecls(const StructDef & struct_def)2015 void GenCopyMoveCtorAndAssigOpDecls(const StructDef &struct_def) {
2016 if (opts_.g_cpp_std < cpp::CPP_STD_11) return;
2017 if (!NeedsCopyCtorAssignOp(struct_def)) return;
2018 code_.SetValue("NATIVE_NAME",
2019 NativeName(Name(struct_def), &struct_def, opts_));
2020 code_ += " {{NATIVE_NAME}}(const {{NATIVE_NAME}} &o);";
2021 code_ +=
2022 " {{NATIVE_NAME}}({{NATIVE_NAME}}&&) FLATBUFFERS_NOEXCEPT = "
2023 "default;";
2024 code_ +=
2025 " {{NATIVE_NAME}} &operator=({{NATIVE_NAME}} o) FLATBUFFERS_NOEXCEPT;";
2026 }
2027
2028 // Generate the >= C++11 copy constructor and assignment operator definitions.
GenCopyCtorAssignOpDefs(const StructDef & struct_def)2029 void GenCopyCtorAssignOpDefs(const StructDef &struct_def) {
2030 if (opts_.g_cpp_std < cpp::CPP_STD_11) return;
2031 if (!NeedsCopyCtorAssignOp(struct_def)) return;
2032 std::string initializer_list;
2033 std::string vector_copies;
2034 std::string swaps;
2035 for (const auto &field : struct_def.fields.vec) {
2036 const auto &type = field->value.type;
2037 if (field->deprecated || type.base_type == BASE_TYPE_UTYPE) continue;
2038 if (type.base_type == BASE_TYPE_STRUCT) {
2039 if (!initializer_list.empty()) { initializer_list += ",\n "; }
2040 const auto cpp_type = field->attributes.Lookup("cpp_type");
2041 const auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type");
2042 const std::string &type_name =
2043 (cpp_type) ? cpp_type->constant
2044 : GenTypeNative(type, /*invector*/ false, *field,
2045 /*forcopy*/ true);
2046 const bool is_ptr = !(IsStruct(type) && field->native_inline) ||
2047 (cpp_type && cpp_ptr_type->constant != "naked");
2048 CodeWriter cw;
2049 cw.SetValue("FIELD", Name(*field));
2050 cw.SetValue("TYPE", type_name);
2051 if (is_ptr) {
2052 cw +=
2053 "{{FIELD}}((o.{{FIELD}}) ? new {{TYPE}}(*o.{{FIELD}}) : "
2054 "nullptr)\\";
2055 initializer_list += cw.ToString();
2056 } else {
2057 cw += "{{FIELD}}(o.{{FIELD}})\\";
2058 initializer_list += cw.ToString();
2059 }
2060 } else if (IsVector(type)) {
2061 const auto vec_type = type.VectorType();
2062 if (vec_type.base_type == BASE_TYPE_UTYPE) continue;
2063 const auto cpp_type = field->attributes.Lookup("cpp_type");
2064 const auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type");
2065 const std::string &type_name =
2066 (cpp_type) ? cpp_type->constant
2067 : GenTypeNative(vec_type, /*invector*/ true, *field,
2068 /*forcopy*/ true);
2069 const bool is_ptr = IsVectorOfPointers(*field) ||
2070 (cpp_type && cpp_ptr_type->constant != "naked");
2071 CodeWriter cw(" ");
2072 cw.SetValue("FIELD", Name(*field));
2073 cw.SetValue("TYPE", type_name);
2074 if (is_ptr) {
2075 // Use emplace_back to construct the potentially-smart pointer element
2076 // from a raw pointer to a new-allocated copy.
2077 cw.IncrementIdentLevel();
2078 cw += "{{FIELD}}.reserve(o.{{FIELD}}.size());";
2079 cw +=
2080 "for (const auto &{{FIELD}}_ : o.{{FIELD}}) { "
2081 "{{FIELD}}.emplace_back(({{FIELD}}_) ? new {{TYPE}}(*{{FIELD}}_) "
2082 ": nullptr); }";
2083 vector_copies += cw.ToString();
2084 } else {
2085 // For non-pointer elements, use std::vector's copy constructor in the
2086 // initializer list. This will yield better performance than an insert
2087 // range loop for trivially-copyable element types.
2088 if (!initializer_list.empty()) { initializer_list += ",\n "; }
2089 cw += "{{FIELD}}(o.{{FIELD}})\\";
2090 initializer_list += cw.ToString();
2091 }
2092 } else {
2093 if (!initializer_list.empty()) { initializer_list += ",\n "; }
2094 CodeWriter cw;
2095 cw.SetValue("FIELD", Name(*field));
2096 cw += "{{FIELD}}(o.{{FIELD}})\\";
2097 initializer_list += cw.ToString();
2098 }
2099 {
2100 if (!swaps.empty()) { swaps += "\n "; }
2101 CodeWriter cw;
2102 cw.SetValue("FIELD", Name(*field));
2103 cw += "std::swap({{FIELD}}, o.{{FIELD}});\\";
2104 swaps += cw.ToString();
2105 }
2106 }
2107 if (!initializer_list.empty()) {
2108 initializer_list = "\n : " + initializer_list;
2109 }
2110 if (!swaps.empty()) { swaps = " " + swaps; }
2111
2112 code_.SetValue("NATIVE_NAME",
2113 NativeName(Name(struct_def), &struct_def, opts_));
2114 code_.SetValue("INIT_LIST", initializer_list);
2115 code_.SetValue("VEC_COPY", vector_copies);
2116 code_.SetValue("SWAPS", swaps);
2117
2118 code_ +=
2119 "inline {{NATIVE_NAME}}::{{NATIVE_NAME}}(const {{NATIVE_NAME}} &o)"
2120 "{{INIT_LIST}} {";
2121 code_ += "{{VEC_COPY}}}\n";
2122 code_ +=
2123 "inline {{NATIVE_NAME}} &{{NATIVE_NAME}}::operator="
2124 "({{NATIVE_NAME}} o) FLATBUFFERS_NOEXCEPT {";
2125 code_ += "{{SWAPS}}";
2126 code_ += " return *this;\n}\n";
2127 }
2128
GenCompareOperator(const StructDef & struct_def,const std::string & accessSuffix="")2129 void GenCompareOperator(const StructDef &struct_def,
2130 const std::string &accessSuffix = "") {
2131 std::string compare_op;
2132 for (auto it = struct_def.fields.vec.begin();
2133 it != struct_def.fields.vec.end(); ++it) {
2134 const auto &field = **it;
2135 const auto accessor = Name(field) + accessSuffix;
2136 const auto lhs_accessor = "lhs." + accessor;
2137 const auto rhs_accessor = "rhs." + accessor;
2138 if (!field.deprecated && // Deprecated fields won't be accessible.
2139 field.value.type.base_type != BASE_TYPE_UTYPE &&
2140 (!IsVector(field.value.type) ||
2141 field.value.type.element != BASE_TYPE_UTYPE)) {
2142 if (!compare_op.empty()) { compare_op += " &&\n "; }
2143 if (struct_def.fixed || field.native_inline ||
2144 field.value.type.base_type != BASE_TYPE_STRUCT) {
2145 // If the field is a vector of tables, the table need to be compared
2146 // by value, instead of by the default unique_ptr == operator which
2147 // compares by address.
2148 if (IsVectorOfPointers(field)) {
2149 const auto type =
2150 GenTypeNative(field.value.type.VectorType(), true, field);
2151 const auto equal_length =
2152 lhs_accessor + ".size() == " + rhs_accessor + ".size()";
2153 const auto elements_equal =
2154 "std::equal(" + lhs_accessor + ".cbegin(), " + lhs_accessor +
2155 ".cend(), " + rhs_accessor + ".cbegin(), [](" + type +
2156 " const &a, " + type +
2157 " const &b) { return (a == b) || (a && b && *a == *b); })";
2158
2159 compare_op += "(" + equal_length + " && " + elements_equal + ")";
2160 } else if (field.value.type.base_type == BASE_TYPE_ARRAY) {
2161 compare_op += "(*" + lhs_accessor + " == *" + rhs_accessor + ")";
2162 } else {
2163 compare_op += "(" + lhs_accessor + " == " + rhs_accessor + ")";
2164 }
2165 } else {
2166 // Deep compare of std::unique_ptr. Null is not equal to empty.
2167 std::string both_null =
2168 "(" + lhs_accessor + " == " + rhs_accessor + ")";
2169 std::string not_null_and_equal = "(lhs." + accessor + " && rhs." +
2170 accessor + " && *lhs." + accessor +
2171 " == *rhs." + accessor + ")";
2172 compare_op += "(" + both_null + " || " + not_null_and_equal + ")";
2173 }
2174 }
2175 }
2176
2177 std::string cmp_lhs;
2178 std::string cmp_rhs;
2179 if (compare_op.empty()) {
2180 cmp_lhs = "";
2181 cmp_rhs = "";
2182 compare_op = " return true;";
2183 } else {
2184 cmp_lhs = "lhs";
2185 cmp_rhs = "rhs";
2186 compare_op = " return\n " + compare_op + ";";
2187 }
2188
2189 code_.SetValue("CMP_OP", compare_op);
2190 code_.SetValue("CMP_LHS", cmp_lhs);
2191 code_.SetValue("CMP_RHS", cmp_rhs);
2192 code_ += "";
2193 code_ +=
2194 "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
2195 "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
2196 code_ += "{{CMP_OP}}";
2197 code_ += "}";
2198
2199 code_ += "";
2200 code_ +=
2201 "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
2202 "{{NATIVE_NAME}} &rhs) {";
2203 code_ += " return !(lhs == rhs);";
2204 code_ += "}";
2205 code_ += "";
2206 }
2207
GenOperatorNewDelete(const StructDef & struct_def)2208 void GenOperatorNewDelete(const StructDef &struct_def) {
2209 if (auto native_custom_alloc =
2210 struct_def.attributes.Lookup("native_custom_alloc")) {
2211 code_ += " inline void *operator new (std::size_t count) {";
2212 code_ += " return " + native_custom_alloc->constant +
2213 "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
2214 code_ += " }";
2215 code_ += " inline void operator delete (void *ptr) {";
2216 code_ += " return " + native_custom_alloc->constant +
2217 "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
2218 "ptr),1);";
2219 code_ += " }";
2220 }
2221 }
2222
GenNativeTable(const StructDef & struct_def)2223 void GenNativeTable(const StructDef &struct_def) {
2224 const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
2225 code_.SetValue("STRUCT_NAME", Name(struct_def));
2226 code_.SetValue("NATIVE_NAME", native_name);
2227
2228 // Generate a C++ object that can hold an unpacked version of this table.
2229 code_ += "struct {{NATIVE_NAME}} : public ::flatbuffers::NativeTable {";
2230 code_ += " typedef {{STRUCT_NAME}} TableType;";
2231 GenFullyQualifiedNameGetter(struct_def, native_name);
2232 for (const auto field : struct_def.fields.vec) { GenMember(*field); }
2233 GenOperatorNewDelete(struct_def);
2234 GenDefaultConstructor(struct_def);
2235 GenCopyMoveCtorAndAssigOpDecls(struct_def);
2236 code_ += "};";
2237 code_ += "";
2238 }
2239
2240 // Adds a typedef to the binary schema type so one could get the bfbs based
2241 // on the type at runtime.
GenBinarySchemaTypeDef(const StructDef * struct_def)2242 void GenBinarySchemaTypeDef(const StructDef *struct_def) {
2243 if (struct_def && opts_.binary_schema_gen_embed) {
2244 code_ += " typedef " + WrapInNameSpace(*struct_def) +
2245 "BinarySchema BinarySchema;";
2246 }
2247 }
2248
GenNativeTablePost(const StructDef & struct_def)2249 void GenNativeTablePost(const StructDef &struct_def) {
2250 if (opts_.gen_compare) {
2251 const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
2252 code_.SetValue("STRUCT_NAME", Name(struct_def));
2253 code_.SetValue("NATIVE_NAME", native_name);
2254 GenCompareOperator(struct_def);
2255 code_ += "";
2256 }
2257 }
2258
2259 // Generate the code to call the appropriate Verify function(s) for a field.
GenVerifyCall(const FieldDef & field,const char * prefix)2260 void GenVerifyCall(const FieldDef &field, const char *prefix) {
2261 code_.SetValue("PRE", prefix);
2262 code_.SetValue("NAME", Name(field));
2263 code_.SetValue("REQUIRED", field.IsRequired() ? "Required" : "");
2264 code_.SetValue("SIZE", GenTypeSize(field.value.type));
2265 code_.SetValue("OFFSET", GenFieldOffsetName(field));
2266 if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
2267 code_.SetValue("ALIGN", NumToString(InlineAlignment(field.value.type)));
2268 code_ +=
2269 "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, "
2270 "{{OFFSET}}, {{ALIGN}})\\";
2271 } else {
2272 code_.SetValue("OFFSET_SIZE", field.offset64 ? "64" : "");
2273 code_ +=
2274 "{{PRE}}VerifyOffset{{OFFSET_SIZE}}{{REQUIRED}}(verifier, "
2275 "{{OFFSET}})\\";
2276 }
2277
2278 switch (field.value.type.base_type) {
2279 case BASE_TYPE_UNION: {
2280 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
2281 code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
2282 code_ +=
2283 "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
2284 "{{NAME}}{{SUFFIX}}())\\";
2285 break;
2286 }
2287 case BASE_TYPE_STRUCT: {
2288 if (!field.value.type.struct_def->fixed) {
2289 code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
2290 }
2291 break;
2292 }
2293 case BASE_TYPE_STRING: {
2294 code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
2295 break;
2296 }
2297 case BASE_TYPE_VECTOR64:
2298 case BASE_TYPE_VECTOR: {
2299 code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
2300
2301 switch (field.value.type.element) {
2302 case BASE_TYPE_STRING: {
2303 code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
2304 break;
2305 }
2306 case BASE_TYPE_STRUCT: {
2307 if (!field.value.type.struct_def->fixed) {
2308 code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
2309 }
2310 break;
2311 }
2312 case BASE_TYPE_UNION: {
2313 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
2314 code_ +=
2315 "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
2316 "{{NAME}}_type())\\";
2317 break;
2318 }
2319 default: break;
2320 }
2321
2322 auto nfn = GetNestedFlatBufferName(field);
2323 if (!nfn.empty()) {
2324 code_.SetValue("CPP_NAME", nfn);
2325 // FIXME: file_identifier.
2326 code_ +=
2327 "{{PRE}}verifier.VerifyNestedFlatBuffer<{{CPP_NAME}}>"
2328 "({{NAME}}(), nullptr)\\";
2329 } else if (field.flexbuffer) {
2330 code_ +=
2331 "{{PRE}}flexbuffers::VerifyNestedFlexBuffer"
2332 "({{NAME}}(), verifier)\\";
2333 }
2334 break;
2335 }
2336 default: {
2337 break;
2338 }
2339 }
2340 }
2341
GenComparatorForStruct(const StructDef & struct_def,size_t space_size,const std::string lhs_struct_literal,const std::string rhs_struct_literal)2342 void GenComparatorForStruct(const StructDef &struct_def, size_t space_size,
2343 const std::string lhs_struct_literal,
2344 const std::string rhs_struct_literal) {
2345 code_.SetValue("LHS_PREFIX", lhs_struct_literal);
2346 code_.SetValue("RHS_PREFIX", rhs_struct_literal);
2347 std::string space(space_size, ' ');
2348 for (const auto &curr_field : struct_def.fields.vec) {
2349 const auto curr_field_name = Name(*curr_field);
2350 code_.SetValue("CURR_FIELD_NAME", curr_field_name);
2351 code_.SetValue("LHS", lhs_struct_literal + "_" + curr_field_name);
2352 code_.SetValue("RHS", rhs_struct_literal + "_" + curr_field_name);
2353 const bool is_scalar = IsScalar(curr_field->value.type.base_type);
2354 const bool is_array = IsArray(curr_field->value.type);
2355 const bool is_struct = IsStruct(curr_field->value.type);
2356
2357 // If encouter a key field, call KeyCompareWithValue to compare this
2358 // field.
2359 if (curr_field->key) {
2360 code_ += space +
2361 "const auto {{RHS}} = {{RHS_PREFIX}}.{{CURR_FIELD_NAME}}();";
2362 code_ += space +
2363 "const auto {{CURR_FIELD_NAME}}_compare_result = "
2364 "{{LHS_PREFIX}}.KeyCompareWithValue({{RHS}});";
2365
2366 code_ += space + "if ({{CURR_FIELD_NAME}}_compare_result != 0)";
2367 code_ += space + " return {{CURR_FIELD_NAME}}_compare_result;";
2368 continue;
2369 }
2370
2371 code_ +=
2372 space + "const auto {{LHS}} = {{LHS_PREFIX}}.{{CURR_FIELD_NAME}}();";
2373 code_ +=
2374 space + "const auto {{RHS}} = {{RHS_PREFIX}}.{{CURR_FIELD_NAME}}();";
2375 if (is_scalar) {
2376 code_ += space + "if ({{LHS}} != {{RHS}})";
2377 code_ += space +
2378 " return static_cast<int>({{LHS}} > {{RHS}}) - "
2379 "static_cast<int>({{LHS}} < {{RHS}});";
2380 } else if (is_array) {
2381 const auto &elem_type = curr_field->value.type.VectorType();
2382 code_ +=
2383 space +
2384 "for (::flatbuffers::uoffset_t i = 0; i < {{LHS}}->size(); i++) {";
2385 code_ += space + " const auto {{LHS}}_elem = {{LHS}}->Get(i);";
2386 code_ += space + " const auto {{RHS}}_elem = {{RHS}}->Get(i);";
2387 if (IsScalar(elem_type.base_type)) {
2388 code_ += space + " if ({{LHS}}_elem != {{RHS}}_elem)";
2389 code_ += space +
2390 " return static_cast<int>({{LHS}}_elem > {{RHS}}_elem) - "
2391 "static_cast<int>({{LHS}}_elem < {{RHS}}_elem);";
2392 code_ += space + "}";
2393
2394 } else if (IsStruct(elem_type)) {
2395 if (curr_field->key) {
2396 code_ += space +
2397 "const auto {{CURR_FIELD_NAME}}_compare_result = "
2398 "{{LHS_PREFIX}}.KeyCompareWithValue({{RHS}});";
2399 code_ += space + "if ({{CURR_FIELD_NAME}}_compare_result != 0)";
2400 code_ += space + " return {{CURR_FIELD_NAME}}_compare_result;";
2401 continue;
2402 }
2403 GenComparatorForStruct(
2404 *curr_field->value.type.struct_def, space_size + 2,
2405 code_.GetValue("LHS") + "_elem", code_.GetValue("RHS") + "_elem");
2406
2407 code_ += space + "}";
2408 }
2409
2410 } else if (is_struct) {
2411 GenComparatorForStruct(*curr_field->value.type.struct_def, space_size,
2412 code_.GetValue("LHS"), code_.GetValue("RHS"));
2413 }
2414 }
2415 }
2416
2417 // Generate CompareWithValue method for a key field.
GenKeyFieldMethods(const FieldDef & field)2418 void GenKeyFieldMethods(const FieldDef &field) {
2419 FLATBUFFERS_ASSERT(field.key);
2420 const bool is_string = IsString(field.value.type);
2421 const bool is_array = IsArray(field.value.type);
2422 const bool is_struct = IsStruct(field.value.type);
2423 // Generate KeyCompareLessThan function
2424 code_ +=
2425 " bool KeyCompareLessThan(const {{STRUCT_NAME}} * const o) const {";
2426 if (is_string) {
2427 // use operator< of ::flatbuffers::String
2428 code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
2429 } else if (is_array || is_struct) {
2430 code_ += " return KeyCompareWithValue(o->{{FIELD_NAME}}()) < 0;";
2431 } else {
2432 code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
2433 }
2434 code_ += " }";
2435
2436 // Generate KeyCompareWithValue function
2437 if (is_string) {
2438 // Compares key against a null-terminated char array.
2439 code_ += " int KeyCompareWithValue(const char *_{{FIELD_NAME}}) const {";
2440 code_ += " return strcmp({{FIELD_NAME}}()->c_str(), _{{FIELD_NAME}});";
2441 code_ += " }";
2442 // Compares key against any string-like object (e.g. std::string_view or
2443 // std::string) that implements operator< comparison with const char*.
2444 code_ += " template<typename StringType>";
2445 code_ +=
2446 " int KeyCompareWithValue(const StringType& _{{FIELD_NAME}}) const "
2447 "{";
2448 code_ +=
2449 " if ({{FIELD_NAME}}()->c_str() < _{{FIELD_NAME}}) return -1;";
2450 code_ += " if (_{{FIELD_NAME}} < {{FIELD_NAME}}()->c_str()) return 1;";
2451 code_ += " return 0;";
2452 } else if (is_array) {
2453 const auto &elem_type = field.value.type.VectorType();
2454 std::string input_type = "::flatbuffers::Array<" +
2455 GenTypeGet(elem_type, "", "", "", false) + ", " +
2456 NumToString(elem_type.fixed_length) + ">";
2457 code_.SetValue("INPUT_TYPE", input_type);
2458 code_ +=
2459 " int KeyCompareWithValue(const {{INPUT_TYPE}} *_{{FIELD_NAME}}"
2460 ") const {";
2461 code_ +=
2462 " const {{INPUT_TYPE}} *curr_{{FIELD_NAME}} = {{FIELD_NAME}}();";
2463 code_ +=
2464 " for (::flatbuffers::uoffset_t i = 0; i < "
2465 "curr_{{FIELD_NAME}}->size(); i++) {";
2466
2467 if (IsScalar(elem_type.base_type)) {
2468 code_ += " const auto lhs = curr_{{FIELD_NAME}}->Get(i);";
2469 code_ += " const auto rhs = _{{FIELD_NAME}}->Get(i);";
2470 code_ += " if (lhs != rhs)";
2471 code_ +=
2472 " return static_cast<int>(lhs > rhs)"
2473 " - static_cast<int>(lhs < rhs);";
2474 } else if (IsStruct(elem_type)) {
2475 code_ +=
2476 " const auto &lhs_{{FIELD_NAME}} = "
2477 "*(curr_{{FIELD_NAME}}->Get(i));";
2478 code_ +=
2479 " const auto &rhs_{{FIELD_NAME}} = "
2480 "*(_{{FIELD_NAME}}->Get(i));";
2481 GenComparatorForStruct(*elem_type.struct_def, 6,
2482 "lhs_" + code_.GetValue("FIELD_NAME"),
2483 "rhs_" + code_.GetValue("FIELD_NAME"));
2484 }
2485 code_ += " }";
2486 code_ += " return 0;";
2487 } else if (is_struct) {
2488 const auto *struct_def = field.value.type.struct_def;
2489 code_.SetValue("INPUT_TYPE",
2490 GenTypeGet(field.value.type, "", "", "", false));
2491 code_ +=
2492 " int KeyCompareWithValue(const {{INPUT_TYPE}} &_{{FIELD_NAME}}) "
2493 "const {";
2494 code_ += " const auto &lhs_{{FIELD_NAME}} = {{FIELD_NAME}}();";
2495 code_ += " const auto &rhs_{{FIELD_NAME}} = _{{FIELD_NAME}};";
2496 GenComparatorForStruct(*struct_def, 4,
2497 "lhs_" + code_.GetValue("FIELD_NAME"),
2498 "rhs_" + code_.GetValue("FIELD_NAME"));
2499 code_ += " return 0;";
2500
2501 } else {
2502 FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
2503 auto type = GenTypeBasic(field.value.type, false);
2504 if (opts_.scoped_enums && field.value.type.enum_def &&
2505 IsScalar(field.value.type.base_type)) {
2506 type = GenTypeGet(field.value.type, " ", "const ", " *", true);
2507 }
2508 // Returns {field<val: -1, field==val: 0, field>val: +1}.
2509 code_.SetValue("KEY_TYPE", type);
2510 code_ +=
2511 " int KeyCompareWithValue({{KEY_TYPE}} _{{FIELD_NAME}}) const {";
2512 code_ +=
2513 " return static_cast<int>({{FIELD_NAME}}() > _{{FIELD_NAME}}) - "
2514 "static_cast<int>({{FIELD_NAME}}() < _{{FIELD_NAME}});";
2515 }
2516 code_ += " }";
2517 }
2518
GenTableUnionAsGetters(const FieldDef & field)2519 void GenTableUnionAsGetters(const FieldDef &field) {
2520 const auto &type = field.value.type;
2521 auto u = type.enum_def;
2522
2523 if (!type.enum_def->uses_multiple_type_instances)
2524 code_ +=
2525 " template<typename T> "
2526 "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
2527
2528 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2529 auto &ev = **u_it;
2530 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
2531 auto full_struct_name = GetUnionElement(ev, false, opts_);
2532
2533 // @TODO: Mby make this decisions more universal? How?
2534 code_.SetValue("U_GET_TYPE",
2535 EscapeKeyword(Name(field) + UnionTypeFieldSuffix()));
2536 code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace,
2537 GetEnumValUse(*u, ev)));
2538 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2539 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2540 code_.SetValue("U_NULLABLE", NullableExtension());
2541
2542 // `const Type *union_name_asType() const` accessor.
2543 code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
2544 code_ +=
2545 " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
2546 "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
2547 ": nullptr;";
2548 code_ += " }";
2549 }
2550 }
2551
GenTableFieldGetter(const FieldDef & field)2552 void GenTableFieldGetter(const FieldDef &field) {
2553 const auto &type = field.value.type;
2554 const auto offset_str = GenFieldOffsetName(field);
2555
2556 GenComment(field.doc_comment, " ");
2557 // Call a different accessor for pointers, that indirects.
2558 if (!field.IsScalarOptional()) {
2559 const bool is_scalar = IsScalar(type.base_type);
2560 std::string accessor;
2561 std::string offset_size = "";
2562 if (is_scalar) {
2563 accessor = "GetField<";
2564 } else if (IsStruct(type)) {
2565 accessor = "GetStruct<";
2566 } else {
2567 if (field.offset64) {
2568 accessor = "GetPointer64<";
2569 } else {
2570 accessor = "GetPointer<";
2571 }
2572 }
2573 auto offset_type = GenTypeGet(type, "", "const ", " *", false);
2574 auto call = accessor + offset_type + ">(" + offset_str;
2575 // Default value as second arg for non-pointer types.
2576 if (is_scalar) { call += ", " + GenDefaultConstant(field); }
2577 call += ")";
2578
2579 std::string afterptr = " *" + NullableExtension();
2580 code_.SetValue("FIELD_TYPE",
2581 GenTypeGet(type, " ", "const ", afterptr.c_str(), true));
2582 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
2583 code_.SetValue("NULLABLE_EXT", NullableExtension());
2584 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
2585 code_ += " return {{FIELD_VALUE}};";
2586 code_ += " }";
2587 } else {
2588 auto wire_type = GenTypeBasic(type, false);
2589 auto face_type = GenTypeBasic(type, true);
2590 auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
2591 offset_str + ")";
2592 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2593 code_ += " {{FIELD_TYPE}} {{FIELD_NAME}}() const {";
2594 code_ += " return " + opt_value + ";";
2595 code_ += " }";
2596 }
2597
2598 if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); }
2599 }
2600
GenTableFieldType(const FieldDef & field)2601 void GenTableFieldType(const FieldDef &field) {
2602 const auto &type = field.value.type;
2603 const auto offset_str = GenFieldOffsetName(field);
2604 if (!field.IsScalarOptional()) {
2605 std::string afterptr = " *" + NullableExtension();
2606 code_.SetValue("FIELD_TYPE",
2607 GenTypeGet(type, "", "const ", afterptr.c_str(), true));
2608 code_ += " {{FIELD_TYPE}}\\";
2609 } else {
2610 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2611 code_ += " {{FIELD_TYPE}}\\";
2612 }
2613 }
2614
GenStructFieldType(const FieldDef & field)2615 void GenStructFieldType(const FieldDef &field) {
2616 const auto is_array = IsArray(field.value.type);
2617 std::string field_type =
2618 GenTypeGet(field.value.type, "", is_array ? "" : "const ",
2619 is_array ? "" : " &", true);
2620 code_.SetValue("FIELD_TYPE", field_type);
2621 code_ += " {{FIELD_TYPE}}\\";
2622 }
2623
GenFieldTypeHelper(const StructDef & struct_def)2624 void GenFieldTypeHelper(const StructDef &struct_def) {
2625 if (struct_def.fields.vec.empty()) { return; }
2626 code_ += " template<size_t Index>";
2627 code_ += " using FieldType = \\";
2628 code_ += "decltype(std::declval<type>().get_field<Index>());";
2629 }
2630
GenIndexBasedFieldGetter(const StructDef & struct_def)2631 void GenIndexBasedFieldGetter(const StructDef &struct_def) {
2632 if (struct_def.fields.vec.empty()) { return; }
2633 code_ += " template<size_t Index>";
2634 code_ += " auto get_field() const {";
2635
2636 size_t index = 0;
2637 bool need_else = false;
2638 // Generate one index-based getter for each field.
2639 for (const auto &field : struct_def.fields.vec) {
2640 if (field->deprecated) {
2641 // Deprecated fields won't be accessible.
2642 continue;
2643 }
2644 code_.SetValue("FIELD_NAME", Name(*field));
2645 code_.SetValue("FIELD_INDEX",
2646 std::to_string(static_cast<long long>(index++)));
2647 if (need_else) {
2648 code_ += " else \\";
2649 } else {
2650 code_ += " \\";
2651 }
2652 need_else = true;
2653 code_ += "if constexpr (Index == {{FIELD_INDEX}}) \\";
2654 code_ += "return {{FIELD_NAME}}();";
2655 }
2656 code_ += " else static_assert(Index != -1, \"Invalid Field Index\");";
2657 code_ += " }";
2658 }
2659
2660 // Sample for Vec3:
2661 //
2662 // static constexpr std::array<const char *, 3> field_names = {
2663 // "x",
2664 // "y",
2665 // "z"
2666 // };
2667 //
GenFieldNames(const StructDef & struct_def)2668 void GenFieldNames(const StructDef &struct_def) {
2669 code_ += " static constexpr std::array<\\";
2670 code_ += "const char *, fields_number> field_names = {\\";
2671 if (struct_def.fields.vec.empty()) {
2672 code_ += "};";
2673 return;
2674 }
2675 code_ += "";
2676 // Generate the field_names elements.
2677 for (auto it = struct_def.fields.vec.begin();
2678 it != struct_def.fields.vec.end(); ++it) {
2679 const auto &field = **it;
2680 if (field.deprecated) {
2681 // Deprecated fields won't be accessible.
2682 continue;
2683 }
2684 code_.SetValue("FIELD_NAME", Name(field));
2685 code_ += R"( "{{FIELD_NAME}}"\)";
2686 if (it + 1 != struct_def.fields.vec.end()) { code_ += ","; }
2687 }
2688 code_ += "\n };";
2689 }
2690
GenFieldsNumber(const StructDef & struct_def)2691 void GenFieldsNumber(const StructDef &struct_def) {
2692 const auto non_deprecated_field_count = std::count_if(
2693 struct_def.fields.vec.begin(), struct_def.fields.vec.end(),
2694 [](const FieldDef *field) { return !field->deprecated; });
2695 code_.SetValue(
2696 "FIELD_COUNT",
2697 std::to_string(static_cast<long long>(non_deprecated_field_count)));
2698 code_ += " static constexpr size_t fields_number = {{FIELD_COUNT}};";
2699 }
2700
GenTraitsStruct(const StructDef & struct_def)2701 void GenTraitsStruct(const StructDef &struct_def) {
2702 code_.SetValue(
2703 "FULLY_QUALIFIED_NAME",
2704 struct_def.defined_namespace->GetFullyQualifiedName(Name(struct_def)));
2705 code_ += "struct {{STRUCT_NAME}}::Traits {";
2706 code_ += " using type = {{STRUCT_NAME}};";
2707 if (!struct_def.fixed) {
2708 // We have a table and not a struct.
2709 code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
2710 }
2711 if (opts_.cpp_static_reflection) {
2712 code_ += " static constexpr auto name = \"{{STRUCT_NAME}}\";";
2713 code_ +=
2714 " static constexpr auto fully_qualified_name = "
2715 "\"{{FULLY_QUALIFIED_NAME}}\";";
2716 GenFieldsNumber(struct_def);
2717 GenFieldNames(struct_def);
2718 GenFieldTypeHelper(struct_def);
2719 }
2720 code_ += "};";
2721 code_ += "";
2722 }
2723
GenTableFieldSetter(const FieldDef & field)2724 void GenTableFieldSetter(const FieldDef &field) {
2725 const auto &type = field.value.type;
2726 const bool is_scalar = IsScalar(type.base_type);
2727 if (is_scalar && IsUnion(type))
2728 return; // changing of a union's type is forbidden
2729
2730 auto offset_str = GenFieldOffsetName(field);
2731 if (is_scalar) {
2732 const auto wire_type = GenTypeWire(type, "", false, field.offset64);
2733 code_.SetValue("SET_FN", "SetField<" + wire_type + ">");
2734 code_.SetValue("OFFSET_NAME", offset_str);
2735 code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true));
2736 code_.SetValue("FIELD_VALUE",
2737 GenUnderlyingCast(field, false, "_" + Name(field)));
2738
2739 code_ += " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} _{{FIELD_NAME}}\\";
2740 if (!field.IsScalarOptional()) {
2741 code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
2742 code_.SetValue(
2743 "INTERFACE_DEFAULT_VALUE",
2744 GenUnderlyingCast(field, true, GenDefaultConstant(field)));
2745
2746 // GenUnderlyingCast for a bool field generates 0 != 0
2747 // So the type has to be checked and the appropriate default chosen
2748 if (IsBool(field.value.type.base_type)) {
2749 code_ += " = {{DEFAULT_VALUE}}) {";
2750 } else {
2751 code_ += " = {{INTERFACE_DEFAULT_VALUE}}) {";
2752 }
2753 code_ +=
2754 " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
2755 "{{DEFAULT_VALUE}});";
2756 } else {
2757 code_ += ") {";
2758 code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
2759 }
2760 code_ += " }";
2761 } else {
2762 auto postptr = " *" + NullableExtension();
2763 auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
2764 const std::string accessor = [&]() {
2765 if (IsStruct(type)) { return "GetStruct<"; }
2766 if (field.offset64) { return "GetPointer64<"; }
2767 return "GetPointer<";
2768 }();
2769 auto underlying = accessor + wire_type + ">(" + offset_str + ")";
2770 code_.SetValue("FIELD_TYPE", wire_type);
2771 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
2772
2773 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
2774 code_ += " return {{FIELD_VALUE}};";
2775 code_ += " }";
2776 }
2777 }
2778
GetNestedFlatBufferName(const FieldDef & field)2779 std::string GetNestedFlatBufferName(const FieldDef &field) {
2780 auto nested = field.attributes.Lookup("nested_flatbuffer");
2781 if (!nested) return "";
2782 std::string qualified_name = nested->constant;
2783 auto nested_root = parser_.LookupStruct(nested->constant);
2784 if (nested_root == nullptr) {
2785 qualified_name =
2786 parser_.current_namespace_->GetFullyQualifiedName(nested->constant);
2787 nested_root = parser_.LookupStruct(qualified_name);
2788 }
2789 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
2790 (void)nested_root;
2791 return TranslateNameSpace(qualified_name);
2792 }
2793
2794 // Generate an accessor struct, builder structs & function for a table.
GenTable(const StructDef & struct_def)2795 void GenTable(const StructDef &struct_def) {
2796 if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
2797
2798 // Generate an accessor struct, with methods of the form:
2799 // type name() const { return GetField<type>(offset, defaultval); }
2800 GenComment(struct_def.doc_comment);
2801
2802 code_.SetValue("STRUCT_NAME", Name(struct_def));
2803 code_ +=
2804 "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
2805 " : private ::flatbuffers::Table {";
2806 if (opts_.generate_object_based_api) {
2807 code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
2808 }
2809 code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
2810 GenBinarySchemaTypeDef(parser_.root_struct_def_);
2811
2812 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
2813 if (opts_.mini_reflect != IDLOptions::kNone) {
2814 code_ +=
2815 " static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {";
2816 code_ += " return {{STRUCT_NAME}}TypeTable();";
2817 code_ += " }";
2818 }
2819
2820 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
2821
2822 // Generate field id constants.
2823 if (!struct_def.fields.vec.empty()) {
2824 // We need to add a trailing comma to all elements except the last one as
2825 // older versions of gcc complain about this.
2826 code_.SetValue("SEP", "");
2827 code_ +=
2828 " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
2829 for (const auto &field : struct_def.fields.vec) {
2830 if (field->deprecated) {
2831 // Deprecated fields won't be accessible.
2832 continue;
2833 }
2834
2835 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(*field));
2836 code_.SetValue("OFFSET_VALUE", NumToString(field->value.offset));
2837 code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
2838 code_.SetValue("SEP", ",\n");
2839 }
2840 code_ += "";
2841 code_ += " };";
2842 }
2843
2844 // Generate the accessors.
2845 for (const auto &field : struct_def.fields.vec) {
2846 if (field->deprecated) {
2847 // Deprecated fields won't be accessible.
2848 continue;
2849 }
2850
2851 code_.SetValue("FIELD_NAME", Name(*field));
2852 GenTableFieldGetter(*field);
2853 if (opts_.mutable_buffer) { GenTableFieldSetter(*field); }
2854
2855 auto nfn = GetNestedFlatBufferName(*field);
2856 if (!nfn.empty()) {
2857 code_.SetValue("CPP_NAME", nfn);
2858 code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
2859 code_ += " const auto _f = {{FIELD_NAME}}();";
2860 code_ +=
2861 " return _f ? ::flatbuffers::GetRoot<{{CPP_NAME}}>(_f->Data())";
2862 code_ += " : nullptr;";
2863 code_ += " }";
2864 }
2865
2866 if (field->flexbuffer) {
2867 code_ +=
2868 " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
2869 " const {";
2870 // Both Data() and size() are const-methods, therefore call order
2871 // doesn't matter.
2872 code_ += " const auto _f = {{FIELD_NAME}}();";
2873 code_ += " return _f ? flexbuffers::GetRoot(_f->Data(), _f->size())";
2874 code_ += " : flexbuffers::Reference();";
2875 code_ += " }";
2876 }
2877
2878 // Generate a comparison function for this field if it is a key.
2879 if (field->key) { GenKeyFieldMethods(*field); }
2880 }
2881
2882 if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
2883
2884 // Generate a verifier function that can check a buffer from an untrusted
2885 // source will never cause reads outside the buffer.
2886 code_ += " bool Verify(::flatbuffers::Verifier &verifier) const {";
2887 code_ += " return VerifyTableStart(verifier)\\";
2888 for (const auto &field : struct_def.fields.vec) {
2889 if (field->deprecated) { continue; }
2890 GenVerifyCall(*field, " &&\n ");
2891 }
2892
2893 code_ += " &&\n verifier.EndTable();";
2894 code_ += " }";
2895
2896 if (opts_.generate_object_based_api) {
2897 // Generate the UnPack() pre declaration.
2898 code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";";
2899 code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";";
2900 code_ += " " + TablePackSignature(struct_def, true, opts_) + ";";
2901 }
2902
2903 code_ += "};"; // End of table.
2904 code_ += "";
2905
2906 // Explicit specializations for union accessors
2907 for (const auto &field : struct_def.fields.vec) {
2908 if (field->deprecated || field->value.type.base_type != BASE_TYPE_UNION) {
2909 continue;
2910 }
2911
2912 auto u = field->value.type.enum_def;
2913 if (u->uses_multiple_type_instances) continue;
2914
2915 code_.SetValue("FIELD_NAME", Name(*field));
2916
2917 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2918 auto &ev = **u_it;
2919 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
2920
2921 auto full_struct_name = GetUnionElement(ev, false, opts_);
2922
2923 code_.SetValue(
2924 "U_ELEMENT_TYPE",
2925 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
2926 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2927 code_.SetValue("U_ELEMENT_NAME", full_struct_name);
2928 code_.SetValue("U_FIELD_NAME", Name(*field) + "_as_" + Name(ev));
2929
2930 // `template<> const T *union_name_as<T>() const` accessor.
2931 code_ +=
2932 "template<> "
2933 "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
2934 "<{{U_ELEMENT_NAME}}>() const {";
2935 code_ += " return {{U_FIELD_NAME}}();";
2936 code_ += "}";
2937 code_ += "";
2938 }
2939 }
2940
2941 GenBuilders(struct_def);
2942
2943 if (opts_.generate_object_based_api) {
2944 // Generate a pre-declaration for a CreateX method that works with an
2945 // unpacked C++ object.
2946 code_ += TableCreateSignature(struct_def, true, opts_) + ";";
2947 code_ += "";
2948 }
2949 }
2950
2951 // Generate code to force vector alignment. Return empty string for vector
2952 // that doesn't need alignment code.
GenVectorForceAlign(const FieldDef & field,const std::string & field_size)2953 std::string GenVectorForceAlign(const FieldDef &field,
2954 const std::string &field_size) {
2955 FLATBUFFERS_ASSERT(IsVector(field.value.type));
2956 // Get the value of the force_align attribute.
2957 const auto *force_align = field.attributes.Lookup("force_align");
2958 const int align = force_align ? atoi(force_align->constant.c_str()) : 1;
2959 // Generate code to do force_align for the vector.
2960 if (align > 1) {
2961 const auto vtype = field.value.type.VectorType();
2962 const std::string &type =
2963 IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def)
2964 : GenTypeWire(vtype, "", false, field.offset64);
2965 return std::string("_fbb.ForceVectorAlignment") +
2966 (field.offset64 ? "64" : "") + "(" + field_size + ", sizeof(" +
2967 type + "), " + std::to_string(static_cast<long long>(align)) +
2968 ");";
2969 }
2970 return "";
2971 }
2972
GenBuilders(const StructDef & struct_def)2973 void GenBuilders(const StructDef &struct_def) {
2974 code_.SetValue("STRUCT_NAME", Name(struct_def));
2975
2976 // Generate a builder struct:
2977 code_ += "struct {{STRUCT_NAME}}Builder {";
2978 code_ += " typedef {{STRUCT_NAME}} Table;";
2979 code_ += " " + GetBuilder() + " &fbb_;";
2980 code_ += " ::flatbuffers::uoffset_t start_;";
2981
2982 bool has_string_or_vector_fields = false;
2983 for (auto it = struct_def.fields.vec.begin();
2984 it != struct_def.fields.vec.end(); ++it) {
2985 const auto &field = **it;
2986 if (field.deprecated) continue;
2987 const bool is_scalar = IsScalar(field.value.type.base_type);
2988 const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
2989 const bool is_string = IsString(field.value.type);
2990 const bool is_vector = IsVector(field.value.type);
2991 if (is_string || is_vector) { has_string_or_vector_fields = true; }
2992
2993 std::string offset = GenFieldOffsetName(field);
2994 std::string name = GenUnderlyingCast(field, false, Name(field));
2995 std::string value = is_default_scalar ? GenDefaultConstant(field) : "";
2996
2997 // Generate accessor functions of the form:
2998 // void add_name(type name) {
2999 // fbb_.AddElement<type>(offset, name, default);
3000 // }
3001 code_.SetValue("FIELD_NAME", Name(field));
3002 code_.SetValue("FIELD_TYPE",
3003 GenTypeWire(field.value.type, " ", true, field.offset64));
3004 code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
3005 code_.SetValue("ADD_NAME", name);
3006 code_.SetValue("ADD_VALUE", value);
3007 if (is_scalar) {
3008 const auto type =
3009 GenTypeWire(field.value.type, "", false, field.offset64);
3010 code_.SetValue("ADD_FN", "AddElement<" + type + ">");
3011 } else if (IsStruct(field.value.type)) {
3012 code_.SetValue("ADD_FN", "AddStruct");
3013 } else {
3014 code_.SetValue("ADD_FN", "AddOffset");
3015 }
3016
3017 code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
3018 code_ += " fbb_.{{ADD_FN}}(\\";
3019 if (is_default_scalar) {
3020 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
3021 } else {
3022 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
3023 }
3024 code_ += " }";
3025 }
3026
3027 // Builder constructor
3028 code_ += " explicit {{STRUCT_NAME}}Builder(" + GetBuilder() +
3029 " "
3030 "&_fbb)";
3031 code_ += " : fbb_(_fbb) {";
3032 code_ += " start_ = fbb_.StartTable();";
3033 code_ += " }";
3034
3035 // Finish() function.
3036 code_ += " ::flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
3037 code_ += " const auto end = fbb_.EndTable(start_);";
3038 code_ += " auto o = ::flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
3039
3040 for (const auto &field : struct_def.fields.vec) {
3041 if (!field->deprecated && field->IsRequired()) {
3042 code_.SetValue("FIELD_NAME", Name(*field));
3043 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(*field));
3044 code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
3045 }
3046 }
3047 code_ += " return o;";
3048 code_ += " }";
3049 code_ += "};";
3050 code_ += "";
3051
3052 // Generate a convenient CreateX function that uses the above builder
3053 // to create a table in one go.
3054 code_ +=
3055 "inline ::flatbuffers::Offset<{{STRUCT_NAME}}> "
3056 "Create{{STRUCT_NAME}}(";
3057 code_ += " " + GetBuilder() + " &_fbb\\";
3058 for (const auto &field : struct_def.fields.vec) {
3059 if (!field->deprecated) { GenParam(*field, false, ",\n "); }
3060 }
3061 code_ += ") {";
3062
3063 code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);";
3064 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
3065 size; size /= 2) {
3066 for (auto it = struct_def.fields.vec.rbegin();
3067 it != struct_def.fields.vec.rend(); ++it) {
3068 const auto &field = **it;
3069 if (!field.deprecated && (!struct_def.sortbysize ||
3070 size == SizeOf(field.value.type.base_type))) {
3071 code_.SetValue("FIELD_NAME", Name(field));
3072 if (field.IsScalarOptional()) {
3073 code_ +=
3074 " if({{FIELD_NAME}}) { "
3075 "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }";
3076 } else {
3077 code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
3078 }
3079 }
3080 }
3081 }
3082 code_ += " return builder_.Finish();";
3083 code_ += "}";
3084 code_ += "";
3085
3086 // Definition for type traits for this table type. This allows querying var-
3087 // ious compile-time traits of the table.
3088 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
3089
3090 // Generate a CreateXDirect function with vector types as parameters
3091 if (opts_.cpp_direct_copy && has_string_or_vector_fields) {
3092 code_ +=
3093 "inline ::flatbuffers::Offset<{{STRUCT_NAME}}> "
3094 "Create{{STRUCT_NAME}}Direct(";
3095 code_ += " " + GetBuilder() + " &_fbb\\";
3096 for (const auto &field : struct_def.fields.vec) {
3097 if (!field->deprecated) { GenParam(*field, true, ",\n "); }
3098 }
3099 // Need to call "Create" with the struct namespace.
3100 const auto qualified_create_name =
3101 struct_def.defined_namespace->GetFullyQualifiedName("Create");
3102 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
3103 code_ += ") {";
3104 // Offset64 bit fields need to be added to the buffer first, so here we
3105 // loop over the fields in order of their offset size, followed by their
3106 // definition order. Otherwise the emitted code might add a Offset
3107 // followed by an Offset64 which would trigger an assertion.
3108
3109 // TODO(derekbailey): maybe optimize for the case where there is no
3110 // 64offsets in the whole schema?
3111 ForAllFieldsOrderedByOffset(struct_def, [&](const FieldDef *field) {
3112 if (field->deprecated) { return; }
3113 code_.SetValue("FIELD_NAME", Name(*field));
3114 if (IsString(field->value.type)) {
3115 if (!field->shared) {
3116 code_.SetValue(
3117 "CREATE_STRING",
3118 "CreateString" + std::string(field->offset64
3119 ? "<::flatbuffers::Offset64>"
3120 : ""));
3121 } else {
3122 code_.SetValue("CREATE_STRING", "CreateSharedString");
3123 }
3124 code_ +=
3125 " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
3126 "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
3127 } else if (IsVector(field->value.type)) {
3128 const std::string force_align_code =
3129 GenVectorForceAlign(*field, Name(*field) + "->size()");
3130 if (!force_align_code.empty()) {
3131 code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }";
3132 }
3133 code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
3134 const auto vtype = field->value.type.VectorType();
3135 const auto has_key = TypeHasKey(vtype);
3136 if (IsStruct(vtype)) {
3137 const std::string type = WrapInNameSpace(*vtype.struct_def);
3138 if (has_key) {
3139 code_ += "_fbb.CreateVectorOfSortedStructs<" + type + ">\\";
3140 } else {
3141 // If the field uses 64-bit addressing, create a 64-bit vector.
3142 if (field->value.type.base_type == BASE_TYPE_VECTOR64) {
3143 code_ += "_fbb.CreateVectorOfStructs64\\";
3144 } else {
3145 code_ += "_fbb.CreateVectorOfStructs\\";
3146 if (field->offset64) {
3147 // This is normal 32-bit vector, with 64-bit addressing.
3148 code_ += "64<::flatbuffers::Vector>\\";
3149 } else {
3150 code_ += "<" + type + ">\\";
3151 }
3152 }
3153 }
3154 } else if (has_key) {
3155 const auto type = WrapInNameSpace(*vtype.struct_def);
3156 code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\";
3157 } else {
3158 const auto type = GenTypeWire(
3159 vtype, "", VectorElementUserFacing(vtype), field->offset64);
3160
3161 if (field->value.type.base_type == BASE_TYPE_VECTOR64) {
3162 code_ += "_fbb.CreateVector64\\";
3163 } else {
3164 // If the field uses 64-bit addressing, create a 64-bit vector.
3165 code_.SetValue("64OFFSET", field->offset64 ? "64" : "");
3166 code_.SetValue("TYPE",
3167 field->offset64 ? "::flatbuffers::Vector" : type);
3168
3169 code_ += "_fbb.CreateVector{{64OFFSET}}<{{TYPE}}>\\";
3170 }
3171 }
3172 code_ += has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;";
3173 }
3174 });
3175 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
3176 code_ += " _fbb\\";
3177 for (const auto &field : struct_def.fields.vec) {
3178 if (field->deprecated) { continue; }
3179 code_.SetValue("FIELD_NAME", Name(*field));
3180 code_ += ",\n {{FIELD_NAME}}\\";
3181 if (IsString(field->value.type) || IsVector(field->value.type)) {
3182 code_ += "__\\";
3183 }
3184 }
3185 code_ += ");";
3186 code_ += "}";
3187 code_ += "";
3188 }
3189 }
3190
GenUnionUnpackVal(const FieldDef & afield,const char * vec_elem_access,const char * vec_type_access)3191 std::string GenUnionUnpackVal(const FieldDef &afield,
3192 const char *vec_elem_access,
3193 const char *vec_type_access) {
3194 auto type_name = WrapInNameSpace(*afield.value.type.enum_def);
3195 return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " +
3196 EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
3197 vec_type_access + ", _resolver)";
3198 }
3199
GenUnpackVal(const Type & type,const std::string & val,bool invector,const FieldDef & afield)3200 std::string GenUnpackVal(const Type &type, const std::string &val,
3201 bool invector, const FieldDef &afield) {
3202 switch (type.base_type) {
3203 case BASE_TYPE_STRING: {
3204 if (FlexibleStringConstructor(&afield)) {
3205 return NativeString(&afield) + "(" + val + "->c_str(), " + val +
3206 "->size())";
3207 } else {
3208 return val + "->str()";
3209 }
3210 }
3211 case BASE_TYPE_STRUCT: {
3212 if (IsStruct(type)) {
3213 const auto &struct_attrs = type.struct_def->attributes;
3214 const auto native_type = struct_attrs.Lookup("native_type");
3215 if (native_type) {
3216 std::string unpack_call = "::flatbuffers::UnPack";
3217 const auto pack_name = struct_attrs.Lookup("native_type_pack_name");
3218 if (pack_name) { unpack_call += pack_name->constant; }
3219 unpack_call += "(*" + val + ")";
3220 return unpack_call;
3221 } else if (invector || afield.native_inline) {
3222 return "*" + val;
3223 } else {
3224 const auto name = WrapInNameSpace(*type.struct_def);
3225 const auto ptype = GenTypeNativePtr(name, &afield, true);
3226 return ptype + "(new " + name + "(*" + val + "))";
3227 }
3228 } else {
3229 std::string ptype = afield.native_inline ? "*" : "";
3230 ptype += GenTypeNativePtr(
3231 WrapNativeNameInNameSpace(*type.struct_def, opts_), &afield,
3232 true);
3233 return ptype + "(" + val + "->UnPack(_resolver))";
3234 }
3235 }
3236 case BASE_TYPE_UNION: {
3237 return GenUnionUnpackVal(
3238 afield, invector ? "->Get(_i)" : "",
3239 invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
3240 : "");
3241 }
3242 default: {
3243 return val;
3244 break;
3245 }
3246 }
3247 }
3248
GenUnpackFieldStatement(const FieldDef & field,const FieldDef * union_field)3249 std::string GenUnpackFieldStatement(const FieldDef &field,
3250 const FieldDef *union_field) {
3251 std::string code;
3252 switch (field.value.type.base_type) {
3253 case BASE_TYPE_VECTOR64:
3254 case BASE_TYPE_VECTOR: {
3255 auto name = Name(field);
3256 if (field.value.type.element == BASE_TYPE_UTYPE) {
3257 name = StripUnionType(Name(field));
3258 }
3259 const std::string vector_field = "_o->" + name;
3260 code += "{ " + vector_field + ".resize(_e->size()); ";
3261 if (!field.value.type.enum_def && !IsBool(field.value.type.element) &&
3262 IsOneByte(field.value.type.element)) {
3263 // For vectors of bytes, std::copy is used to improve performance.
3264 // This doesn't work for:
3265 // - enum types because they have to be explicitly static_cast.
3266 // - vectors of bool, since they are a template specialization.
3267 // - multiple-byte types due to endianness.
3268 code +=
3269 "std::copy(_e->begin(), _e->end(), _o->" + name + ".begin()); }";
3270 } else {
3271 std::string indexing;
3272 if (field.value.type.enum_def) {
3273 indexing += "static_cast<" +
3274 WrapInNameSpace(*field.value.type.enum_def) + ">(";
3275 }
3276 indexing += "_e->Get(_i)";
3277 if (field.value.type.enum_def) { indexing += ")"; }
3278 if (field.value.type.element == BASE_TYPE_BOOL) {
3279 indexing += " != 0";
3280 }
3281 // Generate code that pushes data from _e to _o in the form:
3282 // for (uoffset_t i = 0; i < _e->size(); ++i) {
3283 // _o->field.push_back(_e->Get(_i));
3284 // }
3285 auto access =
3286 field.value.type.element == BASE_TYPE_UTYPE
3287 ? ".type"
3288 : (field.value.type.element == BASE_TYPE_UNION ? ".value"
3289 : "");
3290 if (field.value.type.base_type == BASE_TYPE_VECTOR64) {
3291 code += "for (::flatbuffers::uoffset64_t _i = 0;";
3292 } else {
3293 code += "for (::flatbuffers::uoffset_t _i = 0;";
3294 }
3295 code += " _i < _e->size(); _i++) { ";
3296 auto cpp_type = field.attributes.Lookup("cpp_type");
3297 if (cpp_type) {
3298 // Generate code that resolves the cpp pointer type, of the form:
3299 // if (resolver)
3300 // (*resolver)(&_o->field, (hash_value_t)(_e));
3301 // else
3302 // _o->field = nullptr;
3303 code += "/*vector resolver, " + PtrType(&field) + "*/ ";
3304 code += "if (_resolver) ";
3305 code += "(*_resolver)";
3306 code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" +
3307 access + "), ";
3308 code +=
3309 "static_cast<::flatbuffers::hash_value_t>(" + indexing + "));";
3310 if (PtrType(&field) == "naked") {
3311 code += " else ";
3312 code += "_o->" + name + "[_i]" + access + " = nullptr; ";
3313 } else {
3314 // code += " else ";
3315 // code += "_o->" + name + "[_i]" + access + " = " +
3316 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
3317 code += "/* else do nothing */";
3318 }
3319 } else {
3320 const bool is_pointer = IsVectorOfPointers(field);
3321 if (is_pointer) {
3322 code += "if(_o->" + name + "[_i]" + ") { ";
3323 code += indexing + "->UnPackTo(_o->" + name +
3324 "[_i].get(), _resolver);";
3325 code += " } else { ";
3326 }
3327 code += "_o->" + name + "[_i]" + access + " = ";
3328 code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
3329 field);
3330 code += "; ";
3331 if (is_pointer) { code += "} "; }
3332 }
3333 code += "} } else { " + vector_field + ".resize(0); }";
3334 }
3335 break;
3336 }
3337 case BASE_TYPE_UTYPE: {
3338 FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
3339 BASE_TYPE_UNION);
3340 // Generate code that sets the union type, of the form:
3341 // _o->field.type = _e;
3342 code += "_o->" + union_field->name + ".type = _e;";
3343 break;
3344 }
3345 case BASE_TYPE_UNION: {
3346 // Generate code that sets the union value, of the form:
3347 // _o->field.value = Union::Unpack(_e, field_type(), resolver);
3348 code += "_o->" + Name(field) + ".value = ";
3349 code += GenUnionUnpackVal(field, "", "");
3350 code += ";";
3351 break;
3352 }
3353 default: {
3354 auto cpp_type = field.attributes.Lookup("cpp_type");
3355 if (cpp_type) {
3356 // Generate code that resolves the cpp pointer type, of the form:
3357 // if (resolver)
3358 // (*resolver)(&_o->field, (hash_value_t)(_e));
3359 // else
3360 // _o->field = nullptr;
3361 code += "/*scalar resolver, " + PtrType(&field) + "*/ ";
3362 code += "if (_resolver) ";
3363 code += "(*_resolver)";
3364 code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
3365 code += "static_cast<::flatbuffers::hash_value_t>(_e));";
3366 if (PtrType(&field) == "naked") {
3367 code += " else ";
3368 code += "_o->" + Name(field) + " = nullptr;";
3369 } else {
3370 // code += " else ";
3371 // code += "_o->" + Name(field) + " = " +
3372 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
3373 code += "/* else do nothing */;";
3374 }
3375 } else {
3376 // Generate code for assigning the value, of the form:
3377 // _o->field = value;
3378 const bool is_pointer = IsPointer(field);
3379
3380 const std::string out_field = "_o->" + Name(field);
3381
3382 if (is_pointer) {
3383 code += "{ if(" + out_field + ") { ";
3384 code += "_e->UnPackTo(" + out_field + ".get(), _resolver);";
3385 code += " } else { ";
3386 }
3387 code += out_field + " = ";
3388 code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
3389 if (is_pointer) {
3390 code += " } } else if (" + out_field + ") { " + out_field +
3391 ".reset(); }";
3392 }
3393 }
3394 break;
3395 }
3396 }
3397 return code;
3398 }
3399
GenCreateParam(const FieldDef & field)3400 std::string GenCreateParam(const FieldDef &field) {
3401 std::string value = "_o->";
3402 if (field.value.type.base_type == BASE_TYPE_UTYPE) {
3403 value += StripUnionType(Name(field));
3404 value += ".type";
3405 } else {
3406 value += Name(field);
3407 }
3408 if (!IsVector(field.value.type) && field.attributes.Lookup("cpp_type")) {
3409 auto type = GenTypeBasic(field.value.type, false);
3410 value =
3411 "_rehasher ? "
3412 "static_cast<" +
3413 type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
3414 }
3415
3416 std::string code;
3417 switch (field.value.type.base_type) {
3418 // String fields are of the form:
3419 // _fbb.CreateString(_o->field)
3420 // or
3421 // _fbb.CreateSharedString(_o->field)
3422 case BASE_TYPE_STRING: {
3423 if (!field.shared) {
3424 code +=
3425 "_fbb.CreateString" +
3426 std::string(field.offset64 ? "<::flatbuffers::Offset64>" : "") +
3427 "(";
3428 } else {
3429 code += "_fbb.CreateSharedString(";
3430 }
3431 code += value;
3432 code.push_back(')');
3433
3434 // For optional fields, check to see if there actually is any data
3435 // in _o->field before attempting to access it. If there isn't,
3436 // depending on set_empty_strings_to_null either set it to 0 or an empty
3437 // string.
3438 if (!field.IsRequired()) {
3439 auto empty_value = opts_.set_empty_strings_to_null
3440 ? "0"
3441 : "_fbb.CreateSharedString(\"\")";
3442 code = value + ".empty() ? " + empty_value + " : " + code;
3443 }
3444 break;
3445 }
3446 // Vector fields come in several flavours, of the forms:
3447 // _fbb.CreateVector(_o->field);
3448 // _fbb.CreateVector((const utype*)_o->field.data(),
3449 // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field)
3450 // _fbb.CreateVectorOfStructs(_o->field)
3451 // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
3452 // return CreateT(_fbb, _o->Get(i), rehasher);
3453 // });
3454 case BASE_TYPE_VECTOR64:
3455 case BASE_TYPE_VECTOR: {
3456 auto vector_type = field.value.type.VectorType();
3457 switch (vector_type.base_type) {
3458 case BASE_TYPE_STRING: {
3459 if (NativeString(&field) == "std::string") {
3460 code += "_fbb.CreateVectorOfStrings(" + value + ")";
3461 } else {
3462 // Use by-function serialization to emulate
3463 // CreateVectorOfStrings(); this works also with non-std strings.
3464 code +=
3465 "_fbb.CreateVector<::flatbuffers::Offset<::flatbuffers::"
3466 "String>>"
3467 " ";
3468 code += "(" + value + ".size(), ";
3469 code += "[](size_t i, _VectorArgs *__va) { ";
3470 code +=
3471 "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
3472 code += " }, &_va )";
3473 }
3474 break;
3475 }
3476 case BASE_TYPE_STRUCT: {
3477 if (IsStruct(vector_type)) {
3478 const auto &struct_attrs =
3479 field.value.type.struct_def->attributes;
3480 const auto native_type = struct_attrs.Lookup("native_type");
3481 if (native_type) {
3482 code += "_fbb.CreateVectorOfNativeStructs<";
3483 code += WrapInNameSpace(*vector_type.struct_def) + ", " +
3484 native_type->constant + ">";
3485 code += "(" + value;
3486 const auto pack_name =
3487 struct_attrs.Lookup("native_type_pack_name");
3488 if (pack_name) {
3489 code += ", ::flatbuffers::Pack" + pack_name->constant;
3490 }
3491 code += ")";
3492 } else {
3493 // If the field uses 64-bit addressing, create a 64-bit vector.
3494 if (field.value.type.base_type == BASE_TYPE_VECTOR64) {
3495 code += "_fbb.CreateVectorOfStructs64";
3496 } else {
3497 code += "_fbb.CreateVectorOfStructs";
3498 if (field.offset64) {
3499 // This is normal 32-bit vector, with 64-bit addressing.
3500 code += "64<::flatbuffers::Vector>";
3501 }
3502 }
3503 code += "(" + value + ")";
3504 }
3505 } else {
3506 code += "_fbb.CreateVector<::flatbuffers::Offset<";
3507 code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
3508 code += "(" + value + ".size(), ";
3509 code += "[](size_t i, _VectorArgs *__va) { ";
3510 code += "return Create" + vector_type.struct_def->name;
3511 code += "(*__va->__fbb, ";
3512 if (field.native_inline) {
3513 code += "&(__va->_" + value + "[i])";
3514 } else {
3515 code += "__va->_" + value + "[i]" + GenPtrGet(field);
3516 }
3517 code += ", __va->__rehasher); }, &_va )";
3518 }
3519 break;
3520 }
3521 case BASE_TYPE_BOOL: {
3522 code += "_fbb.CreateVector(" + value + ")";
3523 break;
3524 }
3525 case BASE_TYPE_UNION: {
3526 code +=
3527 "_fbb.CreateVector<::flatbuffers::"
3528 "Offset<void>>(" +
3529 value +
3530 ".size(), [](size_t i, _VectorArgs *__va) { "
3531 "return __va->_" +
3532 value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
3533 break;
3534 }
3535 case BASE_TYPE_UTYPE: {
3536 value = StripUnionType(value);
3537 auto underlying_type = GenTypeBasic(vector_type, false);
3538 const std::string &type = opts_.scoped_enums
3539 ? Name(*field.value.type.enum_def)
3540 : underlying_type;
3541 auto enum_value = "__va->_" + value + "[i].type";
3542 if (!opts_.scoped_enums)
3543 enum_value =
3544 "static_cast<" + underlying_type + ">(" + enum_value + ")";
3545
3546 code += "_fbb.CreateVector<" + type + ">(" + value +
3547 ".size(), [](size_t i, _VectorArgs *__va) { return " +
3548 enum_value + "; }, &_va)";
3549 break;
3550 }
3551 default: {
3552 if (field.value.type.enum_def &&
3553 !VectorElementUserFacing(vector_type)) {
3554 // For enumerations, we need to get access to the array data for
3555 // the underlying storage type (eg. uint8_t).
3556 const auto basetype = GenTypeBasic(
3557 field.value.type.enum_def->underlying_type, false);
3558 code += "_fbb.CreateVectorScalarCast<" + basetype +
3559 ">(::flatbuffers::data(" + value + "), " + value +
3560 ".size())";
3561 } else if (field.attributes.Lookup("cpp_type")) {
3562 auto type = GenTypeBasic(vector_type, false);
3563 code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
3564 code += "[](size_t i, _VectorArgs *__va) { ";
3565 code += "return __va->__rehasher ? ";
3566 code += "static_cast<" + type + ">((*__va->__rehasher)";
3567 code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
3568 code += "; }, &_va )";
3569 } else {
3570 // If the field uses 64-bit addressing, create a 64-bit vector.
3571 if (field.value.type.base_type == BASE_TYPE_VECTOR64) {
3572 code += "_fbb.CreateVector64(" + value + ")";
3573 } else {
3574 code += "_fbb.CreateVector";
3575 if (field.offset64) {
3576 // This is normal 32-bit vector, with 64-bit addressing.
3577 code += "64<::flatbuffers::Vector>";
3578 }
3579 code += "(" + value + ")";
3580 }
3581 }
3582 break;
3583 }
3584 }
3585
3586 // If set_empty_vectors_to_null option is enabled, for optional fields,
3587 // check to see if there actually is any data in _o->field before
3588 // attempting to access it.
3589 if (field.attributes.Lookup("nested_flatbuffer") ||
3590 (opts_.set_empty_vectors_to_null && !field.IsRequired())) {
3591 code = value + ".size() ? " + code + " : 0";
3592 }
3593 break;
3594 }
3595 case BASE_TYPE_UNION: {
3596 // _o->field.Pack(_fbb);
3597 code += value + ".Pack(_fbb)";
3598 break;
3599 }
3600 case BASE_TYPE_STRUCT: {
3601 if (IsStruct(field.value.type)) {
3602 const auto &struct_attribs = field.value.type.struct_def->attributes;
3603 const auto native_type = struct_attribs.Lookup("native_type");
3604 if (native_type) {
3605 code += "::flatbuffers::Pack";
3606 const auto pack_name =
3607 struct_attribs.Lookup("native_type_pack_name");
3608 if (pack_name) { code += pack_name->constant; }
3609 code += "(" + value + ")";
3610 } else if (field.native_inline) {
3611 code += "&" + value;
3612 } else {
3613 code += value + " ? " + value + GenPtrGet(field) + " : nullptr";
3614 }
3615 } else {
3616 // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
3617 const std::string &type = field.value.type.struct_def->name;
3618 code += value + " ? Create" + type;
3619 code += "(_fbb, " + value;
3620 if (!field.native_inline) code += GenPtrGet(field);
3621 code += ", _rehasher) : 0";
3622 }
3623 break;
3624 }
3625 default: {
3626 code += value;
3627 break;
3628 }
3629 }
3630 return code;
3631 }
3632
3633 // Generate code for tables that needs to come after the regular definition.
GenTablePost(const StructDef & struct_def)3634 void GenTablePost(const StructDef &struct_def) {
3635 if (opts_.generate_object_based_api) { GenNativeTablePost(struct_def); }
3636
3637 code_.SetValue("STRUCT_NAME", Name(struct_def));
3638 code_.SetValue("NATIVE_NAME",
3639 NativeName(Name(struct_def), &struct_def, opts_));
3640
3641 if (opts_.generate_object_based_api) {
3642 // Generate the >= C++11 copy ctor and assignment operator definitions.
3643 GenCopyCtorAssignOpDefs(struct_def);
3644
3645 // Generate the X::UnPack() method.
3646 code_ +=
3647 "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
3648
3649 if (opts_.g_cpp_std == cpp::CPP_STD_X0) {
3650 auto native_name = WrapNativeNameInNameSpace(struct_def, parser_.opts);
3651 code_.SetValue("POINTER_TYPE",
3652 GenTypeNativePtr(native_name, nullptr, false));
3653 code_ +=
3654 " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
3655 } else if (opts_.g_cpp_std == cpp::CPP_STD_11) {
3656 code_ +=
3657 " auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new "
3658 "{{NATIVE_NAME}}());";
3659 } else {
3660 code_ += " auto _o = std::make_unique<{{NATIVE_NAME}}>();";
3661 }
3662 code_ += " UnPackTo(_o.get(), _resolver);";
3663 code_ += " return _o.release();";
3664 code_ += "}";
3665 code_ += "";
3666 code_ +=
3667 "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
3668 code_ += " (void)_o;";
3669 code_ += " (void)_resolver;";
3670
3671 for (auto it = struct_def.fields.vec.begin();
3672 it != struct_def.fields.vec.end(); ++it) {
3673 const auto &field = **it;
3674 if (field.deprecated) { continue; }
3675
3676 // Assign a value from |this| to |_o|. Values from |this| are stored
3677 // in a variable |_e| by calling this->field_type(). The value is then
3678 // assigned to |_o| using the GenUnpackFieldStatement.
3679 const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
3680 const auto statement =
3681 GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
3682
3683 code_.SetValue("FIELD_NAME", Name(field));
3684 auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
3685 auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
3686 auto postfix = " }";
3687 code_ += std::string(prefix) + check + statement + postfix;
3688 }
3689 code_ += "}";
3690 code_ += "";
3691
3692 // Generate the X::Pack member function that simply calls the global
3693 // CreateX function.
3694 code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
3695 code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
3696 code_ += "}";
3697 code_ += "";
3698
3699 // Generate a CreateX method that works with an unpacked C++ object.
3700 code_ +=
3701 "inline " + TableCreateSignature(struct_def, false, opts_) + " {";
3702 code_ += " (void)_rehasher;";
3703 code_ += " (void)_o;";
3704
3705 code_ +=
3706 " struct _VectorArgs "
3707 "{ " +
3708 GetBuilder() +
3709 " *__fbb; "
3710 "const " +
3711 NativeName(Name(struct_def), &struct_def, opts_) +
3712 "* __o; "
3713 "const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { "
3714 "&_fbb, _o, _rehasher}; (void)_va;";
3715
3716 for (auto it = struct_def.fields.vec.begin();
3717 it != struct_def.fields.vec.end(); ++it) {
3718 auto &field = **it;
3719 if (field.deprecated) { continue; }
3720 if (IsVector(field.value.type)) {
3721 const std::string force_align_code =
3722 GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
3723 if (!force_align_code.empty()) { code_ += " " + force_align_code; }
3724 }
3725 code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
3726 }
3727 // Need to call "Create" with the struct namespace.
3728 const auto qualified_create_name =
3729 struct_def.defined_namespace->GetFullyQualifiedName("Create");
3730 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
3731
3732 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
3733 code_ += " _fbb\\";
3734 for (const auto &field : struct_def.fields.vec) {
3735 if (field->deprecated) { continue; }
3736
3737 bool pass_by_address = false;
3738 if (field->value.type.base_type == BASE_TYPE_STRUCT) {
3739 if (IsStruct(field->value.type)) {
3740 auto native_type =
3741 field->value.type.struct_def->attributes.Lookup("native_type");
3742 if (native_type) { pass_by_address = true; }
3743 }
3744 }
3745
3746 // Call the CreateX function using values from |_o|.
3747 if (pass_by_address) {
3748 code_ += ",\n &_" + Name(*field) + "\\";
3749 } else {
3750 code_ += ",\n _" + Name(*field) + "\\";
3751 }
3752 }
3753 code_ += ");";
3754 code_ += "}";
3755 code_ += "";
3756 }
3757 }
3758
GenPadding(const FieldDef & field,std::string * code_ptr,int * id,const std::function<void (int bits,std::string * code_ptr,int * id)> & f)3759 static void GenPadding(
3760 const FieldDef &field, std::string *code_ptr, int *id,
3761 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
3762 if (field.padding) {
3763 for (int i = 0; i < 4; i++) {
3764 if (static_cast<int>(field.padding) & (1 << i)) {
3765 f((1 << i) * 8, code_ptr, id);
3766 }
3767 }
3768 FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
3769 }
3770 }
3771
PaddingDefinition(int bits,std::string * code_ptr,int * id)3772 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
3773 *code_ptr += " int" + NumToString(bits) + "_t padding" +
3774 NumToString((*id)++) + "__;";
3775 }
3776
PaddingInitializer(int bits,std::string * code_ptr,int * id)3777 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
3778 (void)bits;
3779 if (!code_ptr->empty()) *code_ptr += ",\n ";
3780 *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
3781 }
3782
PaddingNoop(int bits,std::string * code_ptr,int * id)3783 static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
3784 (void)bits;
3785 if (!code_ptr->empty()) *code_ptr += '\n';
3786 *code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
3787 }
3788
GenStructDefaultConstructor(const StructDef & struct_def)3789 void GenStructDefaultConstructor(const StructDef &struct_def) {
3790 std::string init_list;
3791 std::string body;
3792 bool first_in_init_list = true;
3793 int padding_initializer_id = 0;
3794 int padding_body_id = 0;
3795 for (const auto &field : struct_def.fields.vec) {
3796 const auto field_name = Name(*field) + "_";
3797
3798 if (first_in_init_list) {
3799 first_in_init_list = false;
3800 } else {
3801 init_list += ",";
3802 init_list += "\n ";
3803 }
3804
3805 init_list += field_name;
3806 if (IsStruct(field->value.type) || IsArray(field->value.type)) {
3807 // this is either default initialization of struct
3808 // or
3809 // implicit initialization of array
3810 // for each object in array it:
3811 // * sets it as zeros for POD types (integral, floating point, etc)
3812 // * calls default constructor for classes/structs
3813 init_list += "()";
3814 } else {
3815 init_list += "(0)";
3816 }
3817 if (field->padding) {
3818 GenPadding(*field, &init_list, &padding_initializer_id,
3819 PaddingInitializer);
3820 GenPadding(*field, &body, &padding_body_id, PaddingNoop);
3821 }
3822 }
3823
3824 if (init_list.empty()) {
3825 code_ += " {{STRUCT_NAME}}()";
3826 code_ += " {}";
3827 } else {
3828 code_.SetValue("INIT_LIST", init_list);
3829 code_ += " {{STRUCT_NAME}}()";
3830 code_ += " : {{INIT_LIST}} {";
3831 if (!body.empty()) { code_ += body; }
3832 code_ += " }";
3833 }
3834 }
3835
GenStructConstructor(const StructDef & struct_def,GenArrayArgMode array_mode)3836 void GenStructConstructor(const StructDef &struct_def,
3837 GenArrayArgMode array_mode) {
3838 std::string arg_list;
3839 std::string init_list;
3840 int padding_id = 0;
3841 auto first = struct_def.fields.vec.begin();
3842 // skip arrays if generate ctor without array assignment
3843 const auto init_arrays = (array_mode != kArrayArgModeNone);
3844 for (auto it = struct_def.fields.vec.begin();
3845 it != struct_def.fields.vec.end(); ++it) {
3846 const auto &field = **it;
3847 const auto &type = field.value.type;
3848 const auto is_array = IsArray(type);
3849 const auto arg_name = "_" + Name(field);
3850 if (!is_array || init_arrays) {
3851 if (it != first && !arg_list.empty()) { arg_list += ", "; }
3852 arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true)
3853 : GenTypeSpan(type, true, type.fixed_length);
3854 arg_list += arg_name;
3855 }
3856 // skip an array with initialization from span
3857 if (false == (is_array && init_arrays)) {
3858 if (it != first && !init_list.empty()) { init_list += ",\n "; }
3859 init_list += Name(field) + "_";
3860 if (IsScalar(type.base_type)) {
3861 auto scalar_type = GenUnderlyingCast(field, false, arg_name);
3862 init_list += "(::flatbuffers::EndianScalar(" + scalar_type + "))";
3863 } else {
3864 FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type));
3865 if (!is_array)
3866 init_list += "(" + arg_name + ")";
3867 else
3868 init_list += "()";
3869 }
3870 }
3871 if (field.padding)
3872 GenPadding(field, &init_list, &padding_id, PaddingInitializer);
3873 }
3874
3875 if (!arg_list.empty()) {
3876 code_.SetValue("ARG_LIST", arg_list);
3877 code_.SetValue("INIT_LIST", init_list);
3878 if (!init_list.empty()) {
3879 code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
3880 code_ += " : {{INIT_LIST}} {";
3881 } else {
3882 code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
3883 }
3884 padding_id = 0;
3885 for (const auto &field : struct_def.fields.vec) {
3886 const auto &type = field->value.type;
3887 if (IsArray(type) && init_arrays) {
3888 const auto &element_type = type.VectorType();
3889 const auto is_enum = IsEnum(element_type);
3890 FLATBUFFERS_ASSERT(
3891 (IsScalar(element_type.base_type) || IsStruct(element_type)) &&
3892 "invalid declaration");
3893 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3894 std::string get_array =
3895 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3896 const auto field_name = Name(*field) + "_";
3897 const auto arg_name = "_" + Name(*field);
3898 code_ += " ::flatbuffers::" + get_array + "(" + field_name +
3899 ").CopyFromSpan(" + arg_name + ");";
3900 }
3901 if (field->padding) {
3902 std::string padding;
3903 GenPadding(*field, &padding, &padding_id, PaddingNoop);
3904 code_ += padding;
3905 }
3906 }
3907 code_ += " }";
3908 }
3909 }
3910
GenArrayAccessor(const Type & type,bool mutable_accessor)3911 void GenArrayAccessor(const Type &type, bool mutable_accessor) {
3912 FLATBUFFERS_ASSERT(IsArray(type));
3913 const auto is_enum = IsEnum(type.VectorType());
3914 // The Array<bool,N> is a tricky case, like std::vector<bool>.
3915 // It requires a specialization of Array class.
3916 // Generate Array<uint8_t> for Array<bool>.
3917 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3918 std::string ret_type = "::flatbuffers::Array<" + face_type + ", " +
3919 NumToString(type.fixed_length) + ">";
3920 if (mutable_accessor)
3921 code_ += " " + ret_type + " *mutable_{{FIELD_NAME}}() {";
3922 else
3923 code_ += " const " + ret_type + " *{{FIELD_NAME}}() const {";
3924
3925 std::string get_array =
3926 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3927 code_ += " return &::flatbuffers::" + get_array + "({{FIELD_VALUE}});";
3928 code_ += " }";
3929 }
3930
3931 // Generate an accessor struct with constructor for a flatbuffers struct.
GenStruct(const StructDef & struct_def)3932 void GenStruct(const StructDef &struct_def) {
3933 // Generate an accessor struct, with private variables of the form:
3934 // type name_;
3935 // Generates manual padding and alignment.
3936 // Variables are private because they contain little endian data on all
3937 // platforms.
3938 GenComment(struct_def.doc_comment);
3939 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
3940 code_.SetValue("STRUCT_NAME", Name(struct_def));
3941
3942 code_ +=
3943 "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
3944 "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
3945 code_ += " private:";
3946
3947 int padding_id = 0;
3948 for (const auto &field : struct_def.fields.vec) {
3949 const auto &field_type = field->value.type;
3950 code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
3951 code_.SetValue("FIELD_NAME", Name(*field));
3952 code_.SetValue("ARRAY",
3953 IsArray(field_type)
3954 ? "[" + NumToString(field_type.fixed_length) + "]"
3955 : "");
3956 code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
3957
3958 if (field->padding) {
3959 std::string padding;
3960 GenPadding(*field, &padding, &padding_id, PaddingDefinition);
3961 code_ += padding;
3962 }
3963 }
3964
3965 // Generate GetFullyQualifiedName
3966 code_ += "";
3967 code_ += " public:";
3968
3969 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
3970
3971 // Make TypeTable accessible via the generated struct.
3972 if (opts_.mini_reflect != IDLOptions::kNone) {
3973 code_ +=
3974 " static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {";
3975 code_ += " return {{STRUCT_NAME}}TypeTable();";
3976 code_ += " }";
3977 }
3978
3979 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
3980
3981 // Generate a default constructor.
3982 GenStructDefaultConstructor(struct_def);
3983
3984 // Generate a constructor that takes all fields as arguments,
3985 // excluding arrays.
3986 GenStructConstructor(struct_def, kArrayArgModeNone);
3987
3988 auto arrays_num = std::count_if(
3989 struct_def.fields.vec.begin(), struct_def.fields.vec.end(),
3990 [](const FieldDef *fd) { return IsArray(fd->value.type); });
3991 if (arrays_num > 0) {
3992 GenStructConstructor(struct_def, kArrayArgModeSpanStatic);
3993 }
3994
3995 // Generate accessor methods of the form:
3996 // type name() const { return ::flatbuffers::EndianScalar(name_); }
3997 for (const auto &field : struct_def.fields.vec) {
3998 const auto &type = field->value.type;
3999 const auto is_scalar = IsScalar(type.base_type);
4000 const auto is_array = IsArray(type);
4001
4002 const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ",
4003 is_array ? "" : " &", true);
4004 auto member = Name(*field) + "_";
4005 const std::string &value =
4006 is_scalar ? "::flatbuffers::EndianScalar(" + member + ")" : member;
4007
4008 code_.SetValue("FIELD_NAME", Name(*field));
4009 code_.SetValue("FIELD_TYPE", field_type);
4010 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(*field, true, value));
4011
4012 GenComment(field->doc_comment, " ");
4013
4014 // Generate a const accessor function.
4015 if (is_array) {
4016 GenArrayAccessor(type, false);
4017 } else {
4018 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
4019 code_ += " return {{FIELD_VALUE}};";
4020 code_ += " }";
4021 }
4022
4023 // Generate a mutable accessor function.
4024 if (opts_.mutable_buffer) {
4025 auto mut_field_type =
4026 GenTypeGet(type, " ", "", is_array ? "" : " &", true);
4027 code_.SetValue("FIELD_TYPE", mut_field_type);
4028 if (is_scalar) {
4029 code_.SetValue("ARG", GenTypeBasic(type, true));
4030 code_.SetValue("FIELD_VALUE",
4031 GenUnderlyingCast(*field, false, "_" + Name(*field)));
4032
4033 code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
4034 code_ +=
4035 " ::flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
4036 "{{FIELD_VALUE}});";
4037 code_ += " }";
4038 } else if (is_array) {
4039 GenArrayAccessor(type, true);
4040 } else {
4041 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
4042 code_ += " return {{FIELD_VALUE}};";
4043 code_ += " }";
4044 }
4045 }
4046
4047 // Generate a comparison function for this field if it is a key.
4048 if (field->key) { GenKeyFieldMethods(*field); }
4049 }
4050 code_.SetValue("NATIVE_NAME", Name(struct_def));
4051 GenOperatorNewDelete(struct_def);
4052
4053 if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
4054
4055 code_ += "};";
4056
4057 code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
4058 code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
4059 if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
4060 code_ += "";
4061
4062 // Definition for type traits for this table type. This allows querying var-
4063 // ious compile-time traits of the table.
4064 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
4065 }
4066
4067 // Set up the correct namespace. Only open a namespace if the existing one is
4068 // different (closing/opening only what is necessary).
4069 //
4070 // The file must start and end with an empty (or null) namespace so that
4071 // namespaces are properly opened and closed.
SetNameSpace(const Namespace * ns)4072 void SetNameSpace(const Namespace *ns) {
4073 if (cur_name_space_ == ns) { return; }
4074
4075 // Compute the size of the longest common namespace prefix.
4076 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
4077 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
4078 // and common_prefix_size = 2
4079 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
4080 size_t new_size = ns ? ns->components.size() : 0;
4081
4082 size_t common_prefix_size = 0;
4083 while (common_prefix_size < old_size && common_prefix_size < new_size &&
4084 ns->components[common_prefix_size] ==
4085 cur_name_space_->components[common_prefix_size]) {
4086 common_prefix_size++;
4087 }
4088
4089 // Close cur_name_space in reverse order to reach the common prefix.
4090 // In the previous example, D then C are closed.
4091 for (size_t j = old_size; j > common_prefix_size; --j) {
4092 code_ += "} // namespace " + cur_name_space_->components[j - 1];
4093 }
4094 if (old_size != common_prefix_size) { code_ += ""; }
4095
4096 // open namespace parts to reach the ns namespace
4097 // in the previous example, E, then F, then G are opened
4098 for (auto j = common_prefix_size; j != new_size; ++j) {
4099 code_ += "namespace " + ns->components[j] + " {";
4100 }
4101 if (new_size != common_prefix_size) { code_ += ""; }
4102
4103 cur_name_space_ = ns;
4104 }
4105 };
4106
4107 } // namespace cpp
4108
GenerateCPP(const Parser & parser,const std::string & path,const std::string & file_name)4109 static bool GenerateCPP(const Parser &parser, const std::string &path,
4110 const std::string &file_name) {
4111 cpp::IDLOptionsCpp opts(parser.opts);
4112 // The '--cpp_std' argument could be extended (like ASAN):
4113 // Example: "flatc --cpp_std c++17:option1:option2".
4114 std::string cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++11";
4115 std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), CharToUpper);
4116 if (cpp_std == "C++0X") {
4117 opts.g_cpp_std = cpp::CPP_STD_X0;
4118 opts.g_only_fixed_enums = false;
4119 } else if (cpp_std == "C++11") {
4120 // Use the standard C++11 code generator.
4121 opts.g_cpp_std = cpp::CPP_STD_11;
4122 opts.g_only_fixed_enums = true;
4123 } else if (cpp_std == "C++17") {
4124 opts.g_cpp_std = cpp::CPP_STD_17;
4125 // With c++17 generate strong enums only.
4126 opts.scoped_enums = true;
4127 // By default, prefixed_enums==true, reset it.
4128 opts.prefixed_enums = false;
4129 } else {
4130 LogCompilerError("Unknown value of the '--cpp-std' switch: " +
4131 opts.cpp_std);
4132 return false;
4133 }
4134 // The opts.scoped_enums has priority.
4135 opts.g_only_fixed_enums |= opts.scoped_enums;
4136
4137 if (opts.cpp_static_reflection && opts.g_cpp_std < cpp::CPP_STD_17) {
4138 LogCompilerError(
4139 "--cpp-static-reflection requires using --cpp-std at \"C++17\" or "
4140 "higher.");
4141 return false;
4142 }
4143
4144 cpp::CppGenerator generator(parser, path, file_name, opts);
4145 return generator.generate();
4146 }
4147
CPPMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)4148 static std::string CPPMakeRule(const Parser &parser, const std::string &path,
4149 const std::string &file_name) {
4150 const auto filebase = StripPath(StripExtension(file_name));
4151 cpp::CppGenerator geneartor(parser, path, file_name, parser.opts);
4152 const auto included_files = parser.GetIncludedFilesRecursive(file_name);
4153 std::string make_rule =
4154 geneartor.GeneratedFileName(path, filebase, parser.opts) + ": ";
4155 for (const std::string &included_file : included_files) {
4156 make_rule += " " + included_file;
4157 }
4158 return make_rule;
4159 }
4160
4161 namespace {
4162
4163 class CppCodeGenerator : public CodeGenerator {
4164 public:
GenerateCode(const Parser & parser,const std::string & path,const std::string & filename)4165 Status GenerateCode(const Parser &parser, const std::string &path,
4166 const std::string &filename) override {
4167 if (!GenerateCPP(parser, path, filename)) { return Status::ERROR; }
4168 return Status::OK;
4169 }
4170
4171 // Generate code from the provided `buffer` of given `length`. The buffer is a
4172 // serialized reflection.fbs.
GenerateCode(const uint8_t *,int64_t,const CodeGenOptions &)4173 Status GenerateCode(const uint8_t *, int64_t,
4174 const CodeGenOptions &) override {
4175 return Status::NOT_IMPLEMENTED;
4176 }
4177
GenerateMakeRule(const Parser & parser,const std::string & path,const std::string & filename,std::string & output)4178 Status GenerateMakeRule(const Parser &parser, const std::string &path,
4179 const std::string &filename,
4180 std::string &output) override {
4181 output = CPPMakeRule(parser, path, filename);
4182 return Status::OK;
4183 }
4184
GenerateGrpcCode(const Parser & parser,const std::string & path,const std::string & filename)4185 Status GenerateGrpcCode(const Parser &parser, const std::string &path,
4186 const std::string &filename) override {
4187 if (!GenerateCppGRPC(parser, path, filename)) { return Status::ERROR; }
4188 return Status::OK;
4189 }
4190
GenerateRootFile(const Parser & parser,const std::string & path)4191 Status GenerateRootFile(const Parser &parser,
4192 const std::string &path) override {
4193 (void)parser;
4194 (void)path;
4195 return Status::NOT_IMPLEMENTED;
4196 }
4197
IsSchemaOnly() const4198 bool IsSchemaOnly() const override { return true; }
4199
SupportsBfbsGeneration() const4200 bool SupportsBfbsGeneration() const override { return false; }
4201
SupportsRootFileGeneration() const4202 bool SupportsRootFileGeneration() const override { return false; }
4203
Language() const4204 IDLOptions::Language Language() const override { return IDLOptions::kCpp; }
4205
LanguageName() const4206 std::string LanguageName() const override { return "C++"; }
4207 };
4208
4209 } // namespace
4210
NewCppCodeGenerator()4211 std::unique_ptr<CodeGenerator> NewCppCodeGenerator() {
4212 return std::unique_ptr<CppCodeGenerator>(new CppCodeGenerator());
4213 }
4214
4215 } // namespace flatbuffers
4216