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
24namespace flatbuffers {
25
26static std::string GeneratedFileName(const std::string &path,
27                                     const std::string &file_name) {
28  return path + file_name + "_generated.h";
29}
30
31namespace cpp {
32class CppGenerator : public BaseGenerator {
33 public:
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
39  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
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.
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
275  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.
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
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
296  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.
312  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.
334  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.
347  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.
358  static std::string NativeName(const std::string &name) { return name + "T"; }
359
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
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
377  std::string GenPtrGet(const FieldDef &field) {
378    auto &ptr_type = PtrType(&field);
379    return ptr_type == "naked" ? "" : ".get()";
380  }
381
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.
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
429  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
434  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
440  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
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
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
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
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
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
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
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
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.
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
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.
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
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
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
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
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
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.
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.
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
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.
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.
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
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
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
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
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.
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
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
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
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
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.
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.
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
1918bool 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
1924std::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