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