bb2920f5d4bbf691a0653af86c42c82eea8b0e06
[platform/upstream/flatbuffers.git] / src / idl_gen_general.cpp
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@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       if (parser_.opts.java_checkerframework) {
232         code += "\nimport org.checkerframework.dataflow.qual.Pure;\n";
233       }
234       code += lang_.class_annotation;
235     }
236     if (parser_.opts.gen_generated) {
237       code += lang_.generated_type_annotation;
238     }
239     code += classcode;
240     if (!namespace_name.empty()) code += lang_.namespace_end;
241     auto filename = NamespaceDir(ns) + defname + lang_.file_extension;
242     return SaveFile(filename.c_str(), code, false);
243   }
244
245   const Namespace *CurrentNameSpace() const { return cur_name_space_; }
246
247   std::string FunctionStart(char upper) const {
248     return std::string() + (lang_.language == IDLOptions::kJava
249                                 ? static_cast<char>(tolower(upper))
250                                 : upper);
251   }
252
253   std::string GenNullableAnnotation(const Type &t) const {
254     return lang_.language == IDLOptions::kJava && parser_.opts.gen_nullable &&
255                    !IsScalar(DestinationType(t, true).base_type) &&
256                    t.base_type != BASE_TYPE_VECTOR
257                ? " @Nullable "
258                : "";
259   }
260
261   std::string GenPureAnnotation(const Type &t) const {
262     return lang_.language == IDLOptions::kJava &&
263                    parser_.opts.java_checkerframework &&
264                    !IsScalar(DestinationType(t, true).base_type)
265                ? " @Pure "
266                : "";
267   }
268
269   std::string GenTypeBasic(const Type &type, bool enableLangOverrides) const {
270     // clang-format off
271   static const char * const java_typename[] = {
272     #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
273         CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
274         #JTYPE,
275       FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
276     #undef FLATBUFFERS_TD
277   };
278
279   static const char * const csharp_typename[] = {
280     #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
281         CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
282         #NTYPE,
283       FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
284     #undef FLATBUFFERS_TD
285   };
286     // clang-format on
287
288     if (enableLangOverrides) {
289       if (lang_.language == IDLOptions::kCSharp) {
290         if (IsEnum(type)) return WrapInNameSpace(*type.enum_def);
291         if (type.base_type == BASE_TYPE_STRUCT) {
292           return "Offset<" + WrapInNameSpace(*type.struct_def) + ">";
293         }
294       }
295     }
296
297     if (lang_.language == IDLOptions::kJava) {
298       return java_typename[type.base_type];
299     } else {
300       FLATBUFFERS_ASSERT(lang_.language == IDLOptions::kCSharp);
301       return csharp_typename[type.base_type];
302     }
303   }
304
305   std::string GenTypeBasic(const Type &type) const {
306     return GenTypeBasic(type, true);
307   }
308
309   std::string GenTypePointer(const Type &type) const {
310     switch (type.base_type) {
311       case BASE_TYPE_STRING: return lang_.string_type;
312       case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
313       case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
314       case BASE_TYPE_UNION:
315         // Unions in C# use a generic Table-derived type for better type safety
316         if (lang_.language == IDLOptions::kCSharp) return "TTable";
317         FLATBUFFERS_FALLTHROUGH();  // else fall thru
318       default: return "Table";
319     }
320   }
321
322   std::string GenTypeGet(const Type &type) const {
323     return IsScalar(type.base_type)
324                ? GenTypeBasic(type)
325                : (IsArray(type) ? GenTypeGet(type.VectorType())
326                                 : GenTypePointer(type));
327   }
328
329   // Find the destination type the user wants to receive the value in (e.g.
330   // one size higher signed types for unsigned serialized values in Java).
331   Type DestinationType(const Type &type, bool vectorelem) const {
332     if (lang_.language != IDLOptions::kJava) return type;
333     switch (type.base_type) {
334       // We use int for both uchar/ushort, since that generally means less
335       // casting than using short for uchar.
336       case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT);
337       case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT);
338       case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
339       case BASE_TYPE_ARRAY:
340       case BASE_TYPE_VECTOR:
341         if (vectorelem) return DestinationType(type.VectorType(), vectorelem);
342         FLATBUFFERS_FALLTHROUGH(); // else fall thru
343       default: return type;
344     }
345   }
346
347   std::string GenOffsetType(const StructDef &struct_def) const {
348     if (lang_.language == IDLOptions::kCSharp) {
349       return "Offset<" + WrapInNameSpace(struct_def) + ">";
350     } else {
351       return "int";
352     }
353   }
354
355   std::string GenOffsetConstruct(const StructDef &struct_def,
356                                  const std::string &variable_name) const {
357     if (lang_.language == IDLOptions::kCSharp) {
358       return "new Offset<" + WrapInNameSpace(struct_def) + ">(" +
359              variable_name + ")";
360     }
361     return variable_name;
362   }
363
364   std::string GenVectorOffsetType() const {
365     if (lang_.language == IDLOptions::kCSharp) {
366       return "VectorOffset";
367     } else {
368       return "int";
369     }
370   }
371
372   // Generate destination type name
373   std::string GenTypeNameDest(const Type &type) const {
374     return GenTypeGet(DestinationType(type, true));
375   }
376
377   // Mask to turn serialized value into destination type value.
378   std::string DestinationMask(const Type &type, bool vectorelem) const {
379     if (lang_.language != IDLOptions::kJava) return "";
380     switch (type.base_type) {
381       case BASE_TYPE_UCHAR: return " & 0xFF";
382       case BASE_TYPE_USHORT: return " & 0xFFFF";
383       case BASE_TYPE_UINT: return " & 0xFFFFFFFFL";
384       case BASE_TYPE_VECTOR:
385         if (vectorelem) return DestinationMask(type.VectorType(), vectorelem);
386         FLATBUFFERS_FALLTHROUGH(); // else fall thru
387       default: return "";
388     }
389   }
390
391   // Casts necessary to correctly read serialized data
392   std::string DestinationCast(const Type &type) const {
393     if (IsSeries(type)) {
394       return DestinationCast(type.VectorType());
395     } else {
396       switch (lang_.language) {
397         case IDLOptions::kJava:
398           // Cast necessary to correctly read serialized unsigned values.
399           if (type.base_type == BASE_TYPE_UINT) return "(long)";
400           break;
401
402         case IDLOptions::kCSharp:
403           // Cast from raw integral types to enum.
404           if (IsEnum(type)) return "(" + WrapInNameSpace(*type.enum_def) + ")";
405           break;
406
407         default: break;
408       }
409     }
410     return "";
411   }
412
413   // Cast statements for mutator method parameters.
414   // In Java, parameters representing unsigned numbers need to be cast down to
415   // their respective type. For example, a long holding an unsigned int value
416   // would be cast down to int before being put onto the buffer. In C#, one cast
417   // directly cast an Enum to its underlying type, which is essential before
418   // putting it onto the buffer.
419   std::string SourceCast(const Type &type, bool castFromDest) const {
420     if (IsSeries(type)) {
421       return SourceCast(type.VectorType(), castFromDest);
422     } else {
423       switch (lang_.language) {
424         case IDLOptions::kJava:
425           if (castFromDest) {
426             if (type.base_type == BASE_TYPE_UINT)
427               return "(int)";
428             else if (type.base_type == BASE_TYPE_USHORT)
429               return "(short)";
430             else if (type.base_type == BASE_TYPE_UCHAR)
431               return "(byte)";
432           }
433           break;
434         case IDLOptions::kCSharp:
435           if (IsEnum(type)) return "(" + GenTypeBasic(type, false) + ")";
436           break;
437         default: break;
438       }
439     }
440     return "";
441   }
442
443   std::string SourceCast(const Type &type) const { return SourceCast(type, true); }
444
445   std::string SourceCastBasic(const Type &type, bool castFromDest) const {
446     return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : "";
447   }
448
449   std::string SourceCastBasic(const Type &type) const {
450     return SourceCastBasic(type, true);
451   }
452
453   std::string GenEnumDefaultValue(const FieldDef &field) const {
454     auto &value = field.value;
455     FLATBUFFERS_ASSERT(value.type.enum_def);
456     auto &enum_def = *value.type.enum_def;
457     auto enum_val = enum_def.FindByValue(value.constant);
458     return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
459                     : value.constant;
460   }
461
462   std::string GenDefaultValue(const FieldDef &field, bool enableLangOverrides) const {
463     auto& value = field.value;
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(field);
470       }
471     }
472
473     auto longSuffix = lang_.language == IDLOptions::kJava ? "L" : "";
474     switch (value.type.base_type) {
475       case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
476       case BASE_TYPE_ULONG: {
477         if (lang_.language != IDLOptions::kJava) return value.constant;
478         // Converts the ulong into its bits signed equivalent
479         uint64_t defaultValue = StringToUInt(value.constant.c_str());
480         return NumToString(static_cast<int64_t>(defaultValue)) + longSuffix;
481       }
482       case BASE_TYPE_UINT:
483       case BASE_TYPE_LONG: return value.constant + longSuffix;
484       default:
485         if(IsFloat(value.type.base_type))
486           return lang_.float_gen->GenFloatConstant(field);
487         else
488           return value.constant;
489     }
490   }
491
492   std::string GenDefaultValue(const FieldDef &field) const {
493     return GenDefaultValue(field, true);
494   }
495
496   std::string GenDefaultValueBasic(const FieldDef &field,
497                                    bool enableLangOverrides) const {
498     auto& value = field.value;
499     if (!IsScalar(value.type.base_type)) {
500       if (enableLangOverrides) {
501         if (lang_.language == IDLOptions::kCSharp) {
502           switch (value.type.base_type) {
503             case BASE_TYPE_STRING: return "default(StringOffset)";
504             case BASE_TYPE_STRUCT:
505               return "default(Offset<" +
506                      WrapInNameSpace(*value.type.struct_def) + ">)";
507             case BASE_TYPE_VECTOR: return "default(VectorOffset)";
508             default: break;
509           }
510         }
511       }
512       return "0";
513     }
514     return GenDefaultValue(field, enableLangOverrides);
515   }
516
517   std::string GenDefaultValueBasic(const FieldDef &field) const {
518     return GenDefaultValueBasic(field, true);
519   }
520
521   void GenEnum(EnumDef &enum_def, std::string *code_ptr) const {
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
532     // In C# this indicates enumeration values can be treated as bit flags.
533     if (lang_.language == IDLOptions::kCSharp && enum_def.attributes.Lookup("bit_flags")) {
534       code += "[System.FlagsAttribute]\n";
535     }
536     if (enum_def.attributes.Lookup("private")) {
537       // For Java, we leave the enum unmarked to indicate package-private
538       // For C# we mark the enum as internal
539       if (lang_.language == IDLOptions::kCSharp) {
540         code += "internal ";
541       }
542     } else {
543       code += "public ";
544     }
545     code += lang_.enum_decl + enum_def.name;
546     if (lang_.language == IDLOptions::kCSharp) {
547       code += lang_.inheritance_marker +
548               GenTypeBasic(enum_def.underlying_type, false);
549     }
550     code += lang_.open_curly;
551     if (lang_.language == IDLOptions::kJava) {
552       code += "  private " + enum_def.name + "() { }\n";
553     }
554     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
555       auto &ev = **it;
556       GenComment(ev.doc_comment, code_ptr, &lang_.comment_config, "  ");
557       if (lang_.language != IDLOptions::kCSharp) {
558         code += "  public static";
559         code += lang_.const_decl;
560         code += GenTypeBasic(enum_def.underlying_type, false);
561       }
562       code += (lang_.language == IDLOptions::kJava) ? " " : "  ";
563       code += ev.name + " = ";
564       code += enum_def.ToString(ev);
565       code += lang_.enum_separator;
566     }
567
568     // Generate a generate string table for enum values.
569     // We do not do that for C# where this functionality is native.
570     if (lang_.language != IDLOptions::kCSharp) {
571       // Problem is, if values are very sparse that could generate really big
572       // tables. Ideally in that case we generate a map lookup instead, but for
573       // the moment we simply don't output a table at all.
574       auto range = enum_def.Distance();
575       // Average distance between values above which we consider a table
576       // "too sparse". Change at will.
577       static const uint64_t kMaxSparseness = 5;
578       if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
579         code += "\n  public static";
580         code += lang_.const_decl;
581         code += lang_.string_type;
582         code += "[] names = { ";
583         auto val = enum_def.Vals().front();
584         for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
585              ++it) {
586           auto ev = *it;
587           for (auto k = enum_def.Distance(val, ev); k > 1; --k)
588             code += "\"\", ";
589           val = ev;
590           code += "\"" + (*it)->name + "\", ";
591         }
592         code += "};\n\n";
593         code += "  public static ";
594         code += lang_.string_type;
595         code += " " + MakeCamel("name", lang_.first_camel_upper);
596         code += "(int e) { return names[e";
597         if (enum_def.MinValue()->IsNonZero())
598           code += " - " + enum_def.MinValue()->name;
599         code += "]; }\n";
600       }
601     }
602
603     // Close the class
604     code += "}";
605     // Java does not need the closing semi-colon on class definitions.
606     code += (lang_.language != IDLOptions::kJava) ? ";" : "";
607     code += "\n\n";
608   }
609
610   // Returns the function name that is able to read a value of the given type.
611   std::string GenGetter(const Type &type) const {
612     switch (type.base_type) {
613       case BASE_TYPE_STRING: return lang_.accessor_prefix + "__string";
614       case BASE_TYPE_STRUCT: return lang_.accessor_prefix + "__struct";
615       case BASE_TYPE_UNION: return lang_.accessor_prefix + "__union";
616       case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
617       case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
618       default: {
619         std::string getter =
620             lang_.accessor_prefix + "bb." + FunctionStart('G') + "et";
621         if (type.base_type == BASE_TYPE_BOOL) {
622           getter = "0!=" + getter;
623         } else if (GenTypeBasic(type, false) != "byte") {
624           getter += MakeCamel(GenTypeBasic(type, false));
625         }
626         return getter;
627       }
628     }
629   }
630
631   // Returns the function name that is able to read a value of the given type.
632   std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
633                                       const std::string &data_buffer,
634                                       const char *num = nullptr) const {
635     auto type = key_field->value.type;
636     auto dest_mask = DestinationMask(type, true);
637     auto dest_cast = DestinationCast(type);
638     auto getter = data_buffer + "." + FunctionStart('G') + "et";
639     if (GenTypeBasic(type, false) != "byte") {
640       getter += MakeCamel(GenTypeBasic(type, false));
641     }
642     getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
643              dest_mask;
644     return getter;
645   }
646
647   // Direct mutation is only allowed for scalar fields.
648   // Hence a setter method will only be generated for such fields.
649   std::string GenSetter(const Type &type) const {
650     if (IsScalar(type.base_type)) {
651       std::string setter =
652           lang_.accessor_prefix + "bb." + FunctionStart('P') + "ut";
653       if (GenTypeBasic(type, false) != "byte" &&
654           type.base_type != BASE_TYPE_BOOL) {
655         setter += MakeCamel(GenTypeBasic(type, false));
656       }
657       return setter;
658     } else {
659       return "";
660     }
661   }
662
663   // Returns the method name for use with add/put calls.
664   std::string GenMethod(const Type &type) const {
665     return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type, false))
666                                     : (IsStruct(type) ? "Struct" : "Offset");
667   }
668
669   // Recursively generate arguments for a constructor, to deal with nested
670   // structs.
671   void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
672                      const char *nameprefix, size_t array_count = 0) const {
673     std::string &code = *code_ptr;
674     for (auto it = struct_def.fields.vec.begin();
675          it != struct_def.fields.vec.end(); ++it) {
676       auto &field = **it;
677       const auto &field_type = field.value.type;
678       const auto array_field = IsArray(field_type);
679       const auto &type = array_field ? field_type.VectorType()
680                                      : DestinationType(field_type, false);
681       const auto array_cnt = array_field ? (array_count + 1) : array_count;
682       if (IsStruct(type)) {
683         // Generate arguments for a struct inside a struct. To ensure names
684         // don't clash, and to make it obvious these arguments are constructing
685         // a nested struct, prefix the name with the field name.
686         GenStructArgs(*field_type.struct_def, code_ptr,
687                       (nameprefix + (field.name + "_")).c_str(), array_cnt);
688       } else {
689         code += ", ";
690         code += GenTypeBasic(type);
691         if (lang_.language == IDLOptions::kJava) {
692           for (size_t i = 0; i < array_cnt; i++) code += "[]";
693         } else if (lang_.language == IDLOptions::kCSharp) {
694           if (array_cnt > 0) {
695             code += "[";
696             for (size_t i = 1; i < array_cnt; i++) code += ",";
697             code += "]";
698           }
699         } else {
700           FLATBUFFERS_ASSERT(0);
701         }
702         code += " ";
703         code += nameprefix;
704         code += MakeCamel(field.name, lang_.first_camel_upper);
705       }
706     }
707   }
708
709   // Recusively generate struct construction statements of the form:
710   // builder.putType(name);
711   // and insert manual padding.
712   void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
713                      const char *nameprefix, size_t index = 0,
714                      bool in_array = false) const {
715     std::string &code = *code_ptr;
716     std::string indent((index + 1) * 2, ' ');
717     code += indent + "  builder." + FunctionStart('P') + "rep(";
718     code += NumToString(struct_def.minalign) + ", ";
719     code += NumToString(struct_def.bytesize) + ");\n";
720     for (auto it = struct_def.fields.vec.rbegin();
721          it != struct_def.fields.vec.rend(); ++it) {
722       auto &field = **it;
723       const auto &field_type = field.value.type;
724       if (field.padding) {
725         code += indent + "  builder." + FunctionStart('P') + "ad(";
726         code += NumToString(field.padding) + ");\n";
727       }
728       if (IsStruct(field_type)) {
729         GenStructBody(*field_type.struct_def, code_ptr,
730                       (nameprefix + (field.name + "_")).c_str(), index,
731                       in_array);
732       } else {
733         const auto &type =
734             IsArray(field_type) ? field_type.VectorType() : field_type;
735         const auto index_var = "_idx" + NumToString(index);
736         if (IsArray(field_type)) {
737           code += indent + "  for (int " + index_var + " = ";
738           code += NumToString(field_type.fixed_length);
739           code += "; " + index_var + " > 0; " + index_var + "--) {\n";
740           in_array = true;
741         }
742         if (IsStruct(type)) {
743           GenStructBody(*field_type.struct_def, code_ptr,
744                         (nameprefix + (field.name + "_")).c_str(), index + 1,
745                         in_array);
746         } else {
747           code += IsArray(field_type) ? "  " : "";
748           code += indent + "  builder." + FunctionStart('P') + "ut";
749           code += GenMethod(type) + "(";
750           code += SourceCast(type);
751           auto argname =
752               nameprefix + MakeCamel(field.name, lang_.first_camel_upper);
753           code += argname;
754           size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
755           if (lang_.language == IDLOptions::kJava) {
756             for (size_t i = 0; in_array && i < array_cnt; i++) {
757               code += "[_idx" + NumToString(i) + "-1]";
758             }
759           } else if (lang_.language == IDLOptions::kCSharp) {
760             if (array_cnt > 0) {
761               code += "[";
762               for (size_t i = 0; in_array && i < array_cnt; i++) {
763                 code += "_idx" + NumToString(i) + "-1";
764                 if (i != (array_cnt - 1)) code += ",";
765               }
766               code += "]";
767             }
768           } else {
769             FLATBUFFERS_ASSERT(0);
770           }
771           code += ");\n";
772         }
773         if (IsArray(field_type)) { code += indent + "  }\n"; }
774       }
775     }
776   }
777
778   std::string GenByteBufferLength(const char *bb_name) const {
779     std::string bb_len = bb_name;
780     if (lang_.language == IDLOptions::kCSharp)
781       bb_len += ".Length";
782     else
783       bb_len += ".capacity()";
784     return bb_len;
785   }
786
787   std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
788                               const char *num = nullptr) const {
789     std::string key_offset = "";
790     key_offset += lang_.accessor_prefix_static + "__offset(" +
791                   NumToString(key_field->value.offset) + ", ";
792     if (num) {
793       key_offset += num;
794       key_offset +=
795           (lang_.language == IDLOptions::kCSharp ? ".Value, builder.DataBuffer)"
796                                                  : ", _bb)");
797     } else {
798       key_offset += GenByteBufferLength("bb");
799       key_offset += " - tableOffset, bb)";
800     }
801     return key_offset;
802   }
803
804   std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
805     std::string key_getter = "      ";
806     key_getter += "int tableOffset = " + lang_.accessor_prefix_static;
807     key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
808     key_getter += ", bb);\n      ";
809     if (key_field->value.type.base_type == BASE_TYPE_STRING) {
810       key_getter += "int comp = " + lang_.accessor_prefix_static;
811       key_getter += FunctionStart('C') + "ompareStrings(";
812       key_getter += GenOffsetGetter(key_field);
813       key_getter += ", byteKey, bb);\n";
814     } else {
815       auto get_val = GenGetterForLookupByKey(key_field, "bb");
816       if (lang_.language == IDLOptions::kCSharp) {
817         key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
818       } else {
819         key_getter += GenTypeNameDest(key_field->value.type) + " val = ";
820         key_getter += get_val + ";\n";
821         key_getter += "      int comp = val > key ? 1 : val < key ? -1 : 0;\n";
822       }
823     }
824     return key_getter;
825   }
826
827   std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
828     std::string key_getter = "";
829     auto data_buffer =
830         (lang_.language == IDLOptions::kCSharp) ? "builder.DataBuffer" : "_bb";
831     if (key_field->value.type.base_type == BASE_TYPE_STRING) {
832       if (lang_.language == IDLOptions::kJava) key_getter += " return ";
833       key_getter += lang_.accessor_prefix_static;
834       key_getter += FunctionStart('C') + "ompareStrings(";
835       key_getter += GenOffsetGetter(key_field, "o1") + ", ";
836       key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
837       if (lang_.language == IDLOptions::kJava) key_getter += ";";
838     } else {
839       auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
840       if (lang_.language == IDLOptions::kCSharp) {
841         key_getter += field_getter;
842         field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
843         key_getter += ".CompareTo(" + field_getter + ")";
844       } else {
845         key_getter +=
846             "\n    " + GenTypeNameDest(key_field->value.type) + " val_1 = ";
847         key_getter +=
848             field_getter + ";\n    " + GenTypeNameDest(key_field->value.type);
849         key_getter += " val_2 = ";
850         field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
851         key_getter += field_getter + ";\n";
852         key_getter +=
853             "    return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
854       }
855     }
856     return key_getter;
857   }
858
859   void GenStruct(StructDef &struct_def, std::string *code_ptr) const {
860     if (struct_def.generated) return;
861     std::string &code = *code_ptr;
862
863     // Generate a struct accessor class, with methods of the form:
864     // public type name() { return bb.getType(i + offset); }
865     // or for tables of the form:
866     // public type name() {
867     //   int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
868     // }
869     GenComment(struct_def.doc_comment, code_ptr, &lang_.comment_config);
870     if (struct_def.attributes.Lookup("private")) {
871       // For Java, we leave the struct unmarked to indicate package-private
872       // For C# we mark the struct as internal
873       if (lang_.language == IDLOptions::kCSharp) {
874         code += "internal ";
875       }
876     } else {
877       code += "public ";
878     }
879     if (lang_.language == IDLOptions::kCSharp &&
880         struct_def.attributes.Lookup("csharp_partial")) {
881       // generate a partial class for this C# struct/table
882       code += "partial ";
883     } else {
884       code += lang_.unsubclassable_decl;
885     }
886     code += lang_.accessor_type + struct_def.name;
887     if (lang_.language == IDLOptions::kCSharp) {
888       code += " : IFlatbufferObject";
889       code += lang_.open_curly;
890       code += "  private ";
891       code += struct_def.fixed ? "Struct" : "Table";
892       code += " __p;\n";
893
894       if (lang_.language == IDLOptions::kCSharp) {
895         code += "  public ByteBuffer ByteBuffer { get { return __p.bb; } }\n";
896       }
897
898     } else {
899       code += lang_.inheritance_marker;
900       code += struct_def.fixed ? "Struct" : "Table";
901       code += lang_.open_curly;
902     }
903
904     if (!struct_def.fixed) {
905       // Generate verson check method.
906       // Force compile time error if not using the same version runtime.
907       code += "  public static void ValidateVersion() {";
908       if (lang_.language == IDLOptions::kCSharp)
909         code += " FlatBufferConstants.";
910       else
911         code += " Constants.";
912       code += "FLATBUFFERS_1_11_1(); ";
913       code += "}\n";
914
915       // Generate a special accessor for the table that when used as the root
916       // of a FlatBuffer
917       std::string method_name =
918           FunctionStart('G') + "etRootAs" + struct_def.name;
919       std::string method_signature =
920           "  public static " + struct_def.name + " " + method_name;
921
922       // create convenience method that doesn't require an existing object
923       code += method_signature + "(ByteBuffer _bb) ";
924       code += "{ return " + method_name + "(_bb, new " + struct_def.name +
925               "()); }\n";
926
927       // create method that allows object reuse
928       code +=
929           method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
930       code += lang_.set_bb_byteorder;
931       code += "return (obj.__assign(_bb." + FunctionStart('G') + "etInt(_bb.";
932       code += lang_.get_bb_position;
933       code += ") + _bb.";
934       code += lang_.get_bb_position;
935       code += ", _bb)); }\n";
936       if (parser_.root_struct_def_ == &struct_def) {
937         if (parser_.file_identifier_.length()) {
938           // Check if a buffer has the identifier.
939           code += "  public static ";
940           code += lang_.bool_type + struct_def.name;
941           code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
942           code += lang_.accessor_prefix_static + "__has_identifier(_bb, \"";
943           code += parser_.file_identifier_;
944           code += "\"); }\n";
945         }
946       }
947     }
948     // Generate the __init method that sets the field in a pre-existing
949     // accessor object. This is to allow object reuse.
950     code += "  public void __init(int _i, ByteBuffer _bb) ";
951     code += "{ ";
952     if (lang_.language == IDLOptions::kCSharp) {
953       code += "__p = new ";
954       code += struct_def.fixed ? "Struct" : "Table";
955       code += "(_i, _bb); ";
956     } else {
957       code += "__reset(_i, _bb); ";
958     }
959     code += "}\n";
960     code +=
961         "  public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
962     code += "{ __init(_i, _bb); return this; }\n\n";
963     for (auto it = struct_def.fields.vec.begin();
964          it != struct_def.fields.vec.end(); ++it) {
965       auto &field = **it;
966       if (field.deprecated) continue;
967       GenComment(field.doc_comment, code_ptr, &lang_.comment_config, "  ");
968       std::string type_name = GenTypeGet(field.value.type);
969       std::string type_name_dest = GenTypeNameDest(field.value.type);
970       std::string conditional_cast = "";
971       std::string optional = "";
972       if (lang_.language == IDLOptions::kCSharp && !struct_def.fixed &&
973           (field.value.type.base_type == BASE_TYPE_STRUCT ||
974            field.value.type.base_type == BASE_TYPE_UNION ||
975            (field.value.type.base_type == BASE_TYPE_VECTOR &&
976             (field.value.type.element == BASE_TYPE_STRUCT ||
977              field.value.type.element == BASE_TYPE_UNION)))) {
978         optional = lang_.optional_suffix;
979         conditional_cast = "(" + type_name_dest + optional + ")";
980       }
981       std::string dest_mask = DestinationMask(field.value.type, true);
982       std::string dest_cast = DestinationCast(field.value.type);
983       std::string src_cast = SourceCast(field.value.type);
984       std::string method_start =
985           "  public " +
986           (field.required ? "" : GenNullableAnnotation(field.value.type)) +
987           GenPureAnnotation(field.value.type) + type_name_dest + optional +
988           " " + MakeCamel(field.name, lang_.first_camel_upper);
989       std::string obj = lang_.language == IDLOptions::kCSharp
990                             ? "(new " + type_name + "())"
991                             : "obj";
992
993       // Most field accessors need to retrieve and test the field offset first,
994       // this is the prefix code for that:
995       auto offset_prefix =
996           IsArray(field.value.type)
997               ? " { return "
998               : (" { int o = " + lang_.accessor_prefix + "__offset(" +
999                  NumToString(field.value.offset) + "); return o != 0 ? ");
1000       // Generate the accessors that don't do object reuse.
1001       if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1002         // Calls the accessor that takes an accessor object with a new object.
1003         if (lang_.language != IDLOptions::kCSharp) {
1004           code += method_start + "() { return ";
1005           code += MakeCamel(field.name, lang_.first_camel_upper);
1006           code += "(new ";
1007           code += type_name + "()); }\n";
1008         }
1009       } else if (field.value.type.base_type == BASE_TYPE_VECTOR &&
1010                  field.value.type.element == BASE_TYPE_STRUCT) {
1011         // Accessors for vectors of structs also take accessor objects, this
1012         // generates a variant without that argument.
1013         if (lang_.language != IDLOptions::kCSharp) {
1014           code += method_start + "(int j) { return ";
1015           code += MakeCamel(field.name, lang_.first_camel_upper);
1016           code += "(new " + type_name + "(), j); }\n";
1017         }
1018       } else if (field.value.type.base_type == BASE_TYPE_UNION ||
1019           (field.value.type.base_type == BASE_TYPE_VECTOR &&
1020            field.value.type.VectorType().base_type == BASE_TYPE_UNION)) {
1021         if (lang_.language == IDLOptions::kCSharp) {
1022           // Union types in C# use generic Table-derived type for better type
1023           // safety.
1024           method_start += "<TTable>";
1025           type_name = type_name_dest;
1026         }
1027       }
1028       std::string getter = dest_cast + GenGetter(field.value.type);
1029       code += method_start;
1030       std::string default_cast = "";
1031       // only create default casts for c# scalars or vectors of scalars
1032       if (lang_.language == IDLOptions::kCSharp &&
1033           (IsScalar(field.value.type.base_type) ||
1034            (field.value.type.base_type == BASE_TYPE_VECTOR &&
1035             IsScalar(field.value.type.element)))) {
1036         // For scalars, default value will be returned by GetDefaultValue().
1037         // If the scalar is an enum, GetDefaultValue() returns an actual c# enum
1038         // that doesn't need to be casted. However, default values for enum
1039         // elements of vectors are integer literals ("0") and are still casted
1040         // for clarity.
1041         if (field.value.type.enum_def == nullptr ||
1042             field.value.type.base_type == BASE_TYPE_VECTOR) {
1043           default_cast = "(" + type_name_dest + ")";
1044         }
1045       }
1046       std::string member_suffix = "; ";
1047       if (IsScalar(field.value.type.base_type)) {
1048         code += lang_.getter_prefix;
1049         member_suffix += lang_.getter_suffix;
1050         if (struct_def.fixed) {
1051           code += " { return " + getter;
1052           code += "(" + lang_.accessor_prefix + "bb_pos + ";
1053           code += NumToString(field.value.offset) + ")";
1054           code += dest_mask;
1055         } else {
1056           code += offset_prefix + getter;
1057           code += "(o + " + lang_.accessor_prefix + "bb_pos)" + dest_mask;
1058           code += " : " + default_cast;
1059           code += GenDefaultValue(field);
1060         }
1061       } else {
1062         switch (field.value.type.base_type) {
1063           case BASE_TYPE_STRUCT:
1064             if (lang_.language != IDLOptions::kCSharp) {
1065               code += "(" + type_name + " obj" + ")";
1066             } else {
1067               code += lang_.getter_prefix;
1068               member_suffix += lang_.getter_suffix;
1069             }
1070             if (struct_def.fixed) {
1071               code += " { return " + obj + ".__assign(" + lang_.accessor_prefix;
1072               code += "bb_pos + " + NumToString(field.value.offset) + ", ";
1073               code += lang_.accessor_prefix + "bb)";
1074             } else {
1075               code += offset_prefix + conditional_cast;
1076               code += obj + ".__assign(";
1077               code += field.value.type.struct_def->fixed
1078                           ? "o + " + lang_.accessor_prefix + "bb_pos"
1079                           : lang_.accessor_prefix + "__indirect(o + " +
1080                                 lang_.accessor_prefix + "bb_pos)";
1081               code += ", " + lang_.accessor_prefix + "bb) : null";
1082             }
1083             break;
1084           case BASE_TYPE_STRING:
1085             code += lang_.getter_prefix;
1086             member_suffix += lang_.getter_suffix;
1087             code += offset_prefix + getter + "(o + " + lang_.accessor_prefix;
1088             code += "bb_pos) : null";
1089             break;
1090           case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();  // fall thru
1091           case BASE_TYPE_VECTOR: {
1092             auto vectortype = field.value.type.VectorType();
1093             if (vectortype.base_type == BASE_TYPE_UNION &&
1094                 lang_.language == IDLOptions::kCSharp) {
1095                   conditional_cast = "(TTable?)";
1096                   getter += "<TTable>";
1097             }
1098             code += "(";
1099             if (vectortype.base_type == BASE_TYPE_STRUCT) {
1100               if (lang_.language != IDLOptions::kCSharp)
1101                 code += type_name + " obj, ";
1102               getter = obj + ".__assign";
1103             } else if (vectortype.base_type == BASE_TYPE_UNION) {
1104               if (lang_.language != IDLOptions::kCSharp)
1105                 code += type_name + " obj, ";
1106             }
1107             code += "int j)";
1108             const auto body = offset_prefix + conditional_cast + getter + "(";
1109             if (vectortype.base_type == BASE_TYPE_UNION) {
1110               if (lang_.language != IDLOptions::kCSharp)
1111                 code += body + "obj, ";
1112               else
1113                 code += " where TTable : struct, IFlatbufferObject" + body;
1114             } else {
1115               code += body;
1116             }
1117             auto index = lang_.accessor_prefix;
1118             if (IsArray(field.value.type)) {
1119               index += "bb_pos + " + NumToString(field.value.offset) + " + ";
1120             } else {
1121               index += "__vector(o) + ";
1122             }
1123             index += "j * " + NumToString(InlineSize(vectortype));
1124             if (vectortype.base_type == BASE_TYPE_STRUCT) {
1125               code += vectortype.struct_def->fixed
1126                           ? index
1127                           : lang_.accessor_prefix + "__indirect(" + index + ")";
1128               code += ", " + lang_.accessor_prefix + "bb";
1129             } else {
1130               code += index;
1131             }
1132             code += ")" + dest_mask;
1133             if (!IsArray(field.value.type)) {
1134               code += " : ";
1135               code +=
1136                   field.value.type.element == BASE_TYPE_BOOL
1137                       ? "false"
1138                       : (IsScalar(field.value.type.element) ? default_cast + "0"
1139                                                             : "null");
1140             }
1141
1142             break;
1143           }
1144           case BASE_TYPE_UNION:
1145             if (lang_.language == IDLOptions::kCSharp) {
1146               code += "() where TTable : struct, IFlatbufferObject";
1147               code += offset_prefix + "(TTable?)" + getter;
1148               code += "<TTable>(o + " + lang_.accessor_prefix + "bb_pos) : null";
1149             } else {
1150               code += "(" + type_name + " obj)" + offset_prefix + getter;
1151               code += "(obj, o + " + lang_.accessor_prefix + "bb_pos) : null";
1152             }
1153             break;
1154           default: FLATBUFFERS_ASSERT(0);
1155         }
1156       }
1157       code += member_suffix;
1158       code += "}\n";
1159       if (field.value.type.base_type == BASE_TYPE_VECTOR) {
1160         code +=
1161             "  public int " + MakeCamel(field.name, lang_.first_camel_upper);
1162         code += "Length";
1163         code += lang_.getter_prefix;
1164         code += offset_prefix;
1165         code += lang_.accessor_prefix + "__vector_len(o) : 0; ";
1166         code += lang_.getter_suffix;
1167         code += "}\n";
1168         // See if we should generate a by-key accessor.
1169         if (field.value.type.element == BASE_TYPE_STRUCT &&
1170             !field.value.type.struct_def->fixed) {
1171           auto &sd = *field.value.type.struct_def;
1172           auto &fields = sd.fields.vec;
1173           for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
1174             auto &key_field = **kit;
1175             if (key_field.key) {
1176               auto qualified_name = WrapInNameSpace(sd);
1177               code += "  public " + qualified_name + lang_.optional_suffix + " ";
1178               code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
1179               code += GenTypeNameDest(key_field.value.type) + " key)";
1180               code += offset_prefix;
1181               code += qualified_name + ".__lookup_by_key(";
1182               if (lang_.language == IDLOptions::kJava)
1183                 code += "null, ";
1184               code += lang_.accessor_prefix + "__vector(o), key, ";
1185               code += lang_.accessor_prefix + "bb) : null; ";
1186               code += "}\n";
1187               if (lang_.language == IDLOptions::kJava) {
1188                 code += "  public " + qualified_name + lang_.optional_suffix + " ";
1189                 code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
1190                 code += qualified_name + lang_.optional_suffix + " obj, ";
1191                 code += GenTypeNameDest(key_field.value.type) + " key)";
1192                 code += offset_prefix;
1193                 code += qualified_name + ".__lookup_by_key(obj, ";
1194                 code += lang_.accessor_prefix + "__vector(o), key, ";
1195                 code += lang_.accessor_prefix + "bb) : null; ";
1196                 code += "}\n";
1197               }
1198               break;
1199             }
1200           }
1201         }
1202       }
1203       // Generate the accessors for vector of structs with vector access object
1204       if (lang_.language == IDLOptions::kJava &&
1205           field.value.type.base_type == BASE_TYPE_VECTOR) {
1206         std::string vector_type_name;
1207         const auto &element_base_type = field.value.type.VectorType().base_type;
1208         if (IsScalar(element_base_type)) {
1209           vector_type_name = MakeCamel(type_name, true) + "Vector";
1210         } else if (element_base_type == BASE_TYPE_STRING) {
1211           vector_type_name = "StringVector";
1212         } else if (element_base_type == BASE_TYPE_UNION) {
1213           vector_type_name = "UnionVector";
1214         } else {
1215           vector_type_name = type_name + ".Vector";
1216         }
1217         auto vector_method_start =
1218             GenNullableAnnotation(field.value.type) + "  public " +
1219             vector_type_name + optional + " " +
1220             MakeCamel(field.name, lang_.first_camel_upper) + "Vector";
1221         code += vector_method_start + "() { return ";
1222         code += MakeCamel(field.name, lang_.first_camel_upper) + "Vector";
1223         code += "(new " + vector_type_name + "()); }\n";
1224         code += vector_method_start + "(" + vector_type_name + " obj)";
1225         code += offset_prefix + conditional_cast + obj + ".__assign" + "(";
1226         code += lang_.accessor_prefix + "__vector(o), ";
1227         if (!IsScalar(element_base_type)) {
1228           auto vectortype = field.value.type.VectorType();
1229           code += NumToString(InlineSize(vectortype)) + ", ";
1230         }
1231         code += lang_.accessor_prefix + "bb) : null" + member_suffix + "}\n";
1232       }
1233       // Generate a ByteBuffer accessor for strings & vectors of scalars.
1234       if ((field.value.type.base_type == BASE_TYPE_VECTOR &&
1235            IsScalar(field.value.type.VectorType().base_type)) ||
1236           field.value.type.base_type == BASE_TYPE_STRING) {
1237         switch (lang_.language) {
1238           case IDLOptions::kJava:
1239             code += "  public ByteBuffer ";
1240             code += MakeCamel(field.name, lang_.first_camel_upper);
1241             code += "AsByteBuffer() { return ";
1242             code += lang_.accessor_prefix + "__vector_as_bytebuffer(";
1243             code += NumToString(field.value.offset) + ", ";
1244             code +=
1245                 NumToString(field.value.type.base_type == BASE_TYPE_STRING
1246                                 ? 1
1247                                 : InlineSize(field.value.type.VectorType()));
1248             code += "); }\n";
1249             code += "  public ByteBuffer ";
1250             code += MakeCamel(field.name, lang_.first_camel_upper);
1251             code += "InByteBuffer(ByteBuffer _bb) { return ";
1252             code += lang_.accessor_prefix + "__vector_in_bytebuffer(_bb, ";
1253             code += NumToString(field.value.offset) + ", ";
1254             code +=
1255                 NumToString(field.value.type.base_type == BASE_TYPE_STRING
1256                                 ? 1
1257                                 : InlineSize(field.value.type.VectorType()));
1258             code += "); }\n";
1259             break;
1260           case IDLOptions::kCSharp:
1261             code += "#if ENABLE_SPAN_T\n";
1262             code += "  public Span<" + GenTypeBasic(field.value.type.VectorType()) + "> Get";
1263             code += MakeCamel(field.name, lang_.first_camel_upper);
1264             code += "Bytes() { return ";
1265             code += lang_.accessor_prefix + "__vector_as_span<"+ GenTypeBasic(field.value.type.VectorType()) +">(";
1266             code += NumToString(field.value.offset);
1267             code += ", " + NumToString(SizeOf(field.value.type.VectorType().base_type));
1268             code += "); }\n";
1269             code += "#else\n";
1270             code += "  public ArraySegment<byte>? Get";
1271             code += MakeCamel(field.name, lang_.first_camel_upper);
1272             code += "Bytes() { return ";
1273             code += lang_.accessor_prefix + "__vector_as_arraysegment(";
1274             code += NumToString(field.value.offset);
1275             code += "); }\n";
1276             code += "#endif\n";
1277
1278             // For direct blockcopying the data into a typed array
1279             code += "  public ";
1280             code += GenTypeBasic(field.value.type.VectorType());
1281             code += "[] Get";
1282             code += MakeCamel(field.name, lang_.first_camel_upper);
1283             code += "Array() { ";
1284             if (IsEnum(field.value.type.VectorType())) {
1285               // Since __vector_as_array does not work for enum types,
1286               // fill array using an explicit loop.
1287               code += "int o = " + lang_.accessor_prefix + "__offset(";
1288               code += NumToString(field.value.offset);
1289               code += "); if (o == 0) return null; int p = ";
1290               code += lang_.accessor_prefix + "__vector(o); int l = ";
1291               code += lang_.accessor_prefix + "__vector_len(o); ";
1292               code += GenTypeBasic(field.value.type.VectorType());
1293               code += "[] a = new ";
1294               code += GenTypeBasic(field.value.type.VectorType());
1295               code += "[l]; for (int i = 0; i < l; i++) { a[i] = " + getter;
1296               code += "(p + i * ";
1297               code += NumToString(InlineSize(field.value.type.VectorType()));
1298               code += "); } return a;";
1299             } else {
1300               code += "return ";
1301               code += lang_.accessor_prefix + "__vector_as_array<";
1302               code += GenTypeBasic(field.value.type.VectorType());
1303               code += ">(";
1304               code += NumToString(field.value.offset);
1305               code += ");";
1306             }
1307             code += " }\n";
1308             break;
1309           default: break;
1310         }
1311       }
1312       // generate object accessors if is nested_flatbuffer
1313       if (field.nested_flatbuffer) {
1314         auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
1315         auto nested_method_name =
1316             MakeCamel(field.name, lang_.first_camel_upper) + "As" +
1317             field.nested_flatbuffer->name;
1318         auto get_nested_method_name = nested_method_name;
1319         if (lang_.language == IDLOptions::kCSharp) {
1320           get_nested_method_name = "Get" + nested_method_name;
1321           conditional_cast =
1322               "(" + nested_type_name + lang_.optional_suffix + ")";
1323         }
1324         if (lang_.language != IDLOptions::kCSharp) {
1325           code += "  public " + nested_type_name + lang_.optional_suffix + " ";
1326           code += nested_method_name + "() { return ";
1327           code +=
1328               get_nested_method_name + "(new " + nested_type_name + "()); }\n";
1329         } else {
1330           obj = "(new " + nested_type_name + "())";
1331         }
1332         code += "  public " + nested_type_name + lang_.optional_suffix + " ";
1333         code += get_nested_method_name + "(";
1334         if (lang_.language != IDLOptions::kCSharp)
1335           code += nested_type_name + " obj";
1336         code += ") { int o = " + lang_.accessor_prefix + "__offset(";
1337         code += NumToString(field.value.offset) + "); ";
1338         code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
1339         code += lang_.accessor_prefix;
1340         code += "__indirect(" + lang_.accessor_prefix + "__vector(o)), ";
1341         code += lang_.accessor_prefix + "bb) : null; }\n";
1342       }
1343       // Generate mutators for scalar fields or vectors of scalars.
1344       if (parser_.opts.mutable_buffer) {
1345         auto is_series = (IsSeries(field.value.type));
1346         const auto &underlying_type =
1347             is_series ? field.value.type.VectorType() : field.value.type;
1348         // Boolean parameters have to be explicitly converted to byte
1349         // representation.
1350         auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
1351                                     ? "(byte)(" + field.name + " ? 1 : 0)"
1352                                     : field.name;
1353         auto mutator_prefix = MakeCamel("mutate", lang_.first_camel_upper);
1354         // A vector mutator also needs the index of the vector element it should
1355         // mutate.
1356         auto mutator_params = (is_series ? "(int j, " : "(") +
1357                               GenTypeNameDest(underlying_type) + " " +
1358                               field.name + ") { ";
1359         auto setter_index =
1360             is_series
1361                 ? lang_.accessor_prefix +
1362                       (IsArray(field.value.type)
1363                            ? "bb_pos + " + NumToString(field.value.offset)
1364                            : "__vector(o)") +
1365                       +" + j * " + NumToString(InlineSize(underlying_type))
1366                 : (struct_def.fixed
1367                        ? lang_.accessor_prefix + "bb_pos + " +
1368                              NumToString(field.value.offset)
1369                        : "o + " + lang_.accessor_prefix + "bb_pos");
1370         if (IsScalar(underlying_type.base_type) && !IsUnion(field.value.type)) {
1371           code += "  public ";
1372           code += struct_def.fixed ? "void " : lang_.bool_type;
1373           code += mutator_prefix + MakeCamel(field.name, true);
1374           code += mutator_params;
1375           if (struct_def.fixed) {
1376             code += GenSetter(underlying_type) + "(" + setter_index + ", ";
1377             code += src_cast + setter_parameter + "); }\n";
1378           } else {
1379             code += "int o = " + lang_.accessor_prefix + "__offset(";
1380             code += NumToString(field.value.offset) + ");";
1381             code += " if (o != 0) { " + GenSetter(underlying_type);
1382             code += "(" + setter_index + ", " + src_cast + setter_parameter +
1383                     "); return true; } else { return false; } }\n";
1384           }
1385         }
1386       }
1387       if (parser_.opts.java_primitive_has_method &&
1388           IsScalar(field.value.type.base_type) && !struct_def.fixed) {
1389         auto vt_offset_constant = "  public static final int VT_" +
1390                                   MakeScreamingCamel(field.name) + " = " +
1391                                   NumToString(field.value.offset) + ";";
1392
1393         code += vt_offset_constant;
1394         code += "\n";
1395       }
1396     }
1397     code += "\n";
1398     flatbuffers::FieldDef *key_field = nullptr;
1399     if (struct_def.fixed) {
1400       // create a struct constructor function
1401       code += "  public static " + GenOffsetType(struct_def) + " ";
1402       code += FunctionStart('C') + "reate";
1403       code += struct_def.name + "(FlatBufferBuilder builder";
1404       GenStructArgs(struct_def, code_ptr, "");
1405       code += ") {\n";
1406       GenStructBody(struct_def, code_ptr, "");
1407       code += "    return ";
1408       code += GenOffsetConstruct(
1409           struct_def, "builder." + std::string(lang_.get_fbb_offset));
1410       code += ";\n  }\n";
1411     } else {
1412       // Generate a method that creates a table in one go. This is only possible
1413       // when the table has no struct fields, since those have to be created
1414       // inline, and there's no way to do so in Java.
1415       bool has_no_struct_fields = true;
1416       int num_fields = 0;
1417       for (auto it = struct_def.fields.vec.begin();
1418            it != struct_def.fields.vec.end(); ++it) {
1419         auto &field = **it;
1420         if (field.deprecated) continue;
1421         if (IsStruct(field.value.type)) {
1422           has_no_struct_fields = false;
1423         } else {
1424           num_fields++;
1425         }
1426       }
1427       // JVM specifications restrict default constructor params to be < 255.
1428       // Longs and doubles take up 2 units, so we set the limit to be < 127.
1429       if (has_no_struct_fields && num_fields && num_fields < 127) {
1430         // Generate a table constructor of the form:
1431         // public static int createName(FlatBufferBuilder builder, args...)
1432         code += "  public static " + GenOffsetType(struct_def) + " ";
1433         code += FunctionStart('C') + "reate" + struct_def.name;
1434         code += "(FlatBufferBuilder builder";
1435         for (auto it = struct_def.fields.vec.begin();
1436              it != struct_def.fields.vec.end(); ++it) {
1437           auto &field = **it;
1438           if (field.deprecated) continue;
1439           code += ",\n      ";
1440           code += GenTypeBasic(DestinationType(field.value.type, false));
1441           code += " ";
1442           code += field.name;
1443           if (!IsScalar(field.value.type.base_type)) code += "Offset";
1444
1445           // Java doesn't have defaults, which means this method must always
1446           // supply all arguments, and thus won't compile when fields are added.
1447           if (lang_.language != IDLOptions::kJava) {
1448             code += " = ";
1449             code += GenDefaultValueBasic(field);
1450           }
1451         }
1452         code += ") {\n    builder.";
1453         code += FunctionStart('S') + "tartTable(";
1454         code += NumToString(struct_def.fields.vec.size()) + ");\n";
1455         for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1456              size; size /= 2) {
1457           for (auto it = struct_def.fields.vec.rbegin();
1458                it != struct_def.fields.vec.rend(); ++it) {
1459             auto &field = **it;
1460             if (!field.deprecated &&
1461                 (!struct_def.sortbysize ||
1462                  size == SizeOf(field.value.type.base_type))) {
1463               code += "    " + struct_def.name + ".";
1464               code += FunctionStart('A') + "dd";
1465               code += MakeCamel(field.name) + "(builder, " + field.name;
1466               if (!IsScalar(field.value.type.base_type)) code += "Offset";
1467               code += ");\n";
1468             }
1469           }
1470         }
1471         code += "    return " + struct_def.name + ".";
1472         code += FunctionStart('E') + "nd" + struct_def.name;
1473         code += "(builder);\n  }\n\n";
1474       }
1475       // Generate a set of static methods that allow table construction,
1476       // of the form:
1477       // public static void addName(FlatBufferBuilder builder, short name)
1478       // { builder.addShort(id, name, default); }
1479       // Unlike the Create function, these always work.
1480       code += "  public static void " + FunctionStart('S') + "tart";
1481       code += struct_def.name;
1482       code += "(FlatBufferBuilder builder) { builder.";
1483       code += FunctionStart('S') + "tartTable(";
1484       code += NumToString(struct_def.fields.vec.size()) + "); }\n";
1485       for (auto it = struct_def.fields.vec.begin();
1486            it != struct_def.fields.vec.end(); ++it) {
1487         auto &field = **it;
1488         if (field.deprecated) continue;
1489         if (field.key) key_field = &field;
1490         code += "  public static void " + FunctionStart('A') + "dd";
1491         code += MakeCamel(field.name);
1492         code += "(FlatBufferBuilder builder, ";
1493         code += GenTypeBasic(DestinationType(field.value.type, false));
1494         auto argname = MakeCamel(field.name, false);
1495         if (!IsScalar(field.value.type.base_type)) argname += "Offset";
1496         code += " " + argname + ") { builder." + FunctionStart('A') + "dd";
1497         code += GenMethod(field.value.type) + "(";
1498         code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
1499         code += SourceCastBasic(field.value.type);
1500         code += argname;
1501         if (!IsScalar(field.value.type.base_type) &&
1502             field.value.type.base_type != BASE_TYPE_UNION &&
1503             lang_.language == IDLOptions::kCSharp) {
1504           code += ".Value";
1505         }
1506         code += ", ";
1507         if (lang_.language == IDLOptions::kJava)
1508           code += SourceCastBasic(field.value.type);
1509         code += GenDefaultValue(field, false);
1510         code += "); }\n";
1511         if (field.value.type.base_type == BASE_TYPE_VECTOR) {
1512           auto vector_type = field.value.type.VectorType();
1513           auto alignment = InlineAlignment(vector_type);
1514           auto elem_size = InlineSize(vector_type);
1515           if (!IsStruct(vector_type)) {
1516             // generate a method to create a vector from a java array.
1517             if (lang_.language == IDLOptions::kJava &&
1518                 (vector_type.base_type == BASE_TYPE_CHAR ||
1519                  vector_type.base_type == BASE_TYPE_UCHAR)) {
1520               // Handle byte[] and ByteBuffers separately for Java
1521               code += "  public static " + GenVectorOffsetType() + " ";
1522               code += FunctionStart('C') + "reate";
1523               code += MakeCamel(field.name);
1524               code += "Vector(FlatBufferBuilder builder, byte[] data) ";
1525               code += "{ return builder.createByteVector(data); }\n";
1526
1527               code += "  public static " + GenVectorOffsetType() + " ";
1528               code += FunctionStart('C') + "reate";
1529               code += MakeCamel(field.name);
1530               code += "Vector(FlatBufferBuilder builder, ByteBuffer data) ";
1531               code += "{ return builder.createByteVector(data); }\n";
1532             } else {
1533               code += "  public static " + GenVectorOffsetType() + " ";
1534               code += FunctionStart('C') + "reate";
1535               code += MakeCamel(field.name);
1536               code += "Vector(FlatBufferBuilder builder, ";
1537               code += GenTypeBasic(vector_type) + "[] data) ";
1538               code += "{ builder." + FunctionStart('S') + "tartVector(";
1539               code += NumToString(elem_size);
1540               code += ", data." + FunctionStart('L') + "ength, ";
1541               code += NumToString(alignment);
1542               code += "); for (int i = data.";
1543               code += FunctionStart('L') + "ength - 1; i >= 0; i--) builder.";
1544               code += FunctionStart('A') + "dd";
1545               code += GenMethod(vector_type);
1546               code += "(";
1547               code += SourceCastBasic(vector_type, false);
1548               code += "data[i]";
1549               if (lang_.language == IDLOptions::kCSharp &&
1550                   (vector_type.base_type == BASE_TYPE_STRUCT ||
1551                    vector_type.base_type == BASE_TYPE_STRING))
1552                 code += ".Value";
1553               code += "); return ";
1554               code += "builder." + FunctionStart('E') + "ndVector(); }\n";
1555               // For C#, include a block copy method signature.
1556               if (lang_.language == IDLOptions::kCSharp) {
1557                 code += "  public static " + GenVectorOffsetType() + " ";
1558                 code += FunctionStart('C') + "reate";
1559                 code += MakeCamel(field.name);
1560                 code += "VectorBlock(FlatBufferBuilder builder, ";
1561                 code += GenTypeBasic(vector_type) + "[] data) ";
1562                 code += "{ builder." + FunctionStart('S') + "tartVector(";
1563                 code += NumToString(elem_size);
1564                 code += ", data." + FunctionStart('L') + "ength, ";
1565                 code += NumToString(alignment);
1566                 code += "); builder.Add(data); return builder.EndVector(); }\n";
1567               }
1568             }
1569           }
1570           // Generate a method to start a vector, data to be added manually
1571           // after.
1572           code += "  public static void " + FunctionStart('S') + "tart";
1573           code += MakeCamel(field.name);
1574           code += "Vector(FlatBufferBuilder builder, int numElems) ";
1575           code += "{ builder." + FunctionStart('S') + "tartVector(";
1576           code += NumToString(elem_size);
1577           code += ", numElems, " + NumToString(alignment);
1578           code += "); }\n";
1579         }
1580       }
1581       code += "  public static " + GenOffsetType(struct_def) + " ";
1582       code += FunctionStart('E') + "nd" + struct_def.name;
1583       code += "(FlatBufferBuilder builder) {\n    int o = builder.";
1584       code += FunctionStart('E') + "ndTable();\n";
1585       for (auto it = struct_def.fields.vec.begin();
1586            it != struct_def.fields.vec.end(); ++it) {
1587         auto &field = **it;
1588         if (!field.deprecated && field.required) {
1589           code += "    builder." + FunctionStart('R') + "equired(o, ";
1590           code += NumToString(field.value.offset);
1591           code += ");  // " + field.name + "\n";
1592         }
1593       }
1594       code += "    return " + GenOffsetConstruct(struct_def, "o") + ";\n  }\n";
1595       if (parser_.root_struct_def_ == &struct_def) {
1596         std::string size_prefix[] = { "", "SizePrefixed" };
1597         for (int i = 0; i < 2; ++i) {
1598           code += "  public static void ";
1599           code += FunctionStart('F') + "inish" + size_prefix[i] +
1600                   struct_def.name;
1601           code += "Buffer(FlatBufferBuilder builder, " +
1602                   GenOffsetType(struct_def);
1603           code += " offset) {";
1604           code += " builder." + FunctionStart('F') + "inish" + size_prefix[i] +
1605                   "(offset";
1606           if (lang_.language == IDLOptions::kCSharp) { code += ".Value"; }
1607
1608           if (parser_.file_identifier_.length())
1609             code += ", \"" + parser_.file_identifier_ + "\"";
1610           code += "); }\n";
1611         }
1612       }
1613     }
1614     // Only generate key compare function for table,
1615     // because `key_field` is not set for struct
1616     if (struct_def.has_key && !struct_def.fixed) {
1617       FLATBUFFERS_ASSERT(key_field);
1618       if (lang_.language == IDLOptions::kJava) {
1619         code += "\n  @Override\n  protected int keysCompare(";
1620         code += "Integer o1, Integer o2, ByteBuffer _bb) {";
1621         code += GenKeyGetter(key_field);
1622         code += " }\n";
1623       } else {
1624         code += "\n  public static VectorOffset ";
1625         code += "CreateSortedVectorOf" + struct_def.name;
1626         code += "(FlatBufferBuilder builder, ";
1627         code += "Offset<" + struct_def.name + ">";
1628         code += "[] offsets) {\n";
1629         code += "    Array.Sort(offsets, (Offset<" + struct_def.name +
1630                 "> o1, Offset<" + struct_def.name + "> o2) => " +
1631                 GenKeyGetter(key_field);
1632         code += ");\n";
1633         code += "    return builder.CreateVectorOfTables(offsets);\n  }\n";
1634       }
1635
1636       code += "\n  public static " + struct_def.name + lang_.optional_suffix;
1637       code += " __lookup_by_key(";
1638       if (lang_.language == IDLOptions::kJava)
1639         code +=  struct_def.name + " obj, ";
1640       code += "int vectorLocation, ";
1641       code += GenTypeNameDest(key_field->value.type);
1642       code += " key, ByteBuffer bb) {\n";
1643       if (key_field->value.type.base_type == BASE_TYPE_STRING) {
1644         code += "    byte[] byteKey = ";
1645         if (lang_.language == IDLOptions::kJava)
1646           code += "key.getBytes(Table.UTF8_CHARSET.get());\n";
1647         else
1648           code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
1649       }
1650       code += "    int span = ";
1651       code += "bb." + FunctionStart('G') + "etInt(vectorLocation - 4);\n";
1652       code += "    int start = 0;\n";
1653       code += "    while (span != 0) {\n";
1654       code += "      int middle = span / 2;\n";
1655       code += GenLookupKeyGetter(key_field);
1656       code += "      if (comp > 0) {\n";
1657       code += "        span = middle;\n";
1658       code += "      } else if (comp < 0) {\n";
1659       code += "        middle++;\n";
1660       code += "        start += middle;\n";
1661       code += "        span -= middle;\n";
1662       code += "      } else {\n";
1663       code += "        return ";
1664       if (lang_.language == IDLOptions::kJava)
1665         code += "(obj == null ? new " + struct_def.name + "() : obj)";
1666       else
1667         code += "new " + struct_def.name + "()";
1668       code += ".__assign(tableOffset, bb);\n";
1669       code += "      }\n    }\n";
1670       code += "    return null;\n";
1671       code += "  }\n";
1672     }
1673     if (lang_.language == IDLOptions::kJava)
1674       GenVectorAccessObject(struct_def, code_ptr);
1675     code += "}";
1676     // Java does not need the closing semi-colon on class definitions.
1677     code += (lang_.language != IDLOptions::kJava) ? ";" : "";
1678     code += "\n\n";
1679   }
1680
1681   void GenVectorAccessObject(StructDef &struct_def,
1682                              std::string *code_ptr) const {
1683     auto &code = *code_ptr;
1684     // Generate a vector of structs accessor class.
1685     code += "\n";
1686     code += "  ";
1687     if (!struct_def.attributes.Lookup("private"))
1688       code += "public ";
1689     code += "static ";
1690     code += lang_.unsubclassable_decl;
1691     code += lang_.accessor_type + "Vector" + lang_.inheritance_marker;
1692     code += "BaseVector" + lang_.open_curly;
1693
1694     // Generate the __assign method that sets the field in a pre-existing
1695     // accessor object. This is to allow object reuse.
1696     std::string method_indent = "    ";
1697     code += method_indent + "public Vector ";
1698     code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { ";
1699     code += "__reset(_vector, _element_size, _bb); return this; }\n\n";
1700
1701     auto type_name = struct_def.name;
1702     auto method_start =
1703         method_indent + "public " + type_name + " " + FunctionStart('G') + "et";
1704     // Generate the accessors that don't do object reuse.
1705     code += method_start + "(int j) { return " + FunctionStart('G') + "et";
1706     code += "(new " + type_name + "(), j); }\n";
1707     code += method_start + "(" + type_name + " obj, int j) { ";
1708     code += " return obj.__assign(";
1709     auto index = lang_.accessor_prefix + "__element(j)";
1710     code += struct_def.fixed
1711                 ? index
1712                 : lang_.accessor_prefix + "__indirect(" + index + ", bb)";
1713     code += ", " + lang_.accessor_prefix + "bb); }\n";
1714     // See if we should generate a by-key accessor.
1715     if (!struct_def.fixed) {
1716       auto &fields = struct_def.fields.vec;
1717       for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
1718         auto &key_field = **kit;
1719         if (key_field.key) {
1720           auto nullable_annotation =
1721               parser_.opts.gen_nullable ? "@Nullable " : "";
1722           code += method_indent + nullable_annotation;
1723           code += "public " + type_name + lang_.optional_suffix + " ";
1724           code += FunctionStart('G') + "et" + "ByKey(";
1725           code += GenTypeNameDest(key_field.value.type) + " key) { ";
1726           code += " return __lookup_by_key(null, ";
1727           code += lang_.accessor_prefix + "__vector(), key, ";
1728           code += lang_.accessor_prefix + "bb); ";
1729           code += "}\n";
1730           code += method_indent + nullable_annotation;
1731           code += "public " + type_name + lang_.optional_suffix + " ";
1732           code += FunctionStart('G') + "et" + "ByKey(";
1733           code += type_name + lang_.optional_suffix + " obj, ";
1734           code += GenTypeNameDest(key_field.value.type) + " key) { ";
1735           code += " return __lookup_by_key(obj, ";
1736           code += lang_.accessor_prefix + "__vector(), key, ";
1737           code += lang_.accessor_prefix + "bb); ";
1738           code += "}\n";
1739           break;
1740         }
1741       }
1742     }
1743     code += "  }\n";
1744   }
1745
1746   const LanguageParameters &lang_;
1747   // This tracks the current namespace used to determine if a type need to be
1748   // prefixed by its namespace
1749   const Namespace *cur_name_space_;
1750 };
1751 }  // namespace general
1752
1753 bool GenerateGeneral(const Parser &parser, const std::string &path,
1754                      const std::string &file_name) {
1755   general::GeneralGenerator generator(parser, path, file_name);
1756   return generator.generate();
1757 }
1758
1759 std::string GeneralMakeRule(const Parser &parser, const std::string &path,
1760                             const std::string &file_name) {
1761   FLATBUFFERS_ASSERT(parser.opts.lang <= IDLOptions::kMAX);
1762   const auto &lang = GetLangParams(parser.opts.lang);
1763
1764   std::string make_rule;
1765
1766   for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
1767        ++it) {
1768     auto &enum_def = **it;
1769     if (!make_rule.empty()) make_rule += " ";
1770     std::string directory =
1771         BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace);
1772     make_rule += directory + enum_def.name + lang.file_extension;
1773   }
1774
1775   for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
1776        ++it) {
1777     auto &struct_def = **it;
1778     if (!make_rule.empty()) make_rule += " ";
1779     std::string directory = BaseGenerator::NamespaceDir(
1780         parser, path, *struct_def.defined_namespace);
1781     make_rule += directory + struct_def.name + lang.file_extension;
1782   }
1783
1784   make_rule += ": ";
1785   auto included_files = parser.GetIncludedFilesRecursive(file_name);
1786   for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1787     make_rule += " " + *it;
1788   }
1789   return make_rule;
1790 }
1791
1792 std::string BinaryFileName(const Parser &parser, const std::string &path,
1793                            const std::string &file_name) {
1794   auto ext = parser.file_extension_.length() ? parser.file_extension_ : "bin";
1795   return path + file_name + "." + ext;
1796 }
1797
1798 bool GenerateBinary(const Parser &parser, const std::string &path,
1799                     const std::string &file_name) {
1800   if (parser.opts.use_flexbuffers) {
1801     auto data_vec = parser.flex_builder_.GetBuffer();
1802     auto data_ptr = reinterpret_cast<char *>(data(data_vec));
1803     return !parser.flex_builder_.GetSize() ||
1804            flatbuffers::SaveFile(
1805                BinaryFileName(parser, path, file_name).c_str(), data_ptr,
1806                parser.flex_builder_.GetSize(), true);
1807   }
1808   return !parser.builder_.GetSize() ||
1809          flatbuffers::SaveFile(
1810              BinaryFileName(parser, path, file_name).c_str(),
1811              reinterpret_cast<char *>(parser.builder_.GetBufferPointer()),
1812              parser.builder_.GetSize(), true);
1813 }
1814
1815 std::string BinaryMakeRule(const Parser &parser, const std::string &path,
1816                            const std::string &file_name) {
1817   if (!parser.builder_.GetSize()) return "";
1818   std::string filebase =
1819       flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
1820   std::string make_rule =
1821       BinaryFileName(parser, path, filebase) + ": " + file_name;
1822   auto included_files =
1823       parser.GetIncludedFilesRecursive(parser.root_struct_def_->file);
1824   for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1825     make_rule += " " + *it;
1826   }
1827   return make_rule;
1828 }
1829
1830 }  // namespace flatbuffers