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