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