1 /*
2 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // independent from idl_parser, since this code is not needed for most clients
18
19 #include "flatbuffers/flatbuffers.h"
20 #include "flatbuffers/idl.h"
21 #include "flatbuffers/util.h"
22 #include "flatbuffers/code_generators.h"
23
24 namespace flatbuffers {
25
GeneratedFileName(const std::string & path,const std::string & file_name)26 static std::string GeneratedFileName(const std::string &path,
27 const std::string &file_name) {
28 return path + file_name + "_generated.h";
29 }
30
31 namespace cpp {
32 class CppGenerator : public BaseGenerator {
33 public:
CppGenerator(const Parser & parser,const std::string & path,const std::string & file_name)34 CppGenerator(const Parser &parser, const std::string &path,
35 const std::string &file_name)
36 : BaseGenerator(parser, path, file_name, "", "::"),
37 cur_name_space_(nullptr) {}
38
GenIncludeGuard() const39 std::string GenIncludeGuard() const {
40 // Generate include guard.
41 std::string guard = file_name_;
42 // Remove any non-alpha-numeric characters that may appear in a filename.
43 struct IsAlnum {
44 bool operator()(char c) { return !isalnum(c); }
45 };
46 guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
47 guard.end());
48 guard = "FLATBUFFERS_GENERATED_" + guard;
49 guard += "_";
50 // For further uniqueness, also add the namespace.
51 auto name_space = parser_.namespaces_.back();
52 for (auto it = name_space->components.begin();
53 it != name_space->components.end(); ++it) {
54 guard += *it + "_";
55 }
56 guard += "H_";
57 std::transform(guard.begin(), guard.end(), guard.begin(), ::toupper);
58 return guard;
59 }
60
GenIncludeDependencies()61 void GenIncludeDependencies() {
62 int num_includes = 0;
63 for (auto it = parser_.native_included_files_.begin();
64 it != parser_.native_included_files_.end(); ++it) {
65 code_ += "#include \"" + *it + "\"";
66 num_includes++;
67 }
68 for (auto it = parser_.included_files_.begin();
69 it != parser_.included_files_.end(); ++it) {
70 const auto basename =
71 flatbuffers::StripPath(flatbuffers::StripExtension(it->first));
72 if (basename != file_name_) {
73 code_ += "#include \"" + parser_.opts.include_prefix + basename +
74 "_generated.h\"";
75 num_includes++;
76 }
77 }
78 if (num_includes) code_ += "";
79 }
80
81 // Iterate through all definitions we haven't generate code for (enums,
82 // structs, and tables) and output them to a single file.
generate()83 bool generate() {
84 if (IsEverythingGenerated()) return true;
85
86 code_.Clear();
87 code_ += "// " + std::string(FlatBuffersGeneratedWarning());
88
89 const auto include_guard = GenIncludeGuard();
90 code_ += "#ifndef " + include_guard;
91 code_ += "#define " + include_guard;
92 code_ += "";
93
94 code_ += "#include \"flatbuffers/flatbuffers.h\"";
95 code_ += "";
96
97 if (parser_.opts.include_dependence_headers) {
98 GenIncludeDependencies();
99 }
100
101 assert(!cur_name_space_);
102
103 // Generate forward declarations for all structs/tables, since they may
104 // have circular references.
105 for (auto it = parser_.structs_.vec.begin();
106 it != parser_.structs_.vec.end(); ++it) {
107 const auto &struct_def = **it;
108 if (!struct_def.generated) {
109 SetNameSpace(struct_def.defined_namespace);
110 code_ += "struct " + struct_def.name + ";";
111 if (parser_.opts.generate_object_based_api && !struct_def.fixed) {
112 code_ += "struct " + NativeName(struct_def.name) + ";";
113 }
114 code_ += "";
115 }
116 }
117
118 // Generate code for all the enum declarations.
119 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
120 ++it) {
121 const auto &enum_def = **it;
122 if (!enum_def.generated) {
123 SetNameSpace(enum_def.defined_namespace);
124 GenEnum(enum_def);
125 }
126 }
127
128 // Generate code for all structs, then all tables.
129 for (auto it = parser_.structs_.vec.begin();
130 it != parser_.structs_.vec.end(); ++it) {
131 const auto &struct_def = **it;
132 if (struct_def.fixed && !struct_def.generated) {
133 SetNameSpace(struct_def.defined_namespace);
134 GenStruct(struct_def);
135 }
136 }
137 for (auto it = parser_.structs_.vec.begin();
138 it != parser_.structs_.vec.end(); ++it) {
139 const auto &struct_def = **it;
140 if (!struct_def.fixed && !struct_def.generated) {
141 SetNameSpace(struct_def.defined_namespace);
142 GenTable(struct_def);
143 }
144 }
145 for (auto it = parser_.structs_.vec.begin();
146 it != parser_.structs_.vec.end(); ++it) {
147 const auto &struct_def = **it;
148 if (!struct_def.fixed && !struct_def.generated) {
149 SetNameSpace(struct_def.defined_namespace);
150 GenTablePost(struct_def);
151 }
152 }
153
154 // Generate code for union verifiers.
155 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
156 ++it) {
157 const auto &enum_def = **it;
158 if (enum_def.is_union && !enum_def.generated) {
159 SetNameSpace(enum_def.defined_namespace);
160 GenUnionPost(enum_def);
161 }
162 }
163
164 // Generate convenient global helper functions:
165 if (parser_.root_struct_def_) {
166 auto &struct_def = *parser_.root_struct_def_;
167 SetNameSpace(struct_def.defined_namespace);
168 const auto &name = struct_def.name;
169 const auto qualified_name =
170 parser_.namespaces_.back()->GetFullyQualifiedName(name);
171 const auto cpp_name = TranslateNameSpace(qualified_name);
172
173 code_.SetValue("STRUCT_NAME", name);
174 code_.SetValue("CPP_NAME", cpp_name);
175
176 // The root datatype accessor:
177 code_ += "inline \\";
178 code_ += "const {{CPP_NAME}} *Get{{STRUCT_NAME}}(const void *buf) {";
179 code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
180 code_ += "}";
181 code_ += "";
182
183 if (parser_.opts.mutable_buffer) {
184 code_ += "inline \\";
185 code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
186 code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
187 code_ += "}";
188 code_ += "";
189 }
190
191 if (parser_.file_identifier_.length()) {
192 // Return the identifier
193 code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
194 code_ += " return \"" + parser_.file_identifier_ + "\";";
195 code_ += "}";
196 code_ += "";
197
198 // Check if a buffer has the identifier.
199 code_ += "inline \\";
200 code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
201 code_ += " return flatbuffers::BufferHasIdentifier(";
202 code_ += " buf, {{STRUCT_NAME}}Identifier());";
203 code_ += "}";
204 code_ += "";
205 }
206
207 // The root verifier.
208 if (parser_.file_identifier_.length()) {
209 code_.SetValue("ID", name + "Identifier()");
210 } else {
211 code_.SetValue("ID", "nullptr");
212 }
213
214 code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
215 code_ += " flatbuffers::Verifier &verifier) {";
216 code_ += " return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
217 code_ += "}";
218 code_ += "";
219
220 if (parser_.file_extension_.length()) {
221 // Return the extension
222 code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
223 code_ += " return \"" + parser_.file_extension_ + "\";";
224 code_ += "}";
225 code_ += "";
226 }
227
228 // Finish a buffer with a given root object:
229 code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
230 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
231 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
232 if (parser_.file_identifier_.length())
233 code_ += " fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
234 else
235 code_ += " fbb.Finish(root);";
236 code_ += "}";
237 code_ += "";
238
239 if (parser_.opts.generate_object_based_api) {
240 // A convenient root unpack function.
241 auto native_name =
242 NativeName(WrapInNameSpace(struct_def));
243 code_.SetValue("UNPACK_RETURN",
244 GenTypeNativePtr(native_name, nullptr, false));
245 code_.SetValue("UNPACK_TYPE",
246 GenTypeNativePtr(native_name, nullptr, true));
247
248 code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
249 code_ += " const void *buf,";
250 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
251 code_ += " return {{UNPACK_TYPE}}\\";
252 code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
253 code_ += "}";
254 code_ += "";
255 }
256 }
257
258 assert(cur_name_space_);
259 SetNameSpace(nullptr);
260
261 // Close the include guard.
262 code_ += "#endif // " + include_guard;
263
264 const auto file_path = GeneratedFileName(path_, file_name_);
265 const auto final_code = code_.ToString();
266 return SaveFile(file_path.c_str(), final_code, false);
267 }
268
269 private:
270 CodeWriter code_;
271
272 // This tracks the current namespace so we can insert namespace declarations.
273 const Namespace *cur_name_space_;
274
CurrentNameSpace() const275 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
276
277 // Translates a qualified name in flatbuffer text format to the same name in
278 // the equivalent C++ namespace.
TranslateNameSpace(const std::string & qualified_name)279 static std::string TranslateNameSpace(const std::string &qualified_name) {
280 std::string cpp_qualified_name = qualified_name;
281 size_t start_pos = 0;
282 while ((start_pos = cpp_qualified_name.find(".", start_pos)) !=
283 std::string::npos) {
284 cpp_qualified_name.replace(start_pos, 1, "::");
285 }
286 return cpp_qualified_name;
287 }
288
GenComment(const std::vector<std::string> & dc,const char * prefix="")289 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
290 std::string text;
291 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
292 code_ += text + "\\";
293 }
294
295 // Return a C++ type from the table in idl.h
GenTypeBasic(const Type & type,bool user_facing_type) const296 std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
297 static const char *ctypename[] = {
298 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
299 #CTYPE,
300 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
301 #undef FLATBUFFERS_TD
302 };
303 if (user_facing_type) {
304 if (type.enum_def) return WrapInNameSpace(*type.enum_def);
305 if (type.base_type == BASE_TYPE_BOOL) return "bool";
306 }
307 return ctypename[type.base_type];
308 }
309
310 // Return a C++ pointer type, specialized to the actual struct/table types,
311 // and vector element types.
GenTypePointer(const Type & type) const312 std::string GenTypePointer(const Type &type) const {
313 switch (type.base_type) {
314 case BASE_TYPE_STRING: {
315 return "flatbuffers::String";
316 }
317 case BASE_TYPE_VECTOR: {
318 const auto type_name = GenTypeWire(type.VectorType(), "", false);
319 return "flatbuffers::Vector<" + type_name + ">";
320 }
321 case BASE_TYPE_STRUCT: {
322 return WrapInNameSpace(*type.struct_def);
323 }
324 case BASE_TYPE_UNION:
325 // fall through
326 default: {
327 return "void";
328 }
329 }
330 }
331
332 // Return a C++ type for any type (scalar/pointer) specifically for
333 // building a flatbuffer.
GenTypeWire(const Type & type,const char * postfix,bool user_facing_type) const334 std::string GenTypeWire(const Type &type, const char *postfix,
335 bool user_facing_type) const {
336 if (IsScalar(type.base_type)) {
337 return GenTypeBasic(type, user_facing_type) + postfix;
338 } else if (IsStruct(type)) {
339 return "const " + GenTypePointer(type) + " *";
340 } else {
341 return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix;
342 }
343 }
344
345 // Return a C++ type for any type (scalar/pointer) that reflects its
346 // serialized size.
GenTypeSize(const Type & type) const347 std::string GenTypeSize(const Type &type) const {
348 if (IsScalar(type.base_type)) {
349 return GenTypeBasic(type, false);
350 } else if (IsStruct(type)) {
351 return GenTypePointer(type);
352 } else {
353 return "flatbuffers::uoffset_t";
354 }
355 }
356
357 // TODO(wvo): make this configurable.
NativeName(const std::string & name)358 static std::string NativeName(const std::string &name) { return name + "T"; }
359
PtrType(const FieldDef * field)360 const std::string &PtrType(const FieldDef *field) {
361 auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
362 return attr ? attr->constant : parser_.opts.cpp_object_api_pointer_type;
363 }
364
GenTypeNativePtr(const std::string & type,const FieldDef * field,bool is_constructor)365 std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
366 bool is_constructor) {
367 auto &ptr_type = PtrType(field);
368 if (ptr_type != "naked") {
369 return ptr_type + "<" + type + ">";
370 } else if (is_constructor) {
371 return "";
372 } else {
373 return type + " *";
374 }
375 }
376
GenPtrGet(const FieldDef & field)377 std::string GenPtrGet(const FieldDef &field) {
378 auto &ptr_type = PtrType(&field);
379 return ptr_type == "naked" ? "" : ".get()";
380 }
381
GenTypeNative(const Type & type,bool invector,const FieldDef & field)382 std::string GenTypeNative(const Type &type, bool invector,
383 const FieldDef &field) {
384 switch (type.base_type) {
385 case BASE_TYPE_STRING: {
386 return "std::string";
387 }
388 case BASE_TYPE_VECTOR: {
389 const auto type_name = GenTypeNative(type.VectorType(), true, field);
390 return "std::vector<" + type_name + ">";
391 }
392 case BASE_TYPE_STRUCT: {
393 auto type_name = WrapInNameSpace(*type.struct_def);
394 if (IsStruct(type)) {
395 auto native_type = type.struct_def->attributes.Lookup("native_type");
396 if (native_type) {
397 type_name = native_type->constant;
398 }
399 if (invector || field.native_inline) {
400 return type_name;
401 } else {
402 return GenTypeNativePtr(type_name, &field, false);
403 }
404 } else {
405 return GenTypeNativePtr(NativeName(type_name), &field, false);
406 }
407 }
408 case BASE_TYPE_UNION: {
409 return type.enum_def->name + "Union";
410 }
411 default: {
412 return GenTypeBasic(type, true);
413 }
414 }
415 }
416
417 // Return a C++ type for any type (scalar/pointer) specifically for
418 // using a flatbuffer.
GenTypeGet(const Type & type,const char * afterbasic,const char * beforeptr,const char * afterptr,bool user_facing_type)419 std::string GenTypeGet(const Type &type, const char *afterbasic,
420 const char *beforeptr, const char *afterptr,
421 bool user_facing_type) {
422 if (IsScalar(type.base_type)) {
423 return GenTypeBasic(type, user_facing_type) + afterbasic;
424 } else {
425 return beforeptr + GenTypePointer(type) + afterptr;
426 }
427 }
428
GenEnumDecl(const EnumDef & enum_def) const429 std::string GenEnumDecl(const EnumDef &enum_def) const {
430 const IDLOptions &opts = parser_.opts;
431 return (opts.scoped_enums ? "enum class " : "enum ") + enum_def.name;
432 }
433
GenEnumValDecl(const EnumDef & enum_def,const std::string & enum_val) const434 std::string GenEnumValDecl(const EnumDef &enum_def,
435 const std::string &enum_val) const {
436 const IDLOptions &opts = parser_.opts;
437 return opts.prefixed_enums ? enum_def.name + "_" + enum_val : enum_val;
438 }
439
GetEnumValUse(const EnumDef & enum_def,const EnumVal & enum_val) const440 std::string GetEnumValUse(const EnumDef &enum_def,
441 const EnumVal &enum_val) const {
442 const IDLOptions &opts = parser_.opts;
443 if (opts.scoped_enums) {
444 return enum_def.name + "::" + enum_val.name;
445 } else if (opts.prefixed_enums) {
446 return enum_def.name + "_" + enum_val.name;
447 } else {
448 return enum_val.name;
449 }
450 }
451
UnionVerifySignature(const EnumDef & enum_def)452 static std::string UnionVerifySignature(const EnumDef &enum_def) {
453 return "bool Verify" + enum_def.name +
454 "(flatbuffers::Verifier &verifier, const void *obj, " +
455 enum_def.name + " type)";
456 }
457
UnionVectorVerifySignature(const EnumDef & enum_def)458 static std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
459 return "bool Verify" + enum_def.name + "Vector" +
460 "(flatbuffers::Verifier &verifier, " +
461 "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
462 "const flatbuffers::Vector<uint8_t> *types)";
463 }
464
UnionUnPackSignature(const EnumDef & enum_def,bool inclass)465 static std::string UnionUnPackSignature(const EnumDef &enum_def,
466 bool inclass) {
467 return (inclass ? "static " : "") +
468 std::string("flatbuffers::NativeTable *") +
469 (inclass ? "" : enum_def.name + "Union::") +
470 "UnPack(const void *obj, " + enum_def.name +
471 " type, const flatbuffers::resolver_function_t *resolver)";
472 }
473
UnionPackSignature(const EnumDef & enum_def,bool inclass)474 static std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
475 return "flatbuffers::Offset<void> " +
476 (inclass ? "" : enum_def.name + "Union::") +
477 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
478 "const flatbuffers::rehasher_function_t *_rehasher" +
479 (inclass ? " = nullptr" : "") + ") const";
480 }
481
TableCreateSignature(const StructDef & struct_def,bool predecl)482 static std::string TableCreateSignature(const StructDef &struct_def,
483 bool predecl) {
484 return "flatbuffers::Offset<" + struct_def.name + "> Create" +
485 struct_def.name +
486 "(flatbuffers::FlatBufferBuilder &_fbb, const " +
487 NativeName(struct_def.name) +
488 " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
489 (predecl ? " = nullptr" : "") + ")";
490 }
491
TablePackSignature(const StructDef & struct_def,bool inclass)492 static std::string TablePackSignature(const StructDef &struct_def,
493 bool inclass) {
494 return std::string(inclass ? "static " : "") +
495 "flatbuffers::Offset<" + struct_def.name + "> " +
496 (inclass ? "" : struct_def.name + "::") +
497 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
498 "const " + NativeName(struct_def.name) + "* _o, " +
499 "const flatbuffers::rehasher_function_t *_rehasher" +
500 (inclass ? " = nullptr" : "") + ")";
501 }
502
TableUnPackSignature(const StructDef & struct_def,bool inclass)503 static std::string TableUnPackSignature(const StructDef &struct_def,
504 bool inclass) {
505 return NativeName(struct_def.name) + " *" +
506 (inclass ? "" : struct_def.name + "::") +
507 "UnPack(const flatbuffers::resolver_function_t *_resolver" +
508 (inclass ? " = nullptr" : "") + ") const";
509 }
510
TableUnPackToSignature(const StructDef & struct_def,bool inclass)511 static std::string TableUnPackToSignature(const StructDef &struct_def,
512 bool inclass) {
513 return "void " + (inclass ? "" : struct_def.name + "::") +
514 "UnPackTo(" + NativeName(struct_def.name) + " *" + "_o, " +
515 "const flatbuffers::resolver_function_t *_resolver" +
516 (inclass ? " = nullptr" : "") + ") const";
517 }
518
519 // Generate an enum declaration and an enum string lookup table.
GenEnum(const EnumDef & enum_def)520 void GenEnum(const EnumDef &enum_def) {
521 code_.SetValue("ENUM_NAME", enum_def.name);
522 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
523 code_.SetValue("SEP", "");
524
525 GenComment(enum_def.doc_comment);
526 code_ += GenEnumDecl(enum_def) + "\\";
527 if (parser_.opts.scoped_enums)
528 code_ += " : {{BASE_TYPE}}\\";
529 code_ += " {";
530
531 int64_t anyv = 0;
532 const EnumVal *minv = nullptr, *maxv = nullptr;
533 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
534 ++it) {
535 const auto &ev = **it;
536
537 GenComment(ev.doc_comment, " ");
538 code_.SetValue("KEY", GenEnumValDecl(enum_def, ev.name));
539 code_.SetValue("VALUE", NumToString(ev.value));
540 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
541 code_.SetValue("SEP", ",\n");
542
543 minv = !minv || minv->value > ev.value ? &ev : minv;
544 maxv = !maxv || maxv->value < ev.value ? &ev : maxv;
545 anyv |= ev.value;
546 }
547
548 if (parser_.opts.scoped_enums || parser_.opts.prefixed_enums) {
549 assert(minv && maxv);
550
551 code_.SetValue("SEP", ",\n");
552 if (enum_def.attributes.Lookup("bit_flags")) {
553 code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
554 code_.SetValue("VALUE", "0");
555 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
556
557 code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
558 code_.SetValue("VALUE", NumToString(anyv));
559 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
560 } else { // MIN & MAX are useless for bit_flags
561 code_.SetValue("KEY",GenEnumValDecl(enum_def, "MIN"));
562 code_.SetValue("VALUE", GenEnumValDecl(enum_def, minv->name));
563 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
564
565 code_.SetValue("KEY",GenEnumValDecl(enum_def, "MAX"));
566 code_.SetValue("VALUE", GenEnumValDecl(enum_def, maxv->name));
567 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
568 }
569 }
570 code_ += "";
571 code_ += "};";
572
573 if (parser_.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
574 code_ += "DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
575 }
576 code_ += "";
577
578 // Generate a generate string table for enum values.
579 // Problem is, if values are very sparse that could generate really big
580 // tables. Ideally in that case we generate a map lookup instead, but for
581 // the moment we simply don't output a table at all.
582 auto range =
583 enum_def.vals.vec.back()->value - enum_def.vals.vec.front()->value + 1;
584 // Average distance between values above which we consider a table
585 // "too sparse". Change at will.
586 static const int kMaxSparseness = 5;
587 if (range / static_cast<int64_t>(enum_def.vals.vec.size()) <
588 kMaxSparseness) {
589 code_ += "inline const char **EnumNames{{ENUM_NAME}}() {";
590 code_ += " static const char *names[] = {";
591
592 auto val = enum_def.vals.vec.front()->value;
593 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
594 ++it) {
595 const auto &ev = **it;
596 while (val++ != ev.value) {
597 code_ += " \"\",";
598 }
599 code_ += " \"" + ev.name + "\",";
600 }
601 code_ += " nullptr";
602 code_ += " };";
603
604 code_ += " return names;";
605 code_ += "}";
606 code_ += "";
607
608 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
609
610 code_ += " const size_t index = static_cast<int>(e)\\";
611 if (enum_def.vals.vec.front()->value) {
612 auto vals = GetEnumValUse(enum_def, *enum_def.vals.vec.front());
613 code_ += " - static_cast<int>(" + vals + ")\\";
614 }
615 code_ += ";";
616
617 code_ += " return EnumNames{{ENUM_NAME}}()[index];";
618 code_ += "}";
619 code_ += "";
620 }
621
622 // Generate type traits for unions to map from a type to union enum value.
623 if (enum_def.is_union) {
624 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
625 ++it) {
626 const auto &ev = **it;
627
628 if (it == enum_def.vals.vec.begin()) {
629 code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
630 }
631 else {
632 auto name = WrapInNameSpace(*ev.struct_def);
633 code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
634 }
635
636 auto value = GetEnumValUse(enum_def, ev);
637 code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
638 code_ += "};";
639 code_ += "";
640 }
641 }
642
643 if (parser_.opts.generate_object_based_api && enum_def.is_union) {
644 // Generate a union type
645 code_.SetValue("NAME", enum_def.name);
646 code_.SetValue("NONE",
647 GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE")));
648
649 code_ += "struct {{NAME}}Union {";
650 code_ += " {{NAME}} type;";
651 code_ += " flatbuffers::NativeTable *table;";
652 code_ += "";
653 code_ += " {{NAME}}Union() : type({{NONE}}), table(nullptr) {}";
654 code_ += " {{NAME}}Union({{NAME}}Union&& u):";
655 code_ += " type(std::move(u.type)), table(std::move(u.table)) {}";
656 code_ += " {{NAME}}Union(const {{NAME}}Union &);";
657 code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &);";
658 code_ += " ~{{NAME}}Union() { Reset(); }";
659 code_ += "";
660 code_ += " void Reset();";
661 code_ += "";
662 code_ += " template <typename T>";
663 code_ += " void Set(T&& value) {";
664 code_ += " Reset();";
665 code_ += " type = {{NAME}}Traits<typename T::TableType>::enum_value;";
666 code_ += " if (type != {{NONE}}) {";
667 code_ += " table = new T(std::forward<T>(value));";
668 code_ += " }";
669 code_ += " }";
670 code_ += "";
671 code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
672 code_ += " " + UnionPackSignature(enum_def, true) + ";";
673 code_ += "";
674
675 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
676 ++it) {
677 const auto &ev = **it;
678 if (!ev.value) {
679 continue;
680 }
681
682 const auto native_type = NativeName(WrapInNameSpace(*ev.struct_def));
683 code_.SetValue("NATIVE_TYPE", native_type);
684 code_.SetValue("NATIVE_NAME", ev.name);
685 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
686
687 code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
688 code_ += " return type == {{NATIVE_ID}} ?";
689 code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(table) : nullptr;";
690 code_ += " }";
691 }
692 code_ += "};";
693 code_ += "";
694 }
695
696 if (enum_def.is_union) {
697 code_ += UnionVerifySignature(enum_def) + ";";
698 code_ += UnionVectorVerifySignature(enum_def) + ";";
699 code_ += "";
700 }
701 }
702
GenUnionPost(const EnumDef & enum_def)703 void GenUnionPost(const EnumDef &enum_def) {
704 // Generate a verifier function for this union that can be called by the
705 // table verifier functions. It uses a switch case to select a specific
706 // verifier function to call, this should be safe even if the union type
707 // has been corrupted, since the verifiers will simply fail when called
708 // on the wrong type.
709 code_.SetValue("ENUM_NAME", enum_def.name);
710
711 code_ += "inline " + UnionVerifySignature(enum_def) + " {";
712 code_ += " switch (type) {";
713 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
714 ++it) {
715 const auto &ev = **it;
716 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
717
718 if (ev.value) {
719 code_.SetValue("TYPE", WrapInNameSpace(*ev.struct_def));
720 code_ += " case {{LABEL}}: {";
721 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
722 code_ += " return verifier.VerifyTable(ptr);";
723 code_ += " }";
724 } else {
725 code_ += " case {{LABEL}}: {";
726 code_ += " return true;"; // "NONE" enum value.
727 code_ += " }";
728 }
729 }
730 code_ += " default: return false;";
731 code_ += " }";
732 code_ += "}";
733 code_ += "";
734
735 code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
736 code_ += " if (values->size() != types->size()) return false;";
737 code_ += " for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
738 code_ += " if (!Verify" + enum_def.name + "(";
739 code_ += " verifier, values->Get(i), types->GetEnum<" + enum_def.name + ">(i))) {";
740 code_ += " return false;";
741 code_ += " }";
742 code_ += " }";
743 code_ += " return true;";
744 code_ += "}";
745 code_ += "";
746
747 if (parser_.opts.generate_object_based_api) {
748 // Generate union Unpack() and Pack() functions.
749 code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
750 code_ += " switch (type) {";
751 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
752 ++it) {
753 const auto &ev = **it;
754 if (!ev.value) {
755 continue;
756 }
757
758 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
759 code_.SetValue("TYPE", WrapInNameSpace(*ev.struct_def));
760 code_ += " case {{LABEL}}: {";
761 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
762 code_ += " return ptr->UnPack(resolver);";
763 code_ += " }";
764 }
765 code_ += " default: return nullptr;";
766 code_ += " }";
767 code_ += "}";
768 code_ += "";
769
770 code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
771 code_ += " switch (type) {";
772 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
773 ++it) {
774 auto &ev = **it;
775 if (!ev.value) {
776 continue;
777 }
778
779 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
780 code_.SetValue("TYPE", NativeName(WrapInNameSpace(*ev.struct_def)));
781 code_.SetValue("NAME", ev.struct_def->name);
782 code_ += " case {{LABEL}}: {";
783 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(table);";
784 code_ += " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
785 code_ += " }";
786 }
787 code_ += " default: return 0;";
788 code_ += " }";
789 code_ += "}";
790 code_ += "";
791
792 // Union Reset() function.
793 code_.SetValue("NONE",
794 GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE")));
795
796 code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
797 code_ += " switch (type) {";
798 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
799 ++it) {
800 const auto &ev = **it;
801 if (!ev.value) {
802 continue;
803 }
804
805 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
806 code_.SetValue("TYPE", NativeName(WrapInNameSpace(*ev.struct_def)));
807
808 code_ += " case {{LABEL}}: {";
809 code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(table);";
810 code_ += " delete ptr;";
811 code_ += " break;";
812 code_ += " }";
813 }
814 code_ += " default: break;";
815 code_ += " }";
816 code_ += " table = nullptr;";
817 code_ += " type = {{NONE}};";
818 code_ += "}";
819 code_ += "";
820 }
821 }
822
823 // Generates a value with optionally a cast applied if the field has a
824 // different underlying type from its interface type (currently only the
825 // case for enums. "from" specify the direction, true meaning from the
826 // underlying type to the interface type.
GenUnderlyingCast(const FieldDef & field,bool from,const std::string & val)827 std::string GenUnderlyingCast(const FieldDef &field, bool from,
828 const std::string &val) {
829 if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
830 return val + " != 0";
831 } else if ((field.value.type.enum_def &&
832 IsScalar(field.value.type.base_type)) ||
833 field.value.type.base_type == BASE_TYPE_BOOL) {
834 return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
835 val + ")";
836 } else {
837 return val;
838 }
839 }
840
GenFieldOffsetName(const FieldDef & field)841 std::string GenFieldOffsetName(const FieldDef &field) {
842 std::string uname = field.name;
843 std::transform(uname.begin(), uname.end(), uname.begin(), ::toupper);
844 return "VT_" + uname;
845 }
846
GenFullyQualifiedNameGetter(const std::string & name)847 void GenFullyQualifiedNameGetter(const std::string &name) {
848 if (!parser_.opts.generate_name_strings) {
849 return;
850 }
851
852 auto fullname = parser_.namespaces_.back()->GetFullyQualifiedName(name);
853 code_.SetValue("NAME", fullname);
854 code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
855
856 code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
857 code_ += " return \"{{NAME}}\";";
858 code_ += " }";
859 }
860
GenDefaultConstant(const FieldDef & field)861 std::string GenDefaultConstant(const FieldDef &field) {
862 return field.value.type.base_type == BASE_TYPE_FLOAT
863 ? field.value.constant + "f"
864 : field.value.constant;
865 }
866
GetDefaultScalarValue(const FieldDef & field)867 std::string GetDefaultScalarValue(const FieldDef &field) {
868 if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) {
869 auto ev = field.value.type.enum_def->ReverseLookup(
870 static_cast<int>(StringToInt(field.value.constant.c_str())), false);
871 if (ev) {
872 return WrapInNameSpace(
873 field.value.type.enum_def->defined_namespace,
874 GetEnumValUse(*field.value.type.enum_def, *ev));
875 } else {
876 return GenUnderlyingCast(field, true, field.value.constant);
877 }
878 } else if (field.value.type.base_type == BASE_TYPE_BOOL) {
879 return field.value.constant == "0" ? "false" : "true";
880 } else {
881 return GenDefaultConstant(field);
882 }
883 }
884
GenParam(const FieldDef & field,bool direct,const char * prefix)885 void GenParam(const FieldDef &field, bool direct, const char *prefix) {
886 code_.SetValue("PRE", prefix);
887 code_.SetValue("PARAM_NAME", field.name);
888 if (direct && field.value.type.base_type == BASE_TYPE_STRING) {
889 code_.SetValue("PARAM_TYPE", "const char *");
890 code_.SetValue("PARAM_VALUE", "nullptr");
891 } else if (direct && field.value.type.base_type == BASE_TYPE_VECTOR) {
892 auto type = GenTypeWire(field.value.type.VectorType(), "", false);
893 code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
894 code_.SetValue("PARAM_VALUE", "nullptr");
895 } else {
896 code_.SetValue("PARAM_TYPE", GenTypeWire(field.value.type, " ", true));
897 code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field));
898 }
899 code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
900 }
901
902 // Generate a member, including a default value for scalars and raw pointers.
GenMember(const FieldDef & field)903 void GenMember(const FieldDef &field) {
904 if (!field.deprecated && // Deprecated fields won't be accessible.
905 field.value.type.base_type != BASE_TYPE_UTYPE) {
906 auto type = GenTypeNative(field.value.type, false, field);
907 auto cpp_type = field.attributes.Lookup("cpp_type");
908 auto full_type = (cpp_type ? cpp_type->constant + " *" : type + " ");
909 code_.SetValue("FIELD_TYPE", full_type);
910 code_.SetValue("FIELD_NAME", field.name);
911 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}};";
912 }
913 }
914
915 // Generate the default constructor for this struct. Properly initialize all
916 // scalar members with default values.
GenDefaultConstructor(const StructDef & struct_def)917 void GenDefaultConstructor(const StructDef& struct_def) {
918 std::string initializer_list;
919 for (auto it = struct_def.fields.vec.begin();
920 it != struct_def.fields.vec.end(); ++it) {
921 const auto &field = **it;
922 if (!field.deprecated && // Deprecated fields won't be accessible.
923 field.value.type.base_type != BASE_TYPE_UTYPE) {
924 auto cpp_type = field.attributes.Lookup("cpp_type");
925 // Scalar types get parsed defaults, raw pointers get nullptrs.
926 if (IsScalar(field.value.type.base_type)) {
927 if (!initializer_list.empty()) {
928 initializer_list += ",\n ";
929 }
930 initializer_list += field.name;
931 initializer_list += "(" + GetDefaultScalarValue(field) + ")";
932 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
933 if (IsStruct(field.value.type)) {
934 auto native_default = field.attributes.Lookup("native_default");
935 if (native_default) {
936 if (!initializer_list.empty()) {
937 initializer_list += ",\n ";
938 }
939 initializer_list +=
940 field.name + "(" + native_default->constant + ")";
941 }
942 }
943 } else if (cpp_type) {
944 if (!initializer_list.empty()) {
945 initializer_list += ",\n ";
946 }
947 initializer_list += field.name + "(0)";
948 }
949 }
950 }
951 if (!initializer_list.empty()) {
952 initializer_list = "\n : " + initializer_list;
953 }
954
955 code_.SetValue("NATIVE_NAME", NativeName(struct_def.name));
956 code_.SetValue("INIT_LIST", initializer_list);
957
958 code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
959 code_ += " }";
960 }
961
GenNativeTable(const StructDef & struct_def)962 void GenNativeTable(const StructDef &struct_def) {
963 const auto native_name = NativeName(struct_def.name);
964 code_.SetValue("STRUCT_NAME", struct_def.name);
965 code_.SetValue("NATIVE_NAME", native_name);
966
967 // Generate a C++ object that can hold an unpacked version of this table.
968 code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
969 code_ += " typedef {{STRUCT_NAME}} TableType;";
970 GenFullyQualifiedNameGetter(native_name);
971 for (auto it = struct_def.fields.vec.begin();
972 it != struct_def.fields.vec.end(); ++it) {
973 GenMember(**it);
974 }
975 GenDefaultConstructor(struct_def);
976 code_ += "};";
977 code_ += "";
978 }
979
980 // Generate the code to call the appropriate Verify function(s) for a field.
GenVerifyCall(const FieldDef & field,const char * prefix)981 void GenVerifyCall(const FieldDef &field, const char* prefix) {
982 code_.SetValue("PRE", prefix);
983 code_.SetValue("NAME", field.name);
984 code_.SetValue("REQUIRED", field.required ? "Required" : "");
985 code_.SetValue("SIZE", GenTypeSize(field.value.type));
986 code_.SetValue("OFFSET", GenFieldOffsetName(field));
987 code_ += "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
988
989 switch (field.value.type.base_type) {
990 case BASE_TYPE_UNION: {
991 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
992 code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
993 code_ += "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
994 "{{NAME}}{{SUFFIX}}())\\";
995 break;
996 }
997 case BASE_TYPE_STRUCT: {
998 if (!field.value.type.struct_def->fixed) {
999 code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
1000 }
1001 break;
1002 }
1003 case BASE_TYPE_STRING: {
1004 code_ += "{{PRE}}verifier.Verify({{NAME}}())\\";
1005 break;
1006 }
1007 case BASE_TYPE_VECTOR: {
1008 code_ += "{{PRE}}verifier.Verify({{NAME}}())\\";
1009
1010 switch (field.value.type.element) {
1011 case BASE_TYPE_STRING: {
1012 code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
1013 break;
1014 }
1015 case BASE_TYPE_STRUCT: {
1016 if (!field.value.type.struct_def->fixed) {
1017 code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
1018 }
1019 break;
1020 }
1021 case BASE_TYPE_UNION: {
1022 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1023 code_ += "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), {{NAME}}_type())\\";
1024 break;
1025 }
1026 default:
1027 break;
1028 }
1029 break;
1030 }
1031 default: {
1032 break;
1033 }
1034 }
1035 }
1036
1037 // Generate an accessor struct, builder structs & function for a table.
GenTable(const StructDef & struct_def)1038 void GenTable(const StructDef &struct_def) {
1039 if (parser_.opts.generate_object_based_api) {
1040 GenNativeTable(struct_def);
1041 }
1042
1043 // Generate an accessor struct, with methods of the form:
1044 // type name() const { return GetField<type>(offset, defaultval); }
1045 GenComment(struct_def.doc_comment);
1046
1047 code_.SetValue("STRUCT_NAME", struct_def.name);
1048 code_ += "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
1049 " : private flatbuffers::Table {";
1050 if (parser_.opts.generate_object_based_api) {
1051 code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
1052 }
1053
1054 GenFullyQualifiedNameGetter(struct_def.name);
1055
1056 // Generate field id constants.
1057 if (struct_def.fields.vec.size() > 0) {
1058 // We need to add a trailing comma to all elements except the last one as
1059 // older versions of gcc complain about this.
1060 code_.SetValue("SEP", "");
1061 code_ += " enum {";
1062 for (auto it = struct_def.fields.vec.begin();
1063 it != struct_def.fields.vec.end(); ++it) {
1064 const auto &field = **it;
1065 if (field.deprecated) {
1066 // Deprecated fields won't be accessible.
1067 continue;
1068 }
1069
1070 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
1071 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
1072 code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
1073 code_.SetValue("SEP", ",\n");
1074 }
1075 code_ += "";
1076 code_ += " };";
1077 }
1078
1079 // Generate the accessors.
1080 for (auto it = struct_def.fields.vec.begin();
1081 it != struct_def.fields.vec.end(); ++it) {
1082 const auto &field = **it;
1083 if (field.deprecated) {
1084 // Deprecated fields won't be accessible.
1085 continue;
1086 }
1087
1088 const bool is_struct = IsStruct(field.value.type);
1089 const bool is_scalar = IsScalar(field.value.type.base_type);
1090 code_.SetValue("FIELD_NAME", field.name);
1091
1092 // Call a different accessor for pointers, that indirects.
1093 std::string accessor = "";
1094 if (is_scalar) {
1095 accessor = "GetField<";
1096 } else if (is_struct) {
1097 accessor = "GetStruct<";
1098 } else {
1099 accessor = "GetPointer<";
1100 }
1101 auto offset_str = GenFieldOffsetName(field);
1102 auto offset_type =
1103 GenTypeGet(field.value.type, "", "const ", " *", false);
1104
1105 auto call = accessor + offset_type + ">(" + offset_str;
1106 // Default value as second arg for non-pointer types.
1107 if (is_scalar) {
1108 call += ", " + GenDefaultConstant(field);
1109 }
1110 call += ")";
1111
1112 GenComment(field.doc_comment, " ");
1113 code_.SetValue("FIELD_TYPE",
1114 GenTypeGet(field.value.type, " ", "const ", " *", true));
1115 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
1116
1117 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
1118 code_ += " return {{FIELD_VALUE}};";
1119 code_ += " }";
1120
1121 if (parser_.opts.mutable_buffer) {
1122 if (is_scalar) {
1123 code_.SetValue("OFFSET_NAME", offset_str);
1124 code_.SetValue("FIELD_TYPE", GenTypeBasic(field.value.type, true));
1125 code_.SetValue("FIELD_VALUE",
1126 GenUnderlyingCast(field, false, "_" + field.name));
1127
1128 code_ += " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
1129 "_{{FIELD_NAME}}) {";
1130 code_ += " return SetField({{OFFSET_NAME}}, {{FIELD_VALUE}});";
1131 code_ += " }";
1132 } else {
1133 auto type = GenTypeGet(field.value.type, " ", "", " *", true);
1134 auto underlying = accessor + type + ">(" + offset_str + ")";
1135 code_.SetValue("FIELD_TYPE", type);
1136 code_.SetValue("FIELD_VALUE",
1137 GenUnderlyingCast(field, true, underlying));
1138
1139 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
1140 code_ += " return {{FIELD_VALUE}};";
1141 code_ += " }";
1142 }
1143 }
1144
1145 auto nested = field.attributes.Lookup("nested_flatbuffer");
1146 if (nested) {
1147 std::string qualified_name =
1148 parser_.namespaces_.back()->GetFullyQualifiedName(
1149 nested->constant);
1150 auto nested_root = parser_.structs_.Lookup(qualified_name);
1151 assert(nested_root); // Guaranteed to exist by parser.
1152 (void)nested_root;
1153 code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
1154
1155 code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
1156 code_ += " const uint8_t* data = {{FIELD_NAME}}()->Data();";
1157 code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(data);";
1158 code_ += " }";
1159 }
1160
1161 // Generate a comparison function for this field if it is a key.
1162 if (field.key) {
1163 const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING);
1164
1165 code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
1166 if (is_string) {
1167 code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
1168 } else {
1169 code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
1170 }
1171 code_ += " }";
1172
1173 if (is_string) {
1174 code_ += " int KeyCompareWithValue(const char *val) const {";
1175 code_ += " return strcmp({{FIELD_NAME}}()->c_str(), val);";
1176 code_ += " }";
1177 } else {
1178 auto type = GenTypeBasic(field.value.type, false);
1179 if (parser_.opts.scoped_enums && field.value.type.enum_def &&
1180 IsScalar(field.value.type.base_type)) {
1181 type = GenTypeGet(field.value.type, " ", "const ", " *", true);
1182 }
1183
1184 code_.SetValue("KEY_TYPE", type);
1185 code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {";
1186 code_ += " const auto key = {{FIELD_NAME}}();";
1187 code_ += " if (key < val) {";
1188 code_ += " return -1;";
1189 code_ += " } else if (key > val) {";
1190 code_ += " return 1;";
1191 code_ += " } else {";
1192 code_ += " return 0;";
1193 code_ += " }";
1194 code_ += " }";
1195 }
1196 }
1197 }
1198
1199 // Generate a verifier function that can check a buffer from an untrusted
1200 // source will never cause reads outside the buffer.
1201 code_ += " bool Verify(flatbuffers::Verifier &verifier) const {";
1202 code_ += " return VerifyTableStart(verifier)\\";
1203 for (auto it = struct_def.fields.vec.begin();
1204 it != struct_def.fields.vec.end(); ++it) {
1205 const auto &field = **it;
1206 if (field.deprecated) {
1207 continue;
1208 }
1209 GenVerifyCall(field, " &&\n ");
1210 }
1211
1212 code_ += " &&\n verifier.EndTable();";
1213 code_ += " }";
1214
1215 if (parser_.opts.generate_object_based_api) {
1216 // Generate the UnPack() pre declaration.
1217 code_ += " " + TableUnPackSignature(struct_def, true) + ";";
1218 code_ += " " + TableUnPackToSignature(struct_def, true) + ";";
1219 code_ += " " + TablePackSignature(struct_def, true) + ";";
1220 }
1221
1222 code_ += "};"; // End of table.
1223 code_ += "";
1224
1225 GenBuilders(struct_def);
1226
1227 if (parser_.opts.generate_object_based_api) {
1228 // Generate a pre-declaration for a CreateX method that works with an
1229 // unpacked C++ object.
1230 code_ += TableCreateSignature(struct_def, true) + ";";
1231 code_ += "";
1232 }
1233 }
1234
GenBuilders(const StructDef & struct_def)1235 void GenBuilders(const StructDef &struct_def) {
1236 code_.SetValue("STRUCT_NAME", struct_def.name);
1237
1238 // Generate a builder struct:
1239 code_ += "struct {{STRUCT_NAME}}Builder {";
1240 code_ += " flatbuffers::FlatBufferBuilder &fbb_;";
1241 code_ += " flatbuffers::uoffset_t start_;";
1242
1243 bool has_string_or_vector_fields = false;
1244 for (auto it = struct_def.fields.vec.begin();
1245 it != struct_def.fields.vec.end(); ++it) {
1246 const auto &field = **it;
1247 if (!field.deprecated) {
1248 const bool is_scalar = IsScalar(field.value.type.base_type);
1249 const bool is_string = field.value.type.base_type == BASE_TYPE_STRING;
1250 const bool is_vector = field.value.type.base_type == BASE_TYPE_VECTOR;
1251 if (is_string || is_vector) {
1252 has_string_or_vector_fields = true;
1253 }
1254
1255 std::string offset = GenFieldOffsetName(field);
1256 std::string name = GenUnderlyingCast(field, false, field.name);
1257 std::string value = is_scalar ? GenDefaultConstant(field) : "";
1258
1259 // Generate accessor functions of the form:
1260 // void add_name(type name) {
1261 // fbb_.AddElement<type>(offset, name, default);
1262 // }
1263 code_.SetValue("FIELD_NAME", field.name);
1264 code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
1265 code_.SetValue("ADD_OFFSET", struct_def.name + "::" + offset);
1266 code_.SetValue("ADD_NAME", name);
1267 code_.SetValue("ADD_VALUE", value);
1268 if (is_scalar) {
1269 const auto type = GenTypeWire(field.value.type, "", false);
1270 code_.SetValue("ADD_FN", "AddElement<" + type + ">");
1271 } else if (IsStruct(field.value.type)) {
1272 code_.SetValue("ADD_FN", "AddStruct");
1273 } else {
1274 code_.SetValue("ADD_FN", "AddOffset");
1275 }
1276
1277 code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
1278 code_ += " fbb_.{{ADD_FN}}(\\";
1279 if (is_scalar) {
1280 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
1281 } else {
1282 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
1283 }
1284 code_ += " }";
1285 }
1286 }
1287
1288 // Builder constructor
1289 code_ += " {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder &_fbb)";
1290 code_ += " : fbb_(_fbb) {";
1291 code_ += " start_ = fbb_.StartTable();";
1292 code_ += " }";
1293
1294 // Assignment operator;
1295 code_ += " {{STRUCT_NAME}}Builder &operator="
1296 "(const {{STRUCT_NAME}}Builder &);";
1297
1298 // Finish() function.
1299 auto num_fields = NumToString(struct_def.fields.vec.size());
1300 code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
1301 code_ += " const auto end = fbb_.EndTable(start_, " + num_fields + ");";
1302 code_ += " auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
1303
1304 for (auto it = struct_def.fields.vec.begin();
1305 it != struct_def.fields.vec.end(); ++it) {
1306 const auto &field = **it;
1307 if (!field.deprecated && field.required) {
1308 code_.SetValue("FIELD_NAME", field.name);
1309 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
1310 code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
1311 }
1312 }
1313 code_ += " return o;";
1314 code_ += " }";
1315 code_ += "};";
1316 code_ += "";
1317
1318 // Generate a convenient CreateX function that uses the above builder
1319 // to create a table in one go.
1320 code_ += "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
1321 "Create{{STRUCT_NAME}}(";
1322 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
1323 for (auto it = struct_def.fields.vec.begin();
1324 it != struct_def.fields.vec.end(); ++it) {
1325 const auto &field = **it;
1326 if (!field.deprecated) {
1327 GenParam(field, false, ",\n ");
1328 }
1329 }
1330 code_ += ") {";
1331
1332 code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);";
1333 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1334 size; size /= 2) {
1335 for (auto it = struct_def.fields.vec.rbegin();
1336 it != struct_def.fields.vec.rend(); ++it) {
1337 const auto &field = **it;
1338 if (!field.deprecated && (!struct_def.sortbysize ||
1339 size == SizeOf(field.value.type.base_type))) {
1340 code_.SetValue("FIELD_NAME", field.name);
1341 code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
1342 }
1343 }
1344 }
1345 code_ += " return builder_.Finish();";
1346 code_ += "}";
1347 code_ += "";
1348
1349 // Generate a CreateXDirect function with vector types as parameters
1350 if (has_string_or_vector_fields) {
1351 code_ += "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
1352 "Create{{STRUCT_NAME}}Direct(";
1353 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
1354 for (auto it = struct_def.fields.vec.begin();
1355 it != struct_def.fields.vec.end(); ++it) {
1356 const auto &field = **it;
1357 if (!field.deprecated) {
1358 GenParam(field, true, ",\n ");
1359 }
1360 }
1361
1362 // Need to call "Create" with the struct namespace.
1363 const auto qualified_create_name = struct_def.defined_namespace->GetFullyQualifiedName("Create");
1364 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
1365
1366 code_ += ") {";
1367 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
1368 code_ += " _fbb\\";
1369 for (auto it = struct_def.fields.vec.begin();
1370 it != struct_def.fields.vec.end(); ++it) {
1371 const auto &field = **it;
1372 if (!field.deprecated) {
1373 code_.SetValue("FIELD_NAME", field.name);
1374
1375 if (field.value.type.base_type == BASE_TYPE_STRING) {
1376 code_ += ",\n {{FIELD_NAME}} ? "
1377 "_fbb.CreateString({{FIELD_NAME}}) : 0\\";
1378 } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
1379 auto type = GenTypeWire(field.value.type.VectorType(), "", false);
1380 code_ += ",\n {{FIELD_NAME}} ? "
1381 "_fbb.CreateVector<" + type + ">(*{{FIELD_NAME}}) : 0\\";
1382 } else {
1383 code_ += ",\n {{FIELD_NAME}}\\";
1384 }
1385 }
1386 }
1387 code_ += ");";
1388 code_ += "}";
1389 code_ += "";
1390 }
1391 }
1392
GenUnpackVal(const Type & type,const std::string & val,bool invector,const FieldDef & afield)1393 std::string GenUnpackVal(const Type &type, const std::string &val,
1394 bool invector, const FieldDef &afield) {
1395 switch (type.base_type) {
1396 case BASE_TYPE_STRING: {
1397 return val + "->str()";
1398 }
1399 case BASE_TYPE_STRUCT: {
1400 const auto name = WrapInNameSpace(*type.struct_def);
1401 if (IsStruct(type)) {
1402 auto native_type = type.struct_def->attributes.Lookup("native_type");
1403 if (native_type) {
1404 return "flatbuffers::UnPack(*" + val + ")";
1405 } else if (invector || afield.native_inline) {
1406 return "*" + val;
1407 } else {
1408 const auto ptype = GenTypeNativePtr(name, &afield, true);
1409 return ptype + "(new " + name + "(*" + val + "))";
1410 }
1411 } else {
1412 const auto ptype = GenTypeNativePtr(NativeName(name), &afield, true);
1413 return ptype + "(" + val + "->UnPack(_resolver))";
1414 }
1415 }
1416 default: {
1417 return val;
1418 break;
1419 }
1420 }
1421 };
1422
GenUnpackFieldStatement(const FieldDef & field,const FieldDef * union_field)1423 std::string GenUnpackFieldStatement(const FieldDef &field,
1424 const FieldDef *union_field) {
1425 std::string code;
1426 switch (field.value.type.base_type) {
1427 case BASE_TYPE_VECTOR: {
1428 std::string indexing;
1429 if (field.value.type.enum_def) {
1430 indexing += "(" + field.value.type.enum_def->name + ")";
1431 }
1432 indexing += "_e->Get(_i)";
1433 if (field.value.type.element == BASE_TYPE_BOOL) {
1434 indexing += " != 0";
1435 }
1436
1437 // Generate code that pushes data from _e to _o in the form:
1438 // for (uoffset_t i = 0; i < _e->size(); ++i) {
1439 // _o->field.push_back(_e->Get(_i));
1440 // }
1441 code += "for (flatbuffers::uoffset_t _i = 0;";
1442 code += " _i < _e->size(); _i++) { ";
1443 code += "_o->" + field.name + ".push_back(";
1444 code += GenUnpackVal(field.value.type.VectorType(),
1445 indexing, true, field);
1446 code += "); }";
1447 break;
1448 }
1449 case BASE_TYPE_UTYPE: {
1450 assert(union_field->value.type.base_type == BASE_TYPE_UNION);
1451 // Generate code that sets the union type, of the form:
1452 // _o->field.type = _e;
1453 code += "_o->" + union_field->name + ".type = _e;";
1454 break;
1455 }
1456 case BASE_TYPE_UNION: {
1457 // Generate code that sets the union table, of the form:
1458 // _o->field.table = Union::Unpack(_e, field_type(), resolver);
1459 code += "_o->" + field.name + ".table = ";
1460 code += field.value.type.enum_def->name + "Union::UnPack(";
1461 code += "_e, " + field.name + UnionTypeFieldSuffix() + "(),";
1462 code += "_resolver);";
1463 break;
1464 }
1465 default: {
1466 auto cpp_type = field.attributes.Lookup("cpp_type");
1467 if (cpp_type) {
1468 // Generate code that resolves the cpp pointer type, of the form:
1469 // if (resolver)
1470 // (*resolver)(&_o->field, (hash_value_t)(_e));
1471 // else
1472 // _o->field = nullptr;
1473 code += "if (_resolver) ";
1474 code += "(*_resolver)";
1475 code += "(reinterpret_cast<void **>(&_o->" + field.name + "), ";
1476 code += "static_cast<flatbuffers::hash_value_t>(_e));";
1477 code += " else ";
1478 code += "_o->" + field.name + " = nullptr;";
1479 } else {
1480 // Generate code for assigning the value, of the form:
1481 // _o->field = value;
1482 code += "_o->" + field.name + " = ";
1483 code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
1484 }
1485 break;
1486 }
1487 }
1488 return code;
1489 }
1490
GenCreateParam(const FieldDef & field)1491 std::string GenCreateParam(const FieldDef &field) {
1492 std::string value = "_o->";
1493 if (field.value.type.base_type == BASE_TYPE_UTYPE) {
1494 value += field.name.substr(0, field.name.size() -
1495 strlen(UnionTypeFieldSuffix()));
1496 value += ".type";
1497 } else {
1498 value += field.name;
1499 }
1500 if (field.attributes.Lookup("cpp_type")) {
1501 auto type = GenTypeBasic(field.value.type, false);
1502 value = "_rehasher ? "
1503 "static_cast<" + type + ">((*_rehasher)(" + value + ")) : 0";
1504 }
1505
1506 std::string code;
1507 switch (field.value.type.base_type) {
1508 // String fields are of the form:
1509 // _fbb.CreateString(_o->field)
1510 case BASE_TYPE_STRING: {
1511 code += "_fbb.CreateString(" + value + ")";
1512
1513 // For optional fields, check to see if there actually is any data
1514 // in _o->field before attempting to access it.
1515 if (!field.required) {
1516 code = value + ".size() ? " + code + " : 0";
1517 }
1518 break;
1519 }
1520 // Vector fields come in several flavours, of the forms:
1521 // _fbb.CreateVector(_o->field);
1522 // _fbb.CreateVector((const utype*)_o->field.data(), _o->field.size());
1523 // _fbb.CreateVectorOfStrings(_o->field)
1524 // _fbb.CreateVectorOfStructs(_o->field)
1525 // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
1526 // return CreateT(_fbb, _o->Get(i), rehasher);
1527 // });
1528 case BASE_TYPE_VECTOR: {
1529 auto vector_type = field.value.type.VectorType();
1530 switch (vector_type.base_type) {
1531 case BASE_TYPE_STRING: {
1532 code += "_fbb.CreateVectorOfStrings(" + value + ")";
1533 break;
1534 }
1535 case BASE_TYPE_STRUCT: {
1536 if (IsStruct(vector_type)) {
1537 code += "_fbb.CreateVectorOfStructs(" + value + ")";
1538 } else {
1539 code += "_fbb.CreateVector<flatbuffers::Offset<";
1540 code += WrapInNameSpace(*vector_type.struct_def) + ">>";
1541 code += "(" + value + ".size(), [&](size_t i) {";
1542 code += " return Create" + vector_type.struct_def->name;
1543 code += "(_fbb, " + value + "[i]" + GenPtrGet(field) + ", ";
1544 code += "_rehasher); })";
1545 }
1546 break;
1547 }
1548 case BASE_TYPE_BOOL: {
1549 code += "_fbb.CreateVector(" + value + ")";
1550 break;
1551 }
1552 default: {
1553 if (field.value.type.enum_def) {
1554 // For enumerations, we need to get access to the array data for
1555 // the underlying storage type (eg. uint8_t).
1556 const auto basetype = GenTypeBasic(
1557 field.value.type.enum_def->underlying_type, false);
1558 code += "_fbb.CreateVector((const " + basetype + "*)" + value +
1559 ".data(), " + value + ".size())";
1560 } else {
1561 code += "_fbb.CreateVector(" + value + ")";
1562 }
1563 break;
1564 }
1565 }
1566
1567 // For optional fields, check to see if there actually is any data
1568 // in _o->field before attempting to access it.
1569 if (!field.required) {
1570 code = value + ".size() ? " + code + " : 0";
1571 }
1572 break;
1573 }
1574 case BASE_TYPE_UNION: {
1575 // _o->field.Pack(_fbb);
1576 code += value + ".Pack(_fbb)";
1577 break;
1578 }
1579 case BASE_TYPE_STRUCT: {
1580 if (IsStruct(field.value.type)) {
1581 auto native_type =
1582 field.value.type.struct_def->attributes.Lookup("native_type");
1583 if (native_type) {
1584 code += "flatbuffers::Pack(" + value + ")";
1585 } else if (field.native_inline) {
1586 code += "&" + value;
1587 } else {
1588 code += value + " ? " + value + GenPtrGet(field) + " : 0";
1589 }
1590 } else {
1591 // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
1592 const auto type = field.value.type.struct_def->name;
1593 code += value + " ? Create" + type;
1594 code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
1595 code += " : 0";
1596 }
1597 break;
1598 }
1599 default: {
1600 code += value;
1601 break;
1602 }
1603 }
1604 return code;
1605 }
1606
1607 // Generate code for tables that needs to come after the regular definition.
GenTablePost(const StructDef & struct_def)1608 void GenTablePost(const StructDef &struct_def) {
1609 code_.SetValue("STRUCT_NAME", struct_def.name);
1610 code_.SetValue("NATIVE_NAME", NativeName(struct_def.name));
1611
1612 if (parser_.opts.generate_object_based_api) {
1613 // Generate the X::UnPack() method.
1614 code_ += "inline " + TableUnPackSignature(struct_def, false) + " {";
1615 code_ += " auto _o = new {{NATIVE_NAME}}();";
1616 code_ += " UnPackTo(_o, _resolver);";
1617 code_ += " return _o;";
1618 code_ += "}";
1619 code_ += "";
1620
1621 code_ += "inline " + TableUnPackToSignature(struct_def, false) + " {";
1622 code_ += " (void)_o;";
1623 code_ += " (void)_resolver;";
1624
1625 for (auto it = struct_def.fields.vec.begin();
1626 it != struct_def.fields.vec.end(); ++it) {
1627 const auto &field = **it;
1628 if (field.deprecated) {
1629 continue;
1630 }
1631
1632 // Assign a value from |this| to |_o|. Values from |this| are stored
1633 // in a variable |_e| by calling this->field_type(). The value is then
1634 // assigned to |_o| using the GenUnpackFieldStatement.
1635 const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
1636 const auto statement =
1637 GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
1638
1639 code_.SetValue("FIELD_NAME", field.name);
1640 auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
1641 auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
1642 auto postfix = " };";
1643 code_ += std::string(prefix) + check + statement + postfix;
1644 }
1645 code_ += "}";
1646 code_ += "";
1647
1648 // Generate the X::Pack member function that simply calls the global
1649 // CreateX function.
1650 code_ += "inline " + TablePackSignature(struct_def, false) + " {";
1651 code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
1652 code_ += "}";
1653 code_ += "";
1654
1655 // Generate a CreateX method that works with an unpacked C++ object.
1656 code_ += "inline " + TableCreateSignature(struct_def, false) + " {";
1657 code_ += " (void)_rehasher;";
1658 code_ += " (void)_o;";
1659
1660 for (auto it = struct_def.fields.vec.begin();
1661 it != struct_def.fields.vec.end(); ++it) {
1662 auto &field = **it;
1663 if (field.deprecated) {
1664 continue;
1665 }
1666 code_ += " auto _" + field.name + " = " + GenCreateParam(field) + ";";
1667 }
1668 // Need to call "Create" with the struct namespace.
1669 const auto qualified_create_name = struct_def.defined_namespace->GetFullyQualifiedName("Create");
1670 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
1671
1672 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
1673 code_ += " _fbb\\";
1674 for (auto it = struct_def.fields.vec.begin();
1675 it != struct_def.fields.vec.end(); ++it) {
1676 auto &field = **it;
1677 if (field.deprecated) {
1678 continue;
1679 }
1680
1681 bool pass_by_address = false;
1682 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1683 if (IsStruct(field.value.type)) {
1684 auto native_type =
1685 field.value.type.struct_def->attributes.Lookup("native_type");
1686 if (native_type) {
1687 pass_by_address = true;
1688 }
1689 }
1690 }
1691
1692 // Call the CreateX function using values from |_o|.
1693 if (pass_by_address) {
1694 code_ += ",\n &_" + field.name + "\\";
1695 } else {
1696 code_ += ",\n _" + field.name + "\\";
1697 }
1698 }
1699 code_ += ");";
1700 code_ += "}";
1701 code_ += "";
1702 }
1703 }
1704
GenPadding(const FieldDef & field,std::string * code_ptr,int * id,const std::function<void (int bits,std::string * code_ptr,int * id)> & f)1705 static void GenPadding(
1706 const FieldDef &field, std::string *code_ptr, int *id,
1707 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
1708 if (field.padding) {
1709 for (int i = 0; i < 4; i++) {
1710 if (static_cast<int>(field.padding) & (1 << i)) {
1711 f((1 << i) * 8, code_ptr, id);
1712 }
1713 }
1714 assert(!(field.padding & ~0xF));
1715 }
1716 }
1717
PaddingDefinition(int bits,std::string * code_ptr,int * id)1718 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
1719 *code_ptr += " int" + NumToString(bits) + "_t padding" +
1720 NumToString((*id)++) + "__;";
1721 }
1722
PaddingInitializer(int bits,std::string * code_ptr,int * id)1723 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
1724 (void)bits;
1725 *code_ptr += ",\n padding" + NumToString((*id)++) + "__(0)";
1726 }
1727
PaddingNoop(int bits,std::string * code_ptr,int * id)1728 static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
1729 (void)bits;
1730 *code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
1731 }
1732
1733 // Generate an accessor struct with constructor for a flatbuffers struct.
GenStruct(const StructDef & struct_def)1734 void GenStruct(const StructDef &struct_def) {
1735 // Generate an accessor struct, with private variables of the form:
1736 // type name_;
1737 // Generates manual padding and alignment.
1738 // Variables are private because they contain little endian data on all
1739 // platforms.
1740 GenComment(struct_def.doc_comment);
1741 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
1742 code_.SetValue("STRUCT_NAME", struct_def.name);
1743
1744 code_ += "MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
1745 "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
1746 code_ += " private:";
1747
1748 int padding_id = 0;
1749 for (auto it = struct_def.fields.vec.begin();
1750 it != struct_def.fields.vec.end(); ++it) {
1751 const auto &field = **it;
1752 code_.SetValue("FIELD_TYPE",
1753 GenTypeGet(field.value.type, " ", "", " ", false));
1754 code_.SetValue("FIELD_NAME", field.name);
1755 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}_;";
1756
1757 if (field.padding) {
1758 std::string padding;
1759 GenPadding(field, &padding, &padding_id, PaddingDefinition);
1760 code_ += padding;
1761 }
1762 }
1763
1764 // Generate GetFullyQualifiedName
1765 code_ += "";
1766 code_ += " public:";
1767 GenFullyQualifiedNameGetter(struct_def.name);
1768
1769 // Generate a default constructor.
1770 code_ += " {{STRUCT_NAME}}() {";
1771 code_ += " memset(this, 0, sizeof({{STRUCT_NAME}}));";
1772 code_ += " }";
1773
1774 // Generate a copy constructor.
1775 code_ += " {{STRUCT_NAME}}(const {{STRUCT_NAME}} &_o) {";
1776 code_ += " memcpy(this, &_o, sizeof({{STRUCT_NAME}}));";
1777 code_ += " }";
1778
1779 // Generate a constructor that takes all fields as arguments.
1780 std::string arg_list;
1781 std::string init_list;
1782 padding_id = 0;
1783 for (auto it = struct_def.fields.vec.begin();
1784 it != struct_def.fields.vec.end(); ++it) {
1785 const auto &field = **it;
1786 const auto member_name = field.name + "_";
1787 const auto arg_name = "_" + field.name;
1788 const auto arg_type =
1789 GenTypeGet(field.value.type, " ", "const ", " &", true);
1790
1791 if (it != struct_def.fields.vec.begin()) {
1792 arg_list += ", ";
1793 init_list += ",\n ";
1794 }
1795 arg_list += arg_type;
1796 arg_list += arg_name;
1797 init_list += member_name;
1798 if (IsScalar(field.value.type.base_type)) {
1799 auto type = GenUnderlyingCast(field, false, arg_name);
1800 init_list += "(flatbuffers::EndianScalar(" + type + "))";
1801 } else {
1802 init_list += "(" + arg_name + ")";
1803 }
1804 if (field.padding) {
1805 GenPadding(field, &init_list, &padding_id, PaddingInitializer);
1806 }
1807 }
1808
1809 code_.SetValue("ARG_LIST", arg_list);
1810 code_.SetValue("INIT_LIST", init_list);
1811 code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
1812 code_ += " : {{INIT_LIST}} {";
1813 padding_id = 0;
1814 for (auto it = struct_def.fields.vec.begin();
1815 it != struct_def.fields.vec.end(); ++it) {
1816 const auto &field = **it;
1817 if (field.padding) {
1818 std::string padding;
1819 GenPadding(field, &padding, &padding_id, PaddingNoop);
1820 code_ += padding;
1821 }
1822 }
1823 code_ += " }";
1824
1825 // Generate accessor methods of the form:
1826 // type name() const { return flatbuffers::EndianScalar(name_); }
1827 for (auto it = struct_def.fields.vec.begin();
1828 it != struct_def.fields.vec.end(); ++it) {
1829 const auto &field = **it;
1830
1831 auto field_type = GenTypeGet(field.value.type, " ", "const ", " &", true);
1832 auto is_scalar = IsScalar(field.value.type.base_type);
1833 auto member = field.name + "_";
1834 auto value = is_scalar ? "flatbuffers::EndianScalar(" + member + ")"
1835 : member;
1836
1837 code_.SetValue("FIELD_NAME", field.name);
1838 code_.SetValue("FIELD_TYPE", field_type);
1839 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
1840
1841 GenComment(field.doc_comment, " ");
1842 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
1843 code_ += " return {{FIELD_VALUE}};";
1844 code_ += " }";
1845
1846 if (parser_.opts.mutable_buffer) {
1847 if (is_scalar) {
1848 code_.SetValue("ARG", GenTypeBasic(field.value.type, true));
1849 code_.SetValue("FIELD_VALUE",
1850 GenUnderlyingCast(field, false, "_" + field.name));
1851
1852 code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
1853 code_ += " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
1854 "{{FIELD_VALUE}});";
1855 code_ += " }";
1856 } else {
1857 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
1858 code_ += " return {{FIELD_NAME}}_;";
1859 code_ += " }";
1860 }
1861 }
1862 }
1863 code_ += "};";
1864
1865 code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
1866 code_ += "STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
1867 code_ += "";
1868 }
1869
1870 // Set up the correct namespace. Only open a namespace if the existing one is
1871 // different (closing/opening only what is necessary).
1872 //
1873 // The file must start and end with an empty (or null) namespace so that
1874 // namespaces are properly opened and closed.
SetNameSpace(const Namespace * ns)1875 void SetNameSpace(const Namespace *ns) {
1876 if (cur_name_space_ == ns) {
1877 return;
1878 }
1879
1880 // Compute the size of the longest common namespace prefix.
1881 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
1882 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
1883 // and common_prefix_size = 2
1884 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
1885 size_t new_size = ns ? ns->components.size() : 0;
1886
1887 size_t common_prefix_size = 0;
1888 while (common_prefix_size < old_size && common_prefix_size < new_size &&
1889 ns->components[common_prefix_size] ==
1890 cur_name_space_->components[common_prefix_size]) {
1891 common_prefix_size++;
1892 }
1893
1894 // Close cur_name_space in reverse order to reach the common prefix.
1895 // In the previous example, D then C are closed.
1896 for (size_t j = old_size; j > common_prefix_size; --j) {
1897 code_ += "} // namespace " + cur_name_space_->components[j - 1];
1898 }
1899 if (old_size != common_prefix_size) {
1900 code_ += "";
1901 }
1902
1903 // open namespace parts to reach the ns namespace
1904 // in the previous example, E, then F, then G are opened
1905 for (auto j = common_prefix_size; j != new_size; ++j) {
1906 code_ += "namespace " + ns->components[j] + " {";
1907 }
1908 if (new_size != common_prefix_size) {
1909 code_ += "";
1910 }
1911
1912 cur_name_space_ = ns;
1913 }
1914 };
1915
1916 } // namespace cpp
1917
GenerateCPP(const Parser & parser,const std::string & path,const std::string & file_name)1918 bool GenerateCPP(const Parser &parser, const std::string &path,
1919 const std::string &file_name) {
1920 cpp::CppGenerator generator(parser, path, file_name);
1921 return generator.generate();
1922 }
1923
CPPMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)1924 std::string CPPMakeRule(const Parser &parser, const std::string &path,
1925 const std::string &file_name) {
1926 const auto filebase =
1927 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
1928 const auto included_files = parser.GetIncludedFilesRecursive(file_name);
1929 std::string make_rule = GeneratedFileName(path, filebase) + ": ";
1930 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1931 make_rule += " " + *it;
1932 }
1933 return make_rule;
1934 }
1935
1936 } // namespace flatbuffers
1937