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