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