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