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