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