[C++] #6501 - Problem when mapping a native type multiple times (#6514)
[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           // Don't generate code to copy if table is not copyable.
1539           // TODO(wvo): make tables copyable instead.
1540           for (auto fit = ev.union_type.struct_def->fields.vec.begin();
1541                fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
1542             const auto &field = **fit;
1543             if (!field.deprecated && field.value.type.struct_def &&
1544                 !field.native_inline) {
1545               copyable = false;
1546               break;
1547             }
1548           }
1549         }
1550         if (copyable) {
1551           code_ +=
1552               "      value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
1553               "(u.value));";
1554         } else {
1555           code_ +=
1556               "      FLATBUFFERS_ASSERT(false);  // {{TYPE}} not copyable.";
1557         }
1558         code_ += "      break;";
1559         code_ += "    }";
1560       }
1561       code_ += "    default:";
1562       code_ += "      break;";
1563       code_ += "  }";
1564       code_ += "}";
1565       code_ += "";
1566
1567       // Union Reset() function.
1568       FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1569       code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1570
1571       code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
1572       code_ += "  switch (type) {";
1573       for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1574            ++it) {
1575         const auto &ev = **it;
1576         if (ev.IsZero()) { continue; }
1577         code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1578         code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
1579         code_ += "    case {{LABEL}}: {";
1580         code_ += "      auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
1581         code_ += "      delete ptr;";
1582         code_ += "      break;";
1583         code_ += "    }";
1584       }
1585       code_ += "    default: break;";
1586       code_ += "  }";
1587       code_ += "  value = nullptr;";
1588       code_ += "  type = {{NONE}};";
1589       code_ += "}";
1590       code_ += "";
1591     }
1592   }
1593
1594   // Generates a value with optionally a cast applied if the field has a
1595   // different underlying type from its interface type (currently only the
1596   // case for enums. "from" specify the direction, true meaning from the
1597   // underlying type to the interface type.
1598   std::string GenUnderlyingCast(const FieldDef &field, bool from,
1599                                 const std::string &val) {
1600     if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
1601       return val + " != 0";
1602     } else if ((field.value.type.enum_def &&
1603                 IsScalar(field.value.type.base_type)) ||
1604                field.value.type.base_type == BASE_TYPE_BOOL) {
1605       return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
1606              val + ")";
1607     } else {
1608       return val;
1609     }
1610   }
1611
1612   std::string GenFieldOffsetName(const FieldDef &field) {
1613     std::string uname = Name(field);
1614     std::transform(uname.begin(), uname.end(), uname.begin(), CharToUpper);
1615     return "VT_" + uname;
1616   }
1617
1618   void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1619                                    const std::string &name) {
1620     if (!opts_.generate_name_strings) { return; }
1621     auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
1622     code_.SetValue("NAME", fullname);
1623     code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
1624     code_ += "  static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
1625     code_ += "    return \"{{NAME}}\";";
1626     code_ += "  }";
1627   }
1628
1629   std::string GenDefaultConstant(const FieldDef &field) {
1630     if (IsFloat(field.value.type.base_type))
1631       return float_const_gen_.GenFloatConstant(field);
1632     else
1633       return NumToStringCpp(field.value.constant, field.value.type.base_type);
1634   }
1635
1636   std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
1637     const auto &type = field.value.type;
1638     if (field.IsScalarOptional()) {
1639       return GenOptionalNull();
1640     } else if (type.enum_def && IsScalar(type.base_type)) {
1641       auto ev = type.enum_def->FindByValue(field.value.constant);
1642       if (ev) {
1643         return WrapInNameSpace(type.enum_def->defined_namespace,
1644                                GetEnumValUse(*type.enum_def, *ev));
1645       } else {
1646         return GenUnderlyingCast(
1647             field, true, NumToStringCpp(field.value.constant, type.base_type));
1648       }
1649     } else if (type.base_type == BASE_TYPE_BOOL) {
1650       return field.value.constant == "0" ? "false" : "true";
1651     } else if (field.attributes.Lookup("cpp_type")) {
1652       if (is_ctor) {
1653         if (PtrType(&field) == "naked") {
1654           return "nullptr";
1655         } else {
1656           return "";
1657         }
1658       } else {
1659         return "0";
1660       }
1661     } else {
1662       return GenDefaultConstant(field);
1663     }
1664   }
1665
1666   void GenParam(const FieldDef &field, bool direct, const char *prefix) {
1667     code_.SetValue("PRE", prefix);
1668     code_.SetValue("PARAM_NAME", Name(field));
1669     if (direct && IsString(field.value.type)) {
1670       code_.SetValue("PARAM_TYPE", "const char *");
1671       code_.SetValue("PARAM_VALUE", "nullptr");
1672     } else if (direct && IsVector(field.value.type)) {
1673       const auto vtype = field.value.type.VectorType();
1674       std::string type;
1675       if (IsStruct(vtype)) {
1676         type = WrapInNameSpace(*vtype.struct_def);
1677       } else {
1678         type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
1679       }
1680       if (TypeHasKey(vtype)) {
1681         code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
1682       } else {
1683         code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
1684       }
1685       code_.SetValue("PARAM_VALUE", "nullptr");
1686     } else {
1687       const auto &type = field.value.type;
1688       code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
1689       if (field.IsScalarOptional())
1690         code_.SetValue("PARAM_TYPE", GenOptionalDecl(type) + " ");
1691       else
1692         code_.SetValue("PARAM_TYPE", GenTypeWire(type, " ", true));
1693     }
1694     code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
1695   }
1696
1697   // Generate a member, including a default value for scalars and raw pointers.
1698   void GenMember(const FieldDef &field) {
1699     if (!field.deprecated &&  // Deprecated fields won't be accessible.
1700         field.value.type.base_type != BASE_TYPE_UTYPE &&
1701         (field.value.type.base_type != BASE_TYPE_VECTOR ||
1702          field.value.type.element != BASE_TYPE_UTYPE)) {
1703       auto type = GenTypeNative(field.value.type, false, field);
1704       auto cpp_type = field.attributes.Lookup("cpp_type");
1705       auto full_type =
1706           (cpp_type
1707                ? (IsVector(field.value.type)
1708                       ? "std::vector<" +
1709                             GenTypeNativePtr(cpp_type->constant, &field,
1710                                              false) +
1711                             "> "
1712                       : GenTypeNativePtr(cpp_type->constant, &field, false))
1713                : type + " ");
1714       // Generate default member initializers for >= C++11.
1715       std::string field_di = "";
1716       if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
1717         field_di = "{}";
1718         auto native_default = field.attributes.Lookup("native_default");
1719         // Scalar types get parsed defaults, raw pointers get nullptrs.
1720         if (IsScalar(field.value.type.base_type)) {
1721           field_di =
1722               " = " + (native_default ? std::string(native_default->constant)
1723                                       : GetDefaultScalarValue(field, true));
1724         } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1725           if (IsStruct(field.value.type) && native_default) {
1726             field_di = " = " + native_default->constant;
1727           }
1728         }
1729       }
1730       code_.SetValue("FIELD_TYPE", full_type);
1731       code_.SetValue("FIELD_NAME", Name(field));
1732       code_.SetValue("FIELD_DI", field_di);
1733       code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}{{FIELD_DI}};";
1734     }
1735   }
1736
1737   // Generate the default constructor for this struct. Properly initialize all
1738   // scalar members with default values.
1739   void GenDefaultConstructor(const StructDef &struct_def) {
1740     code_.SetValue("NATIVE_NAME",
1741                    NativeName(Name(struct_def), &struct_def, opts_));
1742     // In >= C++11, default member initializers are generated.
1743     if (opts_.g_cpp_std >= cpp::CPP_STD_11) { return; }
1744     std::string initializer_list;
1745     for (auto it = struct_def.fields.vec.begin();
1746          it != struct_def.fields.vec.end(); ++it) {
1747       const auto &field = **it;
1748       if (!field.deprecated &&  // Deprecated fields won't be accessible.
1749           field.value.type.base_type != BASE_TYPE_UTYPE) {
1750         auto cpp_type = field.attributes.Lookup("cpp_type");
1751         auto native_default = field.attributes.Lookup("native_default");
1752         // Scalar types get parsed defaults, raw pointers get nullptrs.
1753         if (IsScalar(field.value.type.base_type)) {
1754           if (!initializer_list.empty()) { initializer_list += ",\n        "; }
1755           initializer_list += Name(field);
1756           initializer_list +=
1757               "(" +
1758               (native_default ? std::string(native_default->constant)
1759                               : GetDefaultScalarValue(field, true)) +
1760               ")";
1761         } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1762           if (IsStruct(field.value.type)) {
1763             if (native_default) {
1764               if (!initializer_list.empty()) {
1765                 initializer_list += ",\n        ";
1766               }
1767               initializer_list +=
1768                   Name(field) + "(" + native_default->constant + ")";
1769             }
1770           }
1771         } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) {
1772           if (!initializer_list.empty()) { initializer_list += ",\n        "; }
1773           initializer_list += Name(field) + "(0)";
1774         }
1775       }
1776     }
1777     if (!initializer_list.empty()) {
1778       initializer_list = "\n      : " + initializer_list;
1779     }
1780
1781     code_.SetValue("INIT_LIST", initializer_list);
1782
1783     code_ += "  {{NATIVE_NAME}}(){{INIT_LIST}} {";
1784     code_ += "  }";
1785   }
1786
1787   void GenCompareOperator(const StructDef &struct_def,
1788                           std::string accessSuffix = "") {
1789     std::string compare_op;
1790     for (auto it = struct_def.fields.vec.begin();
1791          it != struct_def.fields.vec.end(); ++it) {
1792       const auto &field = **it;
1793       if (!field.deprecated &&  // Deprecated fields won't be accessible.
1794           field.value.type.base_type != BASE_TYPE_UTYPE &&
1795           (field.value.type.base_type != BASE_TYPE_VECTOR ||
1796            field.value.type.element != BASE_TYPE_UTYPE)) {
1797         if (!compare_op.empty()) { compare_op += " &&\n      "; }
1798         auto accessor = Name(field) + accessSuffix;
1799         compare_op += "(lhs." + accessor + " == rhs." + accessor + ")";
1800       }
1801     }
1802
1803     std::string cmp_lhs;
1804     std::string cmp_rhs;
1805     if (compare_op.empty()) {
1806       cmp_lhs = "";
1807       cmp_rhs = "";
1808       compare_op = "  return true;";
1809     } else {
1810       cmp_lhs = "lhs";
1811       cmp_rhs = "rhs";
1812       compare_op = "  return\n      " + compare_op + ";";
1813     }
1814
1815     code_.SetValue("CMP_OP", compare_op);
1816     code_.SetValue("CMP_LHS", cmp_lhs);
1817     code_.SetValue("CMP_RHS", cmp_rhs);
1818     code_ += "";
1819     code_ +=
1820         "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
1821         "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
1822     code_ += "{{CMP_OP}}";
1823     code_ += "}";
1824
1825     code_ += "";
1826     code_ +=
1827         "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
1828         "{{NATIVE_NAME}} &rhs) {";
1829     code_ += "    return !(lhs == rhs);";
1830     code_ += "}";
1831     code_ += "";
1832   }
1833
1834   void GenOperatorNewDelete(const StructDef &struct_def) {
1835     if (auto native_custom_alloc =
1836             struct_def.attributes.Lookup("native_custom_alloc")) {
1837       code_ += "  inline void *operator new (std::size_t count) {";
1838       code_ += "    return " + native_custom_alloc->constant +
1839                "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
1840       code_ += "  }";
1841       code_ += "  inline void operator delete (void *ptr) {";
1842       code_ += "    return " + native_custom_alloc->constant +
1843                "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
1844                "ptr),1);";
1845       code_ += "  }";
1846     }
1847   }
1848
1849   void GenNativeTable(const StructDef &struct_def) {
1850     const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
1851     code_.SetValue("STRUCT_NAME", Name(struct_def));
1852     code_.SetValue("NATIVE_NAME", native_name);
1853
1854     // Generate a C++ object that can hold an unpacked version of this table.
1855     code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
1856     code_ += "  typedef {{STRUCT_NAME}} TableType;";
1857     GenFullyQualifiedNameGetter(struct_def, native_name);
1858     for (auto it = struct_def.fields.vec.begin();
1859          it != struct_def.fields.vec.end(); ++it) {
1860       GenMember(**it);
1861     }
1862     GenOperatorNewDelete(struct_def);
1863     GenDefaultConstructor(struct_def);
1864     code_ += "};";
1865     if (opts_.gen_compare) GenCompareOperator(struct_def);
1866     code_ += "";
1867   }
1868
1869   // Generate the code to call the appropriate Verify function(s) for a field.
1870   void GenVerifyCall(const FieldDef &field, const char *prefix) {
1871     code_.SetValue("PRE", prefix);
1872     code_.SetValue("NAME", Name(field));
1873     code_.SetValue("REQUIRED", field.IsRequired() ? "Required" : "");
1874     code_.SetValue("SIZE", GenTypeSize(field.value.type));
1875     code_.SetValue("OFFSET", GenFieldOffsetName(field));
1876     if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
1877       code_ +=
1878           "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
1879     } else {
1880       code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
1881     }
1882
1883     switch (field.value.type.base_type) {
1884       case BASE_TYPE_UNION: {
1885         code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1886         code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
1887         code_ +=
1888             "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
1889             "{{NAME}}{{SUFFIX}}())\\";
1890         break;
1891       }
1892       case BASE_TYPE_STRUCT: {
1893         if (!field.value.type.struct_def->fixed) {
1894           code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
1895         }
1896         break;
1897       }
1898       case BASE_TYPE_STRING: {
1899         code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
1900         break;
1901       }
1902       case BASE_TYPE_VECTOR: {
1903         code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
1904
1905         switch (field.value.type.element) {
1906           case BASE_TYPE_STRING: {
1907             code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
1908             break;
1909           }
1910           case BASE_TYPE_STRUCT: {
1911             if (!field.value.type.struct_def->fixed) {
1912               code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
1913             }
1914             break;
1915           }
1916           case BASE_TYPE_UNION: {
1917             code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1918             code_ +=
1919                 "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
1920                 "{{NAME}}_type())\\";
1921             break;
1922           }
1923           default: break;
1924         }
1925         break;
1926       }
1927       default: {
1928         break;
1929       }
1930     }
1931   }
1932
1933   // Generate CompareWithValue method for a key field.
1934   void GenKeyFieldMethods(const FieldDef &field) {
1935     FLATBUFFERS_ASSERT(field.key);
1936     const bool is_string = (IsString(field.value.type));
1937
1938     code_ += "  bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
1939     if (is_string) {
1940       // use operator< of flatbuffers::String
1941       code_ += "    return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
1942     } else {
1943       code_ += "    return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
1944     }
1945     code_ += "  }";
1946
1947     if (is_string) {
1948       code_ += "  int KeyCompareWithValue(const char *val) const {";
1949       code_ += "    return strcmp({{FIELD_NAME}}()->c_str(), val);";
1950       code_ += "  }";
1951     } else {
1952       FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
1953       auto type = GenTypeBasic(field.value.type, false);
1954       if (opts_.scoped_enums && field.value.type.enum_def &&
1955           IsScalar(field.value.type.base_type)) {
1956         type = GenTypeGet(field.value.type, " ", "const ", " *", true);
1957       }
1958       // Returns {field<val: -1, field==val: 0, field>val: +1}.
1959       code_.SetValue("KEY_TYPE", type);
1960       code_ += "  int KeyCompareWithValue({{KEY_TYPE}} val) const {";
1961       code_ +=
1962           "    return static_cast<int>({{FIELD_NAME}}() > val) - "
1963           "static_cast<int>({{FIELD_NAME}}() < val);";
1964       code_ += "  }";
1965     }
1966   }
1967
1968   void GenTableUnionAsGetters(const FieldDef &field) {
1969     const auto &type = field.value.type;
1970     auto u = type.enum_def;
1971
1972     if (!type.enum_def->uses_multiple_type_instances)
1973       code_ +=
1974           "  template<typename T> "
1975           "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
1976
1977     for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
1978       auto &ev = **u_it;
1979       if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1980       auto full_struct_name = GetUnionElement(ev, false, opts_);
1981
1982       // @TODO: Mby make this decisions more universal? How?
1983       code_.SetValue("U_GET_TYPE",
1984                      EscapeKeyword(field.name + UnionTypeFieldSuffix()));
1985       code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace,
1986                                                        GetEnumValUse(*u, ev)));
1987       code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
1988       code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
1989       code_.SetValue("U_NULLABLE", NullableExtension());
1990
1991       // `const Type *union_name_asType() const` accessor.
1992       code_ += "  {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
1993       code_ +=
1994           "    return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
1995           "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
1996           ": nullptr;";
1997       code_ += "  }";
1998     }
1999   }
2000
2001   void GenTableFieldGetter(const FieldDef &field) {
2002     const auto &type = field.value.type;
2003     const auto offset_str = GenFieldOffsetName(field);
2004
2005     GenComment(field.doc_comment, "  ");
2006     // Call a different accessor for pointers, that indirects.
2007     if (false == field.IsScalarOptional()) {
2008       const bool is_scalar = IsScalar(type.base_type);
2009       std::string accessor;
2010       if (is_scalar)
2011         accessor = "GetField<";
2012       else if (IsStruct(type))
2013         accessor = "GetStruct<";
2014       else
2015         accessor = "GetPointer<";
2016       auto offset_type = GenTypeGet(type, "", "const ", " *", false);
2017       auto call = accessor + offset_type + ">(" + offset_str;
2018       // Default value as second arg for non-pointer types.
2019       if (is_scalar) { call += ", " + GenDefaultConstant(field); }
2020       call += ")";
2021
2022       std::string afterptr = " *" + NullableExtension();
2023       code_.SetValue("FIELD_TYPE",
2024                      GenTypeGet(type, " ", "const ", afterptr.c_str(), true));
2025       code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
2026       code_.SetValue("NULLABLE_EXT", NullableExtension());
2027       code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
2028       code_ += "    return {{FIELD_VALUE}};";
2029       code_ += "  }";
2030     } else {
2031       auto wire_type = GenTypeBasic(type, false);
2032       auto face_type = GenTypeBasic(type, true);
2033       auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
2034                        offset_str + ")";
2035       code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2036       code_ += "  {{FIELD_TYPE}} {{FIELD_NAME}}() const {";
2037       code_ += "    return " + opt_value + ";";
2038       code_ += "  }";
2039     }
2040
2041     if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); }
2042   }
2043
2044   void GenTableFieldType(const FieldDef &field) {
2045     const auto &type = field.value.type;
2046     const auto offset_str = GenFieldOffsetName(field);
2047     if (!field.IsScalarOptional()) {
2048       std::string afterptr = " *" + NullableExtension();
2049       code_.SetValue("FIELD_TYPE",
2050                      GenTypeGet(type, "", "const ", afterptr.c_str(), true));
2051       code_ += "    {{FIELD_TYPE}}\\";
2052     } else {
2053       code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2054       code_ += "    {{FIELD_TYPE}}\\";
2055     }
2056   }
2057
2058   void GenStructFieldType(const FieldDef &field) {
2059     const auto is_array = IsArray(field.value.type);
2060     std::string field_type =
2061         GenTypeGet(field.value.type, "", is_array ? "" : "const ",
2062                    is_array ? "" : " &", true);
2063     code_.SetValue("FIELD_TYPE", field_type);
2064     code_ += "    {{FIELD_TYPE}}\\";
2065   }
2066
2067   void GenFieldTypeHelper(const StructDef &struct_def) {
2068     if (struct_def.fields.vec.empty()) { return; }
2069     code_ += "  template<size_t Index>";
2070     code_ += "  using FieldType = \\";
2071     code_ += "decltype(std::declval<type>().get_field<Index>());";
2072   }
2073
2074   void GenIndexBasedFieldGetter(const StructDef &struct_def) {
2075     if (struct_def.fields.vec.empty()) { return; }
2076     code_ += "  template<size_t Index>";
2077     code_ += "  auto get_field() const {";
2078
2079     size_t index = 0;
2080     bool need_else = false;
2081     // Generate one index-based getter for each field.
2082     for (auto it = struct_def.fields.vec.begin();
2083          it != struct_def.fields.vec.end(); ++it) {
2084       const auto &field = **it;
2085       if (field.deprecated) {
2086         // Deprecated fields won't be accessible.
2087         continue;
2088       }
2089       code_.SetValue("FIELD_NAME", Name(field));
2090       code_.SetValue("FIELD_INDEX",
2091                      std::to_string(static_cast<long long>(index++)));
2092       if (need_else) {
2093         code_ += "    else \\";
2094       } else {
2095         code_ += "         \\";
2096       }
2097       need_else = true;
2098       code_ += "if constexpr (Index == {{FIELD_INDEX}}) \\";
2099       code_ += "return {{FIELD_NAME}}();";
2100     }
2101     code_ += "    else static_assert(Index != Index, \"Invalid Field Index\");";
2102     code_ += "  }";
2103   }
2104
2105   // Sample for Vec3:
2106   //
2107   //   static constexpr std::array<const char *, 3> field_names = {
2108   //     "x",
2109   //     "y",
2110   //     "z"
2111   //   };
2112   //
2113   void GenFieldNames(const StructDef &struct_def) {
2114     auto non_deprecated_field_count = std::count_if(
2115         struct_def.fields.vec.begin(), struct_def.fields.vec.end(),
2116         [](const FieldDef *field) { return !field->deprecated; });
2117     code_ += "  static constexpr std::array<\\";
2118     code_.SetValue(
2119         "FIELD_COUNT",
2120         std::to_string(static_cast<long long>(non_deprecated_field_count)));
2121     code_ += "const char *, {{FIELD_COUNT}}> field_names = {\\";
2122     if (struct_def.fields.vec.empty()) {
2123       code_ += "};";
2124       return;
2125     }
2126     code_ += "";
2127     // Generate the field_names elements.
2128     for (auto it = struct_def.fields.vec.begin();
2129          it != struct_def.fields.vec.end(); ++it) {
2130       const auto &field = **it;
2131       if (field.deprecated) {
2132         // Deprecated fields won't be accessible.
2133         continue;
2134       }
2135       code_.SetValue("FIELD_NAME", Name(field));
2136       code_ += "    \"{{FIELD_NAME}}\"\\";
2137       if (it + 1 != struct_def.fields.vec.end()) { code_ += ","; }
2138     }
2139     code_ += "\n  };";
2140   }
2141
2142   void GenFieldsNumber(const StructDef &struct_def) {
2143     auto non_deprecated_field_count = std::count_if(
2144         struct_def.fields.vec.begin(), struct_def.fields.vec.end(),
2145         [](const FieldDef *field) { return !field->deprecated; });
2146     code_.SetValue(
2147         "FIELD_COUNT",
2148         std::to_string(static_cast<long long>(non_deprecated_field_count)));
2149     code_ += "  static constexpr size_t fields_number = {{FIELD_COUNT}};";
2150   }
2151
2152   void GenTraitsStruct(const StructDef &struct_def) {
2153     code_.SetValue(
2154         "FULLY_QUALIFIED_NAME",
2155         struct_def.defined_namespace->GetFullyQualifiedName(Name(struct_def)));
2156     code_ += "struct {{STRUCT_NAME}}::Traits {";
2157     code_ += "  using type = {{STRUCT_NAME}};";
2158     if (!struct_def.fixed) {
2159       // We have a table and not a struct.
2160       code_ += "  static auto constexpr Create = Create{{STRUCT_NAME}};";
2161     }
2162     if (opts_.cpp_static_reflection) {
2163       code_ += "  static constexpr auto name = \"{{STRUCT_NAME}}\";";
2164       code_ +=
2165           "  static constexpr auto fully_qualified_name = "
2166           "\"{{FULLY_QUALIFIED_NAME}}\";";
2167       GenFieldNames(struct_def);
2168       GenFieldTypeHelper(struct_def);
2169       GenFieldsNumber(struct_def);
2170     }
2171     code_ += "};";
2172     code_ += "";
2173   }
2174
2175   void GenTableFieldSetter(const FieldDef &field) {
2176     const auto &type = field.value.type;
2177     const bool is_scalar = IsScalar(type.base_type);
2178     if (is_scalar && IsUnion(type))
2179       return;  // changing of a union's type is forbidden
2180
2181     auto offset_str = GenFieldOffsetName(field);
2182     if (is_scalar) {
2183       const auto wire_type = GenTypeWire(type, "", false);
2184       code_.SetValue("SET_FN", "SetField<" + wire_type + ">");
2185       code_.SetValue("OFFSET_NAME", offset_str);
2186       code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true));
2187       code_.SetValue("FIELD_VALUE",
2188                      GenUnderlyingCast(field, false, "_" + Name(field)));
2189
2190       code_ +=
2191           "  bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
2192           "_{{FIELD_NAME}}) {";
2193       if (false == field.IsScalarOptional()) {
2194         code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
2195         code_ +=
2196             "    return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
2197             "{{DEFAULT_VALUE}});";
2198       } else {
2199         code_ += "    return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
2200       }
2201       code_ += "  }";
2202     } else {
2203       auto postptr = " *" + NullableExtension();
2204       auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
2205       std::string accessor = IsStruct(type) ? "GetStruct<" : "GetPointer<";
2206       auto underlying = accessor + wire_type + ">(" + offset_str + ")";
2207       code_.SetValue("FIELD_TYPE", wire_type);
2208       code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
2209
2210       code_ += "  {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
2211       code_ += "    return {{FIELD_VALUE}};";
2212       code_ += "  }";
2213     }
2214   }
2215
2216   // Generate an accessor struct, builder structs & function for a table.
2217   void GenTable(const StructDef &struct_def) {
2218     if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
2219
2220     // Generate an accessor struct, with methods of the form:
2221     // type name() const { return GetField<type>(offset, defaultval); }
2222     GenComment(struct_def.doc_comment);
2223
2224     code_.SetValue("STRUCT_NAME", Name(struct_def));
2225     code_ +=
2226         "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
2227         " : private flatbuffers::Table {";
2228     if (opts_.generate_object_based_api) {
2229       code_ += "  typedef {{NATIVE_NAME}} NativeTableType;";
2230     }
2231     code_ += "  typedef {{STRUCT_NAME}}Builder Builder;";
2232     if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += "  struct Traits;"; }
2233     if (opts_.mini_reflect != IDLOptions::kNone) {
2234       code_ +=
2235           "  static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
2236       code_ += "    return {{STRUCT_NAME}}TypeTable();";
2237       code_ += "  }";
2238     }
2239
2240     GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
2241
2242     // Generate field id constants.
2243     if (struct_def.fields.vec.size() > 0) {
2244       // We need to add a trailing comma to all elements except the last one as
2245       // older versions of gcc complain about this.
2246       code_.SetValue("SEP", "");
2247       code_ +=
2248           "  enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
2249       for (auto it = struct_def.fields.vec.begin();
2250            it != struct_def.fields.vec.end(); ++it) {
2251         const auto &field = **it;
2252         if (field.deprecated) {
2253           // Deprecated fields won't be accessible.
2254           continue;
2255         }
2256
2257         code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2258         code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
2259         code_ += "{{SEP}}    {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
2260         code_.SetValue("SEP", ",\n");
2261       }
2262       code_ += "";
2263       code_ += "  };";
2264     }
2265
2266     // Generate the accessors.
2267     for (auto it = struct_def.fields.vec.begin();
2268          it != struct_def.fields.vec.end(); ++it) {
2269       const auto &field = **it;
2270       if (field.deprecated) {
2271         // Deprecated fields won't be accessible.
2272         continue;
2273       }
2274
2275       code_.SetValue("FIELD_NAME", Name(field));
2276       GenTableFieldGetter(field);
2277       if (opts_.mutable_buffer) { GenTableFieldSetter(field); }
2278
2279       auto nested = field.attributes.Lookup("nested_flatbuffer");
2280       if (nested) {
2281         std::string qualified_name = nested->constant;
2282         auto nested_root = parser_.LookupStruct(nested->constant);
2283         if (nested_root == nullptr) {
2284           qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
2285               nested->constant);
2286           nested_root = parser_.LookupStruct(qualified_name);
2287         }
2288         FLATBUFFERS_ASSERT(nested_root);  // Guaranteed to exist by parser.
2289         (void)nested_root;
2290         code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
2291
2292         code_ += "  const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
2293         code_ +=
2294             "    return "
2295             "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());";
2296         code_ += "  }";
2297       }
2298
2299       if (field.flexbuffer) {
2300         code_ +=
2301             "  flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
2302             " const {";
2303         // Both Data() and size() are const-methods, therefore call order
2304         // doesn't matter.
2305         code_ +=
2306             "    return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), "
2307             "{{FIELD_NAME}}()->size());";
2308         code_ += "  }";
2309       }
2310
2311       // Generate a comparison function for this field if it is a key.
2312       if (field.key) { GenKeyFieldMethods(field); }
2313     }
2314
2315     if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
2316
2317     // Generate a verifier function that can check a buffer from an untrusted
2318     // source will never cause reads outside the buffer.
2319     code_ += "  bool Verify(flatbuffers::Verifier &verifier) const {";
2320     code_ += "    return VerifyTableStart(verifier)\\";
2321     for (auto it = struct_def.fields.vec.begin();
2322          it != struct_def.fields.vec.end(); ++it) {
2323       const auto &field = **it;
2324       if (field.deprecated) { continue; }
2325       GenVerifyCall(field, " &&\n           ");
2326     }
2327
2328     code_ += " &&\n           verifier.EndTable();";
2329     code_ += "  }";
2330
2331     if (opts_.generate_object_based_api) {
2332       // Generate the UnPack() pre declaration.
2333       code_ += "  " + TableUnPackSignature(struct_def, true, opts_) + ";";
2334       code_ += "  " + TableUnPackToSignature(struct_def, true, opts_) + ";";
2335       code_ += "  " + TablePackSignature(struct_def, true, opts_) + ";";
2336     }
2337
2338     code_ += "};";  // End of table.
2339     code_ += "";
2340
2341     // Explicit specializations for union accessors
2342     for (auto it = struct_def.fields.vec.begin();
2343          it != struct_def.fields.vec.end(); ++it) {
2344       const auto &field = **it;
2345       if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
2346         continue;
2347       }
2348
2349       auto u = field.value.type.enum_def;
2350       if (u->uses_multiple_type_instances) continue;
2351
2352       code_.SetValue("FIELD_NAME", Name(field));
2353
2354       for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2355         auto &ev = **u_it;
2356         if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
2357
2358         auto full_struct_name = GetUnionElement(ev, false, opts_);
2359
2360         code_.SetValue(
2361             "U_ELEMENT_TYPE",
2362             WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
2363         code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2364         code_.SetValue("U_ELEMENT_NAME", full_struct_name);
2365         code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2366
2367         // `template<> const T *union_name_as<T>() const` accessor.
2368         code_ +=
2369             "template<> "
2370             "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
2371             "<{{U_ELEMENT_NAME}}>() const {";
2372         code_ += "  return {{U_FIELD_NAME}}();";
2373         code_ += "}";
2374         code_ += "";
2375       }
2376     }
2377
2378     GenBuilders(struct_def);
2379
2380     if (opts_.generate_object_based_api) {
2381       // Generate a pre-declaration for a CreateX method that works with an
2382       // unpacked C++ object.
2383       code_ += TableCreateSignature(struct_def, true, opts_) + ";";
2384       code_ += "";
2385     }
2386   }
2387
2388   // Generate code to force vector alignment. Return empty string for vector
2389   // that doesn't need alignment code.
2390   std::string GenVectorForceAlign(const FieldDef &field,
2391                                   const std::string &field_size) {
2392     FLATBUFFERS_ASSERT(IsVector(field.value.type));
2393     // Get the value of the force_align attribute.
2394     const auto *force_align = field.attributes.Lookup("force_align");
2395     const int align = force_align ? atoi(force_align->constant.c_str()) : 1;
2396     // Generate code to do force_align for the vector.
2397     if (align > 1) {
2398       const auto vtype = field.value.type.VectorType();
2399       const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def)
2400                                         : GenTypeWire(vtype, "", false);
2401       return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type +
2402              "), " + std::to_string(static_cast<long long>(align)) + ");";
2403     }
2404     return "";
2405   }
2406
2407   void GenBuilders(const StructDef &struct_def) {
2408     code_.SetValue("STRUCT_NAME", Name(struct_def));
2409
2410     // Generate a builder struct:
2411     code_ += "struct {{STRUCT_NAME}}Builder {";
2412     code_ += "  typedef {{STRUCT_NAME}} Table;";
2413     code_ += "  flatbuffers::FlatBufferBuilder &fbb_;";
2414     code_ += "  flatbuffers::uoffset_t start_;";
2415
2416     bool has_string_or_vector_fields = false;
2417     for (auto it = struct_def.fields.vec.begin();
2418          it != struct_def.fields.vec.end(); ++it) {
2419       const auto &field = **it;
2420       if (field.deprecated) continue;
2421       const bool is_scalar = IsScalar(field.value.type.base_type);
2422       const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
2423       const bool is_string = IsString(field.value.type);
2424       const bool is_vector = IsVector(field.value.type);
2425       if (is_string || is_vector) { has_string_or_vector_fields = true; }
2426
2427       std::string offset = GenFieldOffsetName(field);
2428       std::string name = GenUnderlyingCast(field, false, Name(field));
2429       std::string value = is_default_scalar ? GenDefaultConstant(field) : "";
2430
2431       // Generate accessor functions of the form:
2432       // void add_name(type name) {
2433       //   fbb_.AddElement<type>(offset, name, default);
2434       // }
2435       code_.SetValue("FIELD_NAME", Name(field));
2436       code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
2437       code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
2438       code_.SetValue("ADD_NAME", name);
2439       code_.SetValue("ADD_VALUE", value);
2440       if (is_scalar) {
2441         const auto type = GenTypeWire(field.value.type, "", false);
2442         code_.SetValue("ADD_FN", "AddElement<" + type + ">");
2443       } else if (IsStruct(field.value.type)) {
2444         code_.SetValue("ADD_FN", "AddStruct");
2445       } else {
2446         code_.SetValue("ADD_FN", "AddOffset");
2447       }
2448
2449       code_ += "  void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
2450       code_ += "    fbb_.{{ADD_FN}}(\\";
2451       if (is_default_scalar) {
2452         code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
2453       } else {
2454         code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
2455       }
2456       code_ += "  }";
2457     }
2458
2459     // Builder constructor
2460     code_ +=
2461         "  explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder "
2462         "&_fbb)";
2463     code_ += "        : fbb_(_fbb) {";
2464     code_ += "    start_ = fbb_.StartTable();";
2465     code_ += "  }";
2466
2467     // Finish() function.
2468     code_ += "  flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
2469     code_ += "    const auto end = fbb_.EndTable(start_);";
2470     code_ += "    auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
2471
2472     for (auto it = struct_def.fields.vec.begin();
2473          it != struct_def.fields.vec.end(); ++it) {
2474       const auto &field = **it;
2475       if (!field.deprecated && field.IsRequired()) {
2476         code_.SetValue("FIELD_NAME", Name(field));
2477         code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2478         code_ += "    fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
2479       }
2480     }
2481     code_ += "    return o;";
2482     code_ += "  }";
2483     code_ += "};";
2484     code_ += "";
2485
2486     // Generate a convenient CreateX function that uses the above builder
2487     // to create a table in one go.
2488     code_ +=
2489         "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2490         "Create{{STRUCT_NAME}}(";
2491     code_ += "    flatbuffers::FlatBufferBuilder &_fbb\\";
2492     for (auto it = struct_def.fields.vec.begin();
2493          it != struct_def.fields.vec.end(); ++it) {
2494       const auto &field = **it;
2495       if (!field.deprecated) { GenParam(field, false, ",\n    "); }
2496     }
2497     code_ += ") {";
2498
2499     code_ += "  {{STRUCT_NAME}}Builder builder_(_fbb);";
2500     for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
2501          size; size /= 2) {
2502       for (auto it = struct_def.fields.vec.rbegin();
2503            it != struct_def.fields.vec.rend(); ++it) {
2504         const auto &field = **it;
2505         if (!field.deprecated && (!struct_def.sortbysize ||
2506                                   size == SizeOf(field.value.type.base_type))) {
2507           code_.SetValue("FIELD_NAME", Name(field));
2508           if (field.IsScalarOptional()) {
2509             code_ +=
2510                 "  if({{FIELD_NAME}}) { "
2511                 "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }";
2512           } else {
2513             code_ += "  builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
2514           }
2515         }
2516       }
2517     }
2518     code_ += "  return builder_.Finish();";
2519     code_ += "}";
2520     code_ += "";
2521
2522     // Definition for type traits for this table type. This allows querying var-
2523     // ious compile-time traits of the table.
2524     if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
2525
2526     // Generate a CreateXDirect function with vector types as parameters
2527     if (opts_.cpp_direct_copy && has_string_or_vector_fields) {
2528       code_ +=
2529           "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2530           "Create{{STRUCT_NAME}}Direct(";
2531       code_ += "    flatbuffers::FlatBufferBuilder &_fbb\\";
2532       for (auto it = struct_def.fields.vec.begin();
2533            it != struct_def.fields.vec.end(); ++it) {
2534         const auto &field = **it;
2535         if (!field.deprecated) { GenParam(field, true, ",\n    "); }
2536       }
2537       // Need to call "Create" with the struct namespace.
2538       const auto qualified_create_name =
2539           struct_def.defined_namespace->GetFullyQualifiedName("Create");
2540       code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2541       code_ += ") {";
2542       for (auto it = struct_def.fields.vec.begin();
2543            it != struct_def.fields.vec.end(); ++it) {
2544         const auto &field = **it;
2545         if (!field.deprecated) {
2546           code_.SetValue("FIELD_NAME", Name(field));
2547           if (IsString(field.value.type)) {
2548             if (!field.shared) {
2549               code_.SetValue("CREATE_STRING", "CreateString");
2550             } else {
2551               code_.SetValue("CREATE_STRING", "CreateSharedString");
2552             }
2553             code_ +=
2554                 "  auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
2555                 "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
2556           } else if (IsVector(field.value.type)) {
2557             const std::string force_align_code =
2558                 GenVectorForceAlign(field, Name(field) + "->size()");
2559             if (!force_align_code.empty()) {
2560               code_ += "  if ({{FIELD_NAME}}) { " + force_align_code + " }";
2561             }
2562             code_ += "  auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
2563             const auto vtype = field.value.type.VectorType();
2564             const auto has_key = TypeHasKey(vtype);
2565             if (IsStruct(vtype)) {
2566               const auto type = WrapInNameSpace(*vtype.struct_def);
2567               code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<"
2568                                 : "_fbb.CreateVectorOfStructs<") +
2569                        type + ">\\";
2570             } else if (has_key) {
2571               const auto type = WrapInNameSpace(*vtype.struct_def);
2572               code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\";
2573             } else {
2574               const auto type =
2575                   GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
2576               code_ += "_fbb.CreateVector<" + type + ">\\";
2577             }
2578             code_ +=
2579                 has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;";
2580           }
2581         }
2582       }
2583       code_ += "  return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2584       code_ += "      _fbb\\";
2585       for (auto it = struct_def.fields.vec.begin();
2586            it != struct_def.fields.vec.end(); ++it) {
2587         const auto &field = **it;
2588         if (!field.deprecated) {
2589           code_.SetValue("FIELD_NAME", Name(field));
2590           code_ += ",\n      {{FIELD_NAME}}\\";
2591           if (IsString(field.value.type) || IsVector(field.value.type)) {
2592             code_ += "__\\";
2593           }
2594         }
2595       }
2596       code_ += ");";
2597       code_ += "}";
2598       code_ += "";
2599     }
2600   }
2601
2602   std::string GenUnionUnpackVal(const FieldDef &afield,
2603                                 const char *vec_elem_access,
2604                                 const char *vec_type_access) {
2605     auto type_name = WrapInNameSpace(*afield.value.type.enum_def);
2606     return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " +
2607            EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
2608            vec_type_access + ", _resolver)";
2609   }
2610
2611   std::string GenUnpackVal(const Type &type, const std::string &val,
2612                            bool invector, const FieldDef &afield) {
2613     switch (type.base_type) {
2614       case BASE_TYPE_STRING: {
2615         if (FlexibleStringConstructor(&afield)) {
2616           return NativeString(&afield) + "(" + val + "->c_str(), " + val +
2617                  "->size())";
2618         } else {
2619           return val + "->str()";
2620         }
2621       }
2622       case BASE_TYPE_STRUCT: {
2623         if (IsStruct(type)) {
2624           const auto &struct_attrs = type.struct_def->attributes;
2625           const auto native_type = struct_attrs.Lookup("native_type");
2626           if (native_type) {
2627             std::string unpack_call = "flatbuffers::UnPack";
2628             const auto pack_name = struct_attrs.Lookup("native_type_pack_name");
2629             if (pack_name) { unpack_call += pack_name->constant; }
2630             unpack_call += "(*" + val + ")";
2631             return unpack_call;
2632           } else if (invector || afield.native_inline) {
2633             return "*" + val;
2634           } else {
2635             const auto name = WrapInNameSpace(*type.struct_def);
2636             const auto ptype = GenTypeNativePtr(name, &afield, true);
2637             return ptype + "(new " + name + "(*" + val + "))";
2638           }
2639         } else {
2640           const auto ptype = GenTypeNativePtr(
2641               WrapNativeNameInNameSpace(*type.struct_def, opts_), &afield,
2642               true);
2643           return ptype + "(" + val + "->UnPack(_resolver))";
2644         }
2645       }
2646       case BASE_TYPE_UNION: {
2647         return GenUnionUnpackVal(
2648             afield, invector ? "->Get(_i)" : "",
2649             invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
2650                      : "");
2651       }
2652       default: {
2653         return val;
2654         break;
2655       }
2656     }
2657   }
2658
2659   std::string GenUnpackFieldStatement(const FieldDef &field,
2660                                       const FieldDef *union_field) {
2661     std::string code;
2662     switch (field.value.type.base_type) {
2663       case BASE_TYPE_VECTOR: {
2664         auto name = Name(field);
2665         if (field.value.type.element == BASE_TYPE_UTYPE) {
2666           name = StripUnionType(Name(field));
2667         }
2668         code += "{ _o->" + name + ".resize(_e->size()); ";
2669         if (!field.value.type.enum_def && !IsBool(field.value.type.element) &&
2670             IsOneByte(field.value.type.element)) {
2671           // For vectors of bytes, std::copy is used to improve performance.
2672           // This doesn't work for:
2673           //  - enum types because they have to be explicitly static_cast.
2674           //  - vectors of bool, since they are a template specialization.
2675           //  - multiple-byte types due to endianness.
2676           code +=
2677               "std::copy(_e->begin(), _e->end(), _o->" + name + ".begin()); }";
2678         } else {
2679           std::string indexing;
2680           if (field.value.type.enum_def) {
2681             indexing += "static_cast<" +
2682                         WrapInNameSpace(*field.value.type.enum_def) + ">(";
2683           }
2684           indexing += "_e->Get(_i)";
2685           if (field.value.type.enum_def) { indexing += ")"; }
2686           if (field.value.type.element == BASE_TYPE_BOOL) {
2687             indexing += " != 0";
2688           }
2689           // Generate code that pushes data from _e to _o in the form:
2690           //   for (uoffset_t i = 0; i < _e->size(); ++i) {
2691           //     _o->field.push_back(_e->Get(_i));
2692           //   }
2693           auto access =
2694               field.value.type.element == BASE_TYPE_UTYPE
2695                   ? ".type"
2696                   : (field.value.type.element == BASE_TYPE_UNION ? ".value"
2697                                                                  : "");
2698
2699           code += "for (flatbuffers::uoffset_t _i = 0;";
2700           code += " _i < _e->size(); _i++) { ";
2701           auto cpp_type = field.attributes.Lookup("cpp_type");
2702           if (cpp_type) {
2703             // Generate code that resolves the cpp pointer type, of the form:
2704             //  if (resolver)
2705             //    (*resolver)(&_o->field, (hash_value_t)(_e));
2706             //  else
2707             //    _o->field = nullptr;
2708             code += "//vector resolver, " + PtrType(&field) + "\n";
2709             code += "if (_resolver) ";
2710             code += "(*_resolver)";
2711             code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" +
2712                     access + "), ";
2713             code +=
2714                 "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
2715             if (PtrType(&field) == "naked") {
2716               code += " else ";
2717               code += "_o->" + name + "[_i]" + access + " = nullptr";
2718             } else {
2719               // code += " else ";
2720               // code += "_o->" + name + "[_i]" + access + " = " +
2721               // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2722               code += "/* else do nothing */";
2723             }
2724           } else {
2725             code += "_o->" + name + "[_i]" + access + " = ";
2726             code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
2727                                  field);
2728           }
2729           code += "; } }";
2730         }
2731         break;
2732       }
2733       case BASE_TYPE_UTYPE: {
2734         FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
2735                            BASE_TYPE_UNION);
2736         // Generate code that sets the union type, of the form:
2737         //   _o->field.type = _e;
2738         code += "_o->" + union_field->name + ".type = _e;";
2739         break;
2740       }
2741       case BASE_TYPE_UNION: {
2742         // Generate code that sets the union value, of the form:
2743         //   _o->field.value = Union::Unpack(_e, field_type(), resolver);
2744         code += "_o->" + Name(field) + ".value = ";
2745         code += GenUnionUnpackVal(field, "", "");
2746         code += ";";
2747         break;
2748       }
2749       default: {
2750         auto cpp_type = field.attributes.Lookup("cpp_type");
2751         if (cpp_type) {
2752           // Generate code that resolves the cpp pointer type, of the form:
2753           //  if (resolver)
2754           //    (*resolver)(&_o->field, (hash_value_t)(_e));
2755           //  else
2756           //    _o->field = nullptr;
2757           code += "//scalar resolver, " + PtrType(&field) + " \n";
2758           code += "if (_resolver) ";
2759           code += "(*_resolver)";
2760           code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
2761           code += "static_cast<flatbuffers::hash_value_t>(_e));";
2762           if (PtrType(&field) == "naked") {
2763             code += " else ";
2764             code += "_o->" + Name(field) + " = nullptr;";
2765           } else {
2766             // code += " else ";
2767             // code += "_o->" + Name(field) + " = " +
2768             // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2769             code += "/* else do nothing */;";
2770           }
2771         } else {
2772           // Generate code for assigning the value, of the form:
2773           //  _o->field = value;
2774           code += "_o->" + Name(field) + " = ";
2775           code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
2776         }
2777         break;
2778       }
2779     }
2780     return code;
2781   }
2782
2783   std::string GenCreateParam(const FieldDef &field) {
2784     std::string value = "_o->";
2785     if (field.value.type.base_type == BASE_TYPE_UTYPE) {
2786       value += StripUnionType(Name(field));
2787       value += ".type";
2788     } else {
2789       value += Name(field);
2790     }
2791     if (field.value.type.base_type != BASE_TYPE_VECTOR &&
2792         field.attributes.Lookup("cpp_type")) {
2793       auto type = GenTypeBasic(field.value.type, false);
2794       value =
2795           "_rehasher ? "
2796           "static_cast<" +
2797           type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
2798     }
2799
2800     std::string code;
2801     switch (field.value.type.base_type) {
2802       // String fields are of the form:
2803       //   _fbb.CreateString(_o->field)
2804       // or
2805       //   _fbb.CreateSharedString(_o->field)
2806       case BASE_TYPE_STRING: {
2807         if (!field.shared) {
2808           code += "_fbb.CreateString(";
2809         } else {
2810           code += "_fbb.CreateSharedString(";
2811         }
2812         code += value;
2813         code.push_back(')');
2814
2815         // For optional fields, check to see if there actually is any data
2816         // in _o->field before attempting to access it. If there isn't,
2817         // depending on set_empty_strings_to_null either set it to 0 or an empty
2818         // string.
2819         if (!field.IsRequired()) {
2820           auto empty_value = opts_.set_empty_strings_to_null
2821                                  ? "0"
2822                                  : "_fbb.CreateSharedString(\"\")";
2823           code = value + ".empty() ? " + empty_value + " : " + code;
2824         }
2825         break;
2826       }
2827         // Vector fields come in several flavours, of the forms:
2828         //   _fbb.CreateVector(_o->field);
2829         //   _fbb.CreateVector((const utype*)_o->field.data(),
2830         //   _o->field.size()); _fbb.CreateVectorOfStrings(_o->field)
2831         //   _fbb.CreateVectorOfStructs(_o->field)
2832         //   _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
2833         //     return CreateT(_fbb, _o->Get(i), rehasher);
2834         //   });
2835       case BASE_TYPE_VECTOR: {
2836         auto vector_type = field.value.type.VectorType();
2837         switch (vector_type.base_type) {
2838           case BASE_TYPE_STRING: {
2839             if (NativeString(&field) == "std::string") {
2840               code += "_fbb.CreateVectorOfStrings(" + value + ")";
2841             } else {
2842               // Use by-function serialization to emulate
2843               // CreateVectorOfStrings(); this works also with non-std strings.
2844               code +=
2845                   "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>"
2846                   " ";
2847               code += "(" + value + ".size(), ";
2848               code += "[](size_t i, _VectorArgs *__va) { ";
2849               code +=
2850                   "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
2851               code += " }, &_va )";
2852             }
2853             break;
2854           }
2855           case BASE_TYPE_STRUCT: {
2856             if (IsStruct(vector_type)) {
2857               const auto &struct_attrs =
2858                   field.value.type.struct_def->attributes;
2859               const auto native_type = struct_attrs.Lookup("native_type");
2860               if (native_type) {
2861                 code += "_fbb.CreateVectorOfNativeStructs<";
2862                 code += WrapInNameSpace(*vector_type.struct_def) + ", " +
2863                         native_type->constant + ">";
2864                 code += "(" + value;
2865                 const auto pack_name =
2866                     struct_attrs.Lookup("native_type_pack_name");
2867                 if (pack_name) {
2868                   code += ", flatbuffers::Pack" + pack_name->constant;
2869                 }
2870                 code += ")";
2871               } else {
2872                 code += "_fbb.CreateVectorOfStructs";
2873                 code += "(" + value + ")";
2874               }
2875             } else {
2876               code += "_fbb.CreateVector<flatbuffers::Offset<";
2877               code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
2878               code += "(" + value + ".size(), ";
2879               code += "[](size_t i, _VectorArgs *__va) { ";
2880               code += "return Create" + vector_type.struct_def->name;
2881               code += "(*__va->__fbb, __va->_" + value + "[i]" +
2882                       GenPtrGet(field) + ", ";
2883               code += "__va->__rehasher); }, &_va )";
2884             }
2885             break;
2886           }
2887           case BASE_TYPE_BOOL: {
2888             code += "_fbb.CreateVector(" + value + ")";
2889             break;
2890           }
2891           case BASE_TYPE_UNION: {
2892             code +=
2893                 "_fbb.CreateVector<flatbuffers::"
2894                 "Offset<void>>(" +
2895                 value +
2896                 ".size(), [](size_t i, _VectorArgs *__va) { "
2897                 "return __va->_" +
2898                 value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
2899             break;
2900           }
2901           case BASE_TYPE_UTYPE: {
2902             value = StripUnionType(value);
2903             code += "_fbb.CreateVector<uint8_t>(" + value +
2904                     ".size(), [](size_t i, _VectorArgs *__va) { "
2905                     "return static_cast<uint8_t>(__va->_" +
2906                     value + "[i].type); }, &_va)";
2907             break;
2908           }
2909           default: {
2910             if (field.value.type.enum_def &&
2911                 !VectorElementUserFacing(vector_type)) {
2912               // For enumerations, we need to get access to the array data for
2913               // the underlying storage type (eg. uint8_t).
2914               const auto basetype = GenTypeBasic(
2915                   field.value.type.enum_def->underlying_type, false);
2916               code += "_fbb.CreateVectorScalarCast<" + basetype +
2917                       ">(flatbuffers::data(" + value + "), " + value +
2918                       ".size())";
2919             } else if (field.attributes.Lookup("cpp_type")) {
2920               auto type = GenTypeBasic(vector_type, false);
2921               code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
2922               code += "[](size_t i, _VectorArgs *__va) { ";
2923               code += "return __va->__rehasher ? ";
2924               code += "static_cast<" + type + ">((*__va->__rehasher)";
2925               code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
2926               code += "; }, &_va )";
2927             } else {
2928               code += "_fbb.CreateVector(" + value + ")";
2929             }
2930             break;
2931           }
2932         }
2933
2934         // If set_empty_vectors_to_null option is enabled, for optional fields,
2935         // check to see if there actually is any data in _o->field before
2936         // attempting to access it.
2937         if (opts_.set_empty_vectors_to_null && !field.IsRequired()) {
2938           code = value + ".size() ? " + code + " : 0";
2939         }
2940         break;
2941       }
2942       case BASE_TYPE_UNION: {
2943         // _o->field.Pack(_fbb);
2944         code += value + ".Pack(_fbb)";
2945         break;
2946       }
2947       case BASE_TYPE_STRUCT: {
2948         if (IsStruct(field.value.type)) {
2949           const auto &struct_attribs = field.value.type.struct_def->attributes;
2950           const auto native_type = struct_attribs.Lookup("native_type");
2951           if (native_type) {
2952             code += "flatbuffers::Pack";
2953             const auto pack_name =
2954                 struct_attribs.Lookup("native_type_pack_name");
2955             if (pack_name) { code += pack_name->constant; }
2956             code += "(" + value + ")";
2957           } else if (field.native_inline) {
2958             code += "&" + value;
2959           } else {
2960             code += value + " ? " + value + GenPtrGet(field) + " : 0";
2961           }
2962         } else {
2963           // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
2964           const auto type = field.value.type.struct_def->name;
2965           code += value + " ? Create" + type;
2966           code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
2967           code += " : 0";
2968         }
2969         break;
2970       }
2971       default: {
2972         code += value;
2973         break;
2974       }
2975     }
2976     return code;
2977   }
2978
2979   // Generate code for tables that needs to come after the regular definition.
2980   void GenTablePost(const StructDef &struct_def) {
2981     code_.SetValue("STRUCT_NAME", Name(struct_def));
2982     code_.SetValue("NATIVE_NAME",
2983                    NativeName(Name(struct_def), &struct_def, opts_));
2984
2985     if (opts_.generate_object_based_api) {
2986       // Generate the X::UnPack() method.
2987       code_ +=
2988           "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
2989
2990       if (opts_.g_cpp_std == cpp::CPP_STD_X0) {
2991         auto native_name = WrapNativeNameInNameSpace(struct_def, parser_.opts);
2992         code_.SetValue("POINTER_TYPE",
2993                        GenTypeNativePtr(native_name, nullptr, false));
2994         code_ +=
2995             "  {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
2996       } else if (opts_.g_cpp_std == cpp::CPP_STD_11) {
2997         code_ +=
2998             "  auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new "
2999             "{{NATIVE_NAME}}());";
3000       } else {
3001         code_ += "  auto _o = std::make_unique<{{NATIVE_NAME}}>();";
3002       }
3003       code_ += "  UnPackTo(_o.get(), _resolver);";
3004       code_ += "  return _o.release();";
3005       code_ += "}";
3006       code_ += "";
3007       code_ +=
3008           "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
3009       code_ += "  (void)_o;";
3010       code_ += "  (void)_resolver;";
3011
3012       for (auto it = struct_def.fields.vec.begin();
3013            it != struct_def.fields.vec.end(); ++it) {
3014         const auto &field = **it;
3015         if (field.deprecated) { continue; }
3016
3017         // Assign a value from |this| to |_o|.   Values from |this| are stored
3018         // in a variable |_e| by calling this->field_type().  The value is then
3019         // assigned to |_o| using the GenUnpackFieldStatement.
3020         const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
3021         const auto statement =
3022             GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
3023
3024         code_.SetValue("FIELD_NAME", Name(field));
3025         auto prefix = "  { auto _e = {{FIELD_NAME}}(); ";
3026         auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
3027         auto postfix = " }";
3028         code_ += std::string(prefix) + check + statement + postfix;
3029       }
3030       code_ += "}";
3031       code_ += "";
3032
3033       // Generate the X::Pack member function that simply calls the global
3034       // CreateX function.
3035       code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
3036       code_ += "  return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
3037       code_ += "}";
3038       code_ += "";
3039
3040       // Generate a CreateX method that works with an unpacked C++ object.
3041       code_ +=
3042           "inline " + TableCreateSignature(struct_def, false, opts_) + " {";
3043       code_ += "  (void)_rehasher;";
3044       code_ += "  (void)_o;";
3045
3046       code_ +=
3047           "  struct _VectorArgs "
3048           "{ flatbuffers::FlatBufferBuilder *__fbb; "
3049           "const " +
3050           NativeName(Name(struct_def), &struct_def, opts_) +
3051           "* __o; "
3052           "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
3053           "&_fbb, _o, _rehasher}; (void)_va;";
3054
3055       for (auto it = struct_def.fields.vec.begin();
3056            it != struct_def.fields.vec.end(); ++it) {
3057         auto &field = **it;
3058         if (field.deprecated) { continue; }
3059         if (IsVector(field.value.type)) {
3060           const std::string force_align_code =
3061               GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
3062           if (!force_align_code.empty()) { code_ += "  " + force_align_code; }
3063         }
3064         code_ += "  auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
3065       }
3066       // Need to call "Create" with the struct namespace.
3067       const auto qualified_create_name =
3068           struct_def.defined_namespace->GetFullyQualifiedName("Create");
3069       code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
3070
3071       code_ += "  return {{CREATE_NAME}}{{STRUCT_NAME}}(";
3072       code_ += "      _fbb\\";
3073       for (auto it = struct_def.fields.vec.begin();
3074            it != struct_def.fields.vec.end(); ++it) {
3075         auto &field = **it;
3076         if (field.deprecated) { continue; }
3077
3078         bool pass_by_address = false;
3079         if (field.value.type.base_type == BASE_TYPE_STRUCT) {
3080           if (IsStruct(field.value.type)) {
3081             auto native_type =
3082                 field.value.type.struct_def->attributes.Lookup("native_type");
3083             if (native_type) { pass_by_address = true; }
3084           }
3085         }
3086
3087         // Call the CreateX function using values from |_o|.
3088         if (pass_by_address) {
3089           code_ += ",\n      &_" + Name(field) + "\\";
3090         } else {
3091           code_ += ",\n      _" + Name(field) + "\\";
3092         }
3093       }
3094       code_ += ");";
3095       code_ += "}";
3096       code_ += "";
3097     }
3098   }
3099
3100   static void GenPadding(
3101       const FieldDef &field, std::string *code_ptr, int *id,
3102       const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
3103     if (field.padding) {
3104       for (int i = 0; i < 4; i++) {
3105         if (static_cast<int>(field.padding) & (1 << i)) {
3106           f((1 << i) * 8, code_ptr, id);
3107         }
3108       }
3109       FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
3110     }
3111   }
3112
3113   static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
3114     *code_ptr += "  int" + NumToString(bits) + "_t padding" +
3115                  NumToString((*id)++) + "__;";
3116   }
3117
3118   static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
3119     (void)bits;
3120     if (!code_ptr->empty()) *code_ptr += ",\n        ";
3121     *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
3122   }
3123
3124   static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
3125     (void)bits;
3126     if (!code_ptr->empty()) *code_ptr += '\n';
3127     *code_ptr += "    (void)padding" + NumToString((*id)++) + "__;";
3128   }
3129
3130   void GenStructDefaultConstructor(const StructDef &struct_def) {
3131     std::string init_list;
3132     std::string body;
3133     bool first_in_init_list = true;
3134     int padding_initializer_id = 0;
3135     int padding_body_id = 0;
3136     for (auto it = struct_def.fields.vec.begin();
3137          it != struct_def.fields.vec.end(); ++it) {
3138       const auto field = *it;
3139       const auto field_name = field->name + "_";
3140
3141       if (first_in_init_list) {
3142         first_in_init_list = false;
3143       } else {
3144         init_list += ",";
3145         init_list += "\n        ";
3146       }
3147
3148       init_list += field_name;
3149       if (IsStruct(field->value.type) || IsArray(field->value.type)) {
3150         // this is either default initialization of struct
3151         // or
3152         // implicit initialization of array
3153         // for each object in array it:
3154         // * sets it as zeros for POD types (integral, floating point, etc)
3155         // * calls default constructor for classes/structs
3156         init_list += "()";
3157       } else {
3158         init_list += "(0)";
3159       }
3160       if (field->padding) {
3161         GenPadding(*field, &init_list, &padding_initializer_id,
3162                    PaddingInitializer);
3163         GenPadding(*field, &body, &padding_body_id, PaddingNoop);
3164       }
3165     }
3166
3167     if (init_list.empty()) {
3168       code_ += "  {{STRUCT_NAME}}()";
3169       code_ += "  {}";
3170     } else {
3171       code_.SetValue("INIT_LIST", init_list);
3172       code_ += "  {{STRUCT_NAME}}()";
3173       code_ += "      : {{INIT_LIST}} {";
3174       if (!body.empty()) { code_ += body; }
3175       code_ += "  }";
3176     }
3177   }
3178
3179   void GenStructConstructor(const StructDef &struct_def,
3180                             GenArrayArgMode array_mode) {
3181     std::string arg_list;
3182     std::string init_list;
3183     int padding_id = 0;
3184     auto first = struct_def.fields.vec.begin();
3185     // skip arrays if generate ctor without array assignment
3186     const auto init_arrays = (array_mode != kArrayArgModeNone);
3187     for (auto it = struct_def.fields.vec.begin();
3188          it != struct_def.fields.vec.end(); ++it) {
3189       const auto &field = **it;
3190       const auto &type = field.value.type;
3191       const auto is_array = IsArray(type);
3192       const auto arg_name = "_" + Name(field);
3193       if (!is_array || init_arrays) {
3194         if (it != first && !arg_list.empty()) { arg_list += ", "; }
3195         arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true)
3196                               : GenTypeSpan(type, true, type.fixed_length);
3197         arg_list += arg_name;
3198       }
3199       // skip an array with initialization from span
3200       if (false == (is_array && init_arrays)) {
3201         if (it != first && !init_list.empty()) { init_list += ",\n        "; }
3202         init_list += Name(field) + "_";
3203         if (IsScalar(type.base_type)) {
3204           auto scalar_type = GenUnderlyingCast(field, false, arg_name);
3205           init_list += "(flatbuffers::EndianScalar(" + scalar_type + "))";
3206         } else {
3207           FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type));
3208           if (!is_array)
3209             init_list += "(" + arg_name + ")";
3210           else
3211             init_list += "()";
3212         }
3213       }
3214       if (field.padding)
3215         GenPadding(field, &init_list, &padding_id, PaddingInitializer);
3216     }
3217
3218     if (!arg_list.empty()) {
3219       code_.SetValue("ARG_LIST", arg_list);
3220       code_.SetValue("INIT_LIST", init_list);
3221       if (!init_list.empty()) {
3222         code_ += "  {{STRUCT_NAME}}({{ARG_LIST}})";
3223         code_ += "      : {{INIT_LIST}} {";
3224       } else {
3225         code_ += "  {{STRUCT_NAME}}({{ARG_LIST}}) {";
3226       }
3227       padding_id = 0;
3228       for (auto it = struct_def.fields.vec.begin();
3229            it != struct_def.fields.vec.end(); ++it) {
3230         const auto &field = **it;
3231         const auto &type = field.value.type;
3232         if (IsArray(type) && init_arrays) {
3233           const auto &element_type = type.VectorType();
3234           const auto is_enum = IsEnum(element_type);
3235           FLATBUFFERS_ASSERT(
3236               (IsScalar(element_type.base_type) || IsStruct(element_type)) &&
3237               "invalid declaration");
3238           const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3239           std::string get_array =
3240               is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3241           const auto field_name = Name(field) + "_";
3242           const auto arg_name = "_" + Name(field);
3243           code_ += "    flatbuffers::" + get_array + "(" + field_name +
3244                    ").CopyFromSpan(" + arg_name + ");";
3245         }
3246         if (field.padding) {
3247           std::string padding;
3248           GenPadding(field, &padding, &padding_id, PaddingNoop);
3249           code_ += padding;
3250         }
3251       }
3252       code_ += "  }";
3253     }
3254   }
3255
3256   void GenArrayAccessor(const Type &type, bool mutable_accessor) {
3257     FLATBUFFERS_ASSERT(IsArray(type));
3258     const auto is_enum = IsEnum(type.VectorType());
3259     // The Array<bool,N> is a tricky case, like std::vector<bool>.
3260     // It requires a specialization of Array class.
3261     // Generate Array<uint8_t> for Array<bool>.
3262     const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3263     std::string ret_type = "flatbuffers::Array<" + face_type + ", " +
3264                            NumToString(type.fixed_length) + ">";
3265     if (mutable_accessor)
3266       code_ += "  " + ret_type + " *mutable_{{FIELD_NAME}}() {";
3267     else
3268       code_ += "  const " + ret_type + " *{{FIELD_NAME}}() const {";
3269
3270     std::string get_array =
3271         is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3272     code_ += "    return &flatbuffers::" + get_array + "({{FIELD_VALUE}});";
3273     code_ += "  }";
3274   }
3275
3276   // Generate an accessor struct with constructor for a flatbuffers struct.
3277   void GenStruct(const StructDef &struct_def) {
3278     // Generate an accessor struct, with private variables of the form:
3279     // type name_;
3280     // Generates manual padding and alignment.
3281     // Variables are private because they contain little endian data on all
3282     // platforms.
3283     GenComment(struct_def.doc_comment);
3284     code_.SetValue("ALIGN", NumToString(struct_def.minalign));
3285     code_.SetValue("STRUCT_NAME", Name(struct_def));
3286
3287     code_ +=
3288         "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
3289         "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
3290     code_ += " private:";
3291
3292     int padding_id = 0;
3293     for (auto it = struct_def.fields.vec.begin();
3294          it != struct_def.fields.vec.end(); ++it) {
3295       const auto &field = **it;
3296       const auto &field_type = field.value.type;
3297       code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
3298       code_.SetValue("FIELD_NAME", Name(field));
3299       code_.SetValue("ARRAY",
3300                      IsArray(field_type)
3301                          ? "[" + NumToString(field_type.fixed_length) + "]"
3302                          : "");
3303       code_ += ("  {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
3304
3305       if (field.padding) {
3306         std::string padding;
3307         GenPadding(field, &padding, &padding_id, PaddingDefinition);
3308         code_ += padding;
3309       }
3310     }
3311
3312     // Generate GetFullyQualifiedName
3313     code_ += "";
3314     code_ += " public:";
3315
3316     if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += "  struct Traits;"; }
3317
3318     // Make TypeTable accessible via the generated struct.
3319     if (opts_.mini_reflect != IDLOptions::kNone) {
3320       code_ +=
3321           "  static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
3322       code_ += "    return {{STRUCT_NAME}}TypeTable();";
3323       code_ += "  }";
3324     }
3325
3326     GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
3327
3328     // Generate a default constructor.
3329     GenStructDefaultConstructor(struct_def);
3330
3331     // Generate a constructor that takes all fields as arguments,
3332     // excluding arrays.
3333     GenStructConstructor(struct_def, kArrayArgModeNone);
3334
3335     auto arrays_num = std::count_if(struct_def.fields.vec.begin(),
3336                                     struct_def.fields.vec.end(),
3337                                     [](const flatbuffers::FieldDef *fd) {
3338                                       return IsArray(fd->value.type);
3339                                     });
3340     if (arrays_num > 0) {
3341       GenStructConstructor(struct_def, kArrayArgModeSpanStatic);
3342     }
3343
3344     // Generate accessor methods of the form:
3345     // type name() const { return flatbuffers::EndianScalar(name_); }
3346     for (auto it = struct_def.fields.vec.begin();
3347          it != struct_def.fields.vec.end(); ++it) {
3348       const auto &field = **it;
3349       const auto &type = field.value.type;
3350       const auto is_scalar = IsScalar(type.base_type);
3351       const auto is_array = IsArray(type);
3352
3353       const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ",
3354                                          is_array ? "" : " &", true);
3355       auto member = Name(field) + "_";
3356       auto value =
3357           is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
3358
3359       code_.SetValue("FIELD_NAME", Name(field));
3360       code_.SetValue("FIELD_TYPE", field_type);
3361       code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
3362
3363       GenComment(field.doc_comment, "  ");
3364
3365       // Generate a const accessor function.
3366       if (is_array) {
3367         GenArrayAccessor(type, false);
3368       } else {
3369         code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
3370         code_ += "    return {{FIELD_VALUE}};";
3371         code_ += "  }";
3372       }
3373
3374       // Generate a mutable accessor function.
3375       if (opts_.mutable_buffer) {
3376         auto mut_field_type =
3377             GenTypeGet(type, " ", "", is_array ? "" : " &", true);
3378         code_.SetValue("FIELD_TYPE", mut_field_type);
3379         if (is_scalar) {
3380           code_.SetValue("ARG", GenTypeBasic(type, true));
3381           code_.SetValue("FIELD_VALUE",
3382                          GenUnderlyingCast(field, false, "_" + Name(field)));
3383
3384           code_ += "  void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
3385           code_ +=
3386               "    flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
3387               "{{FIELD_VALUE}});";
3388           code_ += "  }";
3389         } else if (is_array) {
3390           GenArrayAccessor(type, true);
3391         } else {
3392           code_ += "  {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
3393           code_ += "    return {{FIELD_VALUE}};";
3394           code_ += "  }";
3395         }
3396       }
3397
3398       // Generate a comparison function for this field if it is a key.
3399       if (field.key) { GenKeyFieldMethods(field); }
3400     }
3401     code_.SetValue("NATIVE_NAME", Name(struct_def));
3402     GenOperatorNewDelete(struct_def);
3403
3404     if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
3405
3406     code_ += "};";
3407
3408     code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
3409     code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
3410     if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
3411     code_ += "";
3412
3413     // Definition for type traits for this table type. This allows querying var-
3414     // ious compile-time traits of the table.
3415     if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
3416   }
3417
3418   // Set up the correct namespace. Only open a namespace if the existing one is
3419   // different (closing/opening only what is necessary).
3420   //
3421   // The file must start and end with an empty (or null) namespace so that
3422   // namespaces are properly opened and closed.
3423   void SetNameSpace(const Namespace *ns) {
3424     if (cur_name_space_ == ns) { return; }
3425
3426     // Compute the size of the longest common namespace prefix.
3427     // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
3428     // the common prefix is A::B:: and we have old_size = 4, new_size = 5
3429     // and common_prefix_size = 2
3430     size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
3431     size_t new_size = ns ? ns->components.size() : 0;
3432
3433     size_t common_prefix_size = 0;
3434     while (common_prefix_size < old_size && common_prefix_size < new_size &&
3435            ns->components[common_prefix_size] ==
3436                cur_name_space_->components[common_prefix_size]) {
3437       common_prefix_size++;
3438     }
3439
3440     // Close cur_name_space in reverse order to reach the common prefix.
3441     // In the previous example, D then C are closed.
3442     for (size_t j = old_size; j > common_prefix_size; --j) {
3443       code_ += "}  // namespace " + cur_name_space_->components[j - 1];
3444     }
3445     if (old_size != common_prefix_size) { code_ += ""; }
3446
3447     // open namespace parts to reach the ns namespace
3448     // in the previous example, E, then F, then G are opened
3449     for (auto j = common_prefix_size; j != new_size; ++j) {
3450       code_ += "namespace " + ns->components[j] + " {";
3451     }
3452     if (new_size != common_prefix_size) { code_ += ""; }
3453
3454     cur_name_space_ = ns;
3455   }
3456 };
3457
3458 }  // namespace cpp
3459
3460 bool GenerateCPP(const Parser &parser, const std::string &path,
3461                  const std::string &file_name) {
3462   cpp::IDLOptionsCpp opts(parser.opts);
3463   // The '--cpp_std' argument could be extended (like ASAN):
3464   // Example: "flatc --cpp_std c++17:option1:option2".
3465   auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++11";
3466   std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), CharToUpper);
3467   if (cpp_std == "C++0X") {
3468     opts.g_cpp_std = cpp::CPP_STD_X0;
3469     opts.g_only_fixed_enums = false;
3470   } else if (cpp_std == "C++11") {
3471     // Use the standard C++11 code generator.
3472     opts.g_cpp_std = cpp::CPP_STD_11;
3473     opts.g_only_fixed_enums = true;
3474   } else if (cpp_std == "C++17") {
3475     opts.g_cpp_std = cpp::CPP_STD_17;
3476     // With c++17 generate strong enums only.
3477     opts.scoped_enums = true;
3478     // By default, prefixed_enums==true, reset it.
3479     opts.prefixed_enums = false;
3480   } else {
3481     LogCompilerError("Unknown value of the '--cpp-std' switch: " +
3482                      opts.cpp_std);
3483     return false;
3484   }
3485   // The opts.scoped_enums has priority.
3486   opts.g_only_fixed_enums |= opts.scoped_enums;
3487
3488   if (opts.cpp_static_reflection && opts.g_cpp_std < cpp::CPP_STD_17) {
3489     LogCompilerError(
3490         "--cpp-static-reflection requires using --cpp-std at \"C++17\" or "
3491         "higher.");
3492     return false;
3493   }
3494
3495   cpp::CppGenerator generator(parser, path, file_name, opts);
3496   return generator.generate();
3497 }
3498
3499 std::string CPPMakeRule(const Parser &parser, const std::string &path,
3500                         const std::string &file_name) {
3501   const auto filebase =
3502       flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
3503   cpp::CppGenerator geneartor(parser, path, file_name, parser.opts);
3504   const auto included_files = parser.GetIncludedFilesRecursive(file_name);
3505   std::string make_rule =
3506       geneartor.GeneratedFileName(path, filebase, parser.opts) + ": ";
3507   for (auto it = included_files.begin(); it != included_files.end(); ++it) {
3508     make_rule += " " + *it;
3509   }
3510   return make_rule;
3511 }
3512
3513 }  // namespace flatbuffers