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