idl_gen_general.cpp 53 KB

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