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