idl_gen_cpp.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  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. namespace cpp {
  22. // Ensure that a type is prefixed with its namespace whenever it is used
  23. // outside of its namespace.
  24. static std::string WrapInNameSpace(const Parser &parser, const Namespace *ns,
  25. const std::string &name) {
  26. if (parser.namespaces_.back() != ns) {
  27. std::string qualified_name;
  28. for (auto it = ns->components.begin();
  29. it != ns->components.end(); ++it) {
  30. qualified_name += *it + "::";
  31. }
  32. return qualified_name + name;
  33. } else {
  34. return name;
  35. }
  36. }
  37. // Return a C++ type from the table in idl.h
  38. static std::string GenTypeBasic(const Parser &parser, const Type &type,
  39. bool real_enum) {
  40. static const char *ctypename[] = {
  41. #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) #CTYPE,
  42. FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
  43. #undef FLATBUFFERS_TD
  44. };
  45. return real_enum && type.enum_def
  46. ? WrapInNameSpace(parser, type.enum_def->defined_namespace,
  47. type.enum_def->name)
  48. : ctypename[type.base_type];
  49. }
  50. static std::string GenTypeWire(const Parser &parser, const Type &type,
  51. const char *postfix, bool real_enum);
  52. // Return a C++ pointer type, specialized to the actual struct/table types,
  53. // and vector element types.
  54. static std::string GenTypePointer(const Parser &parser, const Type &type) {
  55. switch (type.base_type) {
  56. case BASE_TYPE_STRING:
  57. return "flatbuffers::String";
  58. case BASE_TYPE_VECTOR:
  59. return "flatbuffers::Vector<" +
  60. GenTypeWire(parser, type.VectorType(), "", false) + ">";
  61. case BASE_TYPE_STRUCT: {
  62. return WrapInNameSpace(parser, type.struct_def->defined_namespace,
  63. type.struct_def->name);
  64. }
  65. case BASE_TYPE_UNION:
  66. // fall through
  67. default:
  68. return "void";
  69. }
  70. }
  71. // Return a C++ type for any type (scalar/pointer) specifically for
  72. // building a flatbuffer.
  73. static std::string GenTypeWire(const Parser &parser, const Type &type,
  74. const char *postfix, bool real_enum) {
  75. return IsScalar(type.base_type)
  76. ? GenTypeBasic(parser, type, real_enum) + postfix
  77. : IsStruct(type)
  78. ? "const " + GenTypePointer(parser, type) + " *"
  79. : "flatbuffers::Offset<" + GenTypePointer(parser, type) + ">" + postfix;
  80. }
  81. // Return a C++ type for any type (scalar/pointer) that reflects its
  82. // serialized size.
  83. static std::string GenTypeSize(const Parser &parser, const Type &type) {
  84. return IsScalar(type.base_type)
  85. ? GenTypeBasic(parser, type, false)
  86. : IsStruct(type)
  87. ? GenTypePointer(parser, type)
  88. : "flatbuffers::uoffset_t";
  89. }
  90. // Return a C++ type for any type (scalar/pointer) specifically for
  91. // using a flatbuffer.
  92. static std::string GenTypeGet(const Parser &parser, const Type &type,
  93. const char *afterbasic, const char *beforeptr,
  94. const char *afterptr, bool real_enum) {
  95. return IsScalar(type.base_type)
  96. ? GenTypeBasic(parser, type, real_enum) + afterbasic
  97. : beforeptr + GenTypePointer(parser, type) + afterptr;
  98. }
  99. static std::string GenEnumVal(const EnumDef &enum_def, const EnumVal &enum_val,
  100. const GeneratorOptions &opts) {
  101. return opts.prefixed_enums ? enum_def.name + "_" + enum_val.name
  102. : enum_val.name;
  103. }
  104. // Generate an enum declaration and an enum string lookup table.
  105. static void GenEnum(EnumDef &enum_def, std::string *code_ptr,
  106. std::string *code_ptr_post,
  107. const GeneratorOptions &opts) {
  108. if (enum_def.generated) return;
  109. std::string &code = *code_ptr;
  110. std::string &code_post = *code_ptr_post;
  111. GenComment(enum_def.doc_comment, code_ptr);
  112. code += "enum " + enum_def.name + " {\n";
  113. for (auto it = enum_def.vals.vec.begin();
  114. it != enum_def.vals.vec.end();
  115. ++it) {
  116. auto &ev = **it;
  117. GenComment(ev.doc_comment, code_ptr, " ");
  118. code += " " + GenEnumVal(enum_def, ev, opts) + " = ";
  119. code += NumToString(ev.value);
  120. code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
  121. }
  122. code += "};\n\n";
  123. // Generate a generate string table for enum values.
  124. // Problem is, if values are very sparse that could generate really big
  125. // tables. Ideally in that case we generate a map lookup instead, but for
  126. // the moment we simply don't output a table at all.
  127. auto range = enum_def.vals.vec.back()->value -
  128. enum_def.vals.vec.front()->value + 1;
  129. // Average distance between values above which we consider a table
  130. // "too sparse". Change at will.
  131. static const int kMaxSparseness = 5;
  132. if (range / static_cast<int64_t>(enum_def.vals.vec.size()) < kMaxSparseness) {
  133. code += "inline const char **EnumNames" + enum_def.name + "() {\n";
  134. code += " static const char *names[] = { ";
  135. auto val = enum_def.vals.vec.front()->value;
  136. for (auto it = enum_def.vals.vec.begin();
  137. it != enum_def.vals.vec.end();
  138. ++it) {
  139. while (val++ != (*it)->value) code += "\"\", ";
  140. code += "\"" + (*it)->name + "\", ";
  141. }
  142. code += "nullptr };\n return names;\n}\n\n";
  143. code += "inline const char *EnumName" + enum_def.name;
  144. code += "(" + enum_def.name + " e) { return EnumNames" + enum_def.name + "()[e";
  145. if (enum_def.vals.vec.front()->value)
  146. code += " - " + GenEnumVal(enum_def, *enum_def.vals.vec.front(), opts);
  147. code += "]; }\n\n";
  148. }
  149. if (enum_def.is_union) {
  150. // Generate a verifier function for this union that can be called by the
  151. // table verifier functions. It uses a switch case to select a specific
  152. // verifier function to call, this should be safe even if the union type
  153. // has been corrupted, since the verifiers will simply fail when called
  154. // on the wrong type.
  155. auto signature = "inline bool Verify" + enum_def.name +
  156. "(flatbuffers::Verifier &verifier, " +
  157. "const void *union_obj, " + enum_def.name + " type)";
  158. code += signature + ";\n\n";
  159. code_post += signature + " {\n switch (type) {\n";
  160. for (auto it = enum_def.vals.vec.begin();
  161. it != enum_def.vals.vec.end();
  162. ++it) {
  163. auto &ev = **it;
  164. code_post += " case " + GenEnumVal(enum_def, ev, opts);
  165. if (!ev.value) {
  166. code_post += ": return true;\n"; // "NONE" enum value.
  167. } else {
  168. code_post += ": return verifier.VerifyTable(reinterpret_cast<const ";
  169. code_post += ev.struct_def->name + " *>(union_obj));\n";
  170. }
  171. }
  172. code_post += " default: return false;\n }\n}\n\n";
  173. }
  174. }
  175. // Generates a value with optionally a cast applied if the field has a
  176. // different underlying type from its interface type (currently only the
  177. // case for enums. "from" specify the direction, true meaning from the
  178. // underlying type to the interface type.
  179. std::string GenUnderlyingCast(const Parser &parser, const FieldDef &field,
  180. bool from, const std::string &val) {
  181. return field.value.type.enum_def && IsScalar(field.value.type.base_type)
  182. ? "static_cast<" + GenTypeBasic(parser, field.value.type, from) + ">(" +
  183. val + ")"
  184. : val;
  185. }
  186. // Generate an accessor struct, builder structs & function for a table.
  187. static void GenTable(const Parser &parser, StructDef &struct_def,
  188. const GeneratorOptions &opts, std::string *code_ptr) {
  189. if (struct_def.generated) return;
  190. std::string &code = *code_ptr;
  191. // Generate an accessor struct, with methods of the form:
  192. // type name() const { return GetField<type>(offset, defaultval); }
  193. GenComment(struct_def.doc_comment, code_ptr);
  194. code += "struct " + struct_def.name + " : private flatbuffers::Table";
  195. code += " {\n";
  196. for (auto it = struct_def.fields.vec.begin();
  197. it != struct_def.fields.vec.end();
  198. ++it) {
  199. auto &field = **it;
  200. if (!field.deprecated) { // Deprecated fields won't be accessible.
  201. GenComment(field.doc_comment, code_ptr, " ");
  202. code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " *",
  203. true);
  204. code += field.name + "() const { return ";
  205. // Call a different accessor for pointers, that indirects.
  206. std::string call = IsScalar(field.value.type.base_type)
  207. ? "GetField<"
  208. : (IsStruct(field.value.type) ? "GetStruct<" : "GetPointer<");
  209. call += GenTypeGet(parser, field.value.type, "", "const ", " *", false);
  210. call += ">(" + NumToString(field.value.offset);
  211. // Default value as second arg for non-pointer types.
  212. if (IsScalar(field.value.type.base_type))
  213. call += ", " + field.value.constant;
  214. call += ")";
  215. code += GenUnderlyingCast(parser, field, true, call);
  216. code += "; }\n";
  217. auto nested = field.attributes.Lookup("nested_flatbuffer");
  218. if (nested) {
  219. auto nested_root = parser.structs_.Lookup(nested->constant);
  220. assert(nested_root); // Guaranteed to exist by parser.
  221. code += " const " + nested_root->name + " *" + field.name;
  222. code += "_nested_root() { return flatbuffers::GetRoot<";
  223. code += nested_root->name + ">(" + field.name + "()->Data()); }\n";
  224. }
  225. }
  226. }
  227. // Generate a verifier function that can check a buffer from an untrusted
  228. // source will never cause reads outside the buffer.
  229. code += " bool Verify(flatbuffers::Verifier &verifier) const {\n";
  230. code += " return VerifyTableStart(verifier)";
  231. std::string prefix = " &&\n ";
  232. for (auto it = struct_def.fields.vec.begin();
  233. it != struct_def.fields.vec.end();
  234. ++it) {
  235. auto &field = **it;
  236. if (!field.deprecated) {
  237. code += prefix + "VerifyField";
  238. if (field.required) code += "Required";
  239. code += "<" + GenTypeSize(parser, field.value.type);
  240. code += ">(verifier, " + NumToString(field.value.offset);
  241. code += " /* " + field.name + " */)";
  242. switch (field.value.type.base_type) {
  243. case BASE_TYPE_UNION:
  244. code += prefix + "Verify" + field.value.type.enum_def->name;
  245. code += "(verifier, " + field.name + "(), " + field.name + "_type())";
  246. break;
  247. case BASE_TYPE_STRUCT:
  248. if (!field.value.type.struct_def->fixed) {
  249. code += prefix + "verifier.VerifyTable(" + field.name;
  250. code += "())";
  251. }
  252. break;
  253. case BASE_TYPE_STRING:
  254. code += prefix + "verifier.Verify(" + field.name + "())";
  255. break;
  256. case BASE_TYPE_VECTOR:
  257. code += prefix + "verifier.Verify(" + field.name + "())";
  258. switch (field.value.type.element) {
  259. case BASE_TYPE_STRING: {
  260. code += prefix + "verifier.VerifyVectorOfStrings(" + field.name;
  261. code += "())";
  262. break;
  263. }
  264. case BASE_TYPE_STRUCT: {
  265. if (!field.value.type.struct_def->fixed) {
  266. code += prefix + "verifier.VerifyVectorOfTables(" + field.name;
  267. code += "())";
  268. }
  269. break;
  270. }
  271. default:
  272. break;
  273. }
  274. break;
  275. default:
  276. break;
  277. }
  278. }
  279. }
  280. code += prefix + "verifier.EndTable()";
  281. code += ";\n }\n";
  282. code += "};\n\n";
  283. // Generate a builder struct, with methods of the form:
  284. // void add_name(type name) { fbb_.AddElement<type>(offset, name, default); }
  285. code += "struct " + struct_def.name;
  286. code += "Builder {\n flatbuffers::FlatBufferBuilder &fbb_;\n";
  287. code += " flatbuffers::uoffset_t start_;\n";
  288. for (auto it = struct_def.fields.vec.begin();
  289. it != struct_def.fields.vec.end();
  290. ++it) {
  291. auto &field = **it;
  292. if (!field.deprecated) {
  293. code += " void add_" + field.name + "(";
  294. code += GenTypeWire(parser, field.value.type, " ", true) + field.name;
  295. code += ") { fbb_.Add";
  296. if (IsScalar(field.value.type.base_type)) {
  297. code += "Element<" + GenTypeWire(parser, field.value.type, "", false);
  298. code += ">";
  299. } else if (IsStruct(field.value.type)) {
  300. code += "Struct";
  301. } else {
  302. code += "Offset";
  303. }
  304. code += "(" + NumToString(field.value.offset) + ", ";
  305. code += GenUnderlyingCast(parser, field, false, field.name);
  306. if (IsScalar(field.value.type.base_type))
  307. code += ", " + field.value.constant;
  308. code += "); }\n";
  309. }
  310. }
  311. code += " " + struct_def.name;
  312. code += "Builder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) ";
  313. code += "{ start_ = fbb_.StartTable(); }\n";
  314. code += " " + struct_def.name + "Builder &operator=(const ";
  315. code += struct_def.name + "Builder &);\n";
  316. code += " flatbuffers::Offset<" + struct_def.name;
  317. code += "> Finish() {\n auto o = flatbuffers::Offset<" + struct_def.name;
  318. code += ">(fbb_.EndTable(start_, ";
  319. code += NumToString(struct_def.fields.vec.size()) + "));\n";
  320. for (auto it = struct_def.fields.vec.begin();
  321. it != struct_def.fields.vec.end();
  322. ++it) {
  323. auto &field = **it;
  324. if (!field.deprecated && field.required) {
  325. code += " fbb_.Required(o, " + NumToString(field.value.offset);
  326. code += "); // " + field.name + "\n";
  327. }
  328. }
  329. code += " return o;\n }\n};\n\n";
  330. // Generate a convenient CreateX function that uses the above builder
  331. // to create a table in one go.
  332. code += "inline flatbuffers::Offset<" + struct_def.name + "> Create";
  333. code += struct_def.name;
  334. code += "(flatbuffers::FlatBufferBuilder &_fbb";
  335. for (auto it = struct_def.fields.vec.begin();
  336. it != struct_def.fields.vec.end();
  337. ++it) {
  338. auto &field = **it;
  339. if (!field.deprecated) {
  340. code += ",\n " + GenTypeWire(parser, field.value.type, " ", true);
  341. code += field.name + " = ";
  342. if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) {
  343. auto ev = field.value.type.enum_def->ReverseLookup(
  344. static_cast<int>(StringToInt(field.value.constant.c_str())), false);
  345. if (ev) {
  346. code += WrapInNameSpace(parser,
  347. field.value.type.enum_def->defined_namespace,
  348. GenEnumVal(*field.value.type.enum_def, *ev,
  349. opts));
  350. } else {
  351. code += GenUnderlyingCast(parser, field, true, field.value.constant);
  352. }
  353. } else {
  354. code += field.value.constant;
  355. }
  356. }
  357. }
  358. code += ") {\n " + struct_def.name + "Builder builder_(_fbb);\n";
  359. for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
  360. size;
  361. size /= 2) {
  362. for (auto it = struct_def.fields.vec.rbegin();
  363. it != struct_def.fields.vec.rend();
  364. ++it) {
  365. auto &field = **it;
  366. if (!field.deprecated &&
  367. (!struct_def.sortbysize ||
  368. size == SizeOf(field.value.type.base_type))) {
  369. code += " builder_.add_" + field.name + "(" + field.name + ");\n";
  370. }
  371. }
  372. }
  373. code += " return builder_.Finish();\n}\n\n";
  374. }
  375. static void GenPadding(const FieldDef &field, const std::function<void (int bits)> &f) {
  376. if (field.padding) {
  377. for (int i = 0; i < 4; i++)
  378. if (static_cast<int>(field.padding) & (1 << i))
  379. f((1 << i) * 8);
  380. assert(!(field.padding & ~0xF));
  381. }
  382. }
  383. // Generate an accessor struct with constructor for a flatbuffers struct.
  384. static void GenStruct(const Parser &parser, StructDef &struct_def,
  385. std::string *code_ptr) {
  386. if (struct_def.generated) return;
  387. std::string &code = *code_ptr;
  388. // Generate an accessor struct, with private variables of the form:
  389. // type name_;
  390. // Generates manual padding and alignment.
  391. // Variables are private because they contain little endian data on all
  392. // platforms.
  393. GenComment(struct_def.doc_comment, code_ptr);
  394. code += "MANUALLY_ALIGNED_STRUCT(" + NumToString(struct_def.minalign) + ") ";
  395. code += struct_def.name + " {\n private:\n";
  396. int padding_id = 0;
  397. for (auto it = struct_def.fields.vec.begin();
  398. it != struct_def.fields.vec.end();
  399. ++it) {
  400. auto &field = **it;
  401. code += " " + GenTypeGet(parser, field.value.type, " ", "", " ", false);
  402. code += field.name + "_;\n";
  403. GenPadding(field, [&code, &padding_id](int bits) {
  404. code += " int" + NumToString(bits) +
  405. "_t __padding" + NumToString(padding_id++) + ";\n";
  406. });
  407. }
  408. // Generate a constructor that takes all fields as arguments.
  409. code += "\n public:\n " + struct_def.name + "(";
  410. for (auto it = struct_def.fields.vec.begin();
  411. it != struct_def.fields.vec.end();
  412. ++it) {
  413. auto &field = **it;
  414. if (it != struct_def.fields.vec.begin()) code += ", ";
  415. code += GenTypeGet(parser, field.value.type, " ", "const ", " &", true);
  416. code += field.name;
  417. }
  418. code += ")\n : ";
  419. padding_id = 0;
  420. for (auto it = struct_def.fields.vec.begin();
  421. it != struct_def.fields.vec.end();
  422. ++it) {
  423. auto &field = **it;
  424. if (it != struct_def.fields.vec.begin()) code += ", ";
  425. code += field.name + "_(";
  426. if (IsScalar(field.value.type.base_type)) {
  427. code += "flatbuffers::EndianScalar(";
  428. code += GenUnderlyingCast(parser, field, false, field.name);
  429. code += "))";
  430. } else {
  431. code += field.name + ")";
  432. }
  433. GenPadding(field, [&code, &padding_id](int bits) {
  434. (void)bits;
  435. code += ", __padding" + NumToString(padding_id++) + "(0)";
  436. });
  437. }
  438. code += " {";
  439. padding_id = 0;
  440. for (auto it = struct_def.fields.vec.begin();
  441. it != struct_def.fields.vec.end();
  442. ++it) {
  443. auto &field = **it;
  444. GenPadding(field, [&code, &padding_id](int bits) {
  445. (void)bits;
  446. code += " (void)__padding" + NumToString(padding_id++) + ";";
  447. });
  448. }
  449. code += " }\n\n";
  450. // Generate accessor methods of the form:
  451. // type name() const { return flatbuffers::EndianScalar(name_); }
  452. for (auto it = struct_def.fields.vec.begin();
  453. it != struct_def.fields.vec.end();
  454. ++it) {
  455. auto &field = **it;
  456. GenComment(field.doc_comment, code_ptr, " ");
  457. code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " &",
  458. true);
  459. code += field.name + "() const { return ";
  460. code += GenUnderlyingCast(parser, field, true,
  461. IsScalar(field.value.type.base_type)
  462. ? "flatbuffers::EndianScalar(" + field.name + "_)"
  463. : field.name + "_");
  464. code += "; }\n";
  465. }
  466. code += "};\nSTRUCT_END(" + struct_def.name + ", ";
  467. code += NumToString(struct_def.bytesize) + ");\n\n";
  468. }
  469. void GenerateNestedNameSpaces(Namespace *ns, std::string *code_ptr) {
  470. for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
  471. *code_ptr += "namespace " + *it + " {\n";
  472. }
  473. }
  474. void CloseNestedNameSpaces(Namespace *ns, std::string *code_ptr) {
  475. for (auto it = ns->components.rbegin(); it != ns->components.rend(); ++it) {
  476. *code_ptr += "} // namespace " + *it + "\n";
  477. }
  478. }
  479. } // namespace cpp
  480. // Iterate through all definitions we haven't generate code for (enums, structs,
  481. // and tables) and output them to a single file.
  482. std::string GenerateCPP(const Parser &parser,
  483. const std::string &file_name,
  484. const GeneratorOptions &opts) {
  485. using namespace cpp;
  486. // Generate code for all the enum declarations.
  487. std::string enum_code, enum_code_post;
  488. for (auto it = parser.enums_.vec.begin();
  489. it != parser.enums_.vec.end(); ++it) {
  490. GenEnum(**it, &enum_code, &enum_code_post, opts);
  491. }
  492. // Generate forward declarations for all structs/tables, since they may
  493. // have circular references.
  494. std::string forward_decl_code_same_namespace;
  495. std::string forward_decl_code_other_namespace;
  496. Namespace *cur_name_space = nullptr;
  497. for (auto it = parser.structs_.vec.begin();
  498. it != parser.structs_.vec.end(); ++it) {
  499. auto &struct_def = **it;
  500. auto decl = "struct " + struct_def.name + ";\n";
  501. if (struct_def.defined_namespace == parser.namespaces_.back()) {
  502. forward_decl_code_same_namespace += decl;
  503. } else {
  504. // Wrap this decl in the correct namespace. Only open a namespace if
  505. // the adjacent one is different.
  506. // TODO: this could be done more intelligently, by sorting to
  507. // namespace path and only opening/closing what is necessary, but that's
  508. // quite a bit more complexity.
  509. if (cur_name_space != struct_def.defined_namespace) {
  510. if (cur_name_space) {
  511. CloseNestedNameSpaces(cur_name_space,
  512. &forward_decl_code_other_namespace);
  513. }
  514. GenerateNestedNameSpaces(struct_def.defined_namespace,
  515. &forward_decl_code_other_namespace);
  516. cur_name_space = struct_def.defined_namespace;
  517. }
  518. forward_decl_code_other_namespace += decl;
  519. }
  520. }
  521. if (cur_name_space) {
  522. CloseNestedNameSpaces(cur_name_space,
  523. &forward_decl_code_other_namespace);
  524. }
  525. // Generate code for all structs, then all tables.
  526. std::string decl_code;
  527. for (auto it = parser.structs_.vec.begin();
  528. it != parser.structs_.vec.end(); ++it) {
  529. if ((**it).fixed) GenStruct(parser, **it, &decl_code);
  530. }
  531. for (auto it = parser.structs_.vec.begin();
  532. it != parser.structs_.vec.end(); ++it) {
  533. if (!(**it).fixed) GenTable(parser, **it, opts, &decl_code);
  534. }
  535. // Only output file-level code if there were any declarations.
  536. if (enum_code.length() || decl_code.length()) {
  537. std::string code;
  538. code = "// automatically generated by the FlatBuffers compiler,"
  539. " do not modify\n\n";
  540. // Generate include guard.
  541. std::string include_guard_ident = file_name;
  542. // Remove any non-alpha-numeric characters that may appear in a filename.
  543. include_guard_ident.erase(
  544. std::remove_if(include_guard_ident.begin(),
  545. include_guard_ident.end(),
  546. [](char c) { return !isalnum(c); }),
  547. include_guard_ident.end());
  548. std::string include_guard = "FLATBUFFERS_GENERATED_" + include_guard_ident;
  549. include_guard += "_";
  550. // For further uniqueness, also add the namespace.
  551. auto name_space = parser.namespaces_.back();
  552. for (auto it = name_space->components.begin();
  553. it != name_space->components.end(); ++it) {
  554. include_guard += *it + "_";
  555. }
  556. include_guard += "H_";
  557. std::transform(include_guard.begin(), include_guard.end(),
  558. include_guard.begin(), ::toupper);
  559. code += "#ifndef " + include_guard + "\n";
  560. code += "#define " + include_guard + "\n\n";
  561. code += "#include \"flatbuffers/flatbuffers.h\"\n\n";
  562. if (opts.include_dependence_headers) {
  563. int num_includes = 0;
  564. for (auto it = parser.included_files_.begin();
  565. it != parser.included_files_.end(); ++it) {
  566. auto basename = flatbuffers::StripPath(
  567. flatbuffers::StripExtension(it->first));
  568. if (basename != file_name) {
  569. code += "#include \"" + basename + "_generated.h\"\n";
  570. num_includes++;
  571. }
  572. }
  573. if (num_includes) code += "\n";
  574. }
  575. code += forward_decl_code_other_namespace;
  576. code += "\n";
  577. GenerateNestedNameSpaces(name_space, &code);
  578. code += "\n";
  579. code += forward_decl_code_same_namespace;
  580. code += "\n";
  581. // Output the main declaration code from above.
  582. code += enum_code;
  583. code += decl_code;
  584. code += enum_code_post;
  585. // Generate convenient global helper functions:
  586. if (parser.root_struct_def) {
  587. // The root datatype accessor:
  588. code += "inline const " + parser.root_struct_def->name + " *Get";
  589. code += parser.root_struct_def->name;
  590. code += "(const void *buf) { return flatbuffers::GetRoot<";
  591. code += parser.root_struct_def->name + ">(buf); }\n\n";
  592. // The root verifier:
  593. code += "inline bool Verify";
  594. code += parser.root_struct_def->name;
  595. code += "Buffer(flatbuffers::Verifier &verifier) { "
  596. "return verifier.VerifyBuffer<";
  597. code += parser.root_struct_def->name + ">(); }\n\n";
  598. // Finish a buffer with a given root object:
  599. code += "inline void Finish" + parser.root_struct_def->name;
  600. code += "Buffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<";
  601. code += parser.root_struct_def->name + "> root) { fbb.Finish(root";
  602. if (parser.file_identifier_.length())
  603. code += ", \"" + parser.file_identifier_ + "\"";
  604. code += "); }\n\n";
  605. if (parser.file_identifier_.length()) {
  606. // Check if a buffer has the identifier.
  607. code += "inline bool " + parser.root_struct_def->name;
  608. code += "BufferHasIdentifier(const void *buf) { return flatbuffers::";
  609. code += "BufferHasIdentifier(buf, \"" + parser.file_identifier_;
  610. code += "\"); }\n\n";
  611. }
  612. }
  613. CloseNestedNameSpaces(name_space, &code);
  614. // Close the include guard.
  615. code += "\n#endif // " + include_guard + "\n";
  616. return code;
  617. }
  618. return std::string();
  619. }
  620. bool GenerateCPP(const Parser &parser,
  621. const std::string &path,
  622. const std::string &file_name,
  623. const GeneratorOptions &opts) {
  624. auto code = GenerateCPP(parser, file_name, opts);
  625. return !code.length() ||
  626. SaveFile((path + file_name + "_generated.h").c_str(), code, false);
  627. }
  628. } // namespace flatbuffers