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