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