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