idl_gen_general.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  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. // independent from idl_parser, since this code is not needed for most clients
  17. #include "flatbuffers/flatbuffers.h"
  18. #include "flatbuffers/idl.h"
  19. #include "flatbuffers/util.h"
  20. namespace flatbuffers {
  21. // Convert an underscore_based_indentifier in to camelCase.
  22. // Also uppercases the first character if first is true.
  23. std::string MakeCamel(const std::string &in, bool first) {
  24. std::string s;
  25. for (size_t i = 0; i < in.length(); i++) {
  26. if (!i && first)
  27. s += static_cast<char>(toupper(in[0]));
  28. else if (in[i] == '_' && i + 1 < in.length())
  29. s += static_cast<char>(toupper(in[++i]));
  30. else
  31. s += in[i];
  32. }
  33. return s;
  34. }
  35. // Generate a documentation comment, if available.
  36. void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
  37. const char *prefix) {
  38. std::string &code = *code_ptr;
  39. for (auto it = dc.begin();
  40. it != dc.end();
  41. ++it) {
  42. code += std::string(prefix) + "///" + *it + "\n";
  43. }
  44. }
  45. // These arrays need to correspond to the GeneratorOptions::k enum.
  46. struct LanguageParameters {
  47. GeneratorOptions::Language language;
  48. // Whether function names in the language typically start with uppercase.
  49. bool first_camel_upper;
  50. const char *file_extension;
  51. const char *string_type;
  52. const char *bool_type;
  53. const char *open_curly;
  54. const char *const_decl;
  55. const char *inheritance_marker;
  56. const char *namespace_ident;
  57. const char *namespace_begin;
  58. const char *namespace_end;
  59. const char *set_bb_byteorder;
  60. const char *includes;
  61. };
  62. LanguageParameters language_parameters[] = {
  63. {
  64. GeneratorOptions::kJava,
  65. false,
  66. ".java",
  67. "String",
  68. "boolean ",
  69. " {\n",
  70. " final ",
  71. " extends ",
  72. "package ",
  73. ";",
  74. "",
  75. "_bb.order(ByteOrder.LITTLE_ENDIAN); ",
  76. "import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n"
  77. "import com.google.flatbuffers.*;\n\n",
  78. },
  79. {
  80. GeneratorOptions::kCSharp,
  81. true,
  82. ".cs",
  83. "string",
  84. "bool ",
  85. "\n{\n",
  86. " readonly ",
  87. " : ",
  88. "namespace ",
  89. "\n{",
  90. "\n}\n",
  91. "",
  92. "using FlatBuffers;\n\n",
  93. }
  94. };
  95. static_assert(sizeof(language_parameters) / sizeof(LanguageParameters) ==
  96. GeneratorOptions::kMAX,
  97. "Please add extra elements to the arrays above.");
  98. static std::string FunctionStart(const LanguageParameters &lang, char upper) {
  99. return std::string() +
  100. (lang.language == GeneratorOptions::kJava
  101. ? static_cast<char>(tolower(upper))
  102. : upper);
  103. }
  104. static std::string GenTypeBasic(const LanguageParameters &lang,
  105. const Type &type) {
  106. static const char *gtypename[] = {
  107. #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
  108. #JTYPE, #NTYPE,
  109. FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
  110. #undef FLATBUFFERS_TD
  111. };
  112. return gtypename[type.base_type * GeneratorOptions::kMAX + lang.language];
  113. }
  114. static std::string GenTypeGet(const LanguageParameters &lang,
  115. const Type &type);
  116. static std::string GenTypePointer(const LanguageParameters &lang,
  117. const Type &type) {
  118. switch (type.base_type) {
  119. case BASE_TYPE_STRING:
  120. return lang.string_type;
  121. case BASE_TYPE_VECTOR:
  122. return GenTypeGet(lang, type.VectorType());
  123. case BASE_TYPE_STRUCT:
  124. return type.struct_def->name;
  125. case BASE_TYPE_UNION:
  126. // fall through
  127. default:
  128. return "Table";
  129. }
  130. }
  131. static std::string GenTypeGet(const LanguageParameters &lang,
  132. const Type &type) {
  133. return IsScalar(type.base_type)
  134. ? GenTypeBasic(lang, type)
  135. : GenTypePointer(lang, type);
  136. }
  137. static void GenEnum(const LanguageParameters &lang, EnumDef &enum_def,
  138. std::string *code_ptr) {
  139. std::string &code = *code_ptr;
  140. if (enum_def.generated) return;
  141. // Generate enum definitions of the form:
  142. // public static (final) int name = value;
  143. // In Java, we use ints rather than the Enum feature, because we want them
  144. // to map directly to how they're used in C/C++ and file formats.
  145. // That, and Java Enums are expensive, and not universally liked.
  146. GenComment(enum_def.doc_comment, code_ptr);
  147. code += "public class " + enum_def.name + lang.open_curly;
  148. for (auto it = enum_def.vals.vec.begin();
  149. it != enum_def.vals.vec.end();
  150. ++it) {
  151. auto &ev = **it;
  152. GenComment(ev.doc_comment, code_ptr, " ");
  153. code += " public static";
  154. code += lang.const_decl;
  155. code += GenTypeBasic(lang, enum_def.underlying_type);
  156. code += " " + ev.name + " = ";
  157. code += NumToString(ev.value) + ";\n";
  158. }
  159. // Generate a generate string table for enum values.
  160. // Problem is, if values are very sparse that could generate really big
  161. // tables. Ideally in that case we generate a map lookup instead, but for
  162. // the moment we simply don't output a table at all.
  163. auto range = enum_def.vals.vec.back()->value -
  164. enum_def.vals.vec.front()->value + 1;
  165. // Average distance between values above which we consider a table
  166. // "too sparse". Change at will.
  167. static const int kMaxSparseness = 5;
  168. if (range / static_cast<int64_t>(enum_def.vals.vec.size()) < kMaxSparseness) {
  169. code += "\n private static";
  170. code += lang.const_decl;
  171. code += lang.string_type;
  172. code += "[] names = { ";
  173. auto val = enum_def.vals.vec.front()->value;
  174. for (auto it = enum_def.vals.vec.begin();
  175. it != enum_def.vals.vec.end();
  176. ++it) {
  177. while (val++ != (*it)->value) code += "\"\", ";
  178. code += "\"" + (*it)->name + "\", ";
  179. }
  180. code += "};\n\n";
  181. code += " public static ";
  182. code += lang.string_type;
  183. code += " " + MakeCamel("name", lang.first_camel_upper);
  184. code += "(int e) { return names[e";
  185. if (enum_def.vals.vec.front()->value)
  186. code += " - " + enum_def.vals.vec.front()->name;
  187. code += "]; }\n";
  188. }
  189. // Close the class
  190. code += "};\n\n";
  191. }
  192. // Returns the function name that is able to read a value of the given type.
  193. static std::string GenGetter(const LanguageParameters &lang,
  194. const Type &type) {
  195. switch (type.base_type) {
  196. case BASE_TYPE_STRING: return "__string";
  197. case BASE_TYPE_STRUCT: return "__struct";
  198. case BASE_TYPE_UNION: return "__union";
  199. case BASE_TYPE_VECTOR: return GenGetter(lang, type.VectorType());
  200. default:
  201. return "bb." + FunctionStart(lang, 'G') + "et" +
  202. (GenTypeBasic(lang, type) != "byte"
  203. ? MakeCamel(GenTypeGet(lang, type))
  204. : "");
  205. }
  206. }
  207. // Returns the method name for use with add/put calls.
  208. static std::string GenMethod(const LanguageParameters &lang, const Type &type) {
  209. return IsScalar(type.base_type)
  210. ? MakeCamel(GenTypeBasic(lang, type))
  211. : (IsStruct(type) ? "Struct" : "Offset");
  212. }
  213. // Recursively generate arguments for a constructor, to deal with nested
  214. // structs.
  215. static void GenStructArgs(const LanguageParameters &lang,
  216. const StructDef &struct_def,
  217. std::string *code_ptr, const char *nameprefix) {
  218. std::string &code = *code_ptr;
  219. for (auto it = struct_def.fields.vec.begin();
  220. it != struct_def.fields.vec.end();
  221. ++it) {
  222. auto &field = **it;
  223. if (IsStruct(field.value.type)) {
  224. // Generate arguments for a struct inside a struct. To ensure names
  225. // don't clash, and to make it obvious these arguments are constructing
  226. // a nested struct, prefix the name with the struct name.
  227. GenStructArgs(lang, *field.value.type.struct_def, code_ptr,
  228. (field.value.type.struct_def->name + "_").c_str());
  229. } else {
  230. code += ", " + GenTypeBasic(lang, field.value.type) + " " + nameprefix;
  231. code += MakeCamel(field.name, lang.first_camel_upper);
  232. }
  233. }
  234. }
  235. // Recusively generate struct construction statements of the form:
  236. // builder.putType(name);
  237. // and insert manual padding.
  238. static void GenStructBody(const LanguageParameters &lang,
  239. const StructDef &struct_def,
  240. std::string *code_ptr, const char *nameprefix) {
  241. std::string &code = *code_ptr;
  242. code += " builder." + FunctionStart(lang, 'P') + "rep(";
  243. code += NumToString(struct_def.minalign) + ", ";
  244. code += NumToString(struct_def.bytesize) + ");\n";
  245. for (auto it = struct_def.fields.vec.rbegin();
  246. it != struct_def.fields.vec.rend(); ++it) {
  247. auto &field = **it;
  248. if (field.padding) {
  249. code += " builder." + FunctionStart(lang, 'P') + "ad(";
  250. code += NumToString(field.padding) + ");\n";
  251. }
  252. if (IsStruct(field.value.type)) {
  253. GenStructBody(lang, *field.value.type.struct_def, code_ptr,
  254. (field.value.type.struct_def->name + "_").c_str());
  255. } else {
  256. code += " builder." + FunctionStart(lang, 'P') + "ut";
  257. code += GenMethod(lang, field.value.type) + "(" += nameprefix;
  258. code += MakeCamel(field.name, lang.first_camel_upper) + ");\n";
  259. }
  260. }
  261. }
  262. static void GenStruct(const LanguageParameters &lang, const Parser &parser,
  263. StructDef &struct_def, std::string *code_ptr) {
  264. if (struct_def.generated) return;
  265. std::string &code = *code_ptr;
  266. // Generate a struct accessor class, with methods of the form:
  267. // public type name() { return bb.getType(i + offset); }
  268. // or for tables of the form:
  269. // public type name() {
  270. // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
  271. // }
  272. GenComment(struct_def.doc_comment, code_ptr);
  273. code += "public class " + struct_def.name + lang.inheritance_marker;
  274. code += struct_def.fixed ? "Struct" : "Table";
  275. code += " {\n";
  276. if (!struct_def.fixed) {
  277. // Generate a special accessor for the table that when used as the root
  278. // of a FlatBuffer
  279. code += " public static " + struct_def.name + " ";
  280. code += FunctionStart(lang, 'G') + "etRootAs" + struct_def.name;
  281. code += "(ByteBuffer _bb) { ";
  282. code += lang.set_bb_byteorder;
  283. code += "return (new " + struct_def.name;
  284. code += "()).__init(_bb." + FunctionStart(lang, 'G');
  285. code += "etInt(_bb.position()) + _bb.position(), _bb); }\n";
  286. if (parser.root_struct_def == &struct_def) {
  287. if (parser.file_identifier_.length()) {
  288. // Check if a buffer has the identifier.
  289. code += " public static ";
  290. code += lang.bool_type + struct_def.name;
  291. code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
  292. code += "__has_identifier(_bb, \"" + parser.file_identifier_;
  293. code += "\"); }\n";
  294. }
  295. }
  296. }
  297. // Generate the __init method that sets the field in a pre-existing
  298. // accessor object. This is to allow object reuse.
  299. code += " public " + struct_def.name;
  300. code += " __init(int _i, ByteBuffer _bb) ";
  301. code += "{ bb_pos = _i; bb = _bb; return this; }\n\n";
  302. for (auto it = struct_def.fields.vec.begin();
  303. it != struct_def.fields.vec.end();
  304. ++it) {
  305. auto &field = **it;
  306. if (field.deprecated) continue;
  307. GenComment(field.doc_comment, code_ptr, " ");
  308. std::string type_name = GenTypeGet(lang, field.value.type);
  309. std::string method_start = " public " + type_name + " " +
  310. MakeCamel(field.name, lang.first_camel_upper);
  311. // Generate the accessors that don't do object reuse.
  312. if (field.value.type.base_type == BASE_TYPE_STRUCT) {
  313. // Calls the accessor that takes an accessor object with a new object.
  314. code += method_start + "() { return ";
  315. code += MakeCamel(field.name, lang.first_camel_upper);
  316. code += "(new ";
  317. code += type_name + "()); }\n";
  318. } else if (field.value.type.base_type == BASE_TYPE_VECTOR &&
  319. field.value.type.element == BASE_TYPE_STRUCT) {
  320. // Accessors for vectors of structs also take accessor objects, this
  321. // generates a variant without that argument.
  322. code += method_start + "(int j) { return ";
  323. code += MakeCamel(field.name, lang.first_camel_upper);
  324. code += "(new ";
  325. code += type_name + "(), j); }\n";
  326. }
  327. std::string getter = GenGetter(lang, field.value.type);
  328. code += method_start + "(";
  329. // Most field accessors need to retrieve and test the field offset first,
  330. // this is the prefix code for that:
  331. auto offset_prefix = ") { int o = __offset(" +
  332. NumToString(field.value.offset) +
  333. "); return o != 0 ? ";
  334. std::string default_cast = "";
  335. if (lang.language == GeneratorOptions::kCSharp)
  336. default_cast = "(" + type_name + ")";
  337. if (IsScalar(field.value.type.base_type)) {
  338. if (struct_def.fixed) {
  339. code += ") { return " + getter;
  340. code += "(bb_pos + " + NumToString(field.value.offset) + ")";
  341. } else {
  342. code += offset_prefix + getter;
  343. code += "(o + bb_pos) : " + default_cast + field.value.constant;
  344. }
  345. } else {
  346. switch (field.value.type.base_type) {
  347. case BASE_TYPE_STRUCT:
  348. code += type_name + " obj";
  349. if (struct_def.fixed) {
  350. code += ") { return obj.__init(bb_pos + ";
  351. code += NumToString(field.value.offset) + ", bb)";
  352. } else {
  353. code += offset_prefix;
  354. code += "obj.__init(";
  355. code += field.value.type.struct_def->fixed
  356. ? "o + bb_pos"
  357. : "__indirect(o + bb_pos)";
  358. code += ", bb) : null";
  359. }
  360. break;
  361. case BASE_TYPE_STRING:
  362. code += offset_prefix + getter +"(o + bb_pos) : null";
  363. break;
  364. case BASE_TYPE_VECTOR: {
  365. auto vectortype = field.value.type.VectorType();
  366. if (vectortype.base_type == BASE_TYPE_STRUCT) {
  367. code += type_name + " obj, ";
  368. getter = "obj.__init";
  369. }
  370. code += "int j" + offset_prefix + getter +"(";
  371. auto index = "__vector(o) + j * " +
  372. NumToString(InlineSize(vectortype));
  373. if (vectortype.base_type == BASE_TYPE_STRUCT) {
  374. code += vectortype.struct_def->fixed
  375. ? index
  376. : "__indirect(" + index + ")";
  377. code += ", bb";
  378. } else {
  379. code += index;
  380. }
  381. code += ") : ";
  382. code += IsScalar(field.value.type.element)
  383. ? default_cast + "0"
  384. : "null";
  385. break;
  386. }
  387. case BASE_TYPE_UNION:
  388. code += type_name + " obj" + offset_prefix + getter;
  389. code += "(obj, o) : null";
  390. break;
  391. default:
  392. assert(0);
  393. }
  394. }
  395. code += "; }\n";
  396. if (field.value.type.base_type == BASE_TYPE_VECTOR) {
  397. code += " public int " + MakeCamel(field.name, lang.first_camel_upper);
  398. code += "Length(" + offset_prefix;
  399. code += "__vector_len(o) : 0; }\n";
  400. }
  401. if ((field.value.type.base_type == BASE_TYPE_VECTOR ||
  402. field.value.type.base_type == BASE_TYPE_STRING) &&
  403. lang.language == GeneratorOptions::kJava) {
  404. code += " public ByteBuffer ";
  405. code += MakeCamel(field.name, lang.first_camel_upper);
  406. code += "AsByteBuffer() { return __vector_as_bytebuffer(";
  407. code += NumToString(field.value.offset) + ", ";
  408. code += NumToString(field.value.type.base_type == BASE_TYPE_STRING ? 1 :
  409. InlineSize(field.value.type.VectorType()));
  410. code += "); }\n";
  411. }
  412. }
  413. code += "\n";
  414. if (struct_def.fixed) {
  415. // create a struct constructor function
  416. code += " public static int " + FunctionStart(lang, 'C') + "reate";
  417. code += struct_def.name + "(FlatBufferBuilder builder";
  418. GenStructArgs(lang, struct_def, code_ptr, "");
  419. code += ") {\n";
  420. GenStructBody(lang, struct_def, code_ptr, "");
  421. code += " return builder.";
  422. code += FunctionStart(lang, 'O') + "ffset();\n }\n";
  423. } else {
  424. // Generate a method that creates a table in one go. This is only possible
  425. // when the table has no struct fields, since those have to be created
  426. // inline, and there's no way to do so in Java.
  427. bool has_no_struct_fields = true;
  428. int num_fields = 0;
  429. for (auto it = struct_def.fields.vec.begin();
  430. it != struct_def.fields.vec.end(); ++it) {
  431. auto &field = **it;
  432. if (field.deprecated) continue;
  433. if (IsStruct(field.value.type)) {
  434. has_no_struct_fields = false;
  435. } else {
  436. num_fields++;
  437. }
  438. }
  439. if (has_no_struct_fields && num_fields) {
  440. // Generate a table constructor of the form:
  441. // public static void createName(FlatBufferBuilder builder, args...)
  442. code += " public static int " + FunctionStart(lang, 'C') + "reate";
  443. code += struct_def.name;
  444. code += "(FlatBufferBuilder builder";
  445. for (auto it = struct_def.fields.vec.begin();
  446. it != struct_def.fields.vec.end(); ++it) {
  447. auto &field = **it;
  448. if (field.deprecated) continue;
  449. code += ",\n " + GenTypeBasic(lang, field.value.type) + " ";
  450. code += field.name;
  451. // Java doesn't have defaults, which means this method must always
  452. // supply all arguments, and thus won't compile when fields are added.
  453. if (lang.language != GeneratorOptions::kJava)
  454. code += " = " + field.value.constant;
  455. }
  456. code += ") {\n builder.";
  457. code += FunctionStart(lang, 'S') + "tartObject(";
  458. code += NumToString(struct_def.fields.vec.size()) + ");\n";
  459. for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
  460. size;
  461. size /= 2) {
  462. for (auto it = struct_def.fields.vec.rbegin();
  463. it != struct_def.fields.vec.rend(); ++it) {
  464. auto &field = **it;
  465. if (!field.deprecated &&
  466. (!struct_def.sortbysize ||
  467. size == SizeOf(field.value.type.base_type))) {
  468. code += " " + struct_def.name + ".";
  469. code += FunctionStart(lang, 'A') + "dd";
  470. code += MakeCamel(field.name) + "(builder, " + field.name + ");\n";
  471. }
  472. }
  473. }
  474. code += " return " + struct_def.name + ".";
  475. code += FunctionStart(lang, 'E') + "nd" + struct_def.name;
  476. code += "(builder);\n }\n\n";
  477. }
  478. // Generate a set of static methods that allow table construction,
  479. // of the form:
  480. // public static void addName(FlatBufferBuilder builder, short name)
  481. // { builder.addShort(id, name, default); }
  482. // Unlike the Create function, these always work.
  483. code += " public static void " + FunctionStart(lang, 'S') + "tart";
  484. code += struct_def.name;
  485. code += "(FlatBufferBuilder builder) { builder.";
  486. code += FunctionStart(lang, 'S') + "tartObject(";
  487. code += NumToString(struct_def.fields.vec.size()) + "); }\n";
  488. for (auto it = struct_def.fields.vec.begin();
  489. it != struct_def.fields.vec.end(); ++it) {
  490. auto &field = **it;
  491. if (field.deprecated) continue;
  492. code += " public static void " + FunctionStart(lang, 'A') + "dd";
  493. code += MakeCamel(field.name);
  494. code += "(FlatBufferBuilder builder, ";
  495. code += GenTypeBasic(lang, field.value.type);
  496. auto argname = MakeCamel(field.name, false);
  497. if (!IsScalar(field.value.type.base_type)) argname += "Offset";
  498. code += " " + argname + ") { builder." + FunctionStart(lang, 'A') + "dd";
  499. code += GenMethod(lang, field.value.type) + "(";
  500. code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
  501. code += argname + ", " + field.value.constant;
  502. code += "); }\n";
  503. if (field.value.type.base_type == BASE_TYPE_VECTOR) {
  504. auto vector_type = field.value.type.VectorType();
  505. auto alignment = InlineAlignment(vector_type);
  506. auto elem_size = InlineSize(vector_type);
  507. if (!IsStruct(vector_type)) {
  508. // Generate a method to create a vector from a Java array.
  509. code += " public static int " + FunctionStart(lang, 'C') + "reate";
  510. code += MakeCamel(field.name);
  511. code += "Vector(FlatBufferBuilder builder, ";
  512. code += GenTypeBasic(lang, vector_type) + "[] data) ";
  513. code += "{ builder." + FunctionStart(lang, 'S') + "tartVector(";
  514. code += NumToString(elem_size);
  515. code += ", data." + FunctionStart(lang, 'L') + "ength, ";
  516. code += NumToString(alignment);
  517. code += "); for (int i = data.";
  518. code += FunctionStart(lang, 'L') + "ength - 1; i >= 0; i--) builder.";
  519. code += FunctionStart(lang, 'A') + "dd";
  520. code += GenMethod(lang, vector_type);
  521. code += "(data[i]); return builder.";
  522. code += FunctionStart(lang, 'E') + "ndVector(); }\n";
  523. }
  524. // Generate a method to start a vector, data to be added manually after.
  525. code += " public static void " + FunctionStart(lang, 'S') + "tart";
  526. code += MakeCamel(field.name);
  527. code += "Vector(FlatBufferBuilder builder, int numElems) ";
  528. code += "{ builder." + FunctionStart(lang, 'S') + "tartVector(";
  529. code += NumToString(elem_size);
  530. code += ", numElems, " + NumToString(alignment);
  531. code += "); }\n";
  532. }
  533. }
  534. code += " public static int ";
  535. code += FunctionStart(lang, 'E') + "nd" + struct_def.name;
  536. code += "(FlatBufferBuilder builder) {\n int o = builder.";
  537. code += FunctionStart(lang, 'E') + "ndObject();\n";
  538. for (auto it = struct_def.fields.vec.begin();
  539. it != struct_def.fields.vec.end();
  540. ++it) {
  541. auto &field = **it;
  542. if (!field.deprecated && field.required) {
  543. code += " builder." + FunctionStart(lang, 'R') + "equired(o, ";
  544. code += NumToString(field.value.offset);
  545. code += "); // " + field.name + "\n";
  546. }
  547. }
  548. code += " return o;\n }\n";
  549. if (parser.root_struct_def == &struct_def) {
  550. code += " public static void ";
  551. code += FunctionStart(lang, 'F') + "inish" + struct_def.name;
  552. code += "Buffer(FlatBufferBuilder builder, int offset) { ";
  553. code += "builder." + FunctionStart(lang, 'F') + "inish(offset";
  554. if (parser.file_identifier_.length())
  555. code += ", \"" + parser.file_identifier_ + "\"";
  556. code += "); }\n";
  557. }
  558. }
  559. code += "};\n\n";
  560. }
  561. // Save out the generated code for a single class while adding
  562. // declaration boilerplate.
  563. static bool SaveClass(const LanguageParameters &lang, const Parser &parser,
  564. const Definition &def, const std::string &classcode,
  565. const std::string &path, bool needs_includes) {
  566. if (!classcode.length()) return true;
  567. std::string namespace_general;
  568. std::string namespace_dir = path;
  569. auto &namespaces = parser.namespaces_.back()->components;
  570. for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
  571. if (namespace_general.length()) {
  572. namespace_general += ".";
  573. namespace_dir += kPathSeparator;
  574. }
  575. namespace_general += *it;
  576. namespace_dir += *it;
  577. }
  578. EnsureDirExists(namespace_dir);
  579. std::string code = "// automatically generated, do not modify\n\n";
  580. code += lang.namespace_ident + namespace_general + lang.namespace_begin;
  581. code += "\n\n";
  582. if (needs_includes) code += lang.includes;
  583. code += classcode;
  584. code += lang.namespace_end;
  585. auto filename = namespace_dir + kPathSeparator + def.name +
  586. lang.file_extension;
  587. return SaveFile(filename.c_str(), code, false);
  588. }
  589. bool GenerateGeneral(const Parser &parser,
  590. const std::string &path,
  591. const std::string & /*file_name*/,
  592. const GeneratorOptions &opts) {
  593. assert(opts.lang <= GeneratorOptions::kMAX);
  594. auto lang = language_parameters[opts.lang];
  595. for (auto it = parser.enums_.vec.begin();
  596. it != parser.enums_.vec.end(); ++it) {
  597. std::string enumcode;
  598. GenEnum(lang, **it, &enumcode);
  599. if (!SaveClass(lang, parser, **it, enumcode, path, false))
  600. return false;
  601. }
  602. for (auto it = parser.structs_.vec.begin();
  603. it != parser.structs_.vec.end(); ++it) {
  604. std::string declcode;
  605. GenStruct(lang, parser, **it, &declcode);
  606. if (!SaveClass(lang, parser, **it, declcode, path, true))
  607. return false;
  608. }
  609. return true;
  610. }
  611. } // namespace flatbuffers