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