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