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