• 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/flatbuffers.h"
20 #include "flatbuffers/idl.h"
21 #include "flatbuffers/util.h"
22 #include "flatbuffers/code_generators.h"
23 
24 namespace flatbuffers {
25 
GeneratedFileName(const std::string & path,const std::string & file_name)26 static std::string GeneratedFileName(const std::string &path,
27                                      const std::string &file_name) {
28   return path + file_name + "_generated.h";
29 }
30 
31 namespace cpp {
32 class CppGenerator : public BaseGenerator {
33  public:
CppGenerator(const Parser & parser,const std::string & path,const std::string & file_name)34   CppGenerator(const Parser &parser, const std::string &path,
35                const std::string &file_name)
36       : BaseGenerator(parser, path, file_name, "", "::"),
37         cur_name_space_(nullptr) {}
38 
GenIncludeGuard() const39   std::string GenIncludeGuard() const {
40     // Generate include guard.
41     std::string guard = file_name_;
42     // Remove any non-alpha-numeric characters that may appear in a filename.
43     struct IsAlnum {
44       bool operator()(char c) { return !isalnum(c); }
45     };
46     guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
47                 guard.end());
48     guard = "FLATBUFFERS_GENERATED_" + guard;
49     guard += "_";
50     // For further uniqueness, also add the namespace.
51     auto name_space = parser_.namespaces_.back();
52     for (auto it = name_space->components.begin();
53          it != name_space->components.end(); ++it) {
54       guard += *it + "_";
55     }
56     guard += "H_";
57     std::transform(guard.begin(), guard.end(), guard.begin(), ::toupper);
58     return guard;
59   }
60 
GenIncludeDependencies()61   void GenIncludeDependencies() {
62     int num_includes = 0;
63     for (auto it = parser_.native_included_files_.begin();
64          it != parser_.native_included_files_.end(); ++it) {
65       code_ += "#include \"" + *it + "\"";
66       num_includes++;
67     }
68     for (auto it = parser_.included_files_.begin();
69          it != parser_.included_files_.end(); ++it) {
70       const auto basename =
71           flatbuffers::StripPath(flatbuffers::StripExtension(it->first));
72       if (basename != file_name_) {
73         code_ += "#include \"" + parser_.opts.include_prefix + basename +
74                  "_generated.h\"";
75         num_includes++;
76       }
77     }
78     if (num_includes) code_ += "";
79   }
80 
81   // Iterate through all definitions we haven't generate code for (enums,
82   // structs, and tables) and output them to a single file.
generate()83   bool generate() {
84     if (IsEverythingGenerated()) return true;
85 
86     code_.Clear();
87     code_ += "// " + std::string(FlatBuffersGeneratedWarning());
88 
89     const auto include_guard = GenIncludeGuard();
90     code_ += "#ifndef " + include_guard;
91     code_ += "#define " + include_guard;
92     code_ += "";
93 
94     code_ += "#include \"flatbuffers/flatbuffers.h\"";
95     code_ += "";
96 
97     if (parser_.opts.include_dependence_headers) {
98       GenIncludeDependencies();
99     }
100 
101     assert(!cur_name_space_);
102 
103     // Generate forward declarations for all structs/tables, since they may
104     // have circular references.
105     for (auto it = parser_.structs_.vec.begin();
106          it != parser_.structs_.vec.end(); ++it) {
107       const auto &struct_def = **it;
108       if (!struct_def.generated) {
109         SetNameSpace(struct_def.defined_namespace);
110         code_ += "struct " + struct_def.name + ";";
111         if (parser_.opts.generate_object_based_api && !struct_def.fixed) {
112           code_ += "struct " + NativeName(struct_def.name) + ";";
113         }
114         code_ += "";
115       }
116     }
117 
118     // Generate code for all the enum declarations.
119     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
120          ++it) {
121       const auto &enum_def = **it;
122       if (!enum_def.generated) {
123         SetNameSpace(enum_def.defined_namespace);
124         GenEnum(enum_def);
125       }
126     }
127 
128     // Generate code for all structs, then all tables.
129     for (auto it = parser_.structs_.vec.begin();
130          it != parser_.structs_.vec.end(); ++it) {
131       const auto &struct_def = **it;
132       if (struct_def.fixed && !struct_def.generated) {
133         SetNameSpace(struct_def.defined_namespace);
134         GenStruct(struct_def);
135       }
136     }
137     for (auto it = parser_.structs_.vec.begin();
138          it != parser_.structs_.vec.end(); ++it) {
139       const auto &struct_def = **it;
140       if (!struct_def.fixed && !struct_def.generated) {
141         SetNameSpace(struct_def.defined_namespace);
142         GenTable(struct_def);
143       }
144     }
145     for (auto it = parser_.structs_.vec.begin();
146          it != parser_.structs_.vec.end(); ++it) {
147       const auto &struct_def = **it;
148       if (!struct_def.fixed && !struct_def.generated) {
149         SetNameSpace(struct_def.defined_namespace);
150         GenTablePost(struct_def);
151       }
152     }
153 
154     // Generate code for union verifiers.
155     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
156          ++it) {
157       const auto &enum_def = **it;
158       if (enum_def.is_union && !enum_def.generated) {
159         SetNameSpace(enum_def.defined_namespace);
160         GenUnionPost(enum_def);
161       }
162     }
163 
164     // Generate convenient global helper functions:
165     if (parser_.root_struct_def_) {
166       auto &struct_def = *parser_.root_struct_def_;
167       SetNameSpace(struct_def.defined_namespace);
168       const auto &name = struct_def.name;
169       const auto qualified_name =
170           parser_.namespaces_.back()->GetFullyQualifiedName(name);
171       const auto cpp_name = TranslateNameSpace(qualified_name);
172 
173       code_.SetValue("STRUCT_NAME", name);
174       code_.SetValue("CPP_NAME", cpp_name);
175 
176       // The root datatype accessor:
177       code_ += "inline \\";
178       code_ += "const {{CPP_NAME}} *Get{{STRUCT_NAME}}(const void *buf) {";
179       code_ += "  return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
180       code_ += "}";
181       code_ += "";
182 
183       if (parser_.opts.mutable_buffer) {
184         code_ += "inline \\";
185         code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
186         code_ += "  return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
187         code_ += "}";
188         code_ += "";
189       }
190 
191       if (parser_.file_identifier_.length()) {
192         // Return the identifier
193         code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
194         code_ += "  return \"" + parser_.file_identifier_ + "\";";
195         code_ += "}";
196         code_ += "";
197 
198         // Check if a buffer has the identifier.
199         code_ += "inline \\";
200         code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
201         code_ += "  return flatbuffers::BufferHasIdentifier(";
202         code_ += "      buf, {{STRUCT_NAME}}Identifier());";
203         code_ += "}";
204         code_ += "";
205       }
206 
207       // The root verifier.
208       if (parser_.file_identifier_.length()) {
209         code_.SetValue("ID", name + "Identifier()");
210       } else {
211         code_.SetValue("ID", "nullptr");
212       }
213 
214       code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
215       code_ += "    flatbuffers::Verifier &verifier) {";
216       code_ += "  return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
217       code_ += "}";
218       code_ += "";
219 
220       if (parser_.file_extension_.length()) {
221         // Return the extension
222         code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
223         code_ += "  return \"" + parser_.file_extension_ + "\";";
224         code_ += "}";
225         code_ += "";
226       }
227 
228       // Finish a buffer with a given root object:
229       code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
230       code_ += "    flatbuffers::FlatBufferBuilder &fbb,";
231       code_ += "    flatbuffers::Offset<{{CPP_NAME}}> root) {";
232       if (parser_.file_identifier_.length())
233         code_ += "  fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
234       else
235         code_ += "  fbb.Finish(root);";
236       code_ += "}";
237       code_ += "";
238 
239       if (parser_.opts.generate_object_based_api) {
240         // A convenient root unpack function.
241         auto native_name =
242             NativeName(WrapInNameSpace(struct_def));
243         code_.SetValue("UNPACK_RETURN",
244                        GenTypeNativePtr(native_name, nullptr, false));
245         code_.SetValue("UNPACK_TYPE",
246                        GenTypeNativePtr(native_name, nullptr, true));
247 
248         code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
249         code_ += "    const void *buf,";
250         code_ += "    const flatbuffers::resolver_function_t *res = nullptr) {";
251         code_ += "  return {{UNPACK_TYPE}}\\";
252         code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
253         code_ += "}";
254         code_ += "";
255       }
256     }
257 
258     assert(cur_name_space_);
259     SetNameSpace(nullptr);
260 
261     // Close the include guard.
262     code_ += "#endif  // " + include_guard;
263 
264     const auto file_path = GeneratedFileName(path_, file_name_);
265     const auto final_code = code_.ToString();
266     return SaveFile(file_path.c_str(), final_code, false);
267   }
268 
269  private:
270   CodeWriter code_;
271 
272   // This tracks the current namespace so we can insert namespace declarations.
273   const Namespace *cur_name_space_;
274 
CurrentNameSpace() const275   const Namespace *CurrentNameSpace() const { return cur_name_space_; }
276 
277   // Translates a qualified name in flatbuffer text format to the same name in
278   // the equivalent C++ namespace.
TranslateNameSpace(const std::string & qualified_name)279   static std::string TranslateNameSpace(const std::string &qualified_name) {
280     std::string cpp_qualified_name = qualified_name;
281     size_t start_pos = 0;
282     while ((start_pos = cpp_qualified_name.find(".", start_pos)) !=
283            std::string::npos) {
284       cpp_qualified_name.replace(start_pos, 1, "::");
285     }
286     return cpp_qualified_name;
287   }
288 
GenComment(const std::vector<std::string> & dc,const char * prefix="")289   void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
290     std::string text;
291     ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
292     code_ += text + "\\";
293   }
294 
295   // Return a C++ type from the table in idl.h
GenTypeBasic(const Type & type,bool user_facing_type) const296   std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
297     static const char *ctypename[] = {
298     #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
299             #CTYPE,
300         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
301     #undef FLATBUFFERS_TD
302     };
303     if (user_facing_type) {
304       if (type.enum_def) return WrapInNameSpace(*type.enum_def);
305       if (type.base_type == BASE_TYPE_BOOL) return "bool";
306     }
307     return ctypename[type.base_type];
308   }
309 
310   // Return a C++ pointer type, specialized to the actual struct/table types,
311   // and vector element types.
GenTypePointer(const Type & type) const312   std::string GenTypePointer(const Type &type) const {
313     switch (type.base_type) {
314       case BASE_TYPE_STRING: {
315         return "flatbuffers::String";
316       }
317       case BASE_TYPE_VECTOR: {
318         const auto type_name = GenTypeWire(type.VectorType(), "", false);
319         return "flatbuffers::Vector<" + type_name + ">";
320       }
321       case BASE_TYPE_STRUCT: {
322         return WrapInNameSpace(*type.struct_def);
323       }
324       case BASE_TYPE_UNION:
325       // fall through
326       default: {
327         return "void";
328       }
329     }
330   }
331 
332   // Return a C++ type for any type (scalar/pointer) specifically for
333   // building a flatbuffer.
GenTypeWire(const Type & type,const char * postfix,bool user_facing_type) const334   std::string GenTypeWire(const Type &type, const char *postfix,
335                           bool user_facing_type) const {
336     if (IsScalar(type.base_type)) {
337       return GenTypeBasic(type, user_facing_type) + postfix;
338     } else if (IsStruct(type)) {
339       return "const " + GenTypePointer(type) + " *";
340     } else {
341       return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix;
342     }
343   }
344 
345   // Return a C++ type for any type (scalar/pointer) that reflects its
346   // serialized size.
GenTypeSize(const Type & type) const347   std::string GenTypeSize(const Type &type) const {
348     if (IsScalar(type.base_type)) {
349       return GenTypeBasic(type, false);
350     } else if (IsStruct(type)) {
351       return GenTypePointer(type);
352     } else {
353       return "flatbuffers::uoffset_t";
354     }
355   }
356 
357   // TODO(wvo): make this configurable.
NativeName(const std::string & name)358   static std::string NativeName(const std::string &name) { return name + "T"; }
359 
PtrType(const FieldDef * field)360   const std::string &PtrType(const FieldDef *field) {
361     auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
362     return attr ? attr->constant : parser_.opts.cpp_object_api_pointer_type;
363   }
364 
GenTypeNativePtr(const std::string & type,const FieldDef * field,bool is_constructor)365   std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
366                                bool is_constructor) {
367     auto &ptr_type = PtrType(field);
368     if (ptr_type != "naked") {
369       return ptr_type + "<" + type + ">";
370     } else if (is_constructor) {
371       return "";
372     } else {
373       return type + " *";
374     }
375   }
376 
GenPtrGet(const FieldDef & field)377   std::string GenPtrGet(const FieldDef &field) {
378     auto &ptr_type = PtrType(&field);
379     return ptr_type == "naked" ? "" : ".get()";
380   }
381 
GenTypeNative(const Type & type,bool invector,const FieldDef & field)382   std::string GenTypeNative(const Type &type, bool invector,
383                             const FieldDef &field) {
384     switch (type.base_type) {
385       case BASE_TYPE_STRING: {
386         return "std::string";
387       }
388       case BASE_TYPE_VECTOR: {
389         const auto type_name = GenTypeNative(type.VectorType(), true, field);
390         return "std::vector<" + type_name + ">";
391       }
392       case BASE_TYPE_STRUCT: {
393         auto type_name = WrapInNameSpace(*type.struct_def);
394         if (IsStruct(type)) {
395           auto native_type = type.struct_def->attributes.Lookup("native_type");
396           if (native_type) {
397             type_name = native_type->constant;
398           }
399           if (invector || field.native_inline) {
400             return type_name;
401           } else {
402             return GenTypeNativePtr(type_name, &field, false);
403           }
404         } else {
405           return GenTypeNativePtr(NativeName(type_name), &field, false);
406         }
407       }
408       case BASE_TYPE_UNION: {
409         return type.enum_def->name + "Union";
410       }
411       default: {
412         return GenTypeBasic(type, true);
413       }
414     }
415   }
416 
417   // Return a C++ type for any type (scalar/pointer) specifically for
418   // using a flatbuffer.
GenTypeGet(const Type & type,const char * afterbasic,const char * beforeptr,const char * afterptr,bool user_facing_type)419   std::string GenTypeGet(const Type &type, const char *afterbasic,
420                          const char *beforeptr, const char *afterptr,
421                          bool user_facing_type) {
422     if (IsScalar(type.base_type)) {
423       return GenTypeBasic(type, user_facing_type) + afterbasic;
424     } else {
425       return beforeptr + GenTypePointer(type) + afterptr;
426     }
427   }
428 
GenEnumDecl(const EnumDef & enum_def) const429   std::string GenEnumDecl(const EnumDef &enum_def) const {
430     const IDLOptions &opts = parser_.opts;
431     return (opts.scoped_enums ? "enum class " : "enum ") + enum_def.name;
432   }
433 
GenEnumValDecl(const EnumDef & enum_def,const std::string & enum_val) const434   std::string GenEnumValDecl(const EnumDef &enum_def,
435                              const std::string &enum_val) const {
436     const IDLOptions &opts = parser_.opts;
437     return opts.prefixed_enums ? enum_def.name + "_" + enum_val : enum_val;
438   }
439 
GetEnumValUse(const EnumDef & enum_def,const EnumVal & enum_val) const440   std::string GetEnumValUse(const EnumDef &enum_def,
441                             const EnumVal &enum_val) const {
442     const IDLOptions &opts = parser_.opts;
443     if (opts.scoped_enums) {
444       return enum_def.name + "::" + enum_val.name;
445     } else if (opts.prefixed_enums) {
446       return enum_def.name + "_" + enum_val.name;
447     } else {
448       return enum_val.name;
449     }
450   }
451 
UnionVerifySignature(const EnumDef & enum_def)452   static std::string UnionVerifySignature(const EnumDef &enum_def) {
453     return "bool Verify" + enum_def.name +
454            "(flatbuffers::Verifier &verifier, const void *obj, " +
455            enum_def.name + " type)";
456   }
457 
UnionVectorVerifySignature(const EnumDef & enum_def)458   static std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
459     return "bool Verify" + enum_def.name + "Vector" +
460            "(flatbuffers::Verifier &verifier, " +
461            "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
462            "const flatbuffers::Vector<uint8_t> *types)";
463   }
464 
UnionUnPackSignature(const EnumDef & enum_def,bool inclass)465   static std::string UnionUnPackSignature(const EnumDef &enum_def,
466                                           bool inclass) {
467     return (inclass ? "static " : "") +
468            std::string("flatbuffers::NativeTable *") +
469            (inclass ? "" : enum_def.name + "Union::") +
470            "UnPack(const void *obj, " + enum_def.name +
471            " type, const flatbuffers::resolver_function_t *resolver)";
472   }
473 
UnionPackSignature(const EnumDef & enum_def,bool inclass)474   static std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
475     return "flatbuffers::Offset<void> " +
476            (inclass ? "" : enum_def.name + "Union::") +
477            "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
478            "const flatbuffers::rehasher_function_t *_rehasher" +
479            (inclass ? " = nullptr" : "") + ") const";
480   }
481 
TableCreateSignature(const StructDef & struct_def,bool predecl)482   static std::string TableCreateSignature(const StructDef &struct_def,
483                                           bool predecl) {
484     return "flatbuffers::Offset<" + struct_def.name + "> Create" +
485            struct_def.name  +
486            "(flatbuffers::FlatBufferBuilder &_fbb, const " +
487            NativeName(struct_def.name) +
488            " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
489            (predecl ? " = nullptr" : "") + ")";
490   }
491 
TablePackSignature(const StructDef & struct_def,bool inclass)492   static std::string TablePackSignature(const StructDef &struct_def,
493                                         bool inclass) {
494     return std::string(inclass ? "static " : "") +
495            "flatbuffers::Offset<" + struct_def.name + "> " +
496            (inclass ? "" : struct_def.name + "::") +
497            "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
498            "const " + NativeName(struct_def.name) + "* _o, " +
499            "const flatbuffers::rehasher_function_t *_rehasher" +
500            (inclass ? " = nullptr" : "") + ")";
501   }
502 
TableUnPackSignature(const StructDef & struct_def,bool inclass)503   static std::string TableUnPackSignature(const StructDef &struct_def,
504                                           bool inclass) {
505     return NativeName(struct_def.name) + " *" +
506            (inclass ? "" : struct_def.name + "::") +
507            "UnPack(const flatbuffers::resolver_function_t *_resolver" +
508            (inclass ? " = nullptr" : "") + ") const";
509   }
510 
TableUnPackToSignature(const StructDef & struct_def,bool inclass)511   static std::string TableUnPackToSignature(const StructDef &struct_def,
512                                             bool inclass) {
513     return "void " + (inclass ? "" : struct_def.name + "::") +
514            "UnPackTo(" + NativeName(struct_def.name) + " *" + "_o, " +
515            "const flatbuffers::resolver_function_t *_resolver" +
516            (inclass ? " = nullptr" : "") + ") const";
517   }
518 
519   // Generate an enum declaration and an enum string lookup table.
GenEnum(const EnumDef & enum_def)520   void GenEnum(const EnumDef &enum_def) {
521     code_.SetValue("ENUM_NAME", enum_def.name);
522     code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
523     code_.SetValue("SEP", "");
524 
525     GenComment(enum_def.doc_comment);
526     code_ += GenEnumDecl(enum_def) + "\\";
527     if (parser_.opts.scoped_enums)
528       code_ += " : {{BASE_TYPE}}\\";
529     code_ += " {";
530 
531     int64_t anyv = 0;
532     const EnumVal *minv = nullptr, *maxv = nullptr;
533     for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
534          ++it) {
535       const auto &ev = **it;
536 
537       GenComment(ev.doc_comment, "  ");
538       code_.SetValue("KEY", GenEnumValDecl(enum_def, ev.name));
539       code_.SetValue("VALUE", NumToString(ev.value));
540       code_ += "{{SEP}}  {{KEY}} = {{VALUE}}\\";
541       code_.SetValue("SEP", ",\n");
542 
543       minv = !minv || minv->value > ev.value ? &ev : minv;
544       maxv = !maxv || maxv->value < ev.value ? &ev : maxv;
545       anyv |= ev.value;
546     }
547 
548     if (parser_.opts.scoped_enums || parser_.opts.prefixed_enums) {
549       assert(minv && maxv);
550 
551       code_.SetValue("SEP", ",\n");
552       if (enum_def.attributes.Lookup("bit_flags")) {
553         code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
554         code_.SetValue("VALUE", "0");
555         code_ += "{{SEP}}  {{KEY}} = {{VALUE}}\\";
556 
557         code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
558         code_.SetValue("VALUE", NumToString(anyv));
559         code_ += "{{SEP}}  {{KEY}} = {{VALUE}}\\";
560       } else {  // MIN & MAX are useless for bit_flags
561         code_.SetValue("KEY",GenEnumValDecl(enum_def, "MIN"));
562         code_.SetValue("VALUE", GenEnumValDecl(enum_def, minv->name));
563         code_ += "{{SEP}}  {{KEY}} = {{VALUE}}\\";
564 
565         code_.SetValue("KEY",GenEnumValDecl(enum_def, "MAX"));
566         code_.SetValue("VALUE", GenEnumValDecl(enum_def, maxv->name));
567         code_ += "{{SEP}}  {{KEY}} = {{VALUE}}\\";
568       }
569     }
570     code_ += "";
571     code_ += "};";
572 
573     if (parser_.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
574       code_ += "DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
575     }
576     code_ += "";
577 
578     // Generate a generate string table for enum values.
579     // Problem is, if values are very sparse that could generate really big
580     // tables. Ideally in that case we generate a map lookup instead, but for
581     // the moment we simply don't output a table at all.
582     auto range =
583         enum_def.vals.vec.back()->value - enum_def.vals.vec.front()->value + 1;
584     // Average distance between values above which we consider a table
585     // "too sparse". Change at will.
586     static const int kMaxSparseness = 5;
587     if (range / static_cast<int64_t>(enum_def.vals.vec.size()) <
588         kMaxSparseness) {
589       code_ += "inline const char **EnumNames{{ENUM_NAME}}() {";
590       code_ += "  static const char *names[] = {";
591 
592       auto val = enum_def.vals.vec.front()->value;
593       for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
594            ++it) {
595         const auto &ev = **it;
596         while (val++ != ev.value) {
597           code_ += "    \"\",";
598         }
599         code_ += "    \"" + ev.name + "\",";
600       }
601       code_ += "    nullptr";
602       code_ += "  };";
603 
604       code_ += "  return names;";
605       code_ += "}";
606       code_ += "";
607 
608       code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
609 
610       code_ += "  const size_t index = static_cast<int>(e)\\";
611       if (enum_def.vals.vec.front()->value) {
612         auto vals = GetEnumValUse(enum_def, *enum_def.vals.vec.front());
613         code_ += " - static_cast<int>(" + vals + ")\\";
614       }
615       code_ += ";";
616 
617       code_ += "  return EnumNames{{ENUM_NAME}}()[index];";
618       code_ += "}";
619       code_ += "";
620     }
621 
622     // Generate type traits for unions to map from a type to union enum value.
623     if (enum_def.is_union) {
624       for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
625         ++it) {
626         const auto &ev = **it;
627 
628         if (it == enum_def.vals.vec.begin()) {
629           code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
630         }
631         else {
632           auto name = WrapInNameSpace(*ev.struct_def);
633           code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
634         }
635 
636         auto value = GetEnumValUse(enum_def, ev);
637         code_ += "  static const {{ENUM_NAME}} enum_value = " + value + ";";
638         code_ += "};";
639         code_ += "";
640       }
641     }
642 
643     if (parser_.opts.generate_object_based_api && enum_def.is_union) {
644       // Generate a union type
645       code_.SetValue("NAME", enum_def.name);
646       code_.SetValue("NONE",
647           GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE")));
648 
649       code_ += "struct {{NAME}}Union {";
650       code_ += "  {{NAME}} type;";
651       code_ += "  flatbuffers::NativeTable *table;";
652       code_ += "";
653       code_ += "  {{NAME}}Union() : type({{NONE}}), table(nullptr) {}";
654       code_ += "  {{NAME}}Union({{NAME}}Union&& u):";
655       code_ += "    type(std::move(u.type)), table(std::move(u.table)) {}";
656       code_ += "  {{NAME}}Union(const {{NAME}}Union &);";
657       code_ += "  {{NAME}}Union &operator=(const {{NAME}}Union &);";
658       code_ += "  ~{{NAME}}Union() { Reset(); }";
659       code_ += "";
660       code_ += "  void Reset();";
661       code_ += "";
662       code_ += "  template <typename T>";
663       code_ += "  void Set(T&& value) {";
664       code_ += "    Reset();";
665       code_ += "    type = {{NAME}}Traits<typename T::TableType>::enum_value;";
666       code_ += "    if (type != {{NONE}}) {";
667       code_ += "      table = new T(std::forward<T>(value));";
668       code_ += "    }";
669       code_ += "  }";
670       code_ += "";
671       code_ += "  " + UnionUnPackSignature(enum_def, true) + ";";
672       code_ += "  " + UnionPackSignature(enum_def, true) + ";";
673       code_ += "";
674 
675       for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
676            ++it) {
677         const auto &ev = **it;
678         if (!ev.value) {
679           continue;
680         }
681 
682         const auto native_type = NativeName(WrapInNameSpace(*ev.struct_def));
683         code_.SetValue("NATIVE_TYPE", native_type);
684         code_.SetValue("NATIVE_NAME", ev.name);
685         code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
686 
687         code_ += "  {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
688         code_ += "    return type == {{NATIVE_ID}} ?";
689         code_ += "      reinterpret_cast<{{NATIVE_TYPE}} *>(table) : nullptr;";
690         code_ += "  }";
691       }
692       code_ += "};";
693       code_ += "";
694     }
695 
696     if (enum_def.is_union) {
697       code_ += UnionVerifySignature(enum_def) + ";";
698       code_ += UnionVectorVerifySignature(enum_def) + ";";
699       code_ += "";
700     }
701   }
702 
GenUnionPost(const EnumDef & enum_def)703   void GenUnionPost(const EnumDef &enum_def) {
704     // Generate a verifier function for this union that can be called by the
705     // table verifier functions. It uses a switch case to select a specific
706     // verifier function to call, this should be safe even if the union type
707     // has been corrupted, since the verifiers will simply fail when called
708     // on the wrong type.
709     code_.SetValue("ENUM_NAME", enum_def.name);
710 
711     code_ += "inline " + UnionVerifySignature(enum_def) + " {";
712     code_ += "  switch (type) {";
713     for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
714          ++it) {
715       const auto &ev = **it;
716       code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
717 
718       if (ev.value) {
719         code_.SetValue("TYPE", WrapInNameSpace(*ev.struct_def));
720         code_ += "    case {{LABEL}}: {";
721         code_ += "      auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
722         code_ += "      return verifier.VerifyTable(ptr);";
723         code_ += "    }";
724       } else {
725         code_ += "    case {{LABEL}}: {";
726         code_ += "      return true;";  // "NONE" enum value.
727         code_ += "    }";
728       }
729     }
730     code_ += "    default: return false;";
731     code_ += "  }";
732     code_ += "}";
733     code_ += "";
734 
735     code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
736     code_ += "  if (values->size() != types->size()) return false;";
737     code_ += "  for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
738     code_ += "    if (!Verify" + enum_def.name + "(";
739     code_ += "        verifier,  values->Get(i), types->GetEnum<" + enum_def.name + ">(i))) {";
740     code_ += "      return false;";
741     code_ += "    }";
742     code_ += "  }";
743     code_ += "  return true;";
744     code_ += "}";
745     code_ += "";
746 
747     if (parser_.opts.generate_object_based_api) {
748       // Generate union Unpack() and Pack() functions.
749       code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
750       code_ += "  switch (type) {";
751       for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
752            ++it) {
753         const auto &ev = **it;
754         if (!ev.value) {
755           continue;
756         }
757 
758         code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
759         code_.SetValue("TYPE", WrapInNameSpace(*ev.struct_def));
760         code_ += "    case {{LABEL}}: {";
761         code_ += "      auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
762         code_ += "      return ptr->UnPack(resolver);";
763         code_ += "    }";
764       }
765       code_ += "    default: return nullptr;";
766       code_ += "  }";
767       code_ += "}";
768       code_ += "";
769 
770       code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
771       code_ += "  switch (type) {";
772       for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
773            ++it) {
774         auto &ev = **it;
775         if (!ev.value) {
776           continue;
777         }
778 
779         code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
780         code_.SetValue("TYPE", NativeName(WrapInNameSpace(*ev.struct_def)));
781         code_.SetValue("NAME", ev.struct_def->name);
782         code_ += "    case {{LABEL}}: {";
783         code_ += "      auto ptr = reinterpret_cast<const {{TYPE}} *>(table);";
784         code_ += "      return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
785         code_ += "    }";
786       }
787       code_ += "    default: return 0;";
788       code_ += "  }";
789       code_ += "}";
790       code_ += "";
791 
792       // Union Reset() function.
793       code_.SetValue("NONE",
794           GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE")));
795 
796       code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
797       code_ += "  switch (type) {";
798       for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
799            ++it) {
800         const auto &ev = **it;
801         if (!ev.value) {
802           continue;
803         }
804 
805         code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
806         code_.SetValue("TYPE", NativeName(WrapInNameSpace(*ev.struct_def)));
807 
808         code_ += "    case {{LABEL}}: {";
809         code_ += "      auto ptr = reinterpret_cast<{{TYPE}} *>(table);";
810         code_ += "      delete ptr;";
811         code_ += "      break;";
812         code_ += "    }";
813       }
814       code_ += "    default: break;";
815       code_ += "  }";
816       code_ += "  table = nullptr;";
817       code_ += "  type = {{NONE}};";
818       code_ += "}";
819       code_ += "";
820     }
821   }
822 
823   // Generates a value with optionally a cast applied if the field has a
824   // different underlying type from its interface type (currently only the
825   // case for enums. "from" specify the direction, true meaning from the
826   // underlying type to the interface type.
GenUnderlyingCast(const FieldDef & field,bool from,const std::string & val)827   std::string GenUnderlyingCast(const FieldDef &field, bool from,
828                                 const std::string &val) {
829     if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
830       return val + " != 0";
831     } else if ((field.value.type.enum_def &&
832                 IsScalar(field.value.type.base_type)) ||
833                field.value.type.base_type == BASE_TYPE_BOOL) {
834       return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
835              val + ")";
836     } else {
837       return val;
838     }
839   }
840 
GenFieldOffsetName(const FieldDef & field)841   std::string GenFieldOffsetName(const FieldDef &field) {
842     std::string uname = field.name;
843     std::transform(uname.begin(), uname.end(), uname.begin(), ::toupper);
844     return "VT_" + uname;
845   }
846 
GenFullyQualifiedNameGetter(const std::string & name)847   void GenFullyQualifiedNameGetter(const std::string &name) {
848     if (!parser_.opts.generate_name_strings) {
849       return;
850     }
851 
852     auto fullname = parser_.namespaces_.back()->GetFullyQualifiedName(name);
853     code_.SetValue("NAME", fullname);
854     code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
855 
856     code_ += "  static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
857     code_ += "    return \"{{NAME}}\";";
858     code_ += "  }";
859   }
860 
GenDefaultConstant(const FieldDef & field)861   std::string GenDefaultConstant(const FieldDef &field) {
862     return field.value.type.base_type == BASE_TYPE_FLOAT
863                ? field.value.constant + "f"
864                : field.value.constant;
865   }
866 
GetDefaultScalarValue(const FieldDef & field)867   std::string GetDefaultScalarValue(const FieldDef &field) {
868     if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) {
869       auto ev = field.value.type.enum_def->ReverseLookup(
870           static_cast<int>(StringToInt(field.value.constant.c_str())), false);
871       if (ev) {
872         return WrapInNameSpace(
873             field.value.type.enum_def->defined_namespace,
874             GetEnumValUse(*field.value.type.enum_def, *ev));
875       } else {
876         return GenUnderlyingCast(field, true, field.value.constant);
877       }
878     } else if (field.value.type.base_type == BASE_TYPE_BOOL) {
879       return field.value.constant == "0" ? "false" : "true";
880     } else {
881       return GenDefaultConstant(field);
882     }
883   }
884 
GenParam(const FieldDef & field,bool direct,const char * prefix)885   void GenParam(const FieldDef &field, bool direct, const char *prefix) {
886     code_.SetValue("PRE", prefix);
887     code_.SetValue("PARAM_NAME", field.name);
888     if (direct && field.value.type.base_type == BASE_TYPE_STRING) {
889       code_.SetValue("PARAM_TYPE", "const char *");
890       code_.SetValue("PARAM_VALUE", "nullptr");
891     } else if (direct && field.value.type.base_type == BASE_TYPE_VECTOR) {
892       auto type = GenTypeWire(field.value.type.VectorType(), "", false);
893       code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
894       code_.SetValue("PARAM_VALUE", "nullptr");
895     } else {
896       code_.SetValue("PARAM_TYPE", GenTypeWire(field.value.type, " ", true));
897       code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field));
898     }
899     code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
900   }
901 
902   // Generate a member, including a default value for scalars and raw pointers.
GenMember(const FieldDef & field)903   void GenMember(const FieldDef &field) {
904     if (!field.deprecated &&  // Deprecated fields won't be accessible.
905         field.value.type.base_type != BASE_TYPE_UTYPE) {
906       auto type = GenTypeNative(field.value.type, false, field);
907       auto cpp_type = field.attributes.Lookup("cpp_type");
908       auto full_type = (cpp_type ? cpp_type->constant + " *" : type + " ");
909       code_.SetValue("FIELD_TYPE", full_type);
910       code_.SetValue("FIELD_NAME", field.name);
911       code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}};";
912     }
913   }
914 
915   // Generate the default constructor for this struct. Properly initialize all
916   // scalar members with default values.
GenDefaultConstructor(const StructDef & struct_def)917   void GenDefaultConstructor(const StructDef& struct_def) {
918     std::string initializer_list;
919     for (auto it = struct_def.fields.vec.begin();
920          it != struct_def.fields.vec.end(); ++it) {
921       const auto &field = **it;
922       if (!field.deprecated &&  // Deprecated fields won't be accessible.
923           field.value.type.base_type != BASE_TYPE_UTYPE) {
924         auto cpp_type = field.attributes.Lookup("cpp_type");
925         // Scalar types get parsed defaults, raw pointers get nullptrs.
926         if (IsScalar(field.value.type.base_type)) {
927           if (!initializer_list.empty()) {
928             initializer_list += ",\n        ";
929           }
930           initializer_list += field.name;
931           initializer_list += "(" + GetDefaultScalarValue(field) + ")";
932         } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
933           if (IsStruct(field.value.type)) {
934             auto native_default = field.attributes.Lookup("native_default");
935             if (native_default) {
936               if (!initializer_list.empty()) {
937                 initializer_list += ",\n        ";
938               }
939               initializer_list +=
940                   field.name + "(" + native_default->constant + ")";
941             }
942           }
943         } else if (cpp_type) {
944           if (!initializer_list.empty()) {
945             initializer_list += ",\n        ";
946           }
947           initializer_list += field.name + "(0)";
948         }
949       }
950     }
951     if (!initializer_list.empty()) {
952       initializer_list = "\n      : " + initializer_list;
953     }
954 
955     code_.SetValue("NATIVE_NAME", NativeName(struct_def.name));
956     code_.SetValue("INIT_LIST", initializer_list);
957 
958     code_ += "  {{NATIVE_NAME}}(){{INIT_LIST}} {";
959     code_ += "  }";
960   }
961 
GenNativeTable(const StructDef & struct_def)962   void GenNativeTable(const StructDef &struct_def) {
963     const auto native_name = NativeName(struct_def.name);
964     code_.SetValue("STRUCT_NAME", struct_def.name);
965     code_.SetValue("NATIVE_NAME", native_name);
966 
967     // Generate a C++ object that can hold an unpacked version of this table.
968     code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
969     code_ += "  typedef {{STRUCT_NAME}} TableType;";
970     GenFullyQualifiedNameGetter(native_name);
971     for (auto it = struct_def.fields.vec.begin();
972          it != struct_def.fields.vec.end(); ++it) {
973       GenMember(**it);
974     }
975     GenDefaultConstructor(struct_def);
976     code_ += "};";
977     code_ += "";
978   }
979 
980   // Generate the code to call the appropriate Verify function(s) for a field.
GenVerifyCall(const FieldDef & field,const char * prefix)981   void GenVerifyCall(const FieldDef &field, const char* prefix) {
982     code_.SetValue("PRE", prefix);
983     code_.SetValue("NAME", field.name);
984     code_.SetValue("REQUIRED", field.required ? "Required" : "");
985     code_.SetValue("SIZE", GenTypeSize(field.value.type));
986     code_.SetValue("OFFSET", GenFieldOffsetName(field));
987     code_ += "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
988 
989     switch (field.value.type.base_type) {
990       case BASE_TYPE_UNION: {
991         code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
992         code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
993         code_ += "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
994                 "{{NAME}}{{SUFFIX}}())\\";
995         break;
996       }
997       case BASE_TYPE_STRUCT: {
998         if (!field.value.type.struct_def->fixed) {
999           code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
1000         }
1001         break;
1002       }
1003       case BASE_TYPE_STRING: {
1004         code_ += "{{PRE}}verifier.Verify({{NAME}}())\\";
1005         break;
1006       }
1007       case BASE_TYPE_VECTOR: {
1008         code_ += "{{PRE}}verifier.Verify({{NAME}}())\\";
1009 
1010         switch (field.value.type.element) {
1011           case BASE_TYPE_STRING: {
1012             code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
1013             break;
1014           }
1015           case BASE_TYPE_STRUCT: {
1016             if (!field.value.type.struct_def->fixed) {
1017               code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
1018             }
1019             break;
1020           }
1021           case BASE_TYPE_UNION: {
1022             code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1023             code_ += "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), {{NAME}}_type())\\";
1024             break;
1025           }
1026           default:
1027             break;
1028         }
1029         break;
1030       }
1031       default: {
1032         break;
1033       }
1034     }
1035   }
1036 
1037   // Generate an accessor struct, builder structs & function for a table.
GenTable(const StructDef & struct_def)1038   void GenTable(const StructDef &struct_def) {
1039     if (parser_.opts.generate_object_based_api) {
1040       GenNativeTable(struct_def);
1041     }
1042 
1043     // Generate an accessor struct, with methods of the form:
1044     // type name() const { return GetField<type>(offset, defaultval); }
1045     GenComment(struct_def.doc_comment);
1046 
1047     code_.SetValue("STRUCT_NAME", struct_def.name);
1048     code_ += "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
1049             " : private flatbuffers::Table {";
1050     if (parser_.opts.generate_object_based_api) {
1051       code_ += "  typedef {{NATIVE_NAME}} NativeTableType;";
1052     }
1053 
1054     GenFullyQualifiedNameGetter(struct_def.name);
1055 
1056     // Generate field id constants.
1057     if (struct_def.fields.vec.size() > 0) {
1058       // We need to add a trailing comma to all elements except the last one as
1059       // older versions of gcc complain about this.
1060       code_.SetValue("SEP", "");
1061       code_ += "  enum {";
1062       for (auto it = struct_def.fields.vec.begin();
1063            it != struct_def.fields.vec.end(); ++it) {
1064         const auto &field = **it;
1065         if (field.deprecated) {
1066           // Deprecated fields won't be accessible.
1067           continue;
1068         }
1069 
1070         code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
1071         code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
1072         code_ += "{{SEP}}    {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
1073         code_.SetValue("SEP", ",\n");
1074       }
1075       code_ += "";
1076       code_ += "  };";
1077     }
1078 
1079     // Generate the accessors.
1080     for (auto it = struct_def.fields.vec.begin();
1081          it != struct_def.fields.vec.end(); ++it) {
1082       const auto &field = **it;
1083       if (field.deprecated) {
1084         // Deprecated fields won't be accessible.
1085         continue;
1086       }
1087 
1088       const bool is_struct = IsStruct(field.value.type);
1089       const bool is_scalar = IsScalar(field.value.type.base_type);
1090       code_.SetValue("FIELD_NAME", field.name);
1091 
1092       // Call a different accessor for pointers, that indirects.
1093       std::string accessor = "";
1094       if (is_scalar) {
1095         accessor = "GetField<";
1096       } else if (is_struct) {
1097         accessor = "GetStruct<";
1098       } else {
1099         accessor = "GetPointer<";
1100       }
1101       auto offset_str = GenFieldOffsetName(field);
1102       auto offset_type =
1103           GenTypeGet(field.value.type, "", "const ", " *", false);
1104 
1105       auto call = accessor + offset_type + ">(" + offset_str;
1106       // Default value as second arg for non-pointer types.
1107       if (is_scalar) {
1108         call += ", " + GenDefaultConstant(field);
1109       }
1110       call += ")";
1111 
1112       GenComment(field.doc_comment, "  ");
1113       code_.SetValue("FIELD_TYPE",
1114           GenTypeGet(field.value.type, " ", "const ", " *", true));
1115       code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
1116 
1117       code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
1118       code_ += "    return {{FIELD_VALUE}};";
1119       code_ += "  }";
1120 
1121       if (parser_.opts.mutable_buffer) {
1122         if (is_scalar) {
1123           code_.SetValue("OFFSET_NAME", offset_str);
1124           code_.SetValue("FIELD_TYPE", GenTypeBasic(field.value.type, true));
1125           code_.SetValue("FIELD_VALUE",
1126                         GenUnderlyingCast(field, false, "_" + field.name));
1127 
1128           code_ += "  bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
1129                   "_{{FIELD_NAME}}) {";
1130           code_ += "    return SetField({{OFFSET_NAME}}, {{FIELD_VALUE}});";
1131           code_ += "  }";
1132         } else {
1133           auto type = GenTypeGet(field.value.type, " ", "", " *", true);
1134           auto underlying = accessor + type + ">(" + offset_str + ")";
1135           code_.SetValue("FIELD_TYPE", type);
1136           code_.SetValue("FIELD_VALUE",
1137                         GenUnderlyingCast(field, true, underlying));
1138 
1139           code_ += "  {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
1140           code_ += "    return {{FIELD_VALUE}};";
1141           code_ += "  }";
1142         }
1143       }
1144 
1145       auto nested = field.attributes.Lookup("nested_flatbuffer");
1146       if (nested) {
1147         std::string qualified_name =
1148             parser_.namespaces_.back()->GetFullyQualifiedName(
1149                 nested->constant);
1150         auto nested_root = parser_.structs_.Lookup(qualified_name);
1151         assert(nested_root);  // Guaranteed to exist by parser.
1152         (void)nested_root;
1153         code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
1154 
1155         code_ += "  const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
1156         code_ += "    const uint8_t* data = {{FIELD_NAME}}()->Data();";
1157         code_ += "    return flatbuffers::GetRoot<{{CPP_NAME}}>(data);";
1158         code_ += "  }";
1159       }
1160 
1161       // Generate a comparison function for this field if it is a key.
1162       if (field.key) {
1163         const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING);
1164 
1165         code_ += "  bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
1166         if (is_string) {
1167           code_ += "    return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
1168         } else {
1169           code_ += "    return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
1170         }
1171         code_ += "  }";
1172 
1173         if (is_string) {
1174           code_ += "  int KeyCompareWithValue(const char *val) const {";
1175           code_ += "    return strcmp({{FIELD_NAME}}()->c_str(), val);";
1176           code_ += "  }";
1177         } else {
1178           auto type = GenTypeBasic(field.value.type, false);
1179           if (parser_.opts.scoped_enums && field.value.type.enum_def &&
1180               IsScalar(field.value.type.base_type)) {
1181             type = GenTypeGet(field.value.type, " ", "const ", " *", true);
1182           }
1183 
1184           code_.SetValue("KEY_TYPE", type);
1185           code_ += "  int KeyCompareWithValue({{KEY_TYPE}} val) const {";
1186           code_ += "    const auto key = {{FIELD_NAME}}();";
1187           code_ += "    if (key < val) {";
1188           code_ += "      return -1;";
1189           code_ += "    } else if (key > val) {";
1190           code_ += "      return 1;";
1191           code_ += "    } else {";
1192           code_ += "      return 0;";
1193           code_ += "    }";
1194           code_ += "  }";
1195         }
1196       }
1197     }
1198 
1199     // Generate a verifier function that can check a buffer from an untrusted
1200     // source will never cause reads outside the buffer.
1201     code_ += "  bool Verify(flatbuffers::Verifier &verifier) const {";
1202     code_ += "    return VerifyTableStart(verifier)\\";
1203     for (auto it = struct_def.fields.vec.begin();
1204          it != struct_def.fields.vec.end(); ++it) {
1205       const auto &field = **it;
1206       if (field.deprecated) {
1207         continue;
1208       }
1209       GenVerifyCall(field, " &&\n           ");
1210     }
1211 
1212     code_ += " &&\n           verifier.EndTable();";
1213     code_ += "  }";
1214 
1215     if (parser_.opts.generate_object_based_api) {
1216       // Generate the UnPack() pre declaration.
1217       code_ += "  " + TableUnPackSignature(struct_def, true) + ";";
1218       code_ += "  " + TableUnPackToSignature(struct_def, true) + ";";
1219       code_ += "  " + TablePackSignature(struct_def, true) + ";";
1220     }
1221 
1222     code_ += "};";  // End of table.
1223     code_ += "";
1224 
1225     GenBuilders(struct_def);
1226 
1227     if (parser_.opts.generate_object_based_api) {
1228       // Generate a pre-declaration for a CreateX method that works with an
1229       // unpacked C++ object.
1230       code_ += TableCreateSignature(struct_def, true) + ";";
1231       code_ += "";
1232     }
1233   }
1234 
GenBuilders(const StructDef & struct_def)1235   void GenBuilders(const StructDef &struct_def) {
1236     code_.SetValue("STRUCT_NAME", struct_def.name);
1237 
1238     // Generate a builder struct:
1239     code_ += "struct {{STRUCT_NAME}}Builder {";
1240     code_ += "  flatbuffers::FlatBufferBuilder &fbb_;";
1241     code_ += "  flatbuffers::uoffset_t start_;";
1242 
1243     bool has_string_or_vector_fields = false;
1244     for (auto it = struct_def.fields.vec.begin();
1245          it != struct_def.fields.vec.end(); ++it) {
1246       const auto &field = **it;
1247       if (!field.deprecated) {
1248         const bool is_scalar = IsScalar(field.value.type.base_type);
1249         const bool is_string = field.value.type.base_type == BASE_TYPE_STRING;
1250         const bool is_vector = field.value.type.base_type == BASE_TYPE_VECTOR;
1251         if (is_string || is_vector) {
1252           has_string_or_vector_fields = true;
1253         }
1254 
1255         std::string offset = GenFieldOffsetName(field);
1256         std::string name = GenUnderlyingCast(field, false, field.name);
1257         std::string value = is_scalar ? GenDefaultConstant(field) : "";
1258 
1259         // Generate accessor functions of the form:
1260         // void add_name(type name) {
1261         //   fbb_.AddElement<type>(offset, name, default);
1262         // }
1263         code_.SetValue("FIELD_NAME", field.name);
1264         code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
1265         code_.SetValue("ADD_OFFSET", struct_def.name + "::" + offset);
1266         code_.SetValue("ADD_NAME", name);
1267         code_.SetValue("ADD_VALUE", value);
1268         if (is_scalar) {
1269           const auto type = GenTypeWire(field.value.type, "", false);
1270           code_.SetValue("ADD_FN", "AddElement<" + type + ">");
1271         } else if (IsStruct(field.value.type)) {
1272           code_.SetValue("ADD_FN", "AddStruct");
1273         } else {
1274           code_.SetValue("ADD_FN", "AddOffset");
1275         }
1276 
1277         code_ += "  void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
1278           code_ += "    fbb_.{{ADD_FN}}(\\";
1279         if (is_scalar) {
1280           code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
1281         } else {
1282           code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
1283         }
1284         code_ += "  }";
1285       }
1286     }
1287 
1288     // Builder constructor
1289     code_ += "  {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder &_fbb)";
1290     code_ += "        : fbb_(_fbb) {";
1291     code_ += "    start_ = fbb_.StartTable();";
1292     code_ += "  }";
1293 
1294     // Assignment operator;
1295     code_ += "  {{STRUCT_NAME}}Builder &operator="
1296              "(const {{STRUCT_NAME}}Builder &);";
1297 
1298     // Finish() function.
1299     auto num_fields = NumToString(struct_def.fields.vec.size());
1300     code_ += "  flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
1301     code_ += "    const auto end = fbb_.EndTable(start_, " + num_fields + ");";
1302     code_ += "    auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
1303 
1304     for (auto it = struct_def.fields.vec.begin();
1305          it != struct_def.fields.vec.end(); ++it) {
1306       const auto &field = **it;
1307       if (!field.deprecated && field.required) {
1308         code_.SetValue("FIELD_NAME", field.name);
1309         code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
1310         code_ += "    fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
1311       }
1312     }
1313     code_ += "    return o;";
1314     code_ += "  }";
1315     code_ += "};";
1316     code_ += "";
1317 
1318     // Generate a convenient CreateX function that uses the above builder
1319     // to create a table in one go.
1320     code_ += "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
1321             "Create{{STRUCT_NAME}}(";
1322     code_ += "    flatbuffers::FlatBufferBuilder &_fbb\\";
1323     for (auto it = struct_def.fields.vec.begin();
1324          it != struct_def.fields.vec.end(); ++it) {
1325       const auto &field = **it;
1326       if (!field.deprecated) {
1327         GenParam(field, false, ",\n    ");
1328       }
1329     }
1330     code_ += ") {";
1331 
1332     code_ += "  {{STRUCT_NAME}}Builder builder_(_fbb);";
1333     for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1334          size; size /= 2) {
1335       for (auto it = struct_def.fields.vec.rbegin();
1336            it != struct_def.fields.vec.rend(); ++it) {
1337         const auto &field = **it;
1338         if (!field.deprecated && (!struct_def.sortbysize ||
1339                                   size == SizeOf(field.value.type.base_type))) {
1340           code_.SetValue("FIELD_NAME", field.name);
1341           code_ += "  builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
1342         }
1343       }
1344     }
1345     code_ += "  return builder_.Finish();";
1346     code_ += "}";
1347     code_ += "";
1348 
1349     // Generate a CreateXDirect function with vector types as parameters
1350     if (has_string_or_vector_fields) {
1351       code_ += "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
1352               "Create{{STRUCT_NAME}}Direct(";
1353       code_ += "    flatbuffers::FlatBufferBuilder &_fbb\\";
1354       for (auto it = struct_def.fields.vec.begin();
1355            it != struct_def.fields.vec.end(); ++it) {
1356         const auto &field = **it;
1357         if (!field.deprecated) {
1358           GenParam(field, true, ",\n    ");
1359         }
1360       }
1361 
1362       // Need to call "Create" with the struct namespace.
1363       const auto qualified_create_name = struct_def.defined_namespace->GetFullyQualifiedName("Create");
1364       code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
1365 
1366       code_ += ") {";
1367       code_ += "  return {{CREATE_NAME}}{{STRUCT_NAME}}(";
1368       code_ += "      _fbb\\";
1369       for (auto it = struct_def.fields.vec.begin();
1370            it != struct_def.fields.vec.end(); ++it) {
1371         const auto &field = **it;
1372         if (!field.deprecated) {
1373           code_.SetValue("FIELD_NAME", field.name);
1374 
1375           if (field.value.type.base_type == BASE_TYPE_STRING) {
1376             code_ += ",\n      {{FIELD_NAME}} ? "
1377                     "_fbb.CreateString({{FIELD_NAME}}) : 0\\";
1378           } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
1379             auto type = GenTypeWire(field.value.type.VectorType(), "", false);
1380             code_ += ",\n      {{FIELD_NAME}} ? "
1381                     "_fbb.CreateVector<" + type + ">(*{{FIELD_NAME}}) : 0\\";
1382           } else {
1383             code_ += ",\n      {{FIELD_NAME}}\\";
1384           }
1385         }
1386       }
1387       code_ += ");";
1388       code_ += "}";
1389       code_ += "";
1390     }
1391   }
1392 
GenUnpackVal(const Type & type,const std::string & val,bool invector,const FieldDef & afield)1393   std::string GenUnpackVal(const Type &type, const std::string &val,
1394                            bool invector, const FieldDef &afield) {
1395     switch (type.base_type) {
1396       case BASE_TYPE_STRING: {
1397         return val + "->str()";
1398       }
1399       case BASE_TYPE_STRUCT: {
1400         const auto name = WrapInNameSpace(*type.struct_def);
1401         if (IsStruct(type)) {
1402           auto native_type = type.struct_def->attributes.Lookup("native_type");
1403           if (native_type) {
1404             return "flatbuffers::UnPack(*" + val + ")";
1405           } else if (invector || afield.native_inline) {
1406             return "*" + val;
1407           } else {
1408             const auto ptype = GenTypeNativePtr(name, &afield, true);
1409             return ptype + "(new " + name + "(*" + val + "))";
1410           }
1411         } else {
1412           const auto ptype = GenTypeNativePtr(NativeName(name), &afield, true);
1413           return ptype + "(" + val + "->UnPack(_resolver))";
1414         }
1415       }
1416       default: {
1417         return val;
1418         break;
1419       }
1420     }
1421   };
1422 
GenUnpackFieldStatement(const FieldDef & field,const FieldDef * union_field)1423   std::string GenUnpackFieldStatement(const FieldDef &field,
1424                                       const FieldDef *union_field) {
1425     std::string code;
1426     switch (field.value.type.base_type) {
1427       case BASE_TYPE_VECTOR: {
1428         std::string indexing;
1429         if (field.value.type.enum_def) {
1430           indexing += "(" + field.value.type.enum_def->name + ")";
1431         }
1432         indexing += "_e->Get(_i)";
1433         if (field.value.type.element == BASE_TYPE_BOOL) {
1434           indexing += " != 0";
1435         }
1436 
1437         // Generate code that pushes data from _e to _o in the form:
1438         //   for (uoffset_t i = 0; i < _e->size(); ++i) {
1439         //     _o->field.push_back(_e->Get(_i));
1440         //   }
1441         code += "for (flatbuffers::uoffset_t _i = 0;";
1442         code += " _i < _e->size(); _i++) { ";
1443         code += "_o->" + field.name + ".push_back(";
1444         code += GenUnpackVal(field.value.type.VectorType(),
1445                                   indexing, true, field);
1446         code += "); }";
1447         break;
1448       }
1449       case BASE_TYPE_UTYPE: {
1450         assert(union_field->value.type.base_type == BASE_TYPE_UNION);
1451         // Generate code that sets the union type, of the form:
1452         //   _o->field.type = _e;
1453         code += "_o->" + union_field->name + ".type = _e;";
1454         break;
1455       }
1456       case BASE_TYPE_UNION: {
1457         // Generate code that sets the union table, of the form:
1458         //   _o->field.table = Union::Unpack(_e, field_type(), resolver);
1459         code += "_o->" + field.name + ".table = ";
1460         code += field.value.type.enum_def->name + "Union::UnPack(";
1461         code += "_e, " + field.name + UnionTypeFieldSuffix() + "(),";
1462         code += "_resolver);";
1463         break;
1464       }
1465       default: {
1466         auto cpp_type = field.attributes.Lookup("cpp_type");
1467         if (cpp_type) {
1468           // Generate code that resolves the cpp pointer type, of the form:
1469           //  if (resolver)
1470           //    (*resolver)(&_o->field, (hash_value_t)(_e));
1471           //  else
1472           //    _o->field = nullptr;
1473           code += "if (_resolver) ";
1474           code += "(*_resolver)";
1475           code += "(reinterpret_cast<void **>(&_o->" + field.name + "), ";
1476           code += "static_cast<flatbuffers::hash_value_t>(_e));";
1477           code += " else ";
1478           code += "_o->" + field.name + " = nullptr;";
1479         } else {
1480           // Generate code for assigning the value, of the form:
1481           //  _o->field = value;
1482           code += "_o->" + field.name + " = ";
1483           code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
1484         }
1485         break;
1486       }
1487     }
1488     return code;
1489   }
1490 
GenCreateParam(const FieldDef & field)1491   std::string GenCreateParam(const FieldDef &field) {
1492     std::string value = "_o->";
1493     if (field.value.type.base_type == BASE_TYPE_UTYPE) {
1494       value += field.name.substr(0, field.name.size() -
1495                                  strlen(UnionTypeFieldSuffix()));
1496       value += ".type";
1497     } else {
1498       value += field.name;
1499     }
1500     if (field.attributes.Lookup("cpp_type")) {
1501       auto type = GenTypeBasic(field.value.type, false);
1502       value = "_rehasher ? "
1503               "static_cast<" + type + ">((*_rehasher)(" + value + ")) : 0";
1504     }
1505 
1506     std::string code;
1507     switch (field.value.type.base_type) {
1508       // String fields are of the form:
1509       //   _fbb.CreateString(_o->field)
1510       case BASE_TYPE_STRING: {
1511         code += "_fbb.CreateString(" + value + ")";
1512 
1513         // For optional fields, check to see if there actually is any data
1514         // in _o->field before attempting to access it.
1515         if (!field.required) {
1516           code = value + ".size() ? " + code + " : 0";
1517         }
1518         break;
1519       }
1520       // Vector fields come in several flavours, of the forms:
1521       //   _fbb.CreateVector(_o->field);
1522       //   _fbb.CreateVector((const utype*)_o->field.data(), _o->field.size());
1523       //   _fbb.CreateVectorOfStrings(_o->field)
1524       //   _fbb.CreateVectorOfStructs(_o->field)
1525       //   _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
1526       //     return CreateT(_fbb, _o->Get(i), rehasher);
1527       //   });
1528       case BASE_TYPE_VECTOR: {
1529         auto vector_type = field.value.type.VectorType();
1530         switch (vector_type.base_type) {
1531           case BASE_TYPE_STRING: {
1532             code += "_fbb.CreateVectorOfStrings(" + value + ")";
1533             break;
1534           }
1535           case BASE_TYPE_STRUCT: {
1536             if (IsStruct(vector_type)) {
1537               code += "_fbb.CreateVectorOfStructs(" + value + ")";
1538             } else {
1539               code += "_fbb.CreateVector<flatbuffers::Offset<";
1540               code += WrapInNameSpace(*vector_type.struct_def) + ">>";
1541               code += "(" + value + ".size(), [&](size_t i) {";
1542               code += " return Create" + vector_type.struct_def->name;
1543               code += "(_fbb, " + value + "[i]" + GenPtrGet(field) + ", ";
1544               code += "_rehasher); })";
1545             }
1546             break;
1547           }
1548           case BASE_TYPE_BOOL: {
1549             code += "_fbb.CreateVector(" + value + ")";
1550             break;
1551           }
1552           default: {
1553             if (field.value.type.enum_def) {
1554               // For enumerations, we need to get access to the array data for
1555               // the underlying storage type (eg. uint8_t).
1556               const auto basetype = GenTypeBasic(
1557                   field.value.type.enum_def->underlying_type, false);
1558               code += "_fbb.CreateVector((const " + basetype + "*)" + value +
1559                       ".data(), " + value + ".size())";
1560             } else {
1561               code += "_fbb.CreateVector(" + value + ")";
1562             }
1563             break;
1564           }
1565         }
1566 
1567         // For optional fields, check to see if there actually is any data
1568         // in _o->field before attempting to access it.
1569         if (!field.required) {
1570           code = value + ".size() ? " + code + " : 0";
1571         }
1572         break;
1573       }
1574       case BASE_TYPE_UNION: {
1575         // _o->field.Pack(_fbb);
1576         code += value + ".Pack(_fbb)";
1577         break;
1578       }
1579       case BASE_TYPE_STRUCT: {
1580         if (IsStruct(field.value.type)) {
1581           auto native_type =
1582               field.value.type.struct_def->attributes.Lookup("native_type");
1583           if (native_type) {
1584             code += "flatbuffers::Pack(" + value + ")";
1585           } else if (field.native_inline) {
1586             code += "&" + value;
1587           } else {
1588             code += value + " ? " + value + GenPtrGet(field) + " : 0";
1589           }
1590         } else {
1591           // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
1592           const auto type = field.value.type.struct_def->name;
1593           code += value + " ? Create" + type;
1594           code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
1595           code += " : 0";
1596         }
1597         break;
1598       }
1599       default: {
1600         code += value;
1601         break;
1602       }
1603     }
1604     return code;
1605   }
1606 
1607   // Generate code for tables that needs to come after the regular definition.
GenTablePost(const StructDef & struct_def)1608   void GenTablePost(const StructDef &struct_def) {
1609     code_.SetValue("STRUCT_NAME", struct_def.name);
1610     code_.SetValue("NATIVE_NAME", NativeName(struct_def.name));
1611 
1612     if (parser_.opts.generate_object_based_api) {
1613       // Generate the X::UnPack() method.
1614       code_ += "inline " + TableUnPackSignature(struct_def, false) + " {";
1615       code_ += "  auto _o = new {{NATIVE_NAME}}();";
1616       code_ += "  UnPackTo(_o, _resolver);";
1617       code_ += "  return _o;";
1618       code_ += "}";
1619       code_ += "";
1620 
1621       code_ += "inline " + TableUnPackToSignature(struct_def, false) + " {";
1622       code_ += "  (void)_o;";
1623       code_ += "  (void)_resolver;";
1624 
1625       for (auto it = struct_def.fields.vec.begin();
1626            it != struct_def.fields.vec.end(); ++it) {
1627         const auto &field = **it;
1628         if (field.deprecated) {
1629           continue;
1630         }
1631 
1632         // Assign a value from |this| to |_o|.   Values from |this| are stored
1633         // in a variable |_e| by calling this->field_type().  The value is then
1634         // assigned to |_o| using the GenUnpackFieldStatement.
1635         const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
1636         const auto statement =
1637             GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
1638 
1639         code_.SetValue("FIELD_NAME", field.name);
1640         auto prefix = "  { auto _e = {{FIELD_NAME}}(); ";
1641         auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
1642         auto postfix = " };";
1643         code_ += std::string(prefix) + check + statement + postfix;
1644       }
1645       code_ += "}";
1646       code_ += "";
1647 
1648       // Generate the X::Pack member function that simply calls the global
1649       // CreateX function.
1650       code_ += "inline " + TablePackSignature(struct_def, false) + " {";
1651       code_ += "  return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
1652       code_ += "}";
1653       code_ += "";
1654 
1655       // Generate a CreateX method that works with an unpacked C++ object.
1656       code_ += "inline " + TableCreateSignature(struct_def, false) + " {";
1657       code_ += "  (void)_rehasher;";
1658       code_ += "  (void)_o;";
1659 
1660       for (auto it = struct_def.fields.vec.begin();
1661            it != struct_def.fields.vec.end(); ++it) {
1662         auto &field = **it;
1663         if (field.deprecated) {
1664           continue;
1665         }
1666         code_ += "  auto _" + field.name + " = " + GenCreateParam(field) + ";";
1667       }
1668       // Need to call "Create" with the struct namespace.
1669       const auto qualified_create_name = struct_def.defined_namespace->GetFullyQualifiedName("Create");
1670       code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
1671 
1672       code_ += "  return {{CREATE_NAME}}{{STRUCT_NAME}}(";
1673       code_ += "      _fbb\\";
1674       for (auto it = struct_def.fields.vec.begin();
1675            it != struct_def.fields.vec.end(); ++it) {
1676         auto &field = **it;
1677         if (field.deprecated) {
1678           continue;
1679         }
1680 
1681         bool pass_by_address = false;
1682         if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1683           if (IsStruct(field.value.type)) {
1684             auto native_type =
1685                 field.value.type.struct_def->attributes.Lookup("native_type");
1686             if (native_type) {
1687               pass_by_address = true;
1688             }
1689           }
1690         }
1691 
1692         // Call the CreateX function using values from |_o|.
1693         if (pass_by_address) {
1694           code_ += ",\n      &_" + field.name + "\\";
1695         } else {
1696           code_ += ",\n      _" + field.name + "\\";
1697         }
1698       }
1699       code_ += ");";
1700       code_ += "}";
1701       code_ += "";
1702     }
1703   }
1704 
GenPadding(const FieldDef & field,std::string * code_ptr,int * id,const std::function<void (int bits,std::string * code_ptr,int * id)> & f)1705   static void GenPadding(
1706       const FieldDef &field, std::string *code_ptr, int *id,
1707       const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
1708     if (field.padding) {
1709       for (int i = 0; i < 4; i++) {
1710         if (static_cast<int>(field.padding) & (1 << i)) {
1711           f((1 << i) * 8, code_ptr, id);
1712         }
1713       }
1714       assert(!(field.padding & ~0xF));
1715     }
1716   }
1717 
PaddingDefinition(int bits,std::string * code_ptr,int * id)1718   static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
1719     *code_ptr += "  int" + NumToString(bits) + "_t padding" +
1720         NumToString((*id)++) + "__;";
1721   }
1722 
PaddingInitializer(int bits,std::string * code_ptr,int * id)1723   static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
1724     (void)bits;
1725     *code_ptr += ",\n        padding" + NumToString((*id)++) + "__(0)";
1726   }
1727 
PaddingNoop(int bits,std::string * code_ptr,int * id)1728   static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
1729     (void)bits;
1730     *code_ptr += "    (void)padding" + NumToString((*id)++) + "__;";
1731   }
1732 
1733   // Generate an accessor struct with constructor for a flatbuffers struct.
GenStruct(const StructDef & struct_def)1734   void GenStruct(const StructDef &struct_def) {
1735     // Generate an accessor struct, with private variables of the form:
1736     // type name_;
1737     // Generates manual padding and alignment.
1738     // Variables are private because they contain little endian data on all
1739     // platforms.
1740     GenComment(struct_def.doc_comment);
1741     code_.SetValue("ALIGN", NumToString(struct_def.minalign));
1742     code_.SetValue("STRUCT_NAME", struct_def.name);
1743 
1744     code_ += "MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
1745             "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
1746     code_ += " private:";
1747 
1748     int padding_id = 0;
1749     for (auto it = struct_def.fields.vec.begin();
1750          it != struct_def.fields.vec.end(); ++it) {
1751       const auto &field = **it;
1752       code_.SetValue("FIELD_TYPE",
1753           GenTypeGet(field.value.type, " ", "", " ", false));
1754       code_.SetValue("FIELD_NAME", field.name);
1755       code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}_;";
1756 
1757       if (field.padding) {
1758         std::string padding;
1759         GenPadding(field, &padding, &padding_id, PaddingDefinition);
1760         code_ += padding;
1761       }
1762     }
1763 
1764     // Generate GetFullyQualifiedName
1765     code_ += "";
1766     code_ += " public:";
1767     GenFullyQualifiedNameGetter(struct_def.name);
1768 
1769     // Generate a default constructor.
1770     code_ += "  {{STRUCT_NAME}}() {";
1771     code_ += "    memset(this, 0, sizeof({{STRUCT_NAME}}));";
1772     code_ += "  }";
1773 
1774     // Generate a copy constructor.
1775     code_ += "  {{STRUCT_NAME}}(const {{STRUCT_NAME}} &_o) {";
1776     code_ += "    memcpy(this, &_o, sizeof({{STRUCT_NAME}}));";
1777     code_ += "  }";
1778 
1779     // Generate a constructor that takes all fields as arguments.
1780     std::string arg_list;
1781     std::string init_list;
1782     padding_id = 0;
1783     for (auto it = struct_def.fields.vec.begin();
1784          it != struct_def.fields.vec.end(); ++it) {
1785       const auto &field = **it;
1786       const auto member_name = field.name + "_";
1787       const auto arg_name = "_" + field.name;
1788       const auto arg_type =
1789           GenTypeGet(field.value.type, " ", "const ", " &", true);
1790 
1791       if (it != struct_def.fields.vec.begin()) {
1792         arg_list += ", ";
1793         init_list += ",\n        ";
1794       }
1795       arg_list += arg_type;
1796       arg_list += arg_name;
1797       init_list += member_name;
1798       if (IsScalar(field.value.type.base_type)) {
1799         auto type = GenUnderlyingCast(field, false, arg_name);
1800         init_list += "(flatbuffers::EndianScalar(" + type + "))";
1801       } else {
1802         init_list += "(" + arg_name + ")";
1803       }
1804       if (field.padding) {
1805         GenPadding(field, &init_list, &padding_id, PaddingInitializer);
1806       }
1807     }
1808 
1809     code_.SetValue("ARG_LIST", arg_list);
1810     code_.SetValue("INIT_LIST", init_list);
1811     code_ += "  {{STRUCT_NAME}}({{ARG_LIST}})";
1812     code_ += "      : {{INIT_LIST}} {";
1813     padding_id = 0;
1814     for (auto it = struct_def.fields.vec.begin();
1815          it != struct_def.fields.vec.end(); ++it) {
1816       const auto &field = **it;
1817       if (field.padding) {
1818         std::string padding;
1819         GenPadding(field, &padding, &padding_id, PaddingNoop);
1820         code_ += padding;
1821       }
1822     }
1823     code_ += "  }";
1824 
1825     // Generate accessor methods of the form:
1826     // type name() const { return flatbuffers::EndianScalar(name_); }
1827     for (auto it = struct_def.fields.vec.begin();
1828          it != struct_def.fields.vec.end(); ++it) {
1829       const auto &field = **it;
1830 
1831       auto field_type = GenTypeGet(field.value.type, " ", "const ", " &", true);
1832       auto is_scalar = IsScalar(field.value.type.base_type);
1833       auto member = field.name + "_";
1834       auto value = is_scalar ? "flatbuffers::EndianScalar(" + member + ")"
1835                              : member;
1836 
1837       code_.SetValue("FIELD_NAME", field.name);
1838       code_.SetValue("FIELD_TYPE", field_type);
1839       code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
1840 
1841       GenComment(field.doc_comment, "  ");
1842       code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
1843       code_ += "    return {{FIELD_VALUE}};";
1844       code_ += "  }";
1845 
1846       if (parser_.opts.mutable_buffer) {
1847         if (is_scalar) {
1848           code_.SetValue("ARG", GenTypeBasic(field.value.type, true));
1849           code_.SetValue("FIELD_VALUE",
1850                         GenUnderlyingCast(field, false, "_" + field.name));
1851 
1852           code_ += "  void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
1853           code_ += "    flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
1854                   "{{FIELD_VALUE}});";
1855           code_ += "  }";
1856         } else {
1857           code_ += "  {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
1858           code_ += "    return {{FIELD_NAME}}_;";
1859           code_ += "  }";
1860         }
1861       }
1862     }
1863     code_ += "};";
1864 
1865     code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
1866     code_ += "STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
1867     code_ += "";
1868   }
1869 
1870   // Set up the correct namespace. Only open a namespace if the existing one is
1871   // different (closing/opening only what is necessary).
1872   //
1873   // The file must start and end with an empty (or null) namespace so that
1874   // namespaces are properly opened and closed.
SetNameSpace(const Namespace * ns)1875   void SetNameSpace(const Namespace *ns) {
1876     if (cur_name_space_ == ns) {
1877       return;
1878     }
1879 
1880     // Compute the size of the longest common namespace prefix.
1881     // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
1882     // the common prefix is A::B:: and we have old_size = 4, new_size = 5
1883     // and common_prefix_size = 2
1884     size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
1885     size_t new_size = ns ? ns->components.size() : 0;
1886 
1887     size_t common_prefix_size = 0;
1888     while (common_prefix_size < old_size && common_prefix_size < new_size &&
1889            ns->components[common_prefix_size] ==
1890                cur_name_space_->components[common_prefix_size]) {
1891       common_prefix_size++;
1892     }
1893 
1894     // Close cur_name_space in reverse order to reach the common prefix.
1895     // In the previous example, D then C are closed.
1896     for (size_t j = old_size; j > common_prefix_size; --j) {
1897       code_ += "}  // namespace " + cur_name_space_->components[j - 1];
1898     }
1899     if (old_size != common_prefix_size) {
1900       code_ += "";
1901     }
1902 
1903     // open namespace parts to reach the ns namespace
1904     // in the previous example, E, then F, then G are opened
1905     for (auto j = common_prefix_size; j != new_size; ++j) {
1906       code_ += "namespace " + ns->components[j] + " {";
1907     }
1908     if (new_size != common_prefix_size) {
1909       code_ += "";
1910     }
1911 
1912     cur_name_space_ = ns;
1913   }
1914 };
1915 
1916 }  // namespace cpp
1917 
GenerateCPP(const Parser & parser,const std::string & path,const std::string & file_name)1918 bool GenerateCPP(const Parser &parser, const std::string &path,
1919                  const std::string &file_name) {
1920   cpp::CppGenerator generator(parser, path, file_name);
1921   return generator.generate();
1922 }
1923 
CPPMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)1924 std::string CPPMakeRule(const Parser &parser, const std::string &path,
1925                         const std::string &file_name) {
1926   const auto filebase =
1927       flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
1928   const auto included_files = parser.GetIncludedFilesRecursive(file_name);
1929   std::string make_rule = GeneratedFileName(path, filebase) + ": ";
1930   for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1931     make_rule += " " + *it;
1932   }
1933   return make_rule;
1934 }
1935 
1936 }  // namespace flatbuffers
1937