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