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 <unordered_set>
20
21 #include "flatbuffers/code_generators.h"
22 #include "flatbuffers/flatbuffers.h"
23 #include "flatbuffers/flatc.h"
24 #include "flatbuffers/idl.h"
25 #include "flatbuffers/util.h"
26
27 namespace flatbuffers {
28
29 // Pedantic warning free version of toupper().
ToUpper(char c)30 inline char ToUpper(char c) {
31 return static_cast<char>(::toupper(static_cast<unsigned char>(c)));
32 }
33
34 // Make numerical literal with type-suffix.
35 // This function is only needed for C++! Other languages do not need it.
NumToStringCpp(std::string val,BaseType type)36 static inline std::string NumToStringCpp(std::string val, BaseType type) {
37 // Avoid issues with -2147483648, -9223372036854775808.
38 switch (type) {
39 case BASE_TYPE_INT:
40 return (val != "-2147483648") ? val : ("(-2147483647 - 1)");
41 case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL");
42 case BASE_TYPE_LONG:
43 if (val == "-9223372036854775808")
44 return "(-9223372036854775807LL - 1LL)";
45 else
46 return (val == "0") ? val : (val + "LL");
47 default: return val;
48 }
49 }
50
GenIncludeGuard(const std::string & file_name,const Namespace & name_space,const std::string & postfix="")51 static std::string GenIncludeGuard(const std::string &file_name,
52 const Namespace &name_space,
53 const std::string &postfix = "") {
54 // Generate include guard.
55 std::string guard = file_name;
56 // Remove any non-alpha-numeric characters that may appear in a filename.
57 struct IsAlnum {
58 bool operator()(char c) const { return !is_alnum(c); }
59 };
60 guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
61 guard.end());
62 guard = "FLATBUFFERS_GENERATED_" + guard;
63 guard += "_";
64 // For further uniqueness, also add the namespace.
65 for (auto it = name_space.components.begin();
66 it != name_space.components.end(); ++it) {
67 guard += *it + "_";
68 }
69 // Anything extra to add to the guard?
70 if (!postfix.empty()) { guard += postfix + "_"; }
71 guard += "H_";
72 std::transform(guard.begin(), guard.end(), guard.begin(), ToUpper);
73 return guard;
74 }
75
76 namespace cpp {
77
78 enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
79
80 // Extension of IDLOptions for cpp-generator.
81 struct IDLOptionsCpp : public IDLOptions {
82 // All fields start with 'g_' prefix to distinguish from the base IDLOptions.
83 CppStandard g_cpp_std; // Base version of C++ standard.
84 bool g_only_fixed_enums; // Generate underlaying type for all enums.
85
IDLOptionsCppflatbuffers::cpp::IDLOptionsCpp86 IDLOptionsCpp(const IDLOptions &opts)
87 : IDLOptions(opts), g_cpp_std(CPP_STD_11), g_only_fixed_enums(true) {}
88 };
89
90 class CppGenerator : public BaseGenerator {
91 public:
CppGenerator(const Parser & parser,const std::string & path,const std::string & file_name,IDLOptionsCpp opts)92 CppGenerator(const Parser &parser, const std::string &path,
93 const std::string &file_name, IDLOptionsCpp opts)
94 : BaseGenerator(parser, path, file_name, "", "::", "h"),
95 cur_name_space_(nullptr),
96 opts_(opts),
97 float_const_gen_("std::numeric_limits<double>::",
98 "std::numeric_limits<float>::", "quiet_NaN()",
99 "infinity()") {
100 static const char *const keywords[] = {
101 "alignas",
102 "alignof",
103 "and",
104 "and_eq",
105 "asm",
106 "atomic_cancel",
107 "atomic_commit",
108 "atomic_noexcept",
109 "auto",
110 "bitand",
111 "bitor",
112 "bool",
113 "break",
114 "case",
115 "catch",
116 "char",
117 "char16_t",
118 "char32_t",
119 "class",
120 "compl",
121 "concept",
122 "const",
123 "constexpr",
124 "const_cast",
125 "continue",
126 "co_await",
127 "co_return",
128 "co_yield",
129 "decltype",
130 "default",
131 "delete",
132 "do",
133 "double",
134 "dynamic_cast",
135 "else",
136 "enum",
137 "explicit",
138 "export",
139 "extern",
140 "false",
141 "float",
142 "for",
143 "friend",
144 "goto",
145 "if",
146 "import",
147 "inline",
148 "int",
149 "long",
150 "module",
151 "mutable",
152 "namespace",
153 "new",
154 "noexcept",
155 "not",
156 "not_eq",
157 "nullptr",
158 "operator",
159 "or",
160 "or_eq",
161 "private",
162 "protected",
163 "public",
164 "register",
165 "reinterpret_cast",
166 "requires",
167 "return",
168 "short",
169 "signed",
170 "sizeof",
171 "static",
172 "static_assert",
173 "static_cast",
174 "struct",
175 "switch",
176 "synchronized",
177 "template",
178 "this",
179 "thread_local",
180 "throw",
181 "true",
182 "try",
183 "typedef",
184 "typeid",
185 "typename",
186 "union",
187 "unsigned",
188 "using",
189 "virtual",
190 "void",
191 "volatile",
192 "wchar_t",
193 "while",
194 "xor",
195 "xor_eq",
196 nullptr,
197 };
198 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
199 }
200
GenIncludeDependencies()201 void GenIncludeDependencies() {
202 int num_includes = 0;
203 for (auto it = parser_.native_included_files_.begin();
204 it != parser_.native_included_files_.end(); ++it) {
205 code_ += "#include \"" + *it + "\"";
206 num_includes++;
207 }
208 for (auto it = parser_.included_files_.begin();
209 it != parser_.included_files_.end(); ++it) {
210 if (it->second.empty()) continue;
211 auto noext = flatbuffers::StripExtension(it->second);
212 auto basename = flatbuffers::StripPath(noext);
213 auto includeName =
214 GeneratedFileName(opts_.include_prefix,
215 opts_.keep_include_path ? noext : basename, opts_);
216 code_ += "#include \"" + includeName + "\"";
217 num_includes++;
218 }
219 if (num_includes) code_ += "";
220 }
221
GenExtraIncludes()222 void GenExtraIncludes() {
223 for (std::size_t i = 0; i < opts_.cpp_includes.size(); ++i) {
224 code_ += "#include \"" + opts_.cpp_includes[i] + "\"";
225 }
226 if (!opts_.cpp_includes.empty()) { code_ += ""; }
227 }
228
EscapeKeyword(const std::string & name) const229 std::string EscapeKeyword(const std::string &name) const {
230 return keywords_.find(name) == keywords_.end() ? name : name + "_";
231 }
232
Name(const Definition & def) const233 std::string Name(const Definition &def) const {
234 return EscapeKeyword(def.name);
235 }
236
Name(const EnumVal & ev) const237 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
238
generate_bfbs_embed()239 bool generate_bfbs_embed() {
240 code_.Clear();
241 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
242
243 // If we don't have a root struct definition,
244 if (!parser_.root_struct_def_) {
245 // put a comment in the output why there is no code generated.
246 code_ += "// Binary schema not generated, no root struct found";
247 } else {
248 auto &struct_def = *parser_.root_struct_def_;
249 const auto include_guard =
250 GenIncludeGuard(file_name_, *struct_def.defined_namespace, "bfbs");
251
252 code_ += "#ifndef " + include_guard;
253 code_ += "#define " + include_guard;
254 code_ += "";
255 if (parser_.opts.gen_nullable) {
256 code_ += "#pragma clang system_header\n\n";
257 }
258
259 SetNameSpace(struct_def.defined_namespace);
260 auto name = Name(struct_def);
261 code_.SetValue("STRUCT_NAME", name);
262
263 // Create code to return the binary schema data.
264 auto binary_schema_hex_text =
265 BufferToHexText(parser_.builder_.GetBufferPointer(),
266 parser_.builder_.GetSize(), 105, " ", "");
267
268 code_ += "struct {{STRUCT_NAME}}BinarySchema {";
269 code_ += " static const uint8_t *data() {";
270 code_ += " // Buffer containing the binary schema.";
271 code_ += " static const uint8_t bfbsData[" +
272 NumToString(parser_.builder_.GetSize()) + "] = {";
273 code_ += binary_schema_hex_text;
274 code_ += " };";
275 code_ += " return bfbsData;";
276 code_ += " }";
277 code_ += " static size_t size() {";
278 code_ += " return " + NumToString(parser_.builder_.GetSize()) + ";";
279 code_ += " }";
280 code_ += " const uint8_t *begin() {";
281 code_ += " return data();";
282 code_ += " }";
283 code_ += " const uint8_t *end() {";
284 code_ += " return data() + size();";
285 code_ += " }";
286 code_ += "};";
287 code_ += "";
288
289 if (cur_name_space_) SetNameSpace(nullptr);
290
291 // Close the include guard.
292 code_ += "#endif // " + include_guard;
293 }
294
295 // We are just adding "_bfbs" to the generated filename.
296 const auto file_path =
297 GeneratedFileName(path_, file_name_ + "_bfbs", opts_);
298 const auto final_code = code_.ToString();
299
300 return SaveFile(file_path.c_str(), final_code, false);
301 }
302
303 // Iterate through all definitions we haven't generate code for (enums,
304 // structs, and tables) and output them to a single file.
generate()305 bool generate() {
306 code_.Clear();
307 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
308
309 const auto include_guard =
310 GenIncludeGuard(file_name_, *parser_.current_namespace_);
311 code_ += "#ifndef " + include_guard;
312 code_ += "#define " + include_guard;
313 code_ += "";
314
315 if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; }
316
317 code_ += "#include \"flatbuffers/flatbuffers.h\"";
318 if (parser_.uses_flexbuffers_) {
319 code_ += "#include \"flatbuffers/flexbuffers.h\"";
320 }
321 code_ += "";
322
323 if (opts_.include_dependence_headers) { GenIncludeDependencies(); }
324 GenExtraIncludes();
325
326 FLATBUFFERS_ASSERT(!cur_name_space_);
327
328 // Generate forward declarations for all structs/tables, since they may
329 // have circular references.
330 for (auto it = parser_.structs_.vec.begin();
331 it != parser_.structs_.vec.end(); ++it) {
332 const auto &struct_def = **it;
333 if (!struct_def.generated) {
334 SetNameSpace(struct_def.defined_namespace);
335 code_ += "struct " + Name(struct_def) + ";";
336 if (!struct_def.fixed) {
337 code_ += "struct " + Name(struct_def) + "Builder;";
338 }
339 if (opts_.generate_object_based_api) {
340 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
341 if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; }
342 }
343 code_ += "";
344 }
345 }
346
347 // Generate forward declarations for all equal operators
348 if (opts_.generate_object_based_api && opts_.gen_compare) {
349 for (auto it = parser_.structs_.vec.begin();
350 it != parser_.structs_.vec.end(); ++it) {
351 const auto &struct_def = **it;
352 if (!struct_def.generated) {
353 SetNameSpace(struct_def.defined_namespace);
354 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
355 code_ += "bool operator==(const " + nativeName + " &lhs, const " +
356 nativeName + " &rhs);";
357 code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
358 nativeName + " &rhs);";
359 }
360 }
361 code_ += "";
362 }
363
364 // Generate preablmle code for mini reflection.
365 if (opts_.mini_reflect != IDLOptions::kNone) {
366 // To break cyclic dependencies, first pre-declare all tables/structs.
367 for (auto it = parser_.structs_.vec.begin();
368 it != parser_.structs_.vec.end(); ++it) {
369 const auto &struct_def = **it;
370 if (!struct_def.generated) {
371 SetNameSpace(struct_def.defined_namespace);
372 GenMiniReflectPre(&struct_def);
373 }
374 }
375 }
376
377 // Generate code for all the enum declarations.
378 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
379 ++it) {
380 const auto &enum_def = **it;
381 if (!enum_def.generated) {
382 SetNameSpace(enum_def.defined_namespace);
383 GenEnum(enum_def);
384 }
385 }
386
387 // Generate code for all structs, then all tables.
388 for (auto it = parser_.structs_.vec.begin();
389 it != parser_.structs_.vec.end(); ++it) {
390 const auto &struct_def = **it;
391 if (struct_def.fixed && !struct_def.generated) {
392 SetNameSpace(struct_def.defined_namespace);
393 GenStruct(struct_def);
394 }
395 }
396 for (auto it = parser_.structs_.vec.begin();
397 it != parser_.structs_.vec.end(); ++it) {
398 const auto &struct_def = **it;
399 if (!struct_def.fixed && !struct_def.generated) {
400 SetNameSpace(struct_def.defined_namespace);
401 GenTable(struct_def);
402 }
403 }
404 for (auto it = parser_.structs_.vec.begin();
405 it != parser_.structs_.vec.end(); ++it) {
406 const auto &struct_def = **it;
407 if (!struct_def.fixed && !struct_def.generated) {
408 SetNameSpace(struct_def.defined_namespace);
409 GenTablePost(struct_def);
410 }
411 }
412
413 // Generate code for union verifiers.
414 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
415 ++it) {
416 const auto &enum_def = **it;
417 if (enum_def.is_union && !enum_def.generated) {
418 SetNameSpace(enum_def.defined_namespace);
419 GenUnionPost(enum_def);
420 }
421 }
422
423 // Generate code for mini reflection.
424 if (opts_.mini_reflect != IDLOptions::kNone) {
425 // Then the unions/enums that may refer to them.
426 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
427 ++it) {
428 const auto &enum_def = **it;
429 if (!enum_def.generated) {
430 SetNameSpace(enum_def.defined_namespace);
431 GenMiniReflect(nullptr, &enum_def);
432 }
433 }
434 // Then the full tables/structs.
435 for (auto it = parser_.structs_.vec.begin();
436 it != parser_.structs_.vec.end(); ++it) {
437 const auto &struct_def = **it;
438 if (!struct_def.generated) {
439 SetNameSpace(struct_def.defined_namespace);
440 GenMiniReflect(&struct_def, nullptr);
441 }
442 }
443 }
444
445 // Generate convenient global helper functions:
446 if (parser_.root_struct_def_) {
447 auto &struct_def = *parser_.root_struct_def_;
448 SetNameSpace(struct_def.defined_namespace);
449 auto name = Name(struct_def);
450 auto qualified_name = cur_name_space_->GetFullyQualifiedName(name);
451 auto cpp_name = TranslateNameSpace(qualified_name);
452
453 code_.SetValue("STRUCT_NAME", name);
454 code_.SetValue("CPP_NAME", cpp_name);
455 code_.SetValue("NULLABLE_EXT", NullableExtension());
456
457 // The root datatype accessor:
458 code_ += "inline \\";
459 code_ +=
460 "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void "
461 "*buf) {";
462 code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
463 code_ += "}";
464 code_ += "";
465
466 code_ += "inline \\";
467 code_ +=
468 "const {{CPP_NAME}} "
469 "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void "
470 "*buf) {";
471 code_ += " return flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}>(buf);";
472 code_ += "}";
473 code_ += "";
474
475 if (opts_.mutable_buffer) {
476 code_ += "inline \\";
477 code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
478 code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
479 code_ += "}";
480 code_ += "";
481 }
482
483 if (parser_.file_identifier_.length()) {
484 // Return the identifier
485 code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
486 code_ += " return \"" + parser_.file_identifier_ + "\";";
487 code_ += "}";
488 code_ += "";
489
490 // Check if a buffer has the identifier.
491 code_ += "inline \\";
492 code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
493 code_ += " return flatbuffers::BufferHasIdentifier(";
494 code_ += " buf, {{STRUCT_NAME}}Identifier());";
495 code_ += "}";
496 code_ += "";
497 }
498
499 // The root verifier.
500 if (parser_.file_identifier_.length()) {
501 code_.SetValue("ID", name + "Identifier()");
502 } else {
503 code_.SetValue("ID", "nullptr");
504 }
505
506 code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
507 code_ += " flatbuffers::Verifier &verifier) {";
508 code_ += " return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
509 code_ += "}";
510 code_ += "";
511
512 code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer(";
513 code_ += " flatbuffers::Verifier &verifier) {";
514 code_ +=
515 " return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});";
516 code_ += "}";
517 code_ += "";
518
519 if (parser_.file_extension_.length()) {
520 // Return the extension
521 code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
522 code_ += " return \"" + parser_.file_extension_ + "\";";
523 code_ += "}";
524 code_ += "";
525 }
526
527 // Finish a buffer with a given root object:
528 code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
529 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
530 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
531 if (parser_.file_identifier_.length())
532 code_ += " fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
533 else
534 code_ += " fbb.Finish(root);";
535 code_ += "}";
536 code_ += "";
537
538 code_ += "inline void FinishSizePrefixed{{STRUCT_NAME}}Buffer(";
539 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
540 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
541 if (parser_.file_identifier_.length())
542 code_ += " fbb.FinishSizePrefixed(root, {{STRUCT_NAME}}Identifier());";
543 else
544 code_ += " fbb.FinishSizePrefixed(root);";
545 code_ += "}";
546 code_ += "";
547
548 if (opts_.generate_object_based_api) {
549 // A convenient root unpack function.
550 auto native_name =
551 NativeName(WrapInNameSpace(struct_def), &struct_def, opts_);
552 code_.SetValue("UNPACK_RETURN",
553 GenTypeNativePtr(native_name, nullptr, false));
554 code_.SetValue("UNPACK_TYPE",
555 GenTypeNativePtr(native_name, nullptr, true));
556
557 code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
558 code_ += " const void *buf,";
559 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
560 code_ += " return {{UNPACK_TYPE}}\\";
561 code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
562 code_ += "}";
563 code_ += "";
564
565 code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}(";
566 code_ += " const void *buf,";
567 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
568 code_ += " return {{UNPACK_TYPE}}\\";
569 code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));";
570 code_ += "}";
571 code_ += "";
572 }
573 }
574
575 if (cur_name_space_) SetNameSpace(nullptr);
576
577 // Close the include guard.
578 code_ += "#endif // " + include_guard;
579
580 const auto file_path = GeneratedFileName(path_, file_name_, opts_);
581 const auto final_code = code_.ToString();
582
583 // Save the file and optionally generate the binary schema code.
584 return SaveFile(file_path.c_str(), final_code, false) &&
585 (!parser_.opts.binary_schema_gen_embed || generate_bfbs_embed());
586 }
587
588 private:
589 CodeWriter code_;
590
591 std::unordered_set<std::string> keywords_;
592
593 // This tracks the current namespace so we can insert namespace declarations.
594 const Namespace *cur_name_space_;
595
596 const IDLOptionsCpp opts_;
597 const TypedFloatConstantGenerator float_const_gen_;
598
CurrentNameSpace() const599 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
600
601 // Translates a qualified name in flatbuffer text format to the same name in
602 // the equivalent C++ namespace.
TranslateNameSpace(const std::string & qualified_name)603 static std::string TranslateNameSpace(const std::string &qualified_name) {
604 std::string cpp_qualified_name = qualified_name;
605 size_t start_pos = 0;
606 while ((start_pos = cpp_qualified_name.find('.', start_pos)) !=
607 std::string::npos) {
608 cpp_qualified_name.replace(start_pos, 1, "::");
609 }
610 return cpp_qualified_name;
611 }
612
TypeHasKey(const Type & type)613 bool TypeHasKey(const Type &type) {
614 if (type.base_type != BASE_TYPE_STRUCT) { return false; }
615 for (auto it = type.struct_def->fields.vec.begin();
616 it != type.struct_def->fields.vec.end(); ++it) {
617 const auto &field = **it;
618 if (field.key) { return true; }
619 }
620 return false;
621 }
622
VectorElementUserFacing(const Type & type) const623 bool VectorElementUserFacing(const Type &type) const {
624 return opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums &&
625 IsEnum(type);
626 }
627
GenComment(const std::vector<std::string> & dc,const char * prefix="")628 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
629 std::string text;
630 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
631 code_ += text + "\\";
632 }
633
634 // Return a C++ type from the table in idl.h
GenTypeBasic(const Type & type,bool user_facing_type) const635 std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
636 // clang-format off
637 static const char *const ctypename[] = {
638 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
639 #CTYPE,
640 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
641 #undef FLATBUFFERS_TD
642 };
643 // clang-format on
644 if (user_facing_type) {
645 if (type.enum_def) return WrapInNameSpace(*type.enum_def);
646 if (type.base_type == BASE_TYPE_BOOL) return "bool";
647 }
648 return ctypename[type.base_type];
649 }
650
651 // Return a C++ pointer type, specialized to the actual struct/table types,
652 // and vector element types.
GenTypePointer(const Type & type) const653 std::string GenTypePointer(const Type &type) const {
654 switch (type.base_type) {
655 case BASE_TYPE_STRING: {
656 return "flatbuffers::String";
657 }
658 case BASE_TYPE_VECTOR: {
659 const auto type_name = GenTypeWire(
660 type.VectorType(), "", VectorElementUserFacing(type.VectorType()));
661 return "flatbuffers::Vector<" + type_name + ">";
662 }
663 case BASE_TYPE_STRUCT: {
664 return WrapInNameSpace(*type.struct_def);
665 }
666 case BASE_TYPE_UNION:
667 // fall through
668 default: {
669 return "void";
670 }
671 }
672 }
673
674 // Return a C++ type for any type (scalar/pointer) specifically for
675 // building a flatbuffer.
GenTypeWire(const Type & type,const char * postfix,bool user_facing_type) const676 std::string GenTypeWire(const Type &type, const char *postfix,
677 bool user_facing_type) const {
678 if (IsScalar(type.base_type)) {
679 return GenTypeBasic(type, user_facing_type) + postfix;
680 } else if (IsStruct(type)) {
681 return "const " + GenTypePointer(type) + " *";
682 } else {
683 return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix;
684 }
685 }
686
687 // Return a C++ type for any type (scalar/pointer) that reflects its
688 // serialized size.
GenTypeSize(const Type & type) const689 std::string GenTypeSize(const Type &type) const {
690 if (IsScalar(type.base_type)) {
691 return GenTypeBasic(type, false);
692 } else if (IsStruct(type)) {
693 return GenTypePointer(type);
694 } else {
695 return "flatbuffers::uoffset_t";
696 }
697 }
698
NullableExtension()699 std::string NullableExtension() {
700 return opts_.gen_nullable ? " _Nullable " : "";
701 }
702
NativeName(const std::string & name,const StructDef * sd,const IDLOptions & opts)703 static std::string NativeName(const std::string &name, const StructDef *sd,
704 const IDLOptions &opts) {
705 return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix
706 : name;
707 }
708
PtrType(const FieldDef * field)709 const std::string &PtrType(const FieldDef *field) {
710 auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
711 return attr ? attr->constant : opts_.cpp_object_api_pointer_type;
712 }
713
NativeString(const FieldDef * field)714 const std::string NativeString(const FieldDef *field) {
715 auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
716 auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type;
717 if (ret.empty()) { return "std::string"; }
718 return ret;
719 }
720
FlexibleStringConstructor(const FieldDef * field)721 bool FlexibleStringConstructor(const FieldDef *field) {
722 auto attr = field
723 ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr)
724 : false;
725 auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor;
726 return ret && NativeString(field) !=
727 "std::string"; // Only for custom string types.
728 }
729
GenTypeNativePtr(const std::string & type,const FieldDef * field,bool is_constructor)730 std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
731 bool is_constructor) {
732 auto &ptr_type = PtrType(field);
733 if (ptr_type != "naked") {
734 return (ptr_type != "default_ptr_type"
735 ? ptr_type
736 : opts_.cpp_object_api_pointer_type) +
737 "<" + type + ">";
738 } else if (is_constructor) {
739 return "";
740 } else {
741 return type + " *";
742 }
743 }
744
GenPtrGet(const FieldDef & field)745 std::string GenPtrGet(const FieldDef &field) {
746 auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get");
747 if (cpp_ptr_type_get) return cpp_ptr_type_get->constant;
748 auto &ptr_type = PtrType(&field);
749 return ptr_type == "naked" ? "" : ".get()";
750 }
751
GenTypeNative(const Type & type,bool invector,const FieldDef & field)752 std::string GenTypeNative(const Type &type, bool invector,
753 const FieldDef &field) {
754 switch (type.base_type) {
755 case BASE_TYPE_STRING: {
756 return NativeString(&field);
757 }
758 case BASE_TYPE_VECTOR: {
759 const auto type_name = GenTypeNative(type.VectorType(), true, field);
760 if (type.struct_def &&
761 type.struct_def->attributes.Lookup("native_custom_alloc")) {
762 auto native_custom_alloc =
763 type.struct_def->attributes.Lookup("native_custom_alloc");
764 return "std::vector<" + type_name + "," +
765 native_custom_alloc->constant + "<" + type_name + ">>";
766 } else
767 return "std::vector<" + type_name + ">";
768 }
769 case BASE_TYPE_STRUCT: {
770 auto type_name = WrapInNameSpace(*type.struct_def);
771 if (IsStruct(type)) {
772 auto native_type = type.struct_def->attributes.Lookup("native_type");
773 if (native_type) { type_name = native_type->constant; }
774 if (invector || field.native_inline) {
775 return type_name;
776 } else {
777 return GenTypeNativePtr(type_name, &field, false);
778 }
779 } else {
780 return GenTypeNativePtr(NativeName(type_name, type.struct_def, opts_),
781 &field, false);
782 }
783 }
784 case BASE_TYPE_UNION: {
785 auto type_name = WrapInNameSpace(*type.enum_def);
786 return type_name + "Union";
787 }
788 default: {
789 return GenTypeBasic(type, true);
790 }
791 }
792 }
793
794 // Return a C++ type for any type (scalar/pointer) specifically for
795 // using a flatbuffer.
GenTypeGet(const Type & type,const char * afterbasic,const char * beforeptr,const char * afterptr,bool user_facing_type)796 std::string GenTypeGet(const Type &type, const char *afterbasic,
797 const char *beforeptr, const char *afterptr,
798 bool user_facing_type) {
799 if (IsScalar(type.base_type)) {
800 return GenTypeBasic(type, user_facing_type) + afterbasic;
801 } else if (IsArray(type)) {
802 auto element_type = type.VectorType();
803 // Check if enum arrays are used in C++ without specifying --scoped-enums
804 if (IsEnum(element_type) && !opts_.g_only_fixed_enums) {
805 LogCompilerError(
806 "--scoped-enums must be enabled to use enum arrays in C++");
807 FLATBUFFERS_ASSERT(true);
808 }
809 return beforeptr +
810 (IsScalar(element_type.base_type)
811 ? GenTypeBasic(element_type, user_facing_type)
812 : GenTypePointer(element_type)) +
813 afterptr;
814 } else {
815 return beforeptr + GenTypePointer(type) + afterptr;
816 }
817 }
818
GenEnumValDecl(const EnumDef & enum_def,const std::string & enum_val) const819 std::string GenEnumValDecl(const EnumDef &enum_def,
820 const std::string &enum_val) const {
821 return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
822 }
823
GetEnumValUse(const EnumDef & enum_def,const EnumVal & enum_val) const824 std::string GetEnumValUse(const EnumDef &enum_def,
825 const EnumVal &enum_val) const {
826 if (opts_.scoped_enums) {
827 return Name(enum_def) + "::" + Name(enum_val);
828 } else if (opts_.prefixed_enums) {
829 return Name(enum_def) + "_" + Name(enum_val);
830 } else {
831 return Name(enum_val);
832 }
833 }
834
StripUnionType(const std::string & name)835 std::string StripUnionType(const std::string &name) {
836 return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
837 }
838
GetUnionElement(const EnumVal & ev,bool wrap,bool actual_type,bool native_type=false)839 std::string GetUnionElement(const EnumVal &ev, bool wrap, bool actual_type,
840 bool native_type = false) {
841 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
842 auto name = actual_type ? ev.union_type.struct_def->name : Name(ev);
843 return wrap ? WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
844 name)
845 : name;
846 } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
847 return actual_type ? (native_type ? "std::string" : "flatbuffers::String")
848 : Name(ev);
849 } else {
850 FLATBUFFERS_ASSERT(false);
851 return Name(ev);
852 }
853 }
854
UnionVerifySignature(const EnumDef & enum_def)855 std::string UnionVerifySignature(const EnumDef &enum_def) {
856 return "bool Verify" + Name(enum_def) +
857 "(flatbuffers::Verifier &verifier, const void *obj, " +
858 Name(enum_def) + " type)";
859 }
860
UnionVectorVerifySignature(const EnumDef & enum_def)861 std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
862 return "bool Verify" + Name(enum_def) + "Vector" +
863 "(flatbuffers::Verifier &verifier, " +
864 "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
865 "const flatbuffers::Vector<uint8_t> *types)";
866 }
867
UnionUnPackSignature(const EnumDef & enum_def,bool inclass)868 std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) {
869 return (inclass ? "static " : "") + std::string("void *") +
870 (inclass ? "" : Name(enum_def) + "Union::") +
871 "UnPack(const void *obj, " + Name(enum_def) +
872 " type, const flatbuffers::resolver_function_t *resolver)";
873 }
874
UnionPackSignature(const EnumDef & enum_def,bool inclass)875 std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
876 return "flatbuffers::Offset<void> " +
877 (inclass ? "" : Name(enum_def) + "Union::") +
878 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
879 "const flatbuffers::rehasher_function_t *_rehasher" +
880 (inclass ? " = nullptr" : "") + ") const";
881 }
882
TableCreateSignature(const StructDef & struct_def,bool predecl,const IDLOptions & opts)883 std::string TableCreateSignature(const StructDef &struct_def, bool predecl,
884 const IDLOptions &opts) {
885 return "flatbuffers::Offset<" + Name(struct_def) + "> Create" +
886 Name(struct_def) + "(flatbuffers::FlatBufferBuilder &_fbb, const " +
887 NativeName(Name(struct_def), &struct_def, opts) +
888 " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
889 (predecl ? " = nullptr" : "") + ")";
890 }
891
TablePackSignature(const StructDef & struct_def,bool inclass,const IDLOptions & opts)892 std::string TablePackSignature(const StructDef &struct_def, bool inclass,
893 const IDLOptions &opts) {
894 return std::string(inclass ? "static " : "") + "flatbuffers::Offset<" +
895 Name(struct_def) + "> " + (inclass ? "" : Name(struct_def) + "::") +
896 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + "const " +
897 NativeName(Name(struct_def), &struct_def, opts) + "* _o, " +
898 "const flatbuffers::rehasher_function_t *_rehasher" +
899 (inclass ? " = nullptr" : "") + ")";
900 }
901
TableUnPackSignature(const StructDef & struct_def,bool inclass,const IDLOptions & opts)902 std::string TableUnPackSignature(const StructDef &struct_def, bool inclass,
903 const IDLOptions &opts) {
904 return NativeName(Name(struct_def), &struct_def, opts) + " *" +
905 (inclass ? "" : Name(struct_def) + "::") +
906 "UnPack(const flatbuffers::resolver_function_t *_resolver" +
907 (inclass ? " = nullptr" : "") + ") const";
908 }
909
TableUnPackToSignature(const StructDef & struct_def,bool inclass,const IDLOptions & opts)910 std::string TableUnPackToSignature(const StructDef &struct_def, bool inclass,
911 const IDLOptions &opts) {
912 return "void " + (inclass ? "" : Name(struct_def) + "::") + "UnPackTo(" +
913 NativeName(Name(struct_def), &struct_def, opts) + " *" +
914 "_o, const flatbuffers::resolver_function_t *_resolver" +
915 (inclass ? " = nullptr" : "") + ") const";
916 }
917
GenMiniReflectPre(const StructDef * struct_def)918 void GenMiniReflectPre(const StructDef *struct_def) {
919 code_.SetValue("NAME", struct_def->name);
920 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable();";
921 code_ += "";
922 }
923
GenMiniReflect(const StructDef * struct_def,const EnumDef * enum_def)924 void GenMiniReflect(const StructDef *struct_def, const EnumDef *enum_def) {
925 code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
926 code_.SetValue("SEQ_TYPE",
927 struct_def ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
928 : (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
929 auto num_fields =
930 struct_def ? struct_def->fields.vec.size() : enum_def->size();
931 code_.SetValue("NUM_FIELDS", NumToString(num_fields));
932 std::vector<std::string> names;
933 std::vector<Type> types;
934
935 if (struct_def) {
936 for (auto it = struct_def->fields.vec.begin();
937 it != struct_def->fields.vec.end(); ++it) {
938 const auto &field = **it;
939 names.push_back(Name(field));
940 types.push_back(field.value.type);
941 }
942 } else {
943 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
944 ++it) {
945 const auto &ev = **it;
946 names.push_back(Name(ev));
947 types.push_back(enum_def->is_union ? ev.union_type
948 : Type(enum_def->underlying_type));
949 }
950 }
951 std::string ts;
952 std::vector<std::string> type_refs;
953 for (auto it = types.begin(); it != types.end(); ++it) {
954 auto &type = *it;
955 if (!ts.empty()) ts += ",\n ";
956 auto is_vector = type.base_type == BASE_TYPE_VECTOR;
957 auto bt = is_vector ? type.element : type.base_type;
958 auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
959 ? bt - BASE_TYPE_UTYPE + ET_UTYPE
960 : ET_SEQUENCE;
961 int ref_idx = -1;
962 std::string ref_name =
963 type.struct_def
964 ? WrapInNameSpace(*type.struct_def)
965 : type.enum_def ? WrapInNameSpace(*type.enum_def) : "";
966 if (!ref_name.empty()) {
967 auto rit = type_refs.begin();
968 for (; rit != type_refs.end(); ++rit) {
969 if (*rit == ref_name) {
970 ref_idx = static_cast<int>(rit - type_refs.begin());
971 break;
972 }
973 }
974 if (rit == type_refs.end()) {
975 ref_idx = static_cast<int>(type_refs.size());
976 type_refs.push_back(ref_name);
977 }
978 }
979 ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
980 NumToString(is_vector) + ", " + NumToString(ref_idx) + " }";
981 }
982 std::string rs;
983 for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
984 if (!rs.empty()) rs += ",\n ";
985 rs += *it + "TypeTable";
986 }
987 std::string ns;
988 for (auto it = names.begin(); it != names.end(); ++it) {
989 if (!ns.empty()) ns += ",\n ";
990 ns += "\"" + *it + "\"";
991 }
992 std::string vs;
993 const auto consecutive_enum_from_zero =
994 enum_def && enum_def->MinValue()->IsZero() &&
995 ((enum_def->size() - 1) == enum_def->Distance());
996 if (enum_def && !consecutive_enum_from_zero) {
997 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
998 ++it) {
999 const auto &ev = **it;
1000 if (!vs.empty()) vs += ", ";
1001 vs += NumToStringCpp(enum_def->ToString(ev),
1002 enum_def->underlying_type.base_type);
1003 }
1004 } else if (struct_def && struct_def->fixed) {
1005 for (auto it = struct_def->fields.vec.begin();
1006 it != struct_def->fields.vec.end(); ++it) {
1007 const auto &field = **it;
1008 vs += NumToString(field.value.offset);
1009 vs += ", ";
1010 }
1011 vs += NumToString(struct_def->bytesize);
1012 }
1013 code_.SetValue("TYPES", ts);
1014 code_.SetValue("REFS", rs);
1015 code_.SetValue("NAMES", ns);
1016 code_.SetValue("VALUES", vs);
1017 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable() {";
1018 if (num_fields) {
1019 code_ += " static const flatbuffers::TypeCode type_codes[] = {";
1020 code_ += " {{TYPES}}";
1021 code_ += " };";
1022 }
1023 if (!type_refs.empty()) {
1024 code_ += " static const flatbuffers::TypeFunction type_refs[] = {";
1025 code_ += " {{REFS}}";
1026 code_ += " };";
1027 }
1028 if (!vs.empty()) {
1029 // Problem with uint64_t values greater than 9223372036854775807ULL.
1030 code_ += " static const int64_t values[] = { {{VALUES}} };";
1031 }
1032 auto has_names =
1033 num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames;
1034 if (has_names) {
1035 code_ += " static const char * const names[] = {";
1036 code_ += " {{NAMES}}";
1037 code_ += " };";
1038 }
1039 code_ += " static const flatbuffers::TypeTable tt = {";
1040 code_ += std::string(" flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
1041 (num_fields ? "type_codes, " : "nullptr, ") +
1042 (!type_refs.empty() ? "type_refs, " : "nullptr, ") +
1043 (!vs.empty() ? "values, " : "nullptr, ") +
1044 (has_names ? "names" : "nullptr");
1045 code_ += " };";
1046 code_ += " return &tt;";
1047 code_ += "}";
1048 code_ += "";
1049 }
1050
1051 // Generate an enum declaration,
1052 // an enum string lookup table,
1053 // and an enum array of values
1054
GenEnum(const EnumDef & enum_def)1055 void GenEnum(const EnumDef &enum_def) {
1056 code_.SetValue("ENUM_NAME", Name(enum_def));
1057 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
1058
1059 GenComment(enum_def.doc_comment);
1060 code_ +=
1061 (opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\";
1062 if (opts_.g_only_fixed_enums) { code_ += " : {{BASE_TYPE}}\\"; }
1063 code_ += " {";
1064
1065 code_.SetValue("SEP", ",");
1066 auto add_sep = false;
1067 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1068 const auto &ev = **it;
1069 if (add_sep) code_ += "{{SEP}}";
1070 GenComment(ev.doc_comment, " ");
1071 code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev)));
1072 code_.SetValue("VALUE",
1073 NumToStringCpp(enum_def.ToString(ev),
1074 enum_def.underlying_type.base_type));
1075 code_ += " {{KEY}} = {{VALUE}}\\";
1076 add_sep = true;
1077 }
1078 const EnumVal *minv = enum_def.MinValue();
1079 const EnumVal *maxv = enum_def.MaxValue();
1080
1081 if (opts_.scoped_enums || opts_.prefixed_enums) {
1082 FLATBUFFERS_ASSERT(minv && maxv);
1083
1084 code_.SetValue("SEP", ",\n");
1085 if (enum_def.attributes.Lookup("bit_flags")) {
1086 code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
1087 code_.SetValue("VALUE", "0");
1088 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1089
1090 code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
1091 code_.SetValue("VALUE",
1092 NumToStringCpp(enum_def.AllFlags(),
1093 enum_def.underlying_type.base_type));
1094 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1095 } else { // MIN & MAX are useless for bit_flags
1096 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN"));
1097 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*minv)));
1098 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1099
1100 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX"));
1101 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*maxv)));
1102 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1103 }
1104 }
1105 code_ += "";
1106 code_ += "};";
1107
1108 if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
1109 code_ +=
1110 "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
1111 }
1112 code_ += "";
1113
1114 // Generate an array of all enumeration values
1115 auto num_fields = NumToString(enum_def.size());
1116 code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
1117 num_fields + "] {";
1118 code_ += " static const {{ENUM_NAME}} values[] = {";
1119 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1120 const auto &ev = **it;
1121 auto value = GetEnumValUse(enum_def, ev);
1122 auto suffix = *it != enum_def.Vals().back() ? "," : "";
1123 code_ += " " + value + suffix;
1124 }
1125 code_ += " };";
1126 code_ += " return values;";
1127 code_ += "}";
1128 code_ += "";
1129
1130 // Generate a generate string table for enum values.
1131 // Problem is, if values are very sparse that could generate really big
1132 // tables. Ideally in that case we generate a map lookup instead, but for
1133 // the moment we simply don't output a table at all.
1134 auto range = enum_def.Distance();
1135 // Average distance between values above which we consider a table
1136 // "too sparse". Change at will.
1137 static const uint64_t kMaxSparseness = 5;
1138 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
1139 code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
1140 code_ += " static const char * const names[" +
1141 NumToString(range + 1 + 1) + "] = {";
1142
1143 auto val = enum_def.Vals().front();
1144 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1145 ++it) {
1146 auto ev = *it;
1147 for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
1148 code_ += " \"\",";
1149 }
1150 val = ev;
1151 code_ += " \"" + Name(*ev) + "\",";
1152 }
1153 code_ += " nullptr";
1154 code_ += " };";
1155
1156 code_ += " return names;";
1157 code_ += "}";
1158 code_ += "";
1159
1160 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1161
1162 code_ += " if (flatbuffers::IsOutRange(e, " +
1163 GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " +
1164 GetEnumValUse(enum_def, *enum_def.MaxValue()) +
1165 ")) return \"\";";
1166
1167 code_ += " const size_t index = static_cast<size_t>(e)\\";
1168 if (enum_def.MinValue()->IsNonZero()) {
1169 auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
1170 code_ += " - static_cast<size_t>(" + vals + ")\\";
1171 }
1172 code_ += ";";
1173
1174 code_ += " return EnumNames{{ENUM_NAME}}()[index];";
1175 code_ += "}";
1176 code_ += "";
1177 } else {
1178 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1179
1180 code_ += " switch (e) {";
1181
1182 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1183 ++it) {
1184 const auto &ev = **it;
1185 code_ += " case " + GetEnumValUse(enum_def, ev) + ": return \"" +
1186 Name(ev) + "\";";
1187 }
1188
1189 code_ += " default: return \"\";";
1190 code_ += " }";
1191
1192 code_ += "}";
1193 code_ += "";
1194 }
1195
1196 // Generate type traits for unions to map from a type to union enum value.
1197 if (enum_def.is_union && !enum_def.uses_multiple_type_instances) {
1198 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1199 ++it) {
1200 const auto &ev = **it;
1201
1202 if (it == enum_def.Vals().begin()) {
1203 code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
1204 } else {
1205 auto name = GetUnionElement(ev, true, true);
1206 code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
1207 }
1208
1209 auto value = GetEnumValUse(enum_def, ev);
1210 code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
1211 code_ += "};";
1212 code_ += "";
1213 }
1214 }
1215
1216 if (opts_.generate_object_based_api && enum_def.is_union) {
1217 // Generate a union type
1218 code_.SetValue("NAME", Name(enum_def));
1219 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1220 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1221
1222 code_ += "struct {{NAME}}Union {";
1223 code_ += " {{NAME}} type;";
1224 code_ += " void *value;";
1225 code_ += "";
1226 code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
1227 code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
1228 code_ += " type({{NONE}}), value(nullptr)";
1229 code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
1230 code_ += " {{NAME}}Union(const {{NAME}}Union &);";
1231 code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)";
1232 code_ +=
1233 " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, "
1234 "t.value); return *this; }";
1235 code_ +=
1236 " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
1237 code_ +=
1238 " { std::swap(type, u.type); std::swap(value, u.value); return "
1239 "*this; }";
1240 code_ += " ~{{NAME}}Union() { Reset(); }";
1241 code_ += "";
1242 code_ += " void Reset();";
1243 code_ += "";
1244 if (!enum_def.uses_multiple_type_instances) {
1245 code_ += "#ifndef FLATBUFFERS_CPP98_STL";
1246 code_ += " template <typename T>";
1247 code_ += " void Set(T&& val) {";
1248 code_ += " using RT = typename std::remove_reference<T>::type;";
1249 code_ += " Reset();";
1250 code_ +=
1251 " type = {{NAME}}Traits<typename RT::TableType>::enum_value;";
1252 code_ += " if (type != {{NONE}}) {";
1253 code_ += " value = new RT(std::forward<T>(val));";
1254 code_ += " }";
1255 code_ += " }";
1256 code_ += "#endif // FLATBUFFERS_CPP98_STL";
1257 code_ += "";
1258 }
1259 code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
1260 code_ += " " + UnionPackSignature(enum_def, true) + ";";
1261 code_ += "";
1262
1263 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1264 ++it) {
1265 const auto &ev = **it;
1266 if (ev.IsZero()) { continue; }
1267
1268 const auto native_type =
1269 NativeName(GetUnionElement(ev, true, true, true),
1270 ev.union_type.struct_def, opts_);
1271 code_.SetValue("NATIVE_TYPE", native_type);
1272 code_.SetValue("NATIVE_NAME", Name(ev));
1273 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1274
1275 code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
1276 code_ += " return type == {{NATIVE_ID}} ?";
1277 code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
1278 code_ += " }";
1279
1280 code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {";
1281 code_ += " return type == {{NATIVE_ID}} ?";
1282 code_ +=
1283 " reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;";
1284 code_ += " }";
1285 }
1286 code_ += "};";
1287 code_ += "";
1288
1289 if (opts_.gen_compare) {
1290 code_ += "";
1291 code_ +=
1292 "inline bool operator==(const {{NAME}}Union &lhs, const "
1293 "{{NAME}}Union &rhs) {";
1294 code_ += " if (lhs.type != rhs.type) return false;";
1295 code_ += " switch (lhs.type) {";
1296
1297 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1298 ++it) {
1299 const auto &ev = **it;
1300 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1301 if (ev.IsNonZero()) {
1302 const auto native_type =
1303 NativeName(GetUnionElement(ev, true, true, true),
1304 ev.union_type.struct_def, opts_);
1305 code_.SetValue("NATIVE_TYPE", native_type);
1306 code_ += " case {{NATIVE_ID}}: {";
1307 code_ +=
1308 " return *(reinterpret_cast<const {{NATIVE_TYPE}} "
1309 "*>(lhs.value)) ==";
1310 code_ +=
1311 " *(reinterpret_cast<const {{NATIVE_TYPE}} "
1312 "*>(rhs.value));";
1313 code_ += " }";
1314 } else {
1315 code_ += " case {{NATIVE_ID}}: {";
1316 code_ += " return true;"; // "NONE" enum value.
1317 code_ += " }";
1318 }
1319 }
1320 code_ += " default: {";
1321 code_ += " return false;";
1322 code_ += " }";
1323 code_ += " }";
1324 code_ += "}";
1325
1326 code_ += "";
1327 code_ +=
1328 "inline bool operator!=(const {{NAME}}Union &lhs, const "
1329 "{{NAME}}Union &rhs) {";
1330 code_ += " return !(lhs == rhs);";
1331 code_ += "}";
1332 code_ += "";
1333 }
1334 }
1335
1336 if (enum_def.is_union) {
1337 code_ += UnionVerifySignature(enum_def) + ";";
1338 code_ += UnionVectorVerifySignature(enum_def) + ";";
1339 code_ += "";
1340 }
1341 }
1342
GenUnionPost(const EnumDef & enum_def)1343 void GenUnionPost(const EnumDef &enum_def) {
1344 // Generate a verifier function for this union that can be called by the
1345 // table verifier functions. It uses a switch case to select a specific
1346 // verifier function to call, this should be safe even if the union type
1347 // has been corrupted, since the verifiers will simply fail when called
1348 // on the wrong type.
1349 code_.SetValue("ENUM_NAME", Name(enum_def));
1350
1351 code_ += "inline " + UnionVerifySignature(enum_def) + " {";
1352 code_ += " switch (type) {";
1353 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1354 const auto &ev = **it;
1355 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1356
1357 if (ev.IsNonZero()) {
1358 code_.SetValue("TYPE", GetUnionElement(ev, true, true));
1359 code_ += " case {{LABEL}}: {";
1360 auto getptr =
1361 " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1362 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1363 if (ev.union_type.struct_def->fixed) {
1364 code_ +=
1365 " return verifier.Verify<{{TYPE}}>(static_cast<const "
1366 "uint8_t *>(obj), 0);";
1367 } else {
1368 code_ += getptr;
1369 code_ += " return verifier.VerifyTable(ptr);";
1370 }
1371 } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
1372 code_ += getptr;
1373 code_ += " return verifier.VerifyString(ptr);";
1374 } else {
1375 FLATBUFFERS_ASSERT(false);
1376 }
1377 code_ += " }";
1378 } else {
1379 code_ += " case {{LABEL}}: {";
1380 code_ += " return true;"; // "NONE" enum value.
1381 code_ += " }";
1382 }
1383 }
1384 code_ += " default: return true;"; // unknown values are OK.
1385 code_ += " }";
1386 code_ += "}";
1387 code_ += "";
1388
1389 code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
1390 code_ += " if (!values || !types) return !values && !types;";
1391 code_ += " if (values->size() != types->size()) return false;";
1392 code_ += " for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
1393 code_ += " if (!Verify" + Name(enum_def) + "(";
1394 code_ += " verifier, values->Get(i), types->GetEnum<" +
1395 Name(enum_def) + ">(i))) {";
1396 code_ += " return false;";
1397 code_ += " }";
1398 code_ += " }";
1399 code_ += " return true;";
1400 code_ += "}";
1401 code_ += "";
1402
1403 if (opts_.generate_object_based_api) {
1404 // Generate union Unpack() and Pack() functions.
1405 code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
1406 code_ += " switch (type) {";
1407 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1408 ++it) {
1409 const auto &ev = **it;
1410 if (ev.IsZero()) { continue; }
1411
1412 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1413 code_.SetValue("TYPE", GetUnionElement(ev, true, true));
1414 code_ += " case {{LABEL}}: {";
1415 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1416 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1417 if (ev.union_type.struct_def->fixed) {
1418 code_ += " return new " +
1419 WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
1420 } else {
1421 code_ += " return ptr->UnPack(resolver);";
1422 }
1423 } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
1424 code_ += " return new std::string(ptr->c_str(), ptr->size());";
1425 } else {
1426 FLATBUFFERS_ASSERT(false);
1427 }
1428 code_ += " }";
1429 }
1430 code_ += " default: return nullptr;";
1431 code_ += " }";
1432 code_ += "}";
1433 code_ += "";
1434
1435 code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
1436 code_ += " switch (type) {";
1437 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1438 ++it) {
1439 auto &ev = **it;
1440 if (ev.IsZero()) { continue; }
1441
1442 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1443 code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
1444 ev.union_type.struct_def, opts_));
1445 code_.SetValue("NAME", GetUnionElement(ev, false, true));
1446 code_ += " case {{LABEL}}: {";
1447 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
1448 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1449 if (ev.union_type.struct_def->fixed) {
1450 code_ += " return _fbb.CreateStruct(*ptr).Union();";
1451 } else {
1452 code_ +=
1453 " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
1454 }
1455 } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
1456 code_ += " return _fbb.CreateString(*ptr).Union();";
1457 } else {
1458 FLATBUFFERS_ASSERT(false);
1459 }
1460 code_ += " }";
1461 }
1462 code_ += " default: return 0;";
1463 code_ += " }";
1464 code_ += "}";
1465 code_ += "";
1466
1467 // Union copy constructor
1468 code_ +=
1469 "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
1470 "{{ENUM_NAME}}Union &u) : type(u.type), value(nullptr) {";
1471 code_ += " switch (type) {";
1472 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1473 ++it) {
1474 const auto &ev = **it;
1475 if (ev.IsZero()) { continue; }
1476 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1477 code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
1478 ev.union_type.struct_def, opts_));
1479 code_ += " case {{LABEL}}: {";
1480 bool copyable = true;
1481 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1482 // Don't generate code to copy if table is not copyable.
1483 // TODO(wvo): make tables copyable instead.
1484 for (auto fit = ev.union_type.struct_def->fields.vec.begin();
1485 fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
1486 const auto &field = **fit;
1487 if (!field.deprecated && field.value.type.struct_def &&
1488 !field.native_inline) {
1489 copyable = false;
1490 break;
1491 }
1492 }
1493 }
1494 if (copyable) {
1495 code_ +=
1496 " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
1497 "(u.value));";
1498 } else {
1499 code_ +=
1500 " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable.";
1501 }
1502 code_ += " break;";
1503 code_ += " }";
1504 }
1505 code_ += " default:";
1506 code_ += " break;";
1507 code_ += " }";
1508 code_ += "}";
1509 code_ += "";
1510
1511 // Union Reset() function.
1512 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1513 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1514
1515 code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
1516 code_ += " switch (type) {";
1517 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1518 ++it) {
1519 const auto &ev = **it;
1520 if (ev.IsZero()) { continue; }
1521 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1522 code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
1523 ev.union_type.struct_def, opts_));
1524 code_ += " case {{LABEL}}: {";
1525 code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
1526 code_ += " delete ptr;";
1527 code_ += " break;";
1528 code_ += " }";
1529 }
1530 code_ += " default: break;";
1531 code_ += " }";
1532 code_ += " value = nullptr;";
1533 code_ += " type = {{NONE}};";
1534 code_ += "}";
1535 code_ += "";
1536 }
1537 }
1538
1539 // Generates a value with optionally a cast applied if the field has a
1540 // different underlying type from its interface type (currently only the
1541 // case for enums. "from" specify the direction, true meaning from the
1542 // underlying type to the interface type.
GenUnderlyingCast(const FieldDef & field,bool from,const std::string & val)1543 std::string GenUnderlyingCast(const FieldDef &field, bool from,
1544 const std::string &val) {
1545 if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
1546 return val + " != 0";
1547 } else if ((field.value.type.enum_def &&
1548 IsScalar(field.value.type.base_type)) ||
1549 field.value.type.base_type == BASE_TYPE_BOOL) {
1550 return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
1551 val + ")";
1552 } else {
1553 return val;
1554 }
1555 }
1556
GenFieldOffsetName(const FieldDef & field)1557 std::string GenFieldOffsetName(const FieldDef &field) {
1558 std::string uname = Name(field);
1559 std::transform(uname.begin(), uname.end(), uname.begin(), ToUpper);
1560 return "VT_" + uname;
1561 }
1562
GenFullyQualifiedNameGetter(const StructDef & struct_def,const std::string & name)1563 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1564 const std::string &name) {
1565 if (!opts_.generate_name_strings) { return; }
1566 auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
1567 code_.SetValue("NAME", fullname);
1568 code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
1569 code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
1570 code_ += " return \"{{NAME}}\";";
1571 code_ += " }";
1572 }
1573
GenDefaultConstant(const FieldDef & field)1574 std::string GenDefaultConstant(const FieldDef &field) {
1575 if (IsFloat(field.value.type.base_type))
1576 return float_const_gen_.GenFloatConstant(field);
1577 else
1578 return NumToStringCpp(field.value.constant, field.value.type.base_type);
1579 }
1580
GetDefaultScalarValue(const FieldDef & field,bool is_ctor)1581 std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
1582 if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) {
1583 auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
1584 if (ev) {
1585 return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
1586 GetEnumValUse(*field.value.type.enum_def, *ev));
1587 } else {
1588 return GenUnderlyingCast(
1589 field, true,
1590 NumToStringCpp(field.value.constant, field.value.type.base_type));
1591 }
1592 } else if (field.value.type.base_type == BASE_TYPE_BOOL) {
1593 return field.value.constant == "0" ? "false" : "true";
1594 } else if (field.attributes.Lookup("cpp_type")) {
1595 if (is_ctor) {
1596 if (PtrType(&field) == "naked") {
1597 return "nullptr";
1598 } else {
1599 return "";
1600 }
1601 } else {
1602 return "0";
1603 }
1604 } else {
1605 return GenDefaultConstant(field);
1606 }
1607 }
1608
GenParam(const FieldDef & field,bool direct,const char * prefix)1609 void GenParam(const FieldDef &field, bool direct, const char *prefix) {
1610 code_.SetValue("PRE", prefix);
1611 code_.SetValue("PARAM_NAME", Name(field));
1612 if (direct && field.value.type.base_type == BASE_TYPE_STRING) {
1613 code_.SetValue("PARAM_TYPE", "const char *");
1614 code_.SetValue("PARAM_VALUE", "nullptr");
1615 } else if (direct && field.value.type.base_type == BASE_TYPE_VECTOR) {
1616 const auto vtype = field.value.type.VectorType();
1617 std::string type;
1618 if (IsStruct(vtype)) {
1619 type = WrapInNameSpace(*vtype.struct_def);
1620 } else {
1621 type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
1622 }
1623 if (TypeHasKey(vtype)) {
1624 code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
1625 } else {
1626 code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
1627 }
1628 code_.SetValue("PARAM_VALUE", "nullptr");
1629 } else {
1630 code_.SetValue("PARAM_TYPE", GenTypeWire(field.value.type, " ", true));
1631 code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
1632 }
1633 code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
1634 }
1635
1636 // Generate a member, including a default value for scalars and raw pointers.
GenMember(const FieldDef & field)1637 void GenMember(const FieldDef &field) {
1638 if (!field.deprecated && // Deprecated fields won't be accessible.
1639 field.value.type.base_type != BASE_TYPE_UTYPE &&
1640 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1641 field.value.type.element != BASE_TYPE_UTYPE)) {
1642 auto type = GenTypeNative(field.value.type, false, field);
1643 auto cpp_type = field.attributes.Lookup("cpp_type");
1644 auto full_type =
1645 (cpp_type
1646 ? (field.value.type.base_type == BASE_TYPE_VECTOR
1647 ? "std::vector<" +
1648 GenTypeNativePtr(cpp_type->constant, &field,
1649 false) +
1650 "> "
1651 : GenTypeNativePtr(cpp_type->constant, &field, false))
1652 : type + " ");
1653 code_.SetValue("FIELD_TYPE", full_type);
1654 code_.SetValue("FIELD_NAME", Name(field));
1655 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}};";
1656 }
1657 }
1658
1659 // Generate the default constructor for this struct. Properly initialize all
1660 // scalar members with default values.
GenDefaultConstructor(const StructDef & struct_def)1661 void GenDefaultConstructor(const StructDef &struct_def) {
1662 std::string initializer_list;
1663 for (auto it = struct_def.fields.vec.begin();
1664 it != struct_def.fields.vec.end(); ++it) {
1665 const auto &field = **it;
1666 if (!field.deprecated && // Deprecated fields won't be accessible.
1667 field.value.type.base_type != BASE_TYPE_UTYPE) {
1668 auto cpp_type = field.attributes.Lookup("cpp_type");
1669 auto native_default = field.attributes.Lookup("native_default");
1670 // Scalar types get parsed defaults, raw pointers get nullptrs.
1671 if (IsScalar(field.value.type.base_type)) {
1672 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1673 initializer_list += Name(field);
1674 initializer_list +=
1675 "(" +
1676 (native_default ? std::string(native_default->constant)
1677 : GetDefaultScalarValue(field, true)) +
1678 ")";
1679 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1680 if (IsStruct(field.value.type)) {
1681 if (native_default) {
1682 if (!initializer_list.empty()) {
1683 initializer_list += ",\n ";
1684 }
1685 initializer_list +=
1686 Name(field) + "(" + native_default->constant + ")";
1687 }
1688 }
1689 } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) {
1690 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1691 initializer_list += Name(field) + "(0)";
1692 }
1693 }
1694 }
1695 if (!initializer_list.empty()) {
1696 initializer_list = "\n : " + initializer_list;
1697 }
1698
1699 code_.SetValue("NATIVE_NAME",
1700 NativeName(Name(struct_def), &struct_def, opts_));
1701 code_.SetValue("INIT_LIST", initializer_list);
1702
1703 code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
1704 code_ += " }";
1705 }
1706
GenCompareOperator(const StructDef & struct_def,std::string accessSuffix="")1707 void GenCompareOperator(const StructDef &struct_def,
1708 std::string accessSuffix = "") {
1709 std::string compare_op;
1710 for (auto it = struct_def.fields.vec.begin();
1711 it != struct_def.fields.vec.end(); ++it) {
1712 const auto &field = **it;
1713 if (!field.deprecated && // Deprecated fields won't be accessible.
1714 field.value.type.base_type != BASE_TYPE_UTYPE &&
1715 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1716 field.value.type.element != BASE_TYPE_UTYPE)) {
1717 if (!compare_op.empty()) { compare_op += " &&\n "; }
1718 auto accessor = Name(field) + accessSuffix;
1719 compare_op += "(lhs." + accessor + " == rhs." + accessor + ")";
1720 }
1721 }
1722
1723 std::string cmp_lhs;
1724 std::string cmp_rhs;
1725 if (compare_op.empty()) {
1726 cmp_lhs = "";
1727 cmp_rhs = "";
1728 compare_op = " return true;";
1729 } else {
1730 cmp_lhs = "lhs";
1731 cmp_rhs = "rhs";
1732 compare_op = " return\n " + compare_op + ";";
1733 }
1734
1735 code_.SetValue("CMP_OP", compare_op);
1736 code_.SetValue("CMP_LHS", cmp_lhs);
1737 code_.SetValue("CMP_RHS", cmp_rhs);
1738 code_ += "";
1739 code_ +=
1740 "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
1741 "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
1742 code_ += "{{CMP_OP}}";
1743 code_ += "}";
1744
1745 code_ += "";
1746 code_ +=
1747 "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
1748 "{{NATIVE_NAME}} &rhs) {";
1749 code_ += " return !(lhs == rhs);";
1750 code_ += "}";
1751 code_ += "";
1752 }
1753
GenOperatorNewDelete(const StructDef & struct_def)1754 void GenOperatorNewDelete(const StructDef &struct_def) {
1755 if (auto native_custom_alloc =
1756 struct_def.attributes.Lookup("native_custom_alloc")) {
1757 code_ += " inline void *operator new (std::size_t count) {";
1758 code_ += " return " + native_custom_alloc->constant +
1759 "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
1760 code_ += " }";
1761 code_ += " inline void operator delete (void *ptr) {";
1762 code_ += " return " + native_custom_alloc->constant +
1763 "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
1764 "ptr),1);";
1765 code_ += " }";
1766 }
1767 }
1768
GenNativeTable(const StructDef & struct_def)1769 void GenNativeTable(const StructDef &struct_def) {
1770 const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
1771 code_.SetValue("STRUCT_NAME", Name(struct_def));
1772 code_.SetValue("NATIVE_NAME", native_name);
1773
1774 // Generate a C++ object that can hold an unpacked version of this table.
1775 code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
1776 code_ += " typedef {{STRUCT_NAME}} TableType;";
1777 GenFullyQualifiedNameGetter(struct_def, native_name);
1778 for (auto it = struct_def.fields.vec.begin();
1779 it != struct_def.fields.vec.end(); ++it) {
1780 GenMember(**it);
1781 }
1782 GenOperatorNewDelete(struct_def);
1783 GenDefaultConstructor(struct_def);
1784 code_ += "};";
1785 if (opts_.gen_compare) GenCompareOperator(struct_def);
1786 code_ += "";
1787 }
1788
1789 // Generate the code to call the appropriate Verify function(s) for a field.
GenVerifyCall(const FieldDef & field,const char * prefix)1790 void GenVerifyCall(const FieldDef &field, const char *prefix) {
1791 code_.SetValue("PRE", prefix);
1792 code_.SetValue("NAME", Name(field));
1793 code_.SetValue("REQUIRED", field.required ? "Required" : "");
1794 code_.SetValue("SIZE", GenTypeSize(field.value.type));
1795 code_.SetValue("OFFSET", GenFieldOffsetName(field));
1796 if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
1797 code_ +=
1798 "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
1799 } else {
1800 code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
1801 }
1802
1803 switch (field.value.type.base_type) {
1804 case BASE_TYPE_UNION: {
1805 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1806 code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
1807 code_ +=
1808 "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
1809 "{{NAME}}{{SUFFIX}}())\\";
1810 break;
1811 }
1812 case BASE_TYPE_STRUCT: {
1813 if (!field.value.type.struct_def->fixed) {
1814 code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
1815 }
1816 break;
1817 }
1818 case BASE_TYPE_STRING: {
1819 code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
1820 break;
1821 }
1822 case BASE_TYPE_VECTOR: {
1823 code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
1824
1825 switch (field.value.type.element) {
1826 case BASE_TYPE_STRING: {
1827 code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
1828 break;
1829 }
1830 case BASE_TYPE_STRUCT: {
1831 if (!field.value.type.struct_def->fixed) {
1832 code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
1833 }
1834 break;
1835 }
1836 case BASE_TYPE_UNION: {
1837 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1838 code_ +=
1839 "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
1840 "{{NAME}}_type())\\";
1841 break;
1842 }
1843 default: break;
1844 }
1845 break;
1846 }
1847 default: {
1848 break;
1849 }
1850 }
1851 }
1852
1853 // Generate CompareWithValue method for a key field.
GenKeyFieldMethods(const FieldDef & field)1854 void GenKeyFieldMethods(const FieldDef &field) {
1855 FLATBUFFERS_ASSERT(field.key);
1856 const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING);
1857
1858 code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
1859 if (is_string) {
1860 // use operator< of flatbuffers::String
1861 code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
1862 } else {
1863 code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
1864 }
1865 code_ += " }";
1866
1867 if (is_string) {
1868 code_ += " int KeyCompareWithValue(const char *val) const {";
1869 code_ += " return strcmp({{FIELD_NAME}}()->c_str(), val);";
1870 code_ += " }";
1871 } else {
1872 FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
1873 auto type = GenTypeBasic(field.value.type, false);
1874 if (opts_.scoped_enums && field.value.type.enum_def &&
1875 IsScalar(field.value.type.base_type)) {
1876 type = GenTypeGet(field.value.type, " ", "const ", " *", true);
1877 }
1878 // Returns {field<val: -1, field==val: 0, field>val: +1}.
1879 code_.SetValue("KEY_TYPE", type);
1880 code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {";
1881 code_ +=
1882 " return static_cast<int>({{FIELD_NAME}}() > val) - "
1883 "static_cast<int>({{FIELD_NAME}}() < val);";
1884 code_ += " }";
1885 }
1886 }
1887
1888 // Generate an accessor struct, builder structs & function for a table.
GenTable(const StructDef & struct_def)1889 void GenTable(const StructDef &struct_def) {
1890 if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
1891
1892 // Generate an accessor struct, with methods of the form:
1893 // type name() const { return GetField<type>(offset, defaultval); }
1894 GenComment(struct_def.doc_comment);
1895
1896 code_.SetValue("STRUCT_NAME", Name(struct_def));
1897 code_ +=
1898 "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
1899 " : private flatbuffers::Table {";
1900 if (opts_.generate_object_based_api) {
1901 code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
1902 }
1903 code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
1904 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
1905 if (opts_.mini_reflect != IDLOptions::kNone) {
1906 code_ +=
1907 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
1908 code_ += " return {{STRUCT_NAME}}TypeTable();";
1909 code_ += " }";
1910 }
1911
1912 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
1913
1914 // Generate field id constants.
1915 if (struct_def.fields.vec.size() > 0) {
1916 // We need to add a trailing comma to all elements except the last one as
1917 // older versions of gcc complain about this.
1918 code_.SetValue("SEP", "");
1919 code_ +=
1920 " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
1921 for (auto it = struct_def.fields.vec.begin();
1922 it != struct_def.fields.vec.end(); ++it) {
1923 const auto &field = **it;
1924 if (field.deprecated) {
1925 // Deprecated fields won't be accessible.
1926 continue;
1927 }
1928
1929 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
1930 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
1931 code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
1932 code_.SetValue("SEP", ",\n");
1933 }
1934 code_ += "";
1935 code_ += " };";
1936 }
1937
1938 // Generate the accessors.
1939 for (auto it = struct_def.fields.vec.begin();
1940 it != struct_def.fields.vec.end(); ++it) {
1941 const auto &field = **it;
1942 if (field.deprecated) {
1943 // Deprecated fields won't be accessible.
1944 continue;
1945 }
1946
1947 const bool is_struct = IsStruct(field.value.type);
1948 const bool is_scalar = IsScalar(field.value.type.base_type);
1949 code_.SetValue("FIELD_NAME", Name(field));
1950
1951 // Call a different accessor for pointers, that indirects.
1952 std::string accessor = "";
1953 if (is_scalar) {
1954 accessor = "GetField<";
1955 } else if (is_struct) {
1956 accessor = "GetStruct<";
1957 } else {
1958 accessor = "GetPointer<";
1959 }
1960 auto offset_str = GenFieldOffsetName(field);
1961 auto offset_type =
1962 GenTypeGet(field.value.type, "", "const ", " *", false);
1963
1964 auto call = accessor + offset_type + ">(" + offset_str;
1965 // Default value as second arg for non-pointer types.
1966 if (is_scalar) { call += ", " + GenDefaultConstant(field); }
1967 call += ")";
1968
1969 std::string afterptr = " *" + NullableExtension();
1970 GenComment(field.doc_comment, " ");
1971 code_.SetValue("FIELD_TYPE", GenTypeGet(field.value.type, " ", "const ",
1972 afterptr.c_str(), true));
1973 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
1974 code_.SetValue("NULLABLE_EXT", NullableExtension());
1975
1976 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
1977 code_ += " return {{FIELD_VALUE}};";
1978 code_ += " }";
1979
1980 if (field.value.type.base_type == BASE_TYPE_UNION) {
1981 auto u = field.value.type.enum_def;
1982
1983 if (!field.value.type.enum_def->uses_multiple_type_instances)
1984 code_ +=
1985 " template<typename T> "
1986 "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
1987
1988 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
1989 auto &ev = **u_it;
1990 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1991 auto full_struct_name = GetUnionElement(ev, true, true);
1992
1993 // @TODO: Mby make this decisions more universal? How?
1994 code_.SetValue("U_GET_TYPE",
1995 EscapeKeyword(field.name + UnionTypeFieldSuffix()));
1996 code_.SetValue(
1997 "U_ELEMENT_TYPE",
1998 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
1999 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2000 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2001 code_.SetValue("U_NULLABLE", NullableExtension());
2002
2003 // `const Type *union_name_asType() const` accessor.
2004 code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
2005 code_ +=
2006 " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
2007 "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
2008 ": nullptr;";
2009 code_ += " }";
2010 }
2011 }
2012
2013 if (opts_.mutable_buffer && !(is_scalar && IsUnion(field.value.type))) {
2014 if (is_scalar) {
2015 const auto type = GenTypeWire(field.value.type, "", false);
2016 code_.SetValue("SET_FN", "SetField<" + type + ">");
2017 code_.SetValue("OFFSET_NAME", offset_str);
2018 code_.SetValue("FIELD_TYPE", GenTypeBasic(field.value.type, true));
2019 code_.SetValue("FIELD_VALUE",
2020 GenUnderlyingCast(field, false, "_" + Name(field)));
2021 code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
2022
2023 code_ +=
2024 " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
2025 "_{{FIELD_NAME}}) {";
2026 code_ +=
2027 " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
2028 "{{DEFAULT_VALUE}});";
2029 code_ += " }";
2030 } else {
2031 auto postptr = " *" + NullableExtension();
2032 auto type =
2033 GenTypeGet(field.value.type, " ", "", postptr.c_str(), true);
2034 auto underlying = accessor + type + ">(" + offset_str + ")";
2035 code_.SetValue("FIELD_TYPE", type);
2036 code_.SetValue("FIELD_VALUE",
2037 GenUnderlyingCast(field, true, underlying));
2038
2039 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
2040 code_ += " return {{FIELD_VALUE}};";
2041 code_ += " }";
2042 }
2043 }
2044
2045 auto nested = field.attributes.Lookup("nested_flatbuffer");
2046 if (nested) {
2047 std::string qualified_name = nested->constant;
2048 auto nested_root = parser_.LookupStruct(nested->constant);
2049 if (nested_root == nullptr) {
2050 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
2051 nested->constant);
2052 nested_root = parser_.LookupStruct(qualified_name);
2053 }
2054 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
2055 (void)nested_root;
2056 code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
2057
2058 code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
2059 code_ +=
2060 " return "
2061 "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());";
2062 code_ += " }";
2063 }
2064
2065 if (field.flexbuffer) {
2066 code_ +=
2067 " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
2068 " const {";
2069 // Both Data() and size() are const-methods, therefore call order
2070 // doesn't matter.
2071 code_ +=
2072 " return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), "
2073 "{{FIELD_NAME}}()->size());";
2074 code_ += " }";
2075 }
2076
2077 // Generate a comparison function for this field if it is a key.
2078 if (field.key) { GenKeyFieldMethods(field); }
2079 }
2080
2081 // Generate a verifier function that can check a buffer from an untrusted
2082 // source will never cause reads outside the buffer.
2083 code_ += " bool Verify(flatbuffers::Verifier &verifier) const {";
2084 code_ += " return VerifyTableStart(verifier)\\";
2085 for (auto it = struct_def.fields.vec.begin();
2086 it != struct_def.fields.vec.end(); ++it) {
2087 const auto &field = **it;
2088 if (field.deprecated) { continue; }
2089 GenVerifyCall(field, " &&\n ");
2090 }
2091
2092 code_ += " &&\n verifier.EndTable();";
2093 code_ += " }";
2094
2095 if (opts_.generate_object_based_api) {
2096 // Generate the UnPack() pre declaration.
2097 code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";";
2098 code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";";
2099 code_ += " " + TablePackSignature(struct_def, true, opts_) + ";";
2100 }
2101
2102 code_ += "};"; // End of table.
2103 code_ += "";
2104
2105 // Explicit specializations for union accessors
2106 for (auto it = struct_def.fields.vec.begin();
2107 it != struct_def.fields.vec.end(); ++it) {
2108 const auto &field = **it;
2109 if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
2110 continue;
2111 }
2112
2113 auto u = field.value.type.enum_def;
2114 if (u->uses_multiple_type_instances) continue;
2115
2116 code_.SetValue("FIELD_NAME", Name(field));
2117
2118 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2119 auto &ev = **u_it;
2120 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
2121
2122 auto full_struct_name = GetUnionElement(ev, true, true);
2123
2124 code_.SetValue(
2125 "U_ELEMENT_TYPE",
2126 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
2127 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2128 code_.SetValue("U_ELEMENT_NAME", full_struct_name);
2129 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2130
2131 // `template<> const T *union_name_as<T>() const` accessor.
2132 code_ +=
2133 "template<> "
2134 "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
2135 "<{{U_ELEMENT_NAME}}>() const {";
2136 code_ += " return {{U_FIELD_NAME}}();";
2137 code_ += "}";
2138 code_ += "";
2139 }
2140 }
2141
2142 GenBuilders(struct_def);
2143
2144 if (opts_.generate_object_based_api) {
2145 // Generate a pre-declaration for a CreateX method that works with an
2146 // unpacked C++ object.
2147 code_ += TableCreateSignature(struct_def, true, opts_) + ";";
2148 code_ += "";
2149 }
2150 }
2151
2152 // Generate code to force vector alignment. Return empty string for vector
2153 // that doesn't need alignment code.
GenVectorForceAlign(const FieldDef & field,const std::string & field_size)2154 std::string GenVectorForceAlign(const FieldDef &field,
2155 const std::string &field_size) {
2156 FLATBUFFERS_ASSERT(field.value.type.base_type == BASE_TYPE_VECTOR);
2157 // Get the value of the force_align attribute.
2158 const auto *force_align = field.attributes.Lookup("force_align");
2159 const int align = force_align ? atoi(force_align->constant.c_str()) : 1;
2160 // Generate code to do force_align for the vector.
2161 if (align > 1) {
2162 const auto vtype = field.value.type.VectorType();
2163 const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def)
2164 : GenTypeWire(vtype, "", false);
2165 return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type +
2166 "), " + std::to_string(static_cast<long long>(align)) + ");";
2167 }
2168 return "";
2169 }
2170
GenBuilders(const StructDef & struct_def)2171 void GenBuilders(const StructDef &struct_def) {
2172 code_.SetValue("STRUCT_NAME", Name(struct_def));
2173
2174 // Generate a builder struct:
2175 code_ += "struct {{STRUCT_NAME}}Builder {";
2176 code_ += " typedef {{STRUCT_NAME}} Table;";
2177 code_ += " flatbuffers::FlatBufferBuilder &fbb_;";
2178 code_ += " flatbuffers::uoffset_t start_;";
2179
2180 bool has_string_or_vector_fields = false;
2181 for (auto it = struct_def.fields.vec.begin();
2182 it != struct_def.fields.vec.end(); ++it) {
2183 const auto &field = **it;
2184 if (!field.deprecated) {
2185 const bool is_scalar = IsScalar(field.value.type.base_type);
2186 const bool is_string = field.value.type.base_type == BASE_TYPE_STRING;
2187 const bool is_vector = field.value.type.base_type == BASE_TYPE_VECTOR;
2188 if (is_string || is_vector) { has_string_or_vector_fields = true; }
2189
2190 std::string offset = GenFieldOffsetName(field);
2191 std::string name = GenUnderlyingCast(field, false, Name(field));
2192 std::string value = is_scalar ? GenDefaultConstant(field) : "";
2193
2194 // Generate accessor functions of the form:
2195 // void add_name(type name) {
2196 // fbb_.AddElement<type>(offset, name, default);
2197 // }
2198 code_.SetValue("FIELD_NAME", Name(field));
2199 code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
2200 code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
2201 code_.SetValue("ADD_NAME", name);
2202 code_.SetValue("ADD_VALUE", value);
2203 if (is_scalar) {
2204 const auto type = GenTypeWire(field.value.type, "", false);
2205 code_.SetValue("ADD_FN", "AddElement<" + type + ">");
2206 } else if (IsStruct(field.value.type)) {
2207 code_.SetValue("ADD_FN", "AddStruct");
2208 } else {
2209 code_.SetValue("ADD_FN", "AddOffset");
2210 }
2211
2212 code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
2213 code_ += " fbb_.{{ADD_FN}}(\\";
2214 if (is_scalar) {
2215 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
2216 } else {
2217 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
2218 }
2219 code_ += " }";
2220 }
2221 }
2222
2223 // Builder constructor
2224 code_ +=
2225 " explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder "
2226 "&_fbb)";
2227 code_ += " : fbb_(_fbb) {";
2228 code_ += " start_ = fbb_.StartTable();";
2229 code_ += " }";
2230
2231 // Assignment operator;
2232 code_ +=
2233 " {{STRUCT_NAME}}Builder &operator="
2234 "(const {{STRUCT_NAME}}Builder &);";
2235
2236 // Finish() function.
2237 code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
2238 code_ += " const auto end = fbb_.EndTable(start_);";
2239 code_ += " auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
2240
2241 for (auto it = struct_def.fields.vec.begin();
2242 it != struct_def.fields.vec.end(); ++it) {
2243 const auto &field = **it;
2244 if (!field.deprecated && field.required) {
2245 code_.SetValue("FIELD_NAME", Name(field));
2246 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2247 code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
2248 }
2249 }
2250 code_ += " return o;";
2251 code_ += " }";
2252 code_ += "};";
2253 code_ += "";
2254
2255 // Generate a convenient CreateX function that uses the above builder
2256 // to create a table in one go.
2257 code_ +=
2258 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2259 "Create{{STRUCT_NAME}}(";
2260 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2261 for (auto it = struct_def.fields.vec.begin();
2262 it != struct_def.fields.vec.end(); ++it) {
2263 const auto &field = **it;
2264 if (!field.deprecated) { GenParam(field, false, ",\n "); }
2265 }
2266 code_ += ") {";
2267
2268 code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);";
2269 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
2270 size; size /= 2) {
2271 for (auto it = struct_def.fields.vec.rbegin();
2272 it != struct_def.fields.vec.rend(); ++it) {
2273 const auto &field = **it;
2274 if (!field.deprecated && (!struct_def.sortbysize ||
2275 size == SizeOf(field.value.type.base_type))) {
2276 code_.SetValue("FIELD_NAME", Name(field));
2277 code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
2278 }
2279 }
2280 }
2281 code_ += " return builder_.Finish();";
2282 code_ += "}";
2283 code_ += "";
2284
2285 // Definition for type traits for this table type. This allows querying var-
2286 // ious compile-time traits of the table.
2287 if (opts_.g_cpp_std >= cpp::CPP_STD_17) {
2288 code_ += "struct {{STRUCT_NAME}}::Traits {";
2289 code_ += " using type = {{STRUCT_NAME}};";
2290 code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
2291 code_ += "};";
2292 code_ += "";
2293 }
2294
2295 // Generate a CreateXDirect function with vector types as parameters
2296 if (has_string_or_vector_fields) {
2297 code_ +=
2298 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2299 "Create{{STRUCT_NAME}}Direct(";
2300 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2301 for (auto it = struct_def.fields.vec.begin();
2302 it != struct_def.fields.vec.end(); ++it) {
2303 const auto &field = **it;
2304 if (!field.deprecated) { GenParam(field, true, ",\n "); }
2305 }
2306 // Need to call "Create" with the struct namespace.
2307 const auto qualified_create_name =
2308 struct_def.defined_namespace->GetFullyQualifiedName("Create");
2309 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2310 code_ += ") {";
2311 for (auto it = struct_def.fields.vec.begin();
2312 it != struct_def.fields.vec.end(); ++it) {
2313 const auto &field = **it;
2314 if (!field.deprecated) {
2315 code_.SetValue("FIELD_NAME", Name(field));
2316 if (field.value.type.base_type == BASE_TYPE_STRING) {
2317 if (!field.shared) {
2318 code_.SetValue("CREATE_STRING", "CreateString");
2319 } else {
2320 code_.SetValue("CREATE_STRING", "CreateSharedString");
2321 }
2322 code_ +=
2323 " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
2324 "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
2325 } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
2326 const std::string force_align_code =
2327 GenVectorForceAlign(field, Name(field) + "->size()");
2328 if (!force_align_code.empty()) {
2329 code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }";
2330 }
2331 code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
2332 const auto vtype = field.value.type.VectorType();
2333 const auto has_key = TypeHasKey(vtype);
2334 if (IsStruct(vtype)) {
2335 const auto type = WrapInNameSpace(*vtype.struct_def);
2336 code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<"
2337 : "_fbb.CreateVectorOfStructs<") +
2338 type + ">\\";
2339 } else if (has_key) {
2340 const auto type = WrapInNameSpace(*vtype.struct_def);
2341 code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\";
2342 } else {
2343 const auto type =
2344 GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
2345 code_ += "_fbb.CreateVector<" + type + ">\\";
2346 }
2347 code_ +=
2348 has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;";
2349 }
2350 }
2351 }
2352 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2353 code_ += " _fbb\\";
2354 for (auto it = struct_def.fields.vec.begin();
2355 it != struct_def.fields.vec.end(); ++it) {
2356 const auto &field = **it;
2357 if (!field.deprecated) {
2358 code_.SetValue("FIELD_NAME", Name(field));
2359 code_ += ",\n {{FIELD_NAME}}\\";
2360 if (field.value.type.base_type == BASE_TYPE_STRING ||
2361 field.value.type.base_type == BASE_TYPE_VECTOR) {
2362 code_ += "__\\";
2363 }
2364 }
2365 }
2366 code_ += ");";
2367 code_ += "}";
2368 code_ += "";
2369 }
2370 }
2371
GenUnionUnpackVal(const FieldDef & afield,const char * vec_elem_access,const char * vec_type_access)2372 std::string GenUnionUnpackVal(const FieldDef &afield,
2373 const char *vec_elem_access,
2374 const char *vec_type_access) {
2375 auto type_name = WrapInNameSpace(*afield.value.type.enum_def);
2376 return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " +
2377 EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
2378 vec_type_access + ", _resolver)";
2379 }
2380
GenUnpackVal(const Type & type,const std::string & val,bool invector,const FieldDef & afield)2381 std::string GenUnpackVal(const Type &type, const std::string &val,
2382 bool invector, const FieldDef &afield) {
2383 switch (type.base_type) {
2384 case BASE_TYPE_STRING: {
2385 if (FlexibleStringConstructor(&afield)) {
2386 return NativeString(&afield) + "(" + val + "->c_str(), " + val +
2387 "->size())";
2388 } else {
2389 return val + "->str()";
2390 }
2391 }
2392 case BASE_TYPE_STRUCT: {
2393 const auto name = WrapInNameSpace(*type.struct_def);
2394 if (IsStruct(type)) {
2395 auto native_type = type.struct_def->attributes.Lookup("native_type");
2396 if (native_type) {
2397 return "flatbuffers::UnPack(*" + val + ")";
2398 } else if (invector || afield.native_inline) {
2399 return "*" + val;
2400 } else {
2401 const auto ptype = GenTypeNativePtr(name, &afield, true);
2402 return ptype + "(new " + name + "(*" + val + "))";
2403 }
2404 } else {
2405 const auto ptype = GenTypeNativePtr(
2406 NativeName(name, type.struct_def, opts_), &afield, true);
2407 return ptype + "(" + val + "->UnPack(_resolver))";
2408 }
2409 }
2410 case BASE_TYPE_UNION: {
2411 return GenUnionUnpackVal(
2412 afield, invector ? "->Get(_i)" : "",
2413 invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
2414 : "");
2415 }
2416 default: {
2417 return val;
2418 break;
2419 }
2420 }
2421 }
2422
GenUnpackFieldStatement(const FieldDef & field,const FieldDef * union_field)2423 std::string GenUnpackFieldStatement(const FieldDef &field,
2424 const FieldDef *union_field) {
2425 std::string code;
2426 switch (field.value.type.base_type) {
2427 case BASE_TYPE_VECTOR: {
2428 auto cpp_type = field.attributes.Lookup("cpp_type");
2429 std::string indexing;
2430 if (field.value.type.enum_def) {
2431 indexing += "static_cast<" +
2432 WrapInNameSpace(*field.value.type.enum_def) + ">(";
2433 }
2434 indexing += "_e->Get(_i)";
2435 if (field.value.type.enum_def) { indexing += ")"; }
2436 if (field.value.type.element == BASE_TYPE_BOOL) { indexing += " != 0"; }
2437
2438 // Generate code that pushes data from _e to _o in the form:
2439 // for (uoffset_t i = 0; i < _e->size(); ++i) {
2440 // _o->field.push_back(_e->Get(_i));
2441 // }
2442 auto name = Name(field);
2443 if (field.value.type.element == BASE_TYPE_UTYPE) {
2444 name = StripUnionType(Name(field));
2445 }
2446 auto access =
2447 field.value.type.element == BASE_TYPE_UTYPE
2448 ? ".type"
2449 : (field.value.type.element == BASE_TYPE_UNION ? ".value" : "");
2450 code += "{ _o->" + name + ".resize(_e->size()); ";
2451 code += "for (flatbuffers::uoffset_t _i = 0;";
2452 code += " _i < _e->size(); _i++) { ";
2453 if (cpp_type) {
2454 // Generate code that resolves the cpp pointer type, of the form:
2455 // if (resolver)
2456 // (*resolver)(&_o->field, (hash_value_t)(_e));
2457 // else
2458 // _o->field = nullptr;
2459 code += "//vector resolver, " + PtrType(&field) + "\n";
2460 code += "if (_resolver) ";
2461 code += "(*_resolver)";
2462 code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" + access +
2463 "), ";
2464 code += "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
2465 if (PtrType(&field) == "naked") {
2466 code += " else ";
2467 code += "_o->" + name + "[_i]" + access + " = nullptr";
2468 } else {
2469 // code += " else ";
2470 // code += "_o->" + name + "[_i]" + access + " = " +
2471 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2472 code += "/* else do nothing */";
2473 }
2474 } else {
2475 code += "_o->" + name + "[_i]" + access + " = ";
2476 code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
2477 field);
2478 }
2479 code += "; } }";
2480 break;
2481 }
2482 case BASE_TYPE_UTYPE: {
2483 FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
2484 BASE_TYPE_UNION);
2485 // Generate code that sets the union type, of the form:
2486 // _o->field.type = _e;
2487 code += "_o->" + union_field->name + ".type = _e;";
2488 break;
2489 }
2490 case BASE_TYPE_UNION: {
2491 // Generate code that sets the union value, of the form:
2492 // _o->field.value = Union::Unpack(_e, field_type(), resolver);
2493 code += "_o->" + Name(field) + ".value = ";
2494 code += GenUnionUnpackVal(field, "", "");
2495 code += ";";
2496 break;
2497 }
2498 default: {
2499 auto cpp_type = field.attributes.Lookup("cpp_type");
2500 if (cpp_type) {
2501 // Generate code that resolves the cpp pointer type, of the form:
2502 // if (resolver)
2503 // (*resolver)(&_o->field, (hash_value_t)(_e));
2504 // else
2505 // _o->field = nullptr;
2506 code += "//scalar resolver, " + PtrType(&field) + " \n";
2507 code += "if (_resolver) ";
2508 code += "(*_resolver)";
2509 code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
2510 code += "static_cast<flatbuffers::hash_value_t>(_e));";
2511 if (PtrType(&field) == "naked") {
2512 code += " else ";
2513 code += "_o->" + Name(field) + " = nullptr;";
2514 } else {
2515 // code += " else ";
2516 // code += "_o->" + Name(field) + " = " +
2517 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2518 code += "/* else do nothing */;";
2519 }
2520 } else {
2521 // Generate code for assigning the value, of the form:
2522 // _o->field = value;
2523 code += "_o->" + Name(field) + " = ";
2524 code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
2525 }
2526 break;
2527 }
2528 }
2529 return code;
2530 }
2531
GenCreateParam(const FieldDef & field)2532 std::string GenCreateParam(const FieldDef &field) {
2533 std::string value = "_o->";
2534 if (field.value.type.base_type == BASE_TYPE_UTYPE) {
2535 value += StripUnionType(Name(field));
2536 value += ".type";
2537 } else {
2538 value += Name(field);
2539 }
2540 if (field.value.type.base_type != BASE_TYPE_VECTOR &&
2541 field.attributes.Lookup("cpp_type")) {
2542 auto type = GenTypeBasic(field.value.type, false);
2543 value =
2544 "_rehasher ? "
2545 "static_cast<" +
2546 type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
2547 }
2548
2549 std::string code;
2550 switch (field.value.type.base_type) {
2551 // String fields are of the form:
2552 // _fbb.CreateString(_o->field)
2553 // or
2554 // _fbb.CreateSharedString(_o->field)
2555 case BASE_TYPE_STRING: {
2556 if (!field.shared) {
2557 code += "_fbb.CreateString(";
2558 } else {
2559 code += "_fbb.CreateSharedString(";
2560 }
2561 code += value;
2562 code.push_back(')');
2563
2564 // For optional fields, check to see if there actually is any data
2565 // in _o->field before attempting to access it. If there isn't,
2566 // depending on set_empty_strings_to_null either set it to 0 or an empty
2567 // string.
2568 if (!field.required) {
2569 auto empty_value = opts_.set_empty_strings_to_null
2570 ? "0"
2571 : "_fbb.CreateSharedString(\"\")";
2572 code = value + ".empty() ? " + empty_value + " : " + code;
2573 }
2574 break;
2575 }
2576 // Vector fields come in several flavours, of the forms:
2577 // _fbb.CreateVector(_o->field);
2578 // _fbb.CreateVector((const utype*)_o->field.data(),
2579 // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field)
2580 // _fbb.CreateVectorOfStructs(_o->field)
2581 // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
2582 // return CreateT(_fbb, _o->Get(i), rehasher);
2583 // });
2584 case BASE_TYPE_VECTOR: {
2585 auto vector_type = field.value.type.VectorType();
2586 switch (vector_type.base_type) {
2587 case BASE_TYPE_STRING: {
2588 if (NativeString(&field) == "std::string") {
2589 code += "_fbb.CreateVectorOfStrings(" + value + ")";
2590 } else {
2591 // Use by-function serialization to emulate
2592 // CreateVectorOfStrings(); this works also with non-std strings.
2593 code +=
2594 "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>"
2595 " ";
2596 code += "(" + value + ".size(), ";
2597 code += "[](size_t i, _VectorArgs *__va) { ";
2598 code +=
2599 "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
2600 code += " }, &_va )";
2601 }
2602 break;
2603 }
2604 case BASE_TYPE_STRUCT: {
2605 if (IsStruct(vector_type)) {
2606 auto native_type =
2607 field.value.type.struct_def->attributes.Lookup("native_type");
2608 if (native_type) {
2609 code += "_fbb.CreateVectorOfNativeStructs<";
2610 code += WrapInNameSpace(*vector_type.struct_def) + ">";
2611 } else {
2612 code += "_fbb.CreateVectorOfStructs";
2613 }
2614 code += "(" + value + ")";
2615 } else {
2616 code += "_fbb.CreateVector<flatbuffers::Offset<";
2617 code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
2618 code += "(" + value + ".size(), ";
2619 code += "[](size_t i, _VectorArgs *__va) { ";
2620 code += "return Create" + vector_type.struct_def->name;
2621 code += "(*__va->__fbb, __va->_" + value + "[i]" +
2622 GenPtrGet(field) + ", ";
2623 code += "__va->__rehasher); }, &_va )";
2624 }
2625 break;
2626 }
2627 case BASE_TYPE_BOOL: {
2628 code += "_fbb.CreateVector(" + value + ")";
2629 break;
2630 }
2631 case BASE_TYPE_UNION: {
2632 code +=
2633 "_fbb.CreateVector<flatbuffers::"
2634 "Offset<void>>(" +
2635 value +
2636 ".size(), [](size_t i, _VectorArgs *__va) { "
2637 "return __va->_" +
2638 value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
2639 break;
2640 }
2641 case BASE_TYPE_UTYPE: {
2642 value = StripUnionType(value);
2643 code += "_fbb.CreateVector<uint8_t>(" + value +
2644 ".size(), [](size_t i, _VectorArgs *__va) { "
2645 "return static_cast<uint8_t>(__va->_" +
2646 value + "[i].type); }, &_va)";
2647 break;
2648 }
2649 default: {
2650 if (field.value.type.enum_def &&
2651 !VectorElementUserFacing(vector_type)) {
2652 // For enumerations, we need to get access to the array data for
2653 // the underlying storage type (eg. uint8_t).
2654 const auto basetype = GenTypeBasic(
2655 field.value.type.enum_def->underlying_type, false);
2656 code += "_fbb.CreateVectorScalarCast<" + basetype +
2657 ">(flatbuffers::data(" + value + "), " + value +
2658 ".size())";
2659 } else if (field.attributes.Lookup("cpp_type")) {
2660 auto type = GenTypeBasic(vector_type, false);
2661 code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
2662 code += "[](size_t i, _VectorArgs *__va) { ";
2663 code += "return __va->__rehasher ? ";
2664 code += "static_cast<" + type + ">((*__va->__rehasher)";
2665 code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
2666 code += "; }, &_va )";
2667 } else {
2668 code += "_fbb.CreateVector(" + value + ")";
2669 }
2670 break;
2671 }
2672 }
2673
2674 // If set_empty_vectors_to_null option is enabled, for optional fields,
2675 // check to see if there actually is any data in _o->field before
2676 // attempting to access it.
2677 if (opts_.set_empty_vectors_to_null && !field.required) {
2678 code = value + ".size() ? " + code + " : 0";
2679 }
2680 break;
2681 }
2682 case BASE_TYPE_UNION: {
2683 // _o->field.Pack(_fbb);
2684 code += value + ".Pack(_fbb)";
2685 break;
2686 }
2687 case BASE_TYPE_STRUCT: {
2688 if (IsStruct(field.value.type)) {
2689 auto native_type =
2690 field.value.type.struct_def->attributes.Lookup("native_type");
2691 if (native_type) {
2692 code += "flatbuffers::Pack(" + value + ")";
2693 } else if (field.native_inline) {
2694 code += "&" + value;
2695 } else {
2696 code += value + " ? " + value + GenPtrGet(field) + " : 0";
2697 }
2698 } else {
2699 // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
2700 const auto type = field.value.type.struct_def->name;
2701 code += value + " ? Create" + type;
2702 code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
2703 code += " : 0";
2704 }
2705 break;
2706 }
2707 default: {
2708 code += value;
2709 break;
2710 }
2711 }
2712 return code;
2713 }
2714
2715 // Generate code for tables that needs to come after the regular definition.
GenTablePost(const StructDef & struct_def)2716 void GenTablePost(const StructDef &struct_def) {
2717 code_.SetValue("STRUCT_NAME", Name(struct_def));
2718 code_.SetValue("NATIVE_NAME",
2719 NativeName(Name(struct_def), &struct_def, opts_));
2720 auto native_name =
2721 NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts);
2722 code_.SetValue("POINTER_TYPE",
2723 GenTypeNativePtr(native_name, nullptr, false));
2724
2725 if (opts_.generate_object_based_api) {
2726 // Generate the X::UnPack() method.
2727 code_ +=
2728 "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
2729
2730 code_ +=
2731 " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
2732 code_ += " UnPackTo(_o.get(), _resolver);";
2733 code_ += " return _o.release();";
2734
2735 code_ += "}";
2736 code_ += "";
2737
2738 code_ +=
2739 "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
2740 code_ += " (void)_o;";
2741 code_ += " (void)_resolver;";
2742
2743 for (auto it = struct_def.fields.vec.begin();
2744 it != struct_def.fields.vec.end(); ++it) {
2745 const auto &field = **it;
2746 if (field.deprecated) { continue; }
2747
2748 // Assign a value from |this| to |_o|. Values from |this| are stored
2749 // in a variable |_e| by calling this->field_type(). The value is then
2750 // assigned to |_o| using the GenUnpackFieldStatement.
2751 const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
2752 const auto statement =
2753 GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
2754
2755 code_.SetValue("FIELD_NAME", Name(field));
2756 auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
2757 auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
2758 auto postfix = " }";
2759 code_ += std::string(prefix) + check + statement + postfix;
2760 }
2761 code_ += "}";
2762 code_ += "";
2763
2764 // Generate the X::Pack member function that simply calls the global
2765 // CreateX function.
2766 code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
2767 code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
2768 code_ += "}";
2769 code_ += "";
2770
2771 // Generate a CreateX method that works with an unpacked C++ object.
2772 code_ +=
2773 "inline " + TableCreateSignature(struct_def, false, opts_) + " {";
2774 code_ += " (void)_rehasher;";
2775 code_ += " (void)_o;";
2776
2777 code_ +=
2778 " struct _VectorArgs "
2779 "{ flatbuffers::FlatBufferBuilder *__fbb; "
2780 "const " +
2781 NativeName(Name(struct_def), &struct_def, opts_) +
2782 "* __o; "
2783 "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
2784 "&_fbb, _o, _rehasher}; (void)_va;";
2785
2786 for (auto it = struct_def.fields.vec.begin();
2787 it != struct_def.fields.vec.end(); ++it) {
2788 auto &field = **it;
2789 if (field.deprecated) { continue; }
2790 if (field.value.type.base_type == BASE_TYPE_VECTOR) {
2791 const std::string force_align_code =
2792 GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
2793 if (!force_align_code.empty()) { code_ += " " + force_align_code; }
2794 }
2795 code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
2796 }
2797 // Need to call "Create" with the struct namespace.
2798 const auto qualified_create_name =
2799 struct_def.defined_namespace->GetFullyQualifiedName("Create");
2800 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2801
2802 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2803 code_ += " _fbb\\";
2804 for (auto it = struct_def.fields.vec.begin();
2805 it != struct_def.fields.vec.end(); ++it) {
2806 auto &field = **it;
2807 if (field.deprecated) { continue; }
2808
2809 bool pass_by_address = false;
2810 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
2811 if (IsStruct(field.value.type)) {
2812 auto native_type =
2813 field.value.type.struct_def->attributes.Lookup("native_type");
2814 if (native_type) { pass_by_address = true; }
2815 }
2816 }
2817
2818 // Call the CreateX function using values from |_o|.
2819 if (pass_by_address) {
2820 code_ += ",\n &_" + Name(field) + "\\";
2821 } else {
2822 code_ += ",\n _" + Name(field) + "\\";
2823 }
2824 }
2825 code_ += ");";
2826 code_ += "}";
2827 code_ += "";
2828 }
2829 }
2830
GenPadding(const FieldDef & field,std::string * code_ptr,int * id,const std::function<void (int bits,std::string * code_ptr,int * id)> & f)2831 static void GenPadding(
2832 const FieldDef &field, std::string *code_ptr, int *id,
2833 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
2834 if (field.padding) {
2835 for (int i = 0; i < 4; i++) {
2836 if (static_cast<int>(field.padding) & (1 << i)) {
2837 f((1 << i) * 8, code_ptr, id);
2838 }
2839 }
2840 FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
2841 }
2842 }
2843
PaddingDefinition(int bits,std::string * code_ptr,int * id)2844 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
2845 *code_ptr += " int" + NumToString(bits) + "_t padding" +
2846 NumToString((*id)++) + "__;";
2847 }
2848
PaddingInitializer(int bits,std::string * code_ptr,int * id)2849 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
2850 (void)bits;
2851 if (*code_ptr != "") *code_ptr += ",\n ";
2852 *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
2853 }
2854
PaddingNoop(int bits,std::string * code_ptr,int * id)2855 static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
2856 (void)bits;
2857 *code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
2858 }
2859
2860 // Generate an accessor struct with constructor for a flatbuffers struct.
GenStruct(const StructDef & struct_def)2861 void GenStruct(const StructDef &struct_def) {
2862 // Generate an accessor struct, with private variables of the form:
2863 // type name_;
2864 // Generates manual padding and alignment.
2865 // Variables are private because they contain little endian data on all
2866 // platforms.
2867 GenComment(struct_def.doc_comment);
2868 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
2869 code_.SetValue("STRUCT_NAME", Name(struct_def));
2870
2871 code_ +=
2872 "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
2873 "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
2874 code_ += " private:";
2875
2876 int padding_id = 0;
2877 for (auto it = struct_def.fields.vec.begin();
2878 it != struct_def.fields.vec.end(); ++it) {
2879 const auto &field = **it;
2880 const auto &field_type = field.value.type;
2881 code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
2882 code_.SetValue("FIELD_NAME", Name(field));
2883 code_.SetValue("ARRAY",
2884 IsArray(field_type)
2885 ? "[" + NumToString(field_type.fixed_length) + "]"
2886 : "");
2887 code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
2888
2889 if (field.padding) {
2890 std::string padding;
2891 GenPadding(field, &padding, &padding_id, PaddingDefinition);
2892 code_ += padding;
2893 }
2894 }
2895
2896 // Generate GetFullyQualifiedName
2897 code_ += "";
2898 code_ += " public:";
2899
2900 // Make TypeTable accessible via the generated struct.
2901 if (opts_.mini_reflect != IDLOptions::kNone) {
2902 code_ +=
2903 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
2904 code_ += " return {{STRUCT_NAME}}TypeTable();";
2905 code_ += " }";
2906 }
2907
2908 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
2909
2910 // Generate a default constructor.
2911 code_ += " {{STRUCT_NAME}}() {";
2912 code_ +=
2913 " memset(static_cast<void *>(this), 0, sizeof({{STRUCT_NAME}}));";
2914 code_ += " }";
2915
2916 // Generate a constructor that takes all fields as arguments,
2917 // excluding arrays
2918 std::string arg_list;
2919 std::string init_list;
2920 padding_id = 0;
2921 auto first = struct_def.fields.vec.begin();
2922 for (auto it = struct_def.fields.vec.begin();
2923 it != struct_def.fields.vec.end(); ++it) {
2924 const auto &field = **it;
2925 if (IsArray(field.value.type)) {
2926 first++;
2927 continue;
2928 }
2929 const auto member_name = Name(field) + "_";
2930 const auto arg_name = "_" + Name(field);
2931 const auto arg_type =
2932 GenTypeGet(field.value.type, " ", "const ", " &", true);
2933
2934 if (it != first) { arg_list += ", "; }
2935 arg_list += arg_type;
2936 arg_list += arg_name;
2937 if (!IsArray(field.value.type)) {
2938 if (it != first && init_list != "") { init_list += ",\n "; }
2939 init_list += member_name;
2940 if (IsScalar(field.value.type.base_type)) {
2941 auto type = GenUnderlyingCast(field, false, arg_name);
2942 init_list += "(flatbuffers::EndianScalar(" + type + "))";
2943 } else {
2944 init_list += "(" + arg_name + ")";
2945 }
2946 }
2947 if (field.padding) {
2948 GenPadding(field, &init_list, &padding_id, PaddingInitializer);
2949 }
2950 }
2951
2952 if (!arg_list.empty()) {
2953 code_.SetValue("ARG_LIST", arg_list);
2954 code_.SetValue("INIT_LIST", init_list);
2955 if (!init_list.empty()) {
2956 code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
2957 code_ += " : {{INIT_LIST}} {";
2958 } else {
2959 code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
2960 }
2961 padding_id = 0;
2962 for (auto it = struct_def.fields.vec.begin();
2963 it != struct_def.fields.vec.end(); ++it) {
2964 const auto &field = **it;
2965 if (IsArray(field.value.type)) {
2966 const auto &member = Name(field) + "_";
2967 code_ +=
2968 " std::memset(" + member + ", 0, sizeof(" + member + "));";
2969 }
2970 if (field.padding) {
2971 std::string padding;
2972 GenPadding(field, &padding, &padding_id, PaddingNoop);
2973 code_ += padding;
2974 }
2975 }
2976 code_ += " }";
2977 }
2978
2979 // Generate accessor methods of the form:
2980 // type name() const { return flatbuffers::EndianScalar(name_); }
2981 for (auto it = struct_def.fields.vec.begin();
2982 it != struct_def.fields.vec.end(); ++it) {
2983 const auto &field = **it;
2984
2985 auto field_type = GenTypeGet(field.value.type, " ",
2986 IsArray(field.value.type) ? "" : "const ",
2987 IsArray(field.value.type) ? "" : " &", true);
2988 auto is_scalar = IsScalar(field.value.type.base_type);
2989 auto member = Name(field) + "_";
2990 auto value =
2991 is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
2992
2993 code_.SetValue("FIELD_NAME", Name(field));
2994 code_.SetValue("FIELD_TYPE", field_type);
2995 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
2996
2997 GenComment(field.doc_comment, " ");
2998
2999 // Generate a const accessor function.
3000 if (IsArray(field.value.type)) {
3001 auto underlying = GenTypeGet(field.value.type, "", "", "", false);
3002 code_ += " const flatbuffers::Array<" + field_type + ", " +
3003 NumToString(field.value.type.fixed_length) + "> *" +
3004 "{{FIELD_NAME}}() const {";
3005 code_ += " return reinterpret_cast<const flatbuffers::Array<" +
3006 field_type + ", " +
3007 NumToString(field.value.type.fixed_length) +
3008 "> *>({{FIELD_VALUE}});";
3009 code_ += " }";
3010 } else {
3011 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
3012 code_ += " return {{FIELD_VALUE}};";
3013 code_ += " }";
3014 }
3015
3016 // Generate a mutable accessor function.
3017 if (opts_.mutable_buffer) {
3018 auto mut_field_type =
3019 GenTypeGet(field.value.type, " ", "",
3020 IsArray(field.value.type) ? "" : " &", true);
3021 code_.SetValue("FIELD_TYPE", mut_field_type);
3022 if (is_scalar) {
3023 code_.SetValue("ARG", GenTypeBasic(field.value.type, true));
3024 code_.SetValue("FIELD_VALUE",
3025 GenUnderlyingCast(field, false, "_" + Name(field)));
3026
3027 code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
3028 code_ +=
3029 " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
3030 "{{FIELD_VALUE}});";
3031 code_ += " }";
3032 } else if (IsArray(field.value.type)) {
3033 auto underlying = GenTypeGet(field.value.type, "", "", "", false);
3034 code_ += " flatbuffers::Array<" + mut_field_type + ", " +
3035 NumToString(field.value.type.fixed_length) + "> *" +
3036 "mutable_{{FIELD_NAME}}() {";
3037 code_ += " return reinterpret_cast<flatbuffers::Array<" +
3038 mut_field_type + ", " +
3039 NumToString(field.value.type.fixed_length) +
3040 "> *>({{FIELD_VALUE}});";
3041 code_ += " }";
3042 } else {
3043 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
3044 code_ += " return {{FIELD_VALUE}};";
3045 code_ += " }";
3046 }
3047 }
3048
3049 // Generate a comparison function for this field if it is a key.
3050 if (field.key) { GenKeyFieldMethods(field); }
3051 }
3052 code_.SetValue("NATIVE_NAME", Name(struct_def));
3053 GenOperatorNewDelete(struct_def);
3054 code_ += "};";
3055
3056 code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
3057 code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
3058 if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
3059 code_ += "";
3060 }
3061
3062 // Set up the correct namespace. Only open a namespace if the existing one is
3063 // different (closing/opening only what is necessary).
3064 //
3065 // The file must start and end with an empty (or null) namespace so that
3066 // namespaces are properly opened and closed.
SetNameSpace(const Namespace * ns)3067 void SetNameSpace(const Namespace *ns) {
3068 if (cur_name_space_ == ns) { return; }
3069
3070 // Compute the size of the longest common namespace prefix.
3071 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
3072 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
3073 // and common_prefix_size = 2
3074 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
3075 size_t new_size = ns ? ns->components.size() : 0;
3076
3077 size_t common_prefix_size = 0;
3078 while (common_prefix_size < old_size && common_prefix_size < new_size &&
3079 ns->components[common_prefix_size] ==
3080 cur_name_space_->components[common_prefix_size]) {
3081 common_prefix_size++;
3082 }
3083
3084 // Close cur_name_space in reverse order to reach the common prefix.
3085 // In the previous example, D then C are closed.
3086 for (size_t j = old_size; j > common_prefix_size; --j) {
3087 code_ += "} // namespace " + cur_name_space_->components[j - 1];
3088 }
3089 if (old_size != common_prefix_size) { code_ += ""; }
3090
3091 // open namespace parts to reach the ns namespace
3092 // in the previous example, E, then F, then G are opened
3093 for (auto j = common_prefix_size; j != new_size; ++j) {
3094 code_ += "namespace " + ns->components[j] + " {";
3095 }
3096 if (new_size != common_prefix_size) { code_ += ""; }
3097
3098 cur_name_space_ = ns;
3099 }
3100 };
3101
3102 } // namespace cpp
3103
GenerateCPP(const Parser & parser,const std::string & path,const std::string & file_name)3104 bool GenerateCPP(const Parser &parser, const std::string &path,
3105 const std::string &file_name) {
3106 cpp::IDLOptionsCpp opts(parser.opts);
3107 // The '--cpp_std' argument could be extended (like ASAN):
3108 // Example: "flatc --cpp_std c++17:option1:option2".
3109 auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++0X";
3110 std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), ToUpper);
3111 if (cpp_std == "C++0X") {
3112 opts.g_cpp_std = cpp::CPP_STD_X0;
3113 opts.g_only_fixed_enums = false;
3114 } else if (cpp_std == "C++11") {
3115 // Use the standard C++11 code generator.
3116 opts.g_cpp_std = cpp::CPP_STD_11;
3117 opts.g_only_fixed_enums = true;
3118 } else if (cpp_std == "C++17") {
3119 opts.g_cpp_std = cpp::CPP_STD_17;
3120 // With c++17 generate strong enums only.
3121 opts.scoped_enums = true;
3122 // By default, prefixed_enums==true, reset it.
3123 opts.prefixed_enums = false;
3124 } else {
3125 LogCompilerError("Unknown value of the '--cpp-std' switch: " +
3126 opts.cpp_std);
3127 return false;
3128 }
3129 // The opts.scoped_enums has priority.
3130 opts.g_only_fixed_enums |= opts.scoped_enums;
3131
3132 cpp::CppGenerator generator(parser, path, file_name, opts);
3133 return generator.generate();
3134 }
3135
CPPMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)3136 std::string CPPMakeRule(const Parser &parser, const std::string &path,
3137 const std::string &file_name) {
3138 const auto filebase =
3139 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
3140 cpp::CppGenerator geneartor(parser, path, file_name, parser.opts);
3141 const auto included_files = parser.GetIncludedFilesRecursive(file_name);
3142 std::string make_rule =
3143 geneartor.GeneratedFileName(path, filebase, parser.opts) + ": ";
3144 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
3145 make_rule += " " + *it;
3146 }
3147 return make_rule;
3148 }
3149
3150 } // namespace flatbuffers
3151