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