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#include <algorithm> 24 25namespace flatbuffers { 26 27// Convert an underscore_based_indentifier in to camelCase. 28// Also uppercases the first character if first is true. 29std::string MakeCamel(const std::string &in, bool first) { 30 std::string s; 31 for (size_t i = 0; i < in.length(); i++) { 32 if (!i && first) 33 s += static_cast<char>(toupper(in[0])); 34 else if (in[i] == '_' && i + 1 < in.length()) 35 s += static_cast<char>(toupper(in[++i])); 36 else 37 s += in[i]; 38 } 39 return s; 40} 41 42// These arrays need to correspond to the IDLOptions::k enum. 43 44struct LanguageParameters { 45 IDLOptions::Language language; 46 // Whether function names in the language typically start with uppercase. 47 bool first_camel_upper; 48 std::string file_extension; 49 std::string string_type; 50 std::string bool_type; 51 std::string open_curly; 52 std::string accessor_type; 53 std::string const_decl; 54 std::string unsubclassable_decl; 55 std::string enum_decl; 56 std::string enum_separator; 57 std::string getter_prefix; 58 std::string getter_suffix; 59 std::string inheritance_marker; 60 std::string namespace_ident; 61 std::string namespace_begin; 62 std::string namespace_end; 63 std::string set_bb_byteorder; 64 std::string get_bb_position; 65 std::string get_fbb_offset; 66 std::string accessor_prefix; 67 std::string accessor_prefix_static; 68 std::string optional_suffix; 69 std::string includes; 70 CommentConfig comment_config; 71}; 72 73const LanguageParameters& GetLangParams(IDLOptions::Language lang) { 74 static LanguageParameters language_parameters[] = { 75 { 76 IDLOptions::kJava, 77 false, 78 ".java", 79 "String", 80 "boolean ", 81 " {\n", 82 "class ", 83 " final ", 84 "final ", 85 "final class ", 86 ";\n", 87 "()", 88 "", 89 " extends ", 90 "package ", 91 ";", 92 "", 93 "_bb.order(ByteOrder.LITTLE_ENDIAN); ", 94 "position()", 95 "offset()", 96 "", 97 "", 98 "", 99 "import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n" 100 "import com.google.flatbuffers.*;\n\n@SuppressWarnings(\"unused\")\n", 101 { 102 "/**", 103 " *", 104 " */", 105 }, 106 }, 107 { 108 IDLOptions::kCSharp, 109 true, 110 ".cs", 111 "string", 112 "bool ", 113 "\n{\n", 114 "struct ", 115 " readonly ", 116 "", 117 "enum ", 118 ",\n", 119 " { get", 120 "} ", 121 " : ", 122 "namespace ", 123 "\n{", 124 "\n}\n", 125 "", 126 "Position", 127 "Offset", 128 "__p.", 129 "Table.", 130 "?", 131 "using System;\nusing FlatBuffers;\n\n", 132 { 133 nullptr, 134 "///", 135 nullptr, 136 }, 137 }, 138 }; 139 140 if (lang == IDLOptions::kJava) { 141 return language_parameters[0]; 142 } else { 143 assert(lang == IDLOptions::kCSharp); 144 return language_parameters[1]; 145 } 146} 147 148namespace general { 149class GeneralGenerator : public BaseGenerator { 150 public: 151 GeneralGenerator(const Parser &parser, const std::string &path, 152 const std::string &file_name) 153 : BaseGenerator(parser, path, file_name, "", "."), 154 lang_(GetLangParams(parser_.opts.lang)), 155 cur_name_space_( nullptr ) { 156 } 157 158 GeneralGenerator &operator=(const GeneralGenerator &); 159 bool generate() { 160 std::string one_file_code; 161 cur_name_space_ = parser_.namespaces_.back(); 162 163 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); 164 ++it) { 165 std::string enumcode; 166 auto &enum_def = **it; 167 if (!parser_.opts.one_file) 168 cur_name_space_ = enum_def.defined_namespace; 169 GenEnum(enum_def, &enumcode); 170 if (parser_.opts.one_file) { 171 one_file_code += enumcode; 172 } else { 173 if (!SaveType(enum_def.name, *enum_def.defined_namespace, 174 enumcode, false)) return false; 175 } 176 } 177 178 for (auto it = parser_.structs_.vec.begin(); 179 it != parser_.structs_.vec.end(); ++it) { 180 std::string declcode; 181 auto &struct_def = **it; 182 if (!parser_.opts.one_file) 183 cur_name_space_ = struct_def.defined_namespace; 184 GenStruct(struct_def, &declcode); 185 if (parser_.opts.one_file) { 186 one_file_code += declcode; 187 } else { 188 if (!SaveType(struct_def.name, *struct_def.defined_namespace, 189 declcode, true)) return false; 190 } 191 } 192 193 if (parser_.opts.one_file) { 194 return SaveType(file_name_, *parser_.namespaces_.back(), 195 one_file_code, true); 196 } 197 return true; 198 } 199 200 // Save out the generated code for a single class while adding 201 // declaration boilerplate. 202 bool SaveType(const std::string &defname, const Namespace &ns, 203 const std::string &classcode, bool needs_includes) { 204 if (!classcode.length()) return true; 205 206 std::string code; 207 code = code + "// " + FlatBuffersGeneratedWarning(); 208 std::string namespace_name = FullNamespace(".", ns); 209 if (!namespace_name.empty()) { 210 code += lang_.namespace_ident + namespace_name + lang_.namespace_begin; 211 code += "\n\n"; 212 } 213 if (needs_includes) code += lang_.includes; 214 code += classcode; 215 if (!namespace_name.empty()) code += lang_.namespace_end; 216 auto filename = NamespaceDir(ns) + defname + lang_.file_extension; 217 return SaveFile(filename.c_str(), code, false); 218 } 219 220 const Namespace *CurrentNameSpace() const { return cur_name_space_; } 221 222 std::string FunctionStart(char upper) { 223 return std::string() + (lang_.language == IDLOptions::kJava 224 ? static_cast<char>(tolower(upper)) 225 : upper); 226} 227 228static bool IsEnum(const Type& type) { 229 return type.enum_def != nullptr && IsInteger(type.base_type); 230} 231 232std::string GenTypeBasic(const Type &type, bool enableLangOverrides) { 233 static const char *java_typename[] = { 234 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ 235 #JTYPE, 236 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) 237 #undef FLATBUFFERS_TD 238 }; 239 240 static const char *csharp_typename[] = { 241 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ 242 #NTYPE, 243 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) 244 #undef FLATBUFFERS_TD 245 }; 246 247 if (enableLangOverrides) { 248 if (lang_.language == IDLOptions::kCSharp) { 249 if (IsEnum(type)) return WrapInNameSpace(*type.enum_def); 250 if (type.base_type == BASE_TYPE_STRUCT) { 251 return "Offset<" + WrapInNameSpace(*type.struct_def) + ">"; 252 } 253 } 254 } 255 256 if (lang_.language == IDLOptions::kJava) { 257 return java_typename[type.base_type]; 258 } else { 259 assert(lang_.language == IDLOptions::kCSharp); 260 return csharp_typename[type.base_type]; 261 } 262} 263 264std::string GenTypeBasic(const Type &type) { 265 return GenTypeBasic(type, true); 266} 267 268std::string GenTypePointer(const Type &type) { 269 switch (type.base_type) { 270 case BASE_TYPE_STRING: 271 return lang_.string_type; 272 case BASE_TYPE_VECTOR: 273 return GenTypeGet(type.VectorType()); 274 case BASE_TYPE_STRUCT: 275 return WrapInNameSpace(*type.struct_def); 276 case BASE_TYPE_UNION: 277 // Unions in C# use a generic Table-derived type for better type safety 278 if (lang_.language == IDLOptions::kCSharp) return "TTable"; 279 // fall through 280 default: 281 return "Table"; 282 } 283} 284 285std::string GenTypeGet(const Type &type) { 286 return IsScalar(type.base_type) 287 ? GenTypeBasic(type) 288 : GenTypePointer(type); 289} 290 291// Find the destination type the user wants to receive the value in (e.g. 292// one size higher signed types for unsigned serialized values in Java). 293Type DestinationType(const Type &type, bool vectorelem) { 294 if (lang_.language != IDLOptions::kJava) return type; 295 switch (type.base_type) { 296 // We use int for both uchar/ushort, since that generally means less casting 297 // than using short for uchar. 298 case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT); 299 case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT); 300 case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG); 301 case BASE_TYPE_VECTOR: 302 if (vectorelem) 303 return DestinationType(type.VectorType(), vectorelem); 304 // else fall thru: 305 default: return type; 306 } 307} 308 309std::string GenOffsetType(const StructDef &struct_def) { 310 if(lang_.language == IDLOptions::kCSharp) { 311 return "Offset<" + WrapInNameSpace(struct_def) + ">"; 312 } else { 313 return "int"; 314 } 315} 316 317std::string GenOffsetConstruct(const StructDef &struct_def, 318 const std::string &variable_name) 319{ 320 if(lang_.language == IDLOptions::kCSharp) { 321 return "new Offset<" + WrapInNameSpace(struct_def) + ">(" + variable_name + 322 ")"; 323 } 324 return variable_name; 325} 326 327std::string GenVectorOffsetType() { 328 if(lang_.language == IDLOptions::kCSharp) { 329 return "VectorOffset"; 330 } else { 331 return "int"; 332 } 333} 334 335// Generate destination type name 336std::string GenTypeNameDest(const Type &type) 337{ 338 return GenTypeGet(DestinationType(type, true)); 339} 340 341// Mask to turn serialized value into destination type value. 342std::string DestinationMask(const Type &type, bool vectorelem) { 343 if (lang_.language != IDLOptions::kJava) return ""; 344 switch (type.base_type) { 345 case BASE_TYPE_UCHAR: return " & 0xFF"; 346 case BASE_TYPE_USHORT: return " & 0xFFFF"; 347 case BASE_TYPE_UINT: return " & 0xFFFFFFFFL"; 348 case BASE_TYPE_VECTOR: 349 if (vectorelem) 350 return DestinationMask(type.VectorType(), vectorelem); 351 // else fall thru: 352 default: return ""; 353 } 354} 355 356// Casts necessary to correctly read serialized data 357std::string DestinationCast(const Type &type) { 358 if (type.base_type == BASE_TYPE_VECTOR) { 359 return DestinationCast(type.VectorType()); 360 } else { 361 switch (lang_.language) { 362 case IDLOptions::kJava: 363 // Cast necessary to correctly read serialized unsigned values. 364 if (type.base_type == BASE_TYPE_UINT) return "(long)"; 365 break; 366 367 case IDLOptions::kCSharp: 368 // Cast from raw integral types to enum. 369 if (IsEnum(type)) return "(" + WrapInNameSpace(*type.enum_def) + ")"; 370 break; 371 372 default: 373 break; 374 } 375 } 376 return ""; 377} 378 379// Cast statements for mutator method parameters. 380// In Java, parameters representing unsigned numbers need to be cast down to 381// their respective type. For example, a long holding an unsigned int value 382// would be cast down to int before being put onto the buffer. In C#, one cast 383// directly cast an Enum to its underlying type, which is essential before 384// putting it onto the buffer. 385std::string SourceCast(const Type &type, bool castFromDest) { 386 if (type.base_type == BASE_TYPE_VECTOR) { 387 return SourceCast(type.VectorType(), castFromDest); 388 } else { 389 switch (lang_.language) { 390 case IDLOptions::kJava: 391 if (castFromDest) { 392 if (type.base_type == BASE_TYPE_UINT) return "(int)"; 393 else if (type.base_type == BASE_TYPE_USHORT) return "(short)"; 394 else if (type.base_type == BASE_TYPE_UCHAR) return "(byte)"; 395 } 396 break; 397 case IDLOptions::kCSharp: 398 if (IsEnum(type)) return "(" + GenTypeBasic(type, false) + ")"; 399 break; 400 default: 401 break; 402 } 403 } 404 return ""; 405} 406 407std::string SourceCast(const Type &type) { 408 return SourceCast(type, true); 409} 410 411std::string SourceCastBasic(const Type &type, bool castFromDest) { 412 return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : ""; 413} 414 415std::string SourceCastBasic(const Type &type) { 416 return SourceCastBasic(type, true); 417} 418 419 420std::string GenEnumDefaultValue(const Value &value) { 421 auto enum_def = value.type.enum_def; 422 auto vec = enum_def->vals.vec; 423 auto default_value = StringToInt(value.constant.c_str()); 424 425 auto result = value.constant; 426 for (auto it = vec.begin(); it != vec.end(); ++it) { 427 auto enum_val = **it; 428 if (enum_val.value == default_value) { 429 result = WrapInNameSpace(*enum_def) + "." + enum_val.name; 430 break; 431 } 432 } 433 434 return result; 435} 436 437std::string GenDefaultValue(const Value &value, bool enableLangOverrides) { 438 if (enableLangOverrides) { 439 // handles both enum case and vector of enum case 440 if (lang_.language == IDLOptions::kCSharp && 441 value.type.enum_def != nullptr && 442 value.type.base_type != BASE_TYPE_UNION) { 443 return GenEnumDefaultValue(value); 444 } 445 } 446 447 auto longSuffix = lang_.language == IDLOptions::kJava ? "L" : ""; 448 switch (value.type.base_type) { 449 case BASE_TYPE_FLOAT: return value.constant + "f"; 450 case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true"; 451 case BASE_TYPE_ULONG: 452 { 453 if (lang_.language != IDLOptions::kJava) 454 return value.constant; 455 // Converts the ulong into its bits signed equivalent 456 uint64_t defaultValue = StringToUInt(value.constant.c_str()); 457 return NumToString(static_cast<int64_t>(defaultValue)) + longSuffix; 458 } 459 case BASE_TYPE_UINT: 460 case BASE_TYPE_LONG: return value.constant + longSuffix; 461 default: return value.constant; 462 } 463} 464 465std::string GenDefaultValue(const Value &value) { 466 return GenDefaultValue(value, true); 467} 468 469std::string GenDefaultValueBasic(const Value &value, bool enableLangOverrides) { 470 if (!IsScalar(value.type.base_type)) { 471 if (enableLangOverrides) { 472 if (lang_.language == IDLOptions::kCSharp) { 473 switch (value.type.base_type) { 474 case BASE_TYPE_STRING: 475 return "default(StringOffset)"; 476 case BASE_TYPE_STRUCT: 477 return "default(Offset<" + WrapInNameSpace(*value.type.struct_def) + 478 ">)"; 479 case BASE_TYPE_VECTOR: 480 return "default(VectorOffset)"; 481 default: 482 break; 483 } 484 } 485 } 486 return "0"; 487 } 488 return GenDefaultValue(value, enableLangOverrides); 489} 490 491std::string GenDefaultValueBasic(const Value &value) { 492 return GenDefaultValueBasic(value, true); 493} 494 495void GenEnum(EnumDef &enum_def, std::string *code_ptr) { 496 std::string &code = *code_ptr; 497 if (enum_def.generated) return; 498 499 // Generate enum definitions of the form: 500 // public static (final) int name = value; 501 // In Java, we use ints rather than the Enum feature, because we want them 502 // to map directly to how they're used in C/C++ and file formats. 503 // That, and Java Enums are expensive, and not universally liked. 504 GenComment(enum_def.doc_comment, code_ptr, &lang_.comment_config); 505 code += std::string("public ") + lang_.enum_decl + enum_def.name; 506 if (lang_.language == IDLOptions::kCSharp) { 507 code += lang_.inheritance_marker + 508 GenTypeBasic(enum_def.underlying_type, false); 509 } 510 code += lang_.open_curly; 511 if (lang_.language == IDLOptions::kJava) { 512 code += " private " + enum_def.name + "() { }\n"; 513 } 514 for (auto it = enum_def.vals.vec.begin(); 515 it != enum_def.vals.vec.end(); 516 ++it) { 517 auto &ev = **it; 518 GenComment(ev.doc_comment, code_ptr, &lang_.comment_config, " "); 519 if (lang_.language != IDLOptions::kCSharp) { 520 code += " public static"; 521 code += lang_.const_decl; 522 code += GenTypeBasic(enum_def.underlying_type, false); 523 } 524 code += " " + ev.name + " = "; 525 code += NumToString(ev.value); 526 code += lang_.enum_separator; 527 } 528 529 // Generate a generate string table for enum values. 530 // We do not do that for C# where this functionality is native. 531 if (lang_.language != IDLOptions::kCSharp) { 532 // Problem is, if values are very sparse that could generate really big 533 // tables. Ideally in that case we generate a map lookup instead, but for 534 // the moment we simply don't output a table at all. 535 auto range = enum_def.vals.vec.back()->value - 536 enum_def.vals.vec.front()->value + 1; 537 // Average distance between values above which we consider a table 538 // "too sparse". Change at will. 539 static const int kMaxSparseness = 5; 540 if (range / static_cast<int64_t>(enum_def.vals.vec.size()) < kMaxSparseness) { 541 code += "\n public static"; 542 code += lang_.const_decl; 543 code += lang_.string_type; 544 code += "[] names = { "; 545 auto val = enum_def.vals.vec.front()->value; 546 for (auto it = enum_def.vals.vec.begin(); 547 it != enum_def.vals.vec.end(); 548 ++it) { 549 while (val++ != (*it)->value) code += "\"\", "; 550 code += "\"" + (*it)->name + "\", "; 551 } 552 code += "};\n\n"; 553 code += " public static "; 554 code += lang_.string_type; 555 code += " " + MakeCamel("name", lang_.first_camel_upper); 556 code += "(int e) { return names[e"; 557 if (enum_def.vals.vec.front()->value) 558 code += " - " + enum_def.vals.vec.front()->name; 559 code += "]; }\n"; 560 } 561 } 562 563 // Close the class 564 code += "}"; 565 // Java does not need the closing semi-colon on class definitions. 566 code += (lang_.language != IDLOptions::kJava) ? ";" : ""; 567 code += "\n\n"; 568} 569 570// Returns the function name that is able to read a value of the given type. 571std::string GenGetter(const Type &type) { 572 switch (type.base_type) { 573 case BASE_TYPE_STRING: return lang_.accessor_prefix + "__string"; 574 case BASE_TYPE_STRUCT: return lang_.accessor_prefix + "__struct"; 575 case BASE_TYPE_UNION: return lang_.accessor_prefix + "__union"; 576 case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); 577 default: { 578 std::string getter = 579 lang_.accessor_prefix + "bb." + FunctionStart('G') + "et"; 580 if (type.base_type == BASE_TYPE_BOOL) { 581 getter = "0!=" + getter; 582 } else if (GenTypeBasic(type, false) != "byte") { 583 getter += MakeCamel(GenTypeBasic(type, false)); 584 } 585 return getter; 586 } 587 } 588} 589 590// Direct mutation is only allowed for scalar fields. 591// Hence a setter method will only be generated for such fields. 592std::string GenSetter(const Type &type) { 593 if (IsScalar(type.base_type)) { 594 std::string setter = 595 lang_.accessor_prefix + "bb." + FunctionStart('P') + "ut"; 596 if (GenTypeBasic(type, false) != "byte" && 597 type.base_type != BASE_TYPE_BOOL) { 598 setter += MakeCamel(GenTypeBasic(type, false)); 599 } 600 return setter; 601 } else { 602 return ""; 603 } 604} 605 606// Returns the method name for use with add/put calls. 607std::string GenMethod(const Type &type) { 608 return IsScalar(type.base_type) 609 ? MakeCamel(GenTypeBasic(type, false)) 610 : (IsStruct(type) ? "Struct" : "Offset"); 611} 612 613// Recursively generate arguments for a constructor, to deal with nested 614// structs. 615void GenStructArgs(const StructDef &struct_def, std::string *code_ptr, 616 const char *nameprefix) { 617 std::string &code = *code_ptr; 618 for (auto it = struct_def.fields.vec.begin(); 619 it != struct_def.fields.vec.end(); 620 ++it) { 621 auto &field = **it; 622 if (IsStruct(field.value.type)) { 623 // Generate arguments for a struct inside a struct. To ensure names 624 // don't clash, and to make it obvious these arguments are constructing 625 // a nested struct, prefix the name with the field name. 626 GenStructArgs(*field.value.type.struct_def, code_ptr, 627 (nameprefix + (field.name + "_")).c_str()); 628 } else { 629 code += ", "; 630 code += GenTypeBasic(DestinationType(field.value.type, false)); 631 code += " "; 632 code += nameprefix; 633 code += MakeCamel(field.name, lang_.first_camel_upper); 634 } 635 } 636} 637 638// Recusively generate struct construction statements of the form: 639// builder.putType(name); 640// and insert manual padding. 641void GenStructBody(const StructDef &struct_def, std::string *code_ptr, 642 const char *nameprefix) { 643 std::string &code = *code_ptr; 644 code += " builder." + FunctionStart('P') + "rep("; 645 code += NumToString(struct_def.minalign) + ", "; 646 code += NumToString(struct_def.bytesize) + ");\n"; 647 for (auto it = struct_def.fields.vec.rbegin(); 648 it != struct_def.fields.vec.rend(); ++it) { 649 auto &field = **it; 650 if (field.padding) { 651 code += " builder." + FunctionStart('P') + "ad("; 652 code += NumToString(field.padding) + ");\n"; 653 } 654 if (IsStruct(field.value.type)) { 655 GenStructBody(*field.value.type.struct_def, code_ptr, 656 (nameprefix + (field.name + "_")).c_str()); 657 } else { 658 code += " builder." + FunctionStart('P') + "ut"; 659 code += GenMethod(field.value.type) + "("; 660 code += SourceCast(field.value.type); 661 auto argname = nameprefix + MakeCamel(field.name, lang_.first_camel_upper); 662 code += argname; 663 code += ");\n"; 664 } 665 } 666} 667 668std::string GenByteBufferLength(const char *bb_name) { 669 std::string bb_len = bb_name; 670 if (lang_.language == IDLOptions::kCSharp) bb_len += ".Length"; 671 else bb_len += ".array().length"; 672 return bb_len; 673} 674 675std::string GenOffsetGetter(flatbuffers::FieldDef *key_field, 676 const char *num = nullptr) { 677 std::string key_offset = ""; 678 key_offset += lang_.accessor_prefix_static + "__offset(" + 679 NumToString(key_field->value.offset) + ", "; 680 if (num) { 681 key_offset += num; 682 key_offset += (lang_.language == IDLOptions::kCSharp ? 683 ".Value, builder.DataBuffer)" : ", _bb)"); 684 } else { 685 key_offset += GenByteBufferLength("bb"); 686 key_offset += " - tableOffset, bb)"; 687 } 688 return key_offset; 689} 690 691std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) { 692 std::string key_getter = " "; 693 key_getter += "int tableOffset = " + lang_.accessor_prefix_static; 694 key_getter += "__indirect(vectorLocation + 4 * (start + middle)"; 695 key_getter += ", bb);\n "; 696 if (key_field->value.type.base_type == BASE_TYPE_STRING) { 697 key_getter += "int comp = " + lang_.accessor_prefix_static; 698 key_getter += FunctionStart('C') + "ompareStrings("; 699 key_getter += GenOffsetGetter(key_field); 700 key_getter += ", byteKey, bb);\n"; 701 } else { 702 auto get_val = GenGetter(key_field->value.type) + 703 "(" + GenOffsetGetter(key_field) + ")"; 704 if (lang_.language == IDLOptions::kCSharp) { 705 key_getter += "int comp = " + get_val + ".CompareTo(key);\n"; 706 } else { 707 key_getter += GenTypeGet(key_field->value.type) + " val = "; 708 key_getter += get_val + ";\n"; 709 key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n"; 710 } 711 } 712 return key_getter; 713} 714 715 716std::string GenKeyGetter(flatbuffers::FieldDef *key_field) { 717 std::string key_getter = ""; 718 auto data_buffer = (lang_.language == IDLOptions::kCSharp) ? 719 "builder.DataBuffer" : "_bb"; 720 if (key_field->value.type.base_type == BASE_TYPE_STRING) { 721 if (lang_.language == IDLOptions::kJava) 722 key_getter += " return "; 723 key_getter += lang_.accessor_prefix_static; 724 key_getter += FunctionStart('C') + "ompareStrings("; 725 key_getter += GenOffsetGetter(key_field, "o1") + ", "; 726 key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")"; 727 if (lang_.language == IDLOptions::kJava) 728 key_getter += ";"; 729 } 730 else { 731 auto field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) + 732 "(" + GenOffsetGetter(key_field, "o1") + ")"; 733 if (lang_.language == IDLOptions::kCSharp) { 734 key_getter += field_getter; 735 field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) + 736 "(" + GenOffsetGetter(key_field, "o2") + ")"; 737 key_getter += ".CompareTo(" + field_getter + ")"; 738 } 739 else { 740 key_getter += "\n " + GenTypeGet(key_field->value.type) + " val_1 = "; 741 key_getter += field_getter + ";\n " + GenTypeGet(key_field->value.type); 742 key_getter += " val_2 = "; 743 field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) + 744 "(" + GenOffsetGetter(key_field, "o2") + ")"; 745 key_getter += field_getter + ";\n"; 746 key_getter += " return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n "; 747 } 748 } 749 return key_getter; 750} 751 752void GenStruct(StructDef &struct_def, std::string *code_ptr) { 753 if (struct_def.generated) return; 754 std::string &code = *code_ptr; 755 756 // Generate a struct accessor class, with methods of the form: 757 // public type name() { return bb.getType(i + offset); } 758 // or for tables of the form: 759 // public type name() { 760 // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default; 761 // } 762 GenComment(struct_def.doc_comment, code_ptr, &lang_.comment_config); 763 code += "public "; 764 if (lang_.language == IDLOptions::kCSharp && 765 struct_def.attributes.Lookup("csharp_partial")) { 766 // generate a partial class for this C# struct/table 767 code += "partial "; 768 } else { 769 code += lang_.unsubclassable_decl; 770 } 771 code += lang_.accessor_type + struct_def.name; 772 if (lang_.language == IDLOptions::kCSharp) { 773 code += " : IFlatbufferObject"; 774 code += lang_.open_curly; 775 code += " private "; 776 code += struct_def.fixed ? "Struct" : "Table"; 777 code += " __p;\n"; 778 779 if (lang_.language == IDLOptions::kCSharp) { 780 code += " public ByteBuffer ByteBuffer { get { return __p.bb; } }\n"; 781 } 782 783 } else { 784 code += lang_.inheritance_marker; 785 code += struct_def.fixed ? "Struct" : "Table"; 786 code += lang_.open_curly; 787 } 788 if (!struct_def.fixed) { 789 // Generate a special accessor for the table that when used as the root 790 // of a FlatBuffer 791 std::string method_name = FunctionStart('G') + "etRootAs" + struct_def.name; 792 std::string method_signature = " public static " + struct_def.name + " " + 793 method_name; 794 795 // create convenience method that doesn't require an existing object 796 code += method_signature + "(ByteBuffer _bb) "; 797 code += "{ return " + method_name + "(_bb, new " + struct_def.name+ "()); }\n"; 798 799 // create method that allows object reuse 800 code += method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { "; 801 code += lang_.set_bb_byteorder; 802 code += "return (obj.__assign(_bb." + FunctionStart('G') + "etInt(_bb."; 803 code += lang_.get_bb_position; 804 code += ") + _bb."; 805 code += lang_.get_bb_position; 806 code += ", _bb)); }\n"; 807 if (parser_.root_struct_def_ == &struct_def) { 808 if (parser_.file_identifier_.length()) { 809 // Check if a buffer has the identifier. 810 code += " public static "; 811 code += lang_.bool_type + struct_def.name; 812 code += "BufferHasIdentifier(ByteBuffer _bb) { return "; 813 code += lang_.accessor_prefix_static + "__has_identifier(_bb, \""; 814 code += parser_.file_identifier_; 815 code += "\"); }\n"; 816 } 817 } 818 } 819 // Generate the __init method that sets the field in a pre-existing 820 // accessor object. This is to allow object reuse. 821 code += " public void __init(int _i, ByteBuffer _bb) "; 822 code += "{ " + lang_.accessor_prefix + "bb_pos = _i; "; 823 code += lang_.accessor_prefix + "bb = _bb; }\n"; 824 code += " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) "; 825 code += "{ __init(_i, _bb); return this; }\n\n"; 826 for (auto it = struct_def.fields.vec.begin(); 827 it != struct_def.fields.vec.end(); 828 ++it) { 829 auto &field = **it; 830 if (field.deprecated) continue; 831 GenComment(field.doc_comment, code_ptr, &lang_.comment_config, " "); 832 std::string type_name = GenTypeGet(field.value.type); 833 std::string type_name_dest = GenTypeNameDest(field.value.type); 834 std::string conditional_cast = ""; 835 std::string optional = ""; 836 if (lang_.language == IDLOptions::kCSharp && 837 !struct_def.fixed && 838 (field.value.type.base_type == BASE_TYPE_STRUCT || 839 field.value.type.base_type == BASE_TYPE_UNION || 840 (field.value.type.base_type == BASE_TYPE_VECTOR && 841 field.value.type.element == BASE_TYPE_STRUCT))) { 842 optional = lang_.optional_suffix; 843 conditional_cast = "(" + type_name_dest + optional + ")"; 844 } 845 std::string dest_mask = DestinationMask(field.value.type, true); 846 std::string dest_cast = DestinationCast(field.value.type); 847 std::string src_cast = SourceCast(field.value.type); 848 std::string method_start = " public " + type_name_dest + optional + " " + 849 MakeCamel(field.name, lang_.first_camel_upper); 850 std::string obj = lang_.language == IDLOptions::kCSharp 851 ? "(new " + type_name + "())" 852 : "obj"; 853 854 // Most field accessors need to retrieve and test the field offset first, 855 // this is the prefix code for that: 856 auto offset_prefix = " { int o = " + lang_.accessor_prefix + "__offset(" + 857 NumToString(field.value.offset) + 858 "); return o != 0 ? "; 859 // Generate the accessors that don't do object reuse. 860 if (field.value.type.base_type == BASE_TYPE_STRUCT) { 861 // Calls the accessor that takes an accessor object with a new object. 862 if (lang_.language != IDLOptions::kCSharp) { 863 code += method_start + "() { return "; 864 code += MakeCamel(field.name, lang_.first_camel_upper); 865 code += "(new "; 866 code += type_name + "()); }\n"; 867 } 868 } else if (field.value.type.base_type == BASE_TYPE_VECTOR && 869 field.value.type.element == BASE_TYPE_STRUCT) { 870 // Accessors for vectors of structs also take accessor objects, this 871 // generates a variant without that argument. 872 if (lang_.language != IDLOptions::kCSharp) { 873 code += method_start + "(int j) { return "; 874 code += MakeCamel(field.name, lang_.first_camel_upper); 875 code += "(new " + type_name + "(), j); }\n"; 876 } 877 } else if (field.value.type.base_type == BASE_TYPE_UNION) { 878 if (lang_.language == IDLOptions::kCSharp) { 879 // Union types in C# use generic Table-derived type for better type 880 // safety. 881 method_start += "<TTable>"; 882 type_name = type_name_dest; 883 } 884 } 885 std::string getter = dest_cast + GenGetter(field.value.type); 886 code += method_start; 887 std::string default_cast = ""; 888 // only create default casts for c# scalars or vectors of scalars 889 if (lang_.language == IDLOptions::kCSharp && 890 (IsScalar(field.value.type.base_type) || 891 (field.value.type.base_type == BASE_TYPE_VECTOR && 892 IsScalar(field.value.type.element)))) { 893 // For scalars, default value will be returned by GetDefaultValue(). 894 // If the scalar is an enum, GetDefaultValue() returns an actual c# enum 895 // that doesn't need to be casted. However, default values for enum 896 // elements of vectors are integer literals ("0") and are still casted 897 // for clarity. 898 if (field.value.type.enum_def == nullptr || 899 field.value.type.base_type == BASE_TYPE_VECTOR) { 900 default_cast = "(" + type_name_dest + ")"; 901 } 902 } 903 std::string member_suffix = "; "; 904 if (IsScalar(field.value.type.base_type)) { 905 code += lang_.getter_prefix; 906 member_suffix += lang_.getter_suffix; 907 if (struct_def.fixed) { 908 code += " { return " + getter; 909 code += "(" + lang_.accessor_prefix + "bb_pos + "; 910 code += NumToString(field.value.offset) + ")"; 911 code += dest_mask; 912 } else { 913 code += offset_prefix + getter; 914 code += "(o + " + lang_.accessor_prefix + "bb_pos)" + dest_mask; 915 code += " : " + default_cast; 916 code += GenDefaultValue(field.value); 917 } 918 } else { 919 switch (field.value.type.base_type) { 920 case BASE_TYPE_STRUCT: 921 if (lang_.language != IDLOptions::kCSharp) { 922 code += "(" + type_name + " obj" + ")"; 923 } else { 924 code += lang_.getter_prefix; 925 member_suffix += lang_.getter_suffix; 926 } 927 if (struct_def.fixed) { 928 code += " { return " + obj + ".__assign(" + lang_.accessor_prefix; 929 code += "bb_pos + " + NumToString(field.value.offset) + ", "; 930 code += lang_.accessor_prefix + "bb)"; 931 } else { 932 code += offset_prefix + conditional_cast; 933 code += obj + ".__assign("; 934 code += field.value.type.struct_def->fixed 935 ? "o + " + lang_.accessor_prefix + "bb_pos" 936 : lang_.accessor_prefix + "__indirect(o + " + 937 lang_.accessor_prefix + "bb_pos)"; 938 code += ", " + lang_.accessor_prefix + "bb) : null"; 939 } 940 break; 941 case BASE_TYPE_STRING: 942 code += lang_.getter_prefix; 943 member_suffix += lang_.getter_suffix; 944 code += offset_prefix + getter + "(o + " + lang_.accessor_prefix; 945 code += "bb_pos) : null"; 946 break; 947 case BASE_TYPE_VECTOR: { 948 auto vectortype = field.value.type.VectorType(); 949 code += "("; 950 if (vectortype.base_type == BASE_TYPE_STRUCT) { 951 if (lang_.language != IDLOptions::kCSharp) 952 code += type_name + " obj, "; 953 getter = obj + ".__assign"; 954 } 955 code += "int j)" + offset_prefix + conditional_cast + getter +"("; 956 auto index = lang_.accessor_prefix + "__vector(o) + j * " + 957 NumToString(InlineSize(vectortype)); 958 if (vectortype.base_type == BASE_TYPE_STRUCT) { 959 code += vectortype.struct_def->fixed 960 ? index 961 : lang_.accessor_prefix + "__indirect(" + index + ")"; 962 code += ", " + lang_.accessor_prefix + "bb"; 963 } else { 964 code += index; 965 } 966 code += ")" + dest_mask + " : "; 967 968 code += field.value.type.element == BASE_TYPE_BOOL ? "false" : 969 (IsScalar(field.value.type.element) ? default_cast + "0" : "null"); 970 break; 971 } 972 case BASE_TYPE_UNION: 973 if (lang_.language == IDLOptions::kCSharp) { 974 code += "() where TTable : struct, IFlatbufferObject"; 975 code += offset_prefix + "(TTable?)" + getter; 976 code += "<TTable>(o) : null"; 977 } else { 978 code += "(" + type_name + " obj)" + offset_prefix + getter; 979 code += "(obj, o) : null"; 980 } 981 break; 982 default: 983 assert(0); 984 } 985 } 986 code += member_suffix; 987 code += "}\n"; 988 if (field.value.type.base_type == BASE_TYPE_VECTOR) { 989 code += " public int " + MakeCamel(field.name, lang_.first_camel_upper); 990 code += "Length"; 991 code += lang_.getter_prefix; 992 code += offset_prefix; 993 code += lang_.accessor_prefix + "__vector_len(o) : 0; "; 994 code += lang_.getter_suffix; 995 code += "}\n"; 996 } 997 // Generate a ByteBuffer accessor for strings & vectors of scalars. 998 if ((field.value.type.base_type == BASE_TYPE_VECTOR && 999 IsScalar(field.value.type.VectorType().base_type)) || 1000 field.value.type.base_type == BASE_TYPE_STRING) { 1001 switch (lang_.language) { 1002 case IDLOptions::kJava: 1003 code += " public ByteBuffer "; 1004 code += MakeCamel(field.name, lang_.first_camel_upper); 1005 code += "AsByteBuffer() { return "; 1006 code += lang_.accessor_prefix + "__vector_as_bytebuffer("; 1007 code += NumToString(field.value.offset) + ", "; 1008 code += NumToString(field.value.type.base_type == BASE_TYPE_STRING 1009 ? 1 1010 : InlineSize(field.value.type.VectorType())); 1011 code += "); }\n"; 1012 break; 1013 case IDLOptions::kCSharp: 1014 code += " public ArraySegment<byte>? Get"; 1015 code += MakeCamel(field.name, lang_.first_camel_upper); 1016 code += "Bytes() { return "; 1017 code += lang_.accessor_prefix + "__vector_as_arraysegment("; 1018 code += NumToString(field.value.offset); 1019 code += "); }\n"; 1020 break; 1021 default: 1022 break; 1023 } 1024 } 1025 // generate object accessors if is nested_flatbuffer 1026 auto nested = field.attributes.Lookup("nested_flatbuffer"); 1027 if (nested) { 1028 auto nested_qualified_name = 1029 parser_.namespaces_.back()->GetFullyQualifiedName(nested->constant); 1030 auto nested_type = parser_.structs_.Lookup(nested_qualified_name); 1031 auto nested_type_name = WrapInNameSpace(*nested_type); 1032 auto nestedMethodName = MakeCamel(field.name, lang_.first_camel_upper) 1033 + "As" + nested_type_name; 1034 auto getNestedMethodName = nestedMethodName; 1035 if (lang_.language == IDLOptions::kCSharp) { 1036 getNestedMethodName = "Get" + nestedMethodName; 1037 conditional_cast = "(" + nested_type_name + lang_.optional_suffix + ")"; 1038 } 1039 if (lang_.language != IDLOptions::kCSharp) { 1040 code += " public " + nested_type_name + lang_.optional_suffix + " "; 1041 code += nestedMethodName + "() { return "; 1042 code += getNestedMethodName + "(new " + nested_type_name + "()); }\n"; 1043 } else { 1044 obj = "(new " + nested_type_name + "())"; 1045 } 1046 code += " public " + nested_type_name + lang_.optional_suffix + " "; 1047 code += getNestedMethodName + "("; 1048 if (lang_.language != IDLOptions::kCSharp) 1049 code += nested_type_name + " obj"; 1050 code += ") { int o = " + lang_.accessor_prefix + "__offset("; 1051 code += NumToString(field.value.offset) +"); "; 1052 code += "return o != 0 ? " + conditional_cast + obj + ".__assign("; 1053 code += lang_.accessor_prefix; 1054 code += "__indirect(" + lang_.accessor_prefix + "__vector(o)), "; 1055 code += lang_.accessor_prefix + "bb) : null; }\n"; 1056 } 1057 // Generate mutators for scalar fields or vectors of scalars. 1058 if (parser_.opts.mutable_buffer) { 1059 auto underlying_type = field.value.type.base_type == BASE_TYPE_VECTOR 1060 ? field.value.type.VectorType() 1061 : field.value.type; 1062 // Boolean parameters have to be explicitly converted to byte 1063 // representation. 1064 auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL 1065 ? "(byte)(" + field.name + " ? 1 : 0)" 1066 : field.name; 1067 auto mutator_prefix = MakeCamel("mutate", lang_.first_camel_upper); 1068 // A vector mutator also needs the index of the vector element it should 1069 // mutate. 1070 auto mutator_params = (field.value.type.base_type == BASE_TYPE_VECTOR 1071 ? "(int j, " 1072 : "(") + GenTypeNameDest(underlying_type) + " " + field.name + ") { "; 1073 auto setter_index = field.value.type.base_type == BASE_TYPE_VECTOR 1074 ? lang_.accessor_prefix + "__vector(o) + j * " + 1075 NumToString(InlineSize(underlying_type)) 1076 : (struct_def.fixed 1077 ? lang_.accessor_prefix + "bb_pos + " + 1078 NumToString(field.value.offset) 1079 : "o + " + lang_.accessor_prefix + "bb_pos"); 1080 if (IsScalar(field.value.type.base_type) || 1081 (field.value.type.base_type == BASE_TYPE_VECTOR && 1082 IsScalar(field.value.type.VectorType().base_type))) { 1083 code += " public "; 1084 code += struct_def.fixed ? "void " : lang_.bool_type; 1085 code += mutator_prefix + MakeCamel(field.name, true); 1086 code += mutator_params; 1087 if (struct_def.fixed) { 1088 code += GenSetter(underlying_type) + "(" + setter_index + ", "; 1089 code += src_cast + setter_parameter + "); }\n"; 1090 } else { 1091 code += "int o = " + lang_.accessor_prefix + "__offset("; 1092 code += NumToString(field.value.offset) + ");"; 1093 code += " if (o != 0) { " + GenSetter(underlying_type); 1094 code += "(" + setter_index + ", " + src_cast + setter_parameter + 1095 "); return true; } else { return false; } }\n"; 1096 } 1097 } 1098 } 1099 } 1100 code += "\n"; 1101 flatbuffers::FieldDef *key_field = nullptr; 1102 if (struct_def.fixed) { 1103 // create a struct constructor function 1104 code += " public static " + GenOffsetType(struct_def) + " "; 1105 code += FunctionStart('C') + "reate"; 1106 code += struct_def.name + "(FlatBufferBuilder builder"; 1107 GenStructArgs(struct_def, code_ptr, ""); 1108 code += ") {\n"; 1109 GenStructBody(struct_def, code_ptr, ""); 1110 code += " return "; 1111 code += GenOffsetConstruct(struct_def, 1112 "builder." + std::string(lang_.get_fbb_offset)); 1113 code += ";\n }\n"; 1114 } else { 1115 // Generate a method that creates a table in one go. This is only possible 1116 // when the table has no struct fields, since those have to be created 1117 // inline, and there's no way to do so in Java. 1118 bool has_no_struct_fields = true; 1119 int num_fields = 0; 1120 for (auto it = struct_def.fields.vec.begin(); 1121 it != struct_def.fields.vec.end(); ++it) { 1122 auto &field = **it; 1123 if (field.deprecated) continue; 1124 if (IsStruct(field.value.type)) { 1125 has_no_struct_fields = false; 1126 } else { 1127 num_fields++; 1128 } 1129 } 1130 if (has_no_struct_fields && num_fields) { 1131 // Generate a table constructor of the form: 1132 // public static int createName(FlatBufferBuilder builder, args...) 1133 code += " public static " + GenOffsetType(struct_def) + " "; 1134 code += FunctionStart('C') + "reate" + struct_def.name; 1135 code += "(FlatBufferBuilder builder"; 1136 for (auto it = struct_def.fields.vec.begin(); 1137 it != struct_def.fields.vec.end(); ++it) { 1138 auto &field = **it; 1139 if (field.deprecated) continue; 1140 code += ",\n "; 1141 code += GenTypeBasic(DestinationType(field.value.type, false)); 1142 code += " "; 1143 code += field.name; 1144 if (!IsScalar(field.value.type.base_type)) code += "Offset"; 1145 1146 // Java doesn't have defaults, which means this method must always 1147 // supply all arguments, and thus won't compile when fields are added. 1148 if (lang_.language != IDLOptions::kJava) { 1149 code += " = "; 1150 code += GenDefaultValueBasic(field.value); 1151 } 1152 } 1153 code += ") {\n builder."; 1154 code += FunctionStart('S') + "tartObject("; 1155 code += NumToString(struct_def.fields.vec.size()) + ");\n"; 1156 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; 1157 size; 1158 size /= 2) { 1159 for (auto it = struct_def.fields.vec.rbegin(); 1160 it != struct_def.fields.vec.rend(); ++it) { 1161 auto &field = **it; 1162 if (!field.deprecated && 1163 (!struct_def.sortbysize || 1164 size == SizeOf(field.value.type.base_type))) { 1165 code += " " + struct_def.name + "."; 1166 code += FunctionStart('A') + "dd"; 1167 code += MakeCamel(field.name) + "(builder, " + field.name; 1168 if (!IsScalar(field.value.type.base_type)) code += "Offset"; 1169 code += ");\n"; 1170 } 1171 } 1172 } 1173 code += " return " + struct_def.name + "."; 1174 code += FunctionStart('E') + "nd" + struct_def.name; 1175 code += "(builder);\n }\n\n"; 1176 } 1177 // Generate a set of static methods that allow table construction, 1178 // of the form: 1179 // public static void addName(FlatBufferBuilder builder, short name) 1180 // { builder.addShort(id, name, default); } 1181 // Unlike the Create function, these always work. 1182 code += " public static void " + FunctionStart('S') + "tart"; 1183 code += struct_def.name; 1184 code += "(FlatBufferBuilder builder) { builder."; 1185 code += FunctionStart('S') + "tartObject("; 1186 code += NumToString(struct_def.fields.vec.size()) + "); }\n"; 1187 for (auto it = struct_def.fields.vec.begin(); 1188 it != struct_def.fields.vec.end(); ++it) { 1189 auto &field = **it; 1190 if (field.deprecated) continue; 1191 if (field.key) key_field = &field; 1192 code += " public static void " + FunctionStart('A') + "dd"; 1193 code += MakeCamel(field.name); 1194 code += "(FlatBufferBuilder builder, "; 1195 code += GenTypeBasic(DestinationType(field.value.type, false)); 1196 auto argname = MakeCamel(field.name, false); 1197 if (!IsScalar(field.value.type.base_type)) argname += "Offset"; 1198 code += " " + argname + ") { builder." + FunctionStart('A') + "dd"; 1199 code += GenMethod(field.value.type) + "("; 1200 code += NumToString(it - struct_def.fields.vec.begin()) + ", "; 1201 code += SourceCastBasic(field.value.type); 1202 code += argname; 1203 if (!IsScalar(field.value.type.base_type) && 1204 field.value.type.base_type != BASE_TYPE_UNION && 1205 lang_.language == IDLOptions::kCSharp) { 1206 code += ".Value"; 1207 } 1208 code += ", "; 1209 if (lang_.language == IDLOptions::kJava) 1210 code += SourceCastBasic( field.value.type ); 1211 code += GenDefaultValue(field.value, false); 1212 code += "); }\n"; 1213 if (field.value.type.base_type == BASE_TYPE_VECTOR) { 1214 auto vector_type = field.value.type.VectorType(); 1215 auto alignment = InlineAlignment(vector_type); 1216 auto elem_size = InlineSize(vector_type); 1217 if (!IsStruct(vector_type)) { 1218 // Generate a method to create a vector from a Java array. 1219 code += " public static " + GenVectorOffsetType() + " "; 1220 code += FunctionStart('C') + "reate"; 1221 code += MakeCamel(field.name); 1222 code += "Vector(FlatBufferBuilder builder, "; 1223 code += GenTypeBasic(vector_type) + "[] data) "; 1224 code += "{ builder." + FunctionStart('S') + "tartVector("; 1225 code += NumToString(elem_size); 1226 code += ", data." + FunctionStart('L') + "ength, "; 1227 code += NumToString(alignment); 1228 code += "); for (int i = data."; 1229 code += FunctionStart('L') + "ength - 1; i >= 0; i--) builder."; 1230 code += FunctionStart('A') + "dd"; 1231 code += GenMethod(vector_type); 1232 code += "("; 1233 code += SourceCastBasic(vector_type, false); 1234 code += "data[i]"; 1235 if (lang_.language == IDLOptions::kCSharp && 1236 (vector_type.base_type == BASE_TYPE_STRUCT || 1237 vector_type.base_type == BASE_TYPE_STRING)) 1238 code += ".Value"; 1239 code += "); return "; 1240 code += "builder." + FunctionStart('E') + "ndVector(); }\n"; 1241 } 1242 // Generate a method to start a vector, data to be added manually after. 1243 code += " public static void " + FunctionStart('S') + "tart"; 1244 code += MakeCamel(field.name); 1245 code += "Vector(FlatBufferBuilder builder, int numElems) "; 1246 code += "{ builder." + FunctionStart('S') + "tartVector("; 1247 code += NumToString(elem_size); 1248 code += ", numElems, " + NumToString(alignment); 1249 code += "); }\n"; 1250 } 1251 } 1252 code += " public static " + GenOffsetType(struct_def) + " "; 1253 code += FunctionStart('E') + "nd" + struct_def.name; 1254 code += "(FlatBufferBuilder builder) {\n int o = builder."; 1255 code += FunctionStart('E') + "ndObject();\n"; 1256 for (auto it = struct_def.fields.vec.begin(); 1257 it != struct_def.fields.vec.end(); 1258 ++it) { 1259 auto &field = **it; 1260 if (!field.deprecated && field.required) { 1261 code += " builder." + FunctionStart('R') + "equired(o, "; 1262 code += NumToString(field.value.offset); 1263 code += "); // " + field.name + "\n"; 1264 } 1265 } 1266 code += " return " + GenOffsetConstruct(struct_def, "o") + ";\n }\n"; 1267 if (parser_.root_struct_def_ == &struct_def) { 1268 code += " public static void "; 1269 code += FunctionStart('F') + "inish" + struct_def.name; 1270 code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def); 1271 code += " offset) {"; 1272 code += " builder." + FunctionStart('F') + "inish(offset"; 1273 if (lang_.language == IDLOptions::kCSharp) { 1274 code += ".Value"; 1275 } 1276 1277 if (parser_.file_identifier_.length()) 1278 code += ", \"" + parser_.file_identifier_ + "\""; 1279 code += "); }\n"; 1280 } 1281 } 1282 if (struct_def.has_key) { 1283 if (lang_.language == IDLOptions::kJava) { 1284 code += "\n @Override\n protected int keysCompare("; 1285 code += "Integer o1, Integer o2, ByteBuffer _bb) {"; 1286 code += GenKeyGetter(key_field); 1287 code += " }\n"; 1288 } 1289 else { 1290 code += "\n public static VectorOffset "; 1291 code += "CreateMySortedVectorOfTables(FlatBufferBuilder builder, "; 1292 code += "Offset<" + struct_def.name + ">"; 1293 code += "[] offsets) {\n"; 1294 code += " Array.Sort(offsets, (Offset<" + struct_def.name + 1295 "> o1, Offset<" + struct_def.name + "> o2) => " + GenKeyGetter(key_field); 1296 code += ");\n"; 1297 code += " return builder.CreateVectorOfTables(offsets);\n }\n"; 1298 } 1299 1300 code += "\n public static " + struct_def.name + lang_.optional_suffix; 1301 code += " " + FunctionStart('L') + "ookupByKey(" + GenVectorOffsetType(); 1302 code += " vectorOffset, " + GenTypeGet(key_field->value.type); 1303 code += " key, ByteBuffer bb) {\n"; 1304 if (key_field->value.type.base_type == BASE_TYPE_STRING) { 1305 code += " byte[] byteKey = "; 1306 if (lang_.language == IDLOptions::kJava) 1307 code += "key.getBytes(Table.UTF8_CHARSET.get());\n"; 1308 else 1309 code += "System.Text.Encoding.UTF8.GetBytes(key);\n"; 1310 } 1311 code += " int vectorLocation = " + GenByteBufferLength("bb"); 1312 code += " - vectorOffset"; 1313 if (lang_.language == IDLOptions::kCSharp) code += ".Value"; 1314 code += ";\n int span = "; 1315 code += "bb." + FunctionStart('G') + "etInt(vectorLocation);\n"; 1316 code += " int start = 0;\n"; 1317 code += " vectorLocation += 4;\n"; 1318 code += " while (span != 0) {\n"; 1319 code += " int middle = span / 2;\n"; 1320 code += GenLookupKeyGetter(key_field); 1321 code += " if (comp > 0) {\n"; 1322 code += " span = middle;\n"; 1323 code += " } else if (comp < 0) {\n"; 1324 code += " middle++;\n"; 1325 code += " start += middle;\n"; 1326 code += " span -= middle;\n"; 1327 code += " } else {\n"; 1328 code += " return new " + struct_def.name; 1329 code += "().__assign(tableOffset, bb);\n"; 1330 code += " }\n }\n"; 1331 code += " return null;\n"; 1332 code += " }\n"; 1333 } 1334 code += "}"; 1335 // Java does not need the closing semi-colon on class definitions. 1336 code += (lang_.language != IDLOptions::kJava) ? ";" : ""; 1337 code += "\n\n"; 1338} 1339 const LanguageParameters& lang_; 1340 // This tracks the current namespace used to determine if a type need to be prefixed by its namespace 1341 const Namespace *cur_name_space_; 1342}; 1343} // namespace general 1344 1345bool GenerateGeneral(const Parser &parser, const std::string &path, 1346 const std::string &file_name) { 1347 general::GeneralGenerator generator(parser, path, file_name); 1348 return generator.generate(); 1349} 1350 1351std::string GeneralMakeRule(const Parser &parser, const std::string &path, 1352 const std::string &file_name) { 1353 assert(parser.opts.lang <= IDLOptions::kMAX); 1354 const auto &lang = GetLangParams(parser.opts.lang); 1355 1356 std::string make_rule; 1357 1358 for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); 1359 ++it) { 1360 auto &enum_def = **it; 1361 if (make_rule != "") make_rule += " "; 1362 std::string directory = 1363 BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace); 1364 make_rule += directory + enum_def.name + lang.file_extension; 1365 } 1366 1367 for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); 1368 ++it) { 1369 auto &struct_def = **it; 1370 if (make_rule != "") make_rule += " "; 1371 std::string directory = 1372 BaseGenerator::NamespaceDir(parser, path, 1373 *struct_def.defined_namespace); 1374 make_rule += directory + struct_def.name + lang.file_extension; 1375 } 1376 1377 make_rule += ": "; 1378 auto included_files = parser.GetIncludedFilesRecursive(file_name); 1379 for (auto it = included_files.begin(); it != included_files.end(); ++it) { 1380 make_rule += " " + *it; 1381 } 1382 return make_rule; 1383} 1384 1385std::string BinaryFileName(const Parser &parser, 1386 const std::string &path, 1387 const std::string &file_name) { 1388 auto ext = parser.file_extension_.length() ? parser.file_extension_ : "bin"; 1389 return path + file_name + "." + ext; 1390} 1391 1392bool GenerateBinary(const Parser &parser, 1393 const std::string &path, 1394 const std::string &file_name) { 1395 return !parser.builder_.GetSize() || 1396 flatbuffers::SaveFile( 1397 BinaryFileName(parser, path, file_name).c_str(), 1398 reinterpret_cast<char *>(parser.builder_.GetBufferPointer()), 1399 parser.builder_.GetSize(), 1400 true); 1401} 1402 1403std::string BinaryMakeRule(const Parser &parser, 1404 const std::string &path, 1405 const std::string &file_name) { 1406 if (!parser.builder_.GetSize()) return ""; 1407 std::string filebase = flatbuffers::StripPath( 1408 flatbuffers::StripExtension(file_name)); 1409 std::string make_rule = BinaryFileName(parser, path, filebase) + ": " + 1410 file_name; 1411 auto included_files = parser.GetIncludedFilesRecursive( 1412 parser.root_struct_def_->file); 1413 for (auto it = included_files.begin(); 1414 it != included_files.end(); ++it) { 1415 make_rule += " " + *it; 1416 } 1417 return make_rule; 1418} 1419 1420} // namespace flatbuffers 1421