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