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