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