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