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