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