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