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