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