2 * Copyright 2014 Google Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 // independent from idl_parser, since this code is not needed for most clients
19 #include <unordered_set>
21 #include "flatbuffers/code_generators.h"
22 #include "flatbuffers/flatbuffers.h"
23 #include "flatbuffers/flatc.h"
24 #include "flatbuffers/idl.h"
25 #include "flatbuffers/util.h"
27 namespace flatbuffers {
29 // Make numerical literal with type-suffix.
30 // This function is only needed for C++! Other languages do not need it.
31 static inline std::string NumToStringCpp(std::string val, BaseType type) {
32 // Avoid issues with -2147483648, -9223372036854775808.
35 return (val != "-2147483648") ? val : ("(-2147483647 - 1)");
36 case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL");
38 if (val == "-9223372036854775808")
39 return "(-9223372036854775807LL - 1LL)";
41 return (val == "0") ? val : (val + "LL");
46 static std::string GenIncludeGuard(const std::string &file_name,
47 const Namespace &name_space,
48 const std::string &postfix = "") {
49 // Generate include guard.
50 std::string guard = file_name;
51 // Remove any non-alpha-numeric characters that may appear in a filename.
53 bool operator()(char c) const { return !is_alnum(c); }
55 guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
57 guard = "FLATBUFFERS_GENERATED_" + guard;
59 // For further uniqueness, also add the namespace.
60 for (auto it = name_space.components.begin();
61 it != name_space.components.end(); ++it) {
64 // Anything extra to add to the guard?
65 if (!postfix.empty()) { guard += postfix + "_"; }
67 std::transform(guard.begin(), guard.end(), guard.begin(), CharToUpper);
73 enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
75 // Define a style of 'struct' constructor if it has 'Array' fields.
76 enum GenArrayArgMode {
77 kArrayArgModeNone, // don't generate initialization args
78 kArrayArgModeSpanStatic, // generate flatbuffers::span<T,N>
81 // Extension of IDLOptions for cpp-generator.
82 struct IDLOptionsCpp : public IDLOptions {
83 // All fields start with 'g_' prefix to distinguish from the base IDLOptions.
84 CppStandard g_cpp_std; // Base version of C++ standard.
85 bool g_only_fixed_enums; // Generate underlaying type for all enums.
87 IDLOptionsCpp(const IDLOptions &opts)
88 : IDLOptions(opts), g_cpp_std(CPP_STD_11), g_only_fixed_enums(true) {}
91 class CppGenerator : public BaseGenerator {
93 CppGenerator(const Parser &parser, const std::string &path,
94 const std::string &file_name, IDLOptionsCpp opts)
95 : BaseGenerator(parser, path, file_name, "", "::", "h"),
96 cur_name_space_(nullptr),
98 float_const_gen_("std::numeric_limits<double>::",
99 "std::numeric_limits<float>::", "quiet_NaN()",
101 static const char *const keywords[] = {
199 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
202 void GenIncludeDependencies() {
203 int num_includes = 0;
204 if (opts_.generate_object_based_api) {
205 for (auto it = parser_.native_included_files_.begin();
206 it != parser_.native_included_files_.end(); ++it) {
207 code_ += "#include \"" + *it + "\"";
211 for (auto it = parser_.included_files_.begin();
212 it != parser_.included_files_.end(); ++it) {
213 if (it->second.empty()) continue;
214 auto noext = flatbuffers::StripExtension(it->second);
215 auto basename = flatbuffers::StripPath(noext);
217 GeneratedFileName(opts_.include_prefix,
218 opts_.keep_include_path ? noext : basename, opts_);
219 code_ += "#include \"" + includeName + "\"";
222 if (num_includes) code_ += "";
225 void GenExtraIncludes() {
226 for (std::size_t i = 0; i < opts_.cpp_includes.size(); ++i) {
227 code_ += "#include \"" + opts_.cpp_includes[i] + "\"";
229 if (!opts_.cpp_includes.empty()) { code_ += ""; }
232 std::string EscapeKeyword(const std::string &name) const {
233 return keywords_.find(name) == keywords_.end() ? name : name + "_";
236 std::string Name(const Definition &def) const {
237 return EscapeKeyword(def.name);
240 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
242 bool generate_bfbs_embed() {
244 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
246 // If we don't have a root struct definition,
247 if (!parser_.root_struct_def_) {
248 // put a comment in the output why there is no code generated.
249 code_ += "// Binary schema not generated, no root struct found";
251 auto &struct_def = *parser_.root_struct_def_;
252 const auto include_guard =
253 GenIncludeGuard(file_name_, *struct_def.defined_namespace, "bfbs");
255 code_ += "#ifndef " + include_guard;
256 code_ += "#define " + include_guard;
258 if (parser_.opts.gen_nullable) {
259 code_ += "#pragma clang system_header\n\n";
262 SetNameSpace(struct_def.defined_namespace);
263 auto name = Name(struct_def);
264 code_.SetValue("STRUCT_NAME", name);
266 // Create code to return the binary schema data.
267 auto binary_schema_hex_text =
268 BufferToHexText(parser_.builder_.GetBufferPointer(),
269 parser_.builder_.GetSize(), 105, " ", "");
271 code_ += "struct {{STRUCT_NAME}}BinarySchema {";
272 code_ += " static const uint8_t *data() {";
273 code_ += " // Buffer containing the binary schema.";
274 code_ += " static const uint8_t bfbsData[" +
275 NumToString(parser_.builder_.GetSize()) + "] = {";
276 code_ += binary_schema_hex_text;
278 code_ += " return bfbsData;";
280 code_ += " static size_t size() {";
281 code_ += " return " + NumToString(parser_.builder_.GetSize()) + ";";
283 code_ += " const uint8_t *begin() {";
284 code_ += " return data();";
286 code_ += " const uint8_t *end() {";
287 code_ += " return data() + size();";
292 if (cur_name_space_) SetNameSpace(nullptr);
294 // Close the include guard.
295 code_ += "#endif // " + include_guard;
298 // We are just adding "_bfbs" to the generated filename.
299 const auto file_path =
300 GeneratedFileName(path_, file_name_ + "_bfbs", opts_);
301 const auto final_code = code_.ToString();
303 return SaveFile(file_path.c_str(), final_code, false);
306 // Iterate through all definitions we haven't generate code for (enums,
307 // structs, and tables) and output them to a single file.
310 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
312 const auto include_guard =
313 GenIncludeGuard(file_name_, *parser_.current_namespace_);
314 code_ += "#ifndef " + include_guard;
315 code_ += "#define " + include_guard;
318 if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; }
320 code_ += "#include \"flatbuffers/flatbuffers.h\"";
321 if (parser_.uses_flexbuffers_) {
322 code_ += "#include \"flatbuffers/flexbuffers.h\"";
326 if (opts_.include_dependence_headers) { GenIncludeDependencies(); }
329 FLATBUFFERS_ASSERT(!cur_name_space_);
331 // Generate forward declarations for all structs/tables, since they may
332 // have circular references.
333 for (auto it = parser_.structs_.vec.begin();
334 it != parser_.structs_.vec.end(); ++it) {
335 const auto &struct_def = **it;
336 if (!struct_def.generated) {
337 SetNameSpace(struct_def.defined_namespace);
338 code_ += "struct " + Name(struct_def) + ";";
339 if (!struct_def.fixed) {
340 code_ += "struct " + Name(struct_def) + "Builder;";
342 if (opts_.generate_object_based_api) {
343 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
344 if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; }
350 // Generate forward declarations for all equal operators
351 if (opts_.generate_object_based_api && opts_.gen_compare) {
352 for (auto it = parser_.structs_.vec.begin();
353 it != parser_.structs_.vec.end(); ++it) {
354 const auto &struct_def = **it;
355 if (!struct_def.generated) {
356 SetNameSpace(struct_def.defined_namespace);
357 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
358 code_ += "bool operator==(const " + nativeName + " &lhs, const " +
359 nativeName + " &rhs);";
360 code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
361 nativeName + " &rhs);";
367 // Generate preablmle code for mini reflection.
368 if (opts_.mini_reflect != IDLOptions::kNone) {
369 // To break cyclic dependencies, first pre-declare all tables/structs.
370 for (auto it = parser_.structs_.vec.begin();
371 it != parser_.structs_.vec.end(); ++it) {
372 const auto &struct_def = **it;
373 if (!struct_def.generated) {
374 SetNameSpace(struct_def.defined_namespace);
375 GenMiniReflectPre(&struct_def);
380 // Generate code for all the enum declarations.
381 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
383 const auto &enum_def = **it;
384 if (!enum_def.generated) {
385 SetNameSpace(enum_def.defined_namespace);
390 // Generate code for all structs, then all tables.
391 for (auto it = parser_.structs_.vec.begin();
392 it != parser_.structs_.vec.end(); ++it) {
393 const auto &struct_def = **it;
394 if (struct_def.fixed && !struct_def.generated) {
395 SetNameSpace(struct_def.defined_namespace);
396 GenStruct(struct_def);
399 for (auto it = parser_.structs_.vec.begin();
400 it != parser_.structs_.vec.end(); ++it) {
401 const auto &struct_def = **it;
402 if (!struct_def.fixed && !struct_def.generated) {
403 SetNameSpace(struct_def.defined_namespace);
404 GenTable(struct_def);
407 for (auto it = parser_.structs_.vec.begin();
408 it != parser_.structs_.vec.end(); ++it) {
409 const auto &struct_def = **it;
410 if (!struct_def.fixed && !struct_def.generated) {
411 SetNameSpace(struct_def.defined_namespace);
412 GenTablePost(struct_def);
416 // Generate code for union verifiers.
417 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
419 const auto &enum_def = **it;
420 if (enum_def.is_union && !enum_def.generated) {
421 SetNameSpace(enum_def.defined_namespace);
422 GenUnionPost(enum_def);
426 // Generate code for mini reflection.
427 if (opts_.mini_reflect != IDLOptions::kNone) {
428 // Then the unions/enums that may refer to them.
429 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
431 const auto &enum_def = **it;
432 if (!enum_def.generated) {
433 SetNameSpace(enum_def.defined_namespace);
434 GenMiniReflect(nullptr, &enum_def);
437 // Then the full tables/structs.
438 for (auto it = parser_.structs_.vec.begin();
439 it != parser_.structs_.vec.end(); ++it) {
440 const auto &struct_def = **it;
441 if (!struct_def.generated) {
442 SetNameSpace(struct_def.defined_namespace);
443 GenMiniReflect(&struct_def, nullptr);
448 // Generate convenient global helper functions:
449 if (parser_.root_struct_def_) {
450 auto &struct_def = *parser_.root_struct_def_;
451 SetNameSpace(struct_def.defined_namespace);
452 auto name = Name(struct_def);
453 auto qualified_name = cur_name_space_->GetFullyQualifiedName(name);
454 auto cpp_name = TranslateNameSpace(qualified_name);
456 code_.SetValue("STRUCT_NAME", name);
457 code_.SetValue("CPP_NAME", cpp_name);
458 code_.SetValue("NULLABLE_EXT", NullableExtension());
460 // The root datatype accessor:
461 code_ += "inline \\";
463 "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void "
465 code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
469 code_ += "inline \\";
471 "const {{CPP_NAME}} "
472 "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void "
474 code_ += " return flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}>(buf);";
478 if (opts_.mutable_buffer) {
479 code_ += "inline \\";
480 code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
481 code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
486 if (parser_.file_identifier_.length()) {
487 // Return the identifier
488 code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
489 code_ += " return \"" + parser_.file_identifier_ + "\";";
493 // Check if a buffer has the identifier.
494 code_ += "inline \\";
495 code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
496 code_ += " return flatbuffers::BufferHasIdentifier(";
497 code_ += " buf, {{STRUCT_NAME}}Identifier());";
502 // The root verifier.
503 if (parser_.file_identifier_.length()) {
504 code_.SetValue("ID", name + "Identifier()");
506 code_.SetValue("ID", "nullptr");
509 code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
510 code_ += " flatbuffers::Verifier &verifier) {";
511 code_ += " return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
515 code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer(";
516 code_ += " flatbuffers::Verifier &verifier) {";
518 " return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});";
522 if (parser_.file_extension_.length()) {
523 // Return the extension
524 code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
525 code_ += " return \"" + parser_.file_extension_ + "\";";
530 // Finish a buffer with a given root object:
531 code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
532 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
533 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
534 if (parser_.file_identifier_.length())
535 code_ += " fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
537 code_ += " fbb.Finish(root);";
541 code_ += "inline void FinishSizePrefixed{{STRUCT_NAME}}Buffer(";
542 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
543 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
544 if (parser_.file_identifier_.length())
545 code_ += " fbb.FinishSizePrefixed(root, {{STRUCT_NAME}}Identifier());";
547 code_ += " fbb.FinishSizePrefixed(root);";
551 if (opts_.generate_object_based_api) {
552 // A convenient root unpack function.
553 auto native_name = WrapNativeNameInNameSpace(struct_def, opts_);
554 code_.SetValue("UNPACK_RETURN",
555 GenTypeNativePtr(native_name, nullptr, false));
556 code_.SetValue("UNPACK_TYPE",
557 GenTypeNativePtr(native_name, nullptr, true));
559 code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
560 code_ += " const void *buf,";
561 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
562 code_ += " return {{UNPACK_TYPE}}\\";
563 code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
567 code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}(";
568 code_ += " const void *buf,";
569 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
570 code_ += " return {{UNPACK_TYPE}}\\";
571 code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));";
577 if (cur_name_space_) SetNameSpace(nullptr);
579 // Close the include guard.
580 code_ += "#endif // " + include_guard;
582 const auto file_path = GeneratedFileName(path_, file_name_, opts_);
583 const auto final_code = code_.ToString();
585 // Save the file and optionally generate the binary schema code.
586 return SaveFile(file_path.c_str(), final_code, false) &&
587 (!parser_.opts.binary_schema_gen_embed || generate_bfbs_embed());
593 std::unordered_set<std::string> keywords_;
595 // This tracks the current namespace so we can insert namespace declarations.
596 const Namespace *cur_name_space_;
598 const IDLOptionsCpp opts_;
599 const TypedFloatConstantGenerator float_const_gen_;
601 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
603 // Translates a qualified name in flatbuffer text format to the same name in
604 // the equivalent C++ namespace.
605 static std::string TranslateNameSpace(const std::string &qualified_name) {
606 std::string cpp_qualified_name = qualified_name;
607 size_t start_pos = 0;
608 while ((start_pos = cpp_qualified_name.find('.', start_pos)) !=
610 cpp_qualified_name.replace(start_pos, 1, "::");
612 return cpp_qualified_name;
615 bool TypeHasKey(const Type &type) {
616 if (type.base_type != BASE_TYPE_STRUCT) { return false; }
617 for (auto it = type.struct_def->fields.vec.begin();
618 it != type.struct_def->fields.vec.end(); ++it) {
619 const auto &field = **it;
620 if (field.key) { return true; }
625 bool VectorElementUserFacing(const Type &type) const {
626 return opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums &&
630 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
632 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
633 code_ += text + "\\";
636 // Return a C++ type from the table in idl.h
637 std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
639 static const char *const ctypename[] = {
640 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
642 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
643 #undef FLATBUFFERS_TD
646 if (user_facing_type) {
647 if (type.enum_def) return WrapInNameSpace(*type.enum_def);
648 if (type.base_type == BASE_TYPE_BOOL) return "bool";
650 return ctypename[type.base_type];
653 // Return a C++ pointer type, specialized to the actual struct/table types,
654 // and vector element types.
655 std::string GenTypePointer(const Type &type) const {
656 switch (type.base_type) {
657 case BASE_TYPE_STRING: {
658 return "flatbuffers::String";
660 case BASE_TYPE_VECTOR: {
661 const auto type_name = GenTypeWire(
662 type.VectorType(), "", VectorElementUserFacing(type.VectorType()));
663 return "flatbuffers::Vector<" + type_name + ">";
665 case BASE_TYPE_STRUCT: {
666 return WrapInNameSpace(*type.struct_def);
668 case BASE_TYPE_UNION:
676 // Return a C++ type for any type (scalar/pointer) specifically for
677 // building a flatbuffer.
678 std::string GenTypeWire(const Type &type, const char *postfix,
679 bool user_facing_type) const {
680 if (IsScalar(type.base_type)) {
681 return GenTypeBasic(type, user_facing_type) + postfix;
682 } else if (IsStruct(type)) {
683 return "const " + GenTypePointer(type) + " *";
685 return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix;
689 // Return a C++ type for any type (scalar/pointer) that reflects its
691 std::string GenTypeSize(const Type &type) const {
692 if (IsScalar(type.base_type)) {
693 return GenTypeBasic(type, false);
694 } else if (IsStruct(type)) {
695 return GenTypePointer(type);
697 return "flatbuffers::uoffset_t";
701 std::string NullableExtension() {
702 return opts_.gen_nullable ? " _Nullable " : "";
705 static std::string NativeName(const std::string &name, const StructDef *sd,
706 const IDLOptions &opts) {
707 return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix
711 std::string WrapNativeNameInNameSpace(const StructDef &struct_def,
712 const IDLOptions &opts) {
713 return WrapInNameSpace(struct_def.defined_namespace,
714 NativeName(Name(struct_def), &struct_def, opts));
717 const std::string &PtrType(const FieldDef *field) {
718 auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
719 return attr ? attr->constant : opts_.cpp_object_api_pointer_type;
722 const std::string NativeString(const FieldDef *field) {
723 auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
724 auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type;
725 if (ret.empty()) { return "std::string"; }
729 bool FlexibleStringConstructor(const FieldDef *field) {
731 ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr)
733 auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor;
734 return ret && NativeString(field) !=
735 "std::string"; // Only for custom string types.
738 std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
739 bool is_constructor) {
740 auto &ptr_type = PtrType(field);
741 if (ptr_type != "naked") {
742 return (ptr_type != "default_ptr_type"
744 : opts_.cpp_object_api_pointer_type) +
746 } else if (is_constructor) {
753 std::string GenPtrGet(const FieldDef &field) {
754 auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get");
755 if (cpp_ptr_type_get) return cpp_ptr_type_get->constant;
756 auto &ptr_type = PtrType(&field);
757 return ptr_type == "naked" ? "" : ".get()";
760 std::string GenOptionalNull() { return "flatbuffers::nullopt"; }
762 std::string GenOptionalDecl(const Type &type) {
763 return "flatbuffers::Optional<" + GenTypeBasic(type, true) + ">";
766 std::string GenTypeNative(const Type &type, bool invector,
767 const FieldDef &field) {
768 switch (type.base_type) {
769 case BASE_TYPE_STRING: {
770 return NativeString(&field);
772 case BASE_TYPE_VECTOR: {
773 const auto type_name = GenTypeNative(type.VectorType(), true, field);
774 if (type.struct_def &&
775 type.struct_def->attributes.Lookup("native_custom_alloc")) {
776 auto native_custom_alloc =
777 type.struct_def->attributes.Lookup("native_custom_alloc");
778 return "std::vector<" + type_name + "," +
779 native_custom_alloc->constant + "<" + type_name + ">>";
781 return "std::vector<" + type_name + ">";
783 case BASE_TYPE_STRUCT: {
784 auto type_name = WrapInNameSpace(*type.struct_def);
785 if (IsStruct(type)) {
786 auto native_type = type.struct_def->attributes.Lookup("native_type");
787 if (native_type) { type_name = native_type->constant; }
788 if (invector || field.native_inline) {
791 return GenTypeNativePtr(type_name, &field, false);
794 return GenTypeNativePtr(
795 WrapNativeNameInNameSpace(*type.struct_def, opts_), &field,
799 case BASE_TYPE_UNION: {
800 auto type_name = WrapInNameSpace(*type.enum_def);
801 return type_name + "Union";
804 return field.IsScalarOptional() ? GenOptionalDecl(type)
805 : GenTypeBasic(type, true);
810 // Return a C++ type for any type (scalar/pointer) specifically for
811 // using a flatbuffer.
812 std::string GenTypeGet(const Type &type, const char *afterbasic,
813 const char *beforeptr, const char *afterptr,
814 bool user_facing_type) {
815 if (IsScalar(type.base_type)) {
816 return GenTypeBasic(type, user_facing_type) + afterbasic;
817 } else if (IsArray(type)) {
818 auto element_type = type.VectorType();
819 // Check if enum arrays are used in C++ without specifying --scoped-enums
820 if (IsEnum(element_type) && !opts_.g_only_fixed_enums) {
822 "--scoped-enums must be enabled to use enum arrays in C++");
823 FLATBUFFERS_ASSERT(true);
826 (IsScalar(element_type.base_type)
827 ? GenTypeBasic(element_type, user_facing_type)
828 : GenTypePointer(element_type)) +
831 return beforeptr + GenTypePointer(type) + afterptr;
835 std::string GenTypeSpan(const Type &type, bool immutable, size_t extent) {
836 // Generate "flatbuffers::span<const U, extent>".
837 FLATBUFFERS_ASSERT(IsSeries(type) && "unexpected type");
838 auto element_type = type.VectorType();
839 std::string text = "flatbuffers::span<";
840 text += immutable ? "const " : "";
841 if (IsScalar(element_type.base_type)) {
842 text += GenTypeBasic(element_type, IsEnum(element_type));
844 switch (element_type.base_type) {
845 case BASE_TYPE_STRING: {
849 case BASE_TYPE_STRUCT: {
850 FLATBUFFERS_ASSERT(type.struct_def);
851 text += WrapInNameSpace(*type.struct_def);
855 FLATBUFFERS_ASSERT(false && "unexpected element's type");
859 if (extent != flatbuffers::dynamic_extent) {
861 text += NumToString(extent);
867 std::string GenEnumValDecl(const EnumDef &enum_def,
868 const std::string &enum_val) const {
869 return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
872 std::string GetEnumValUse(const EnumDef &enum_def,
873 const EnumVal &enum_val) const {
874 if (opts_.scoped_enums) {
875 return Name(enum_def) + "::" + Name(enum_val);
876 } else if (opts_.prefixed_enums) {
877 return Name(enum_def) + "_" + Name(enum_val);
879 return Name(enum_val);
883 std::string StripUnionType(const std::string &name) {
884 return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
887 std::string GetUnionElement(const EnumVal &ev, bool native_type,
888 const IDLOptions &opts) {
889 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
890 auto name = ev.union_type.struct_def->name;
892 name = NativeName(name, ev.union_type.struct_def, opts);
894 return WrapInNameSpace(ev.union_type.struct_def->defined_namespace, name);
895 } else if (IsString(ev.union_type)) {
896 return native_type ? "std::string" : "flatbuffers::String";
898 FLATBUFFERS_ASSERT(false);
903 std::string UnionVerifySignature(const EnumDef &enum_def) {
904 return "bool Verify" + Name(enum_def) +
905 "(flatbuffers::Verifier &verifier, const void *obj, " +
906 Name(enum_def) + " type)";
909 std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
910 return "bool Verify" + Name(enum_def) + "Vector" +
911 "(flatbuffers::Verifier &verifier, " +
912 "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
913 "const flatbuffers::Vector<uint8_t> *types)";
916 std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) {
917 return (inclass ? "static " : "") + std::string("void *") +
918 (inclass ? "" : Name(enum_def) + "Union::") +
919 "UnPack(const void *obj, " + Name(enum_def) +
920 " type, const flatbuffers::resolver_function_t *resolver)";
923 std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
924 return "flatbuffers::Offset<void> " +
925 (inclass ? "" : Name(enum_def) + "Union::") +
926 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
927 "const flatbuffers::rehasher_function_t *_rehasher" +
928 (inclass ? " = nullptr" : "") + ") const";
931 std::string TableCreateSignature(const StructDef &struct_def, bool predecl,
932 const IDLOptions &opts) {
933 return "flatbuffers::Offset<" + Name(struct_def) + "> Create" +
934 Name(struct_def) + "(flatbuffers::FlatBufferBuilder &_fbb, const " +
935 NativeName(Name(struct_def), &struct_def, opts) +
936 " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
937 (predecl ? " = nullptr" : "") + ")";
940 std::string TablePackSignature(const StructDef &struct_def, bool inclass,
941 const IDLOptions &opts) {
942 return std::string(inclass ? "static " : "") + "flatbuffers::Offset<" +
943 Name(struct_def) + "> " + (inclass ? "" : Name(struct_def) + "::") +
944 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + "const " +
945 NativeName(Name(struct_def), &struct_def, opts) + "* _o, " +
946 "const flatbuffers::rehasher_function_t *_rehasher" +
947 (inclass ? " = nullptr" : "") + ")";
950 std::string TableUnPackSignature(const StructDef &struct_def, bool inclass,
951 const IDLOptions &opts) {
952 return NativeName(Name(struct_def), &struct_def, opts) + " *" +
953 (inclass ? "" : Name(struct_def) + "::") +
954 "UnPack(const flatbuffers::resolver_function_t *_resolver" +
955 (inclass ? " = nullptr" : "") + ") const";
958 std::string TableUnPackToSignature(const StructDef &struct_def, bool inclass,
959 const IDLOptions &opts) {
960 return "void " + (inclass ? "" : Name(struct_def) + "::") + "UnPackTo(" +
961 NativeName(Name(struct_def), &struct_def, opts) + " *" +
962 "_o, const flatbuffers::resolver_function_t *_resolver" +
963 (inclass ? " = nullptr" : "") + ") const";
966 void GenMiniReflectPre(const StructDef *struct_def) {
967 code_.SetValue("NAME", struct_def->name);
968 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable();";
972 void GenMiniReflect(const StructDef *struct_def, const EnumDef *enum_def) {
973 code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
974 code_.SetValue("SEQ_TYPE",
975 struct_def ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
976 : (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
978 struct_def ? struct_def->fields.vec.size() : enum_def->size();
979 code_.SetValue("NUM_FIELDS", NumToString(num_fields));
980 std::vector<std::string> names;
981 std::vector<Type> types;
984 for (auto it = struct_def->fields.vec.begin();
985 it != struct_def->fields.vec.end(); ++it) {
986 const auto &field = **it;
987 names.push_back(Name(field));
988 types.push_back(field.value.type);
991 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
993 const auto &ev = **it;
994 names.push_back(Name(ev));
995 types.push_back(enum_def->is_union ? ev.union_type
996 : Type(enum_def->underlying_type));
1000 std::vector<std::string> type_refs;
1001 std::vector<uint16_t> array_sizes;
1002 for (auto it = types.begin(); it != types.end(); ++it) {
1004 if (!ts.empty()) ts += ",\n ";
1005 auto is_vector = IsVector(type);
1006 auto is_array = IsArray(type);
1007 auto bt = is_vector || is_array ? type.element : type.base_type;
1008 auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
1009 ? bt - BASE_TYPE_UTYPE + ET_UTYPE
1012 std::string ref_name =
1014 ? WrapInNameSpace(*type.struct_def)
1015 : type.enum_def ? WrapInNameSpace(*type.enum_def) : "";
1016 if (!ref_name.empty()) {
1017 auto rit = type_refs.begin();
1018 for (; rit != type_refs.end(); ++rit) {
1019 if (*rit == ref_name) {
1020 ref_idx = static_cast<int>(rit - type_refs.begin());
1024 if (rit == type_refs.end()) {
1025 ref_idx = static_cast<int>(type_refs.size());
1026 type_refs.push_back(ref_name);
1029 if (is_array) { array_sizes.push_back(type.fixed_length); }
1030 ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
1031 NumToString(is_vector || is_array) + ", " + NumToString(ref_idx) +
1035 for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
1036 if (!rs.empty()) rs += ",\n ";
1037 rs += *it + "TypeTable";
1040 for (auto it = array_sizes.begin(); it != array_sizes.end(); ++it) {
1041 as += NumToString(*it);
1045 for (auto it = names.begin(); it != names.end(); ++it) {
1046 if (!ns.empty()) ns += ",\n ";
1047 ns += "\"" + *it + "\"";
1050 const auto consecutive_enum_from_zero =
1051 enum_def && enum_def->MinValue()->IsZero() &&
1052 ((enum_def->size() - 1) == enum_def->Distance());
1053 if (enum_def && !consecutive_enum_from_zero) {
1054 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
1056 const auto &ev = **it;
1057 if (!vs.empty()) vs += ", ";
1058 vs += NumToStringCpp(enum_def->ToString(ev),
1059 enum_def->underlying_type.base_type);
1061 } else if (struct_def && struct_def->fixed) {
1062 for (auto it = struct_def->fields.vec.begin();
1063 it != struct_def->fields.vec.end(); ++it) {
1064 const auto &field = **it;
1065 vs += NumToString(field.value.offset);
1068 vs += NumToString(struct_def->bytesize);
1070 code_.SetValue("TYPES", ts);
1071 code_.SetValue("REFS", rs);
1072 code_.SetValue("ARRAYSIZES", as);
1073 code_.SetValue("NAMES", ns);
1074 code_.SetValue("VALUES", vs);
1075 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable() {";
1077 code_ += " static const flatbuffers::TypeCode type_codes[] = {";
1078 code_ += " {{TYPES}}";
1081 if (!type_refs.empty()) {
1082 code_ += " static const flatbuffers::TypeFunction type_refs[] = {";
1083 code_ += " {{REFS}}";
1087 code_ += " static const int16_t array_sizes[] = { {{ARRAYSIZES}} };";
1090 // Problem with uint64_t values greater than 9223372036854775807ULL.
1091 code_ += " static const int64_t values[] = { {{VALUES}} };";
1094 num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames;
1096 code_ += " static const char * const names[] = {";
1097 code_ += " {{NAMES}}";
1100 code_ += " static const flatbuffers::TypeTable tt = {";
1101 code_ += std::string(" flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
1102 (num_fields ? "type_codes, " : "nullptr, ") +
1103 (!type_refs.empty() ? "type_refs, " : "nullptr, ") +
1104 (!as.empty() ? "array_sizes, " : "nullptr, ") +
1105 (!vs.empty() ? "values, " : "nullptr, ") +
1106 (has_names ? "names" : "nullptr");
1108 code_ += " return &tt;";
1113 // Generate an enum declaration,
1114 // an enum string lookup table,
1115 // and an enum array of values
1117 void GenEnum(const EnumDef &enum_def) {
1118 code_.SetValue("ENUM_NAME", Name(enum_def));
1119 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
1121 GenComment(enum_def.doc_comment);
1123 (opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\";
1124 if (opts_.g_only_fixed_enums) { code_ += " : {{BASE_TYPE}}\\"; }
1127 code_.SetValue("SEP", ",");
1128 auto add_sep = false;
1129 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1130 const auto &ev = **it;
1131 if (add_sep) code_ += "{{SEP}}";
1132 GenComment(ev.doc_comment, " ");
1133 code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev)));
1134 code_.SetValue("VALUE",
1135 NumToStringCpp(enum_def.ToString(ev),
1136 enum_def.underlying_type.base_type));
1137 code_ += " {{KEY}} = {{VALUE}}\\";
1140 const EnumVal *minv = enum_def.MinValue();
1141 const EnumVal *maxv = enum_def.MaxValue();
1143 if (opts_.scoped_enums || opts_.prefixed_enums) {
1144 FLATBUFFERS_ASSERT(minv && maxv);
1146 code_.SetValue("SEP", ",\n");
1147 if (enum_def.attributes.Lookup("bit_flags")) {
1148 code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
1149 code_.SetValue("VALUE", "0");
1150 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1152 code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
1153 code_.SetValue("VALUE",
1154 NumToStringCpp(enum_def.AllFlags(),
1155 enum_def.underlying_type.base_type));
1156 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1157 } else { // MIN & MAX are useless for bit_flags
1158 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN"));
1159 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*minv)));
1160 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1162 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX"));
1163 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*maxv)));
1164 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1170 if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
1172 "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
1176 // Generate an array of all enumeration values
1177 auto num_fields = NumToString(enum_def.size());
1178 code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
1180 code_ += " static const {{ENUM_NAME}} values[] = {";
1181 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1182 const auto &ev = **it;
1183 auto value = GetEnumValUse(enum_def, ev);
1184 auto suffix = *it != enum_def.Vals().back() ? "," : "";
1185 code_ += " " + value + suffix;
1188 code_ += " return values;";
1192 // Generate a generate string table for enum values.
1193 // Problem is, if values are very sparse that could generate really big
1194 // tables. Ideally in that case we generate a map lookup instead, but for
1195 // the moment we simply don't output a table at all.
1196 auto range = enum_def.Distance();
1197 // Average distance between values above which we consider a table
1198 // "too sparse". Change at will.
1199 static const uint64_t kMaxSparseness = 5;
1200 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
1201 code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
1202 code_ += " static const char * const names[" +
1203 NumToString(range + 1 + 1) + "] = {";
1205 auto val = enum_def.Vals().front();
1206 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1209 for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
1213 code_ += " \"" + Name(*ev) + "\",";
1215 code_ += " nullptr";
1218 code_ += " return names;";
1222 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1224 code_ += " if (flatbuffers::IsOutRange(e, " +
1225 GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " +
1226 GetEnumValUse(enum_def, *enum_def.MaxValue()) +
1229 code_ += " const size_t index = static_cast<size_t>(e)\\";
1230 if (enum_def.MinValue()->IsNonZero()) {
1231 auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
1232 code_ += " - static_cast<size_t>(" + vals + ")\\";
1236 code_ += " return EnumNames{{ENUM_NAME}}()[index];";
1240 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1242 code_ += " switch (e) {";
1244 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1246 const auto &ev = **it;
1247 code_ += " case " + GetEnumValUse(enum_def, ev) + ": return \"" +
1251 code_ += " default: return \"\";";
1258 // Generate type traits for unions to map from a type to union enum value.
1259 if (enum_def.is_union && !enum_def.uses_multiple_type_instances) {
1260 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1262 const auto &ev = **it;
1264 if (it == enum_def.Vals().begin()) {
1265 code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
1267 auto name = GetUnionElement(ev, false, opts_);
1268 code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
1271 auto value = GetEnumValUse(enum_def, ev);
1272 code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
1278 if (opts_.generate_object_based_api && enum_def.is_union) {
1279 // Generate a union type
1280 code_.SetValue("NAME", Name(enum_def));
1281 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1282 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1284 code_ += "struct {{NAME}}Union {";
1285 code_ += " {{NAME}} type;";
1286 code_ += " void *value;";
1288 code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
1289 code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
1290 code_ += " type({{NONE}}), value(nullptr)";
1291 code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
1292 code_ += " {{NAME}}Union(const {{NAME}}Union &);";
1293 code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)";
1295 " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, "
1296 "t.value); return *this; }";
1298 " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
1300 " { std::swap(type, u.type); std::swap(value, u.value); return "
1302 code_ += " ~{{NAME}}Union() { Reset(); }";
1304 code_ += " void Reset();";
1306 if (!enum_def.uses_multiple_type_instances) {
1307 code_ += "#ifndef FLATBUFFERS_CPP98_STL";
1308 code_ += " template <typename T>";
1309 code_ += " void Set(T&& val) {";
1310 code_ += " using RT = typename std::remove_reference<T>::type;";
1311 code_ += " Reset();";
1313 " type = {{NAME}}Traits<typename RT::TableType>::enum_value;";
1314 code_ += " if (type != {{NONE}}) {";
1315 code_ += " value = new RT(std::forward<T>(val));";
1318 code_ += "#endif // FLATBUFFERS_CPP98_STL";
1321 code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
1322 code_ += " " + UnionPackSignature(enum_def, true) + ";";
1325 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1327 const auto &ev = **it;
1328 if (ev.IsZero()) { continue; }
1330 const auto native_type = GetUnionElement(ev, true, opts_);
1331 code_.SetValue("NATIVE_TYPE", native_type);
1332 code_.SetValue("NATIVE_NAME", Name(ev));
1333 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1335 code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
1336 code_ += " return type == {{NATIVE_ID}} ?";
1337 code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
1340 code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {";
1341 code_ += " return type == {{NATIVE_ID}} ?";
1343 " reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;";
1349 if (opts_.gen_compare) {
1352 "inline bool operator==(const {{NAME}}Union &lhs, const "
1353 "{{NAME}}Union &rhs) {";
1354 code_ += " if (lhs.type != rhs.type) return false;";
1355 code_ += " switch (lhs.type) {";
1357 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1359 const auto &ev = **it;
1360 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1361 if (ev.IsNonZero()) {
1362 const auto native_type = GetUnionElement(ev, true, opts_);
1363 code_.SetValue("NATIVE_TYPE", native_type);
1364 code_ += " case {{NATIVE_ID}}: {";
1366 " return *(reinterpret_cast<const {{NATIVE_TYPE}} "
1367 "*>(lhs.value)) ==";
1369 " *(reinterpret_cast<const {{NATIVE_TYPE}} "
1373 code_ += " case {{NATIVE_ID}}: {";
1374 code_ += " return true;"; // "NONE" enum value.
1378 code_ += " default: {";
1379 code_ += " return false;";
1386 "inline bool operator!=(const {{NAME}}Union &lhs, const "
1387 "{{NAME}}Union &rhs) {";
1388 code_ += " return !(lhs == rhs);";
1394 if (enum_def.is_union) {
1395 code_ += UnionVerifySignature(enum_def) + ";";
1396 code_ += UnionVectorVerifySignature(enum_def) + ";";
1401 void GenUnionPost(const EnumDef &enum_def) {
1402 // Generate a verifier function for this union that can be called by the
1403 // table verifier functions. It uses a switch case to select a specific
1404 // verifier function to call, this should be safe even if the union type
1405 // has been corrupted, since the verifiers will simply fail when called
1406 // on the wrong type.
1407 code_.SetValue("ENUM_NAME", Name(enum_def));
1409 code_ += "inline " + UnionVerifySignature(enum_def) + " {";
1410 code_ += " switch (type) {";
1411 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1412 const auto &ev = **it;
1413 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1415 if (ev.IsNonZero()) {
1416 code_.SetValue("TYPE", GetUnionElement(ev, false, opts_));
1417 code_ += " case {{LABEL}}: {";
1419 " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1420 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1421 if (ev.union_type.struct_def->fixed) {
1423 " return verifier.Verify<{{TYPE}}>(static_cast<const "
1424 "uint8_t *>(obj), 0);";
1427 code_ += " return verifier.VerifyTable(ptr);";
1429 } else if (IsString(ev.union_type)) {
1431 code_ += " return verifier.VerifyString(ptr);";
1433 FLATBUFFERS_ASSERT(false);
1437 code_ += " case {{LABEL}}: {";
1438 code_ += " return true;"; // "NONE" enum value.
1442 code_ += " default: return true;"; // unknown values are OK.
1447 code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
1448 code_ += " if (!values || !types) return !values && !types;";
1449 code_ += " if (values->size() != types->size()) return false;";
1450 code_ += " for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
1451 code_ += " if (!Verify" + Name(enum_def) + "(";
1452 code_ += " verifier, values->Get(i), types->GetEnum<" +
1453 Name(enum_def) + ">(i))) {";
1454 code_ += " return false;";
1457 code_ += " return true;";
1461 if (opts_.generate_object_based_api) {
1462 // Generate union Unpack() and Pack() functions.
1463 code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
1464 code_ += " switch (type) {";
1465 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1467 const auto &ev = **it;
1468 if (ev.IsZero()) { continue; }
1470 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1471 code_.SetValue("TYPE", GetUnionElement(ev, false, opts_));
1472 code_ += " case {{LABEL}}: {";
1473 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1474 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1475 if (ev.union_type.struct_def->fixed) {
1476 code_ += " return new " +
1477 WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
1479 code_ += " return ptr->UnPack(resolver);";
1481 } else if (IsString(ev.union_type)) {
1482 code_ += " return new std::string(ptr->c_str(), ptr->size());";
1484 FLATBUFFERS_ASSERT(false);
1488 code_ += " default: return nullptr;";
1493 code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
1494 code_ += " switch (type) {";
1495 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1498 if (ev.IsZero()) { continue; }
1500 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1501 code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
1502 code_ += " case {{LABEL}}: {";
1503 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
1504 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1505 if (ev.union_type.struct_def->fixed) {
1506 code_ += " return _fbb.CreateStruct(*ptr).Union();";
1508 code_.SetValue("NAME", ev.union_type.struct_def->name);
1510 " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
1512 } else if (IsString(ev.union_type)) {
1513 code_ += " return _fbb.CreateString(*ptr).Union();";
1515 FLATBUFFERS_ASSERT(false);
1519 code_ += " default: return 0;";
1524 // Union copy constructor
1526 "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
1527 "{{ENUM_NAME}}Union &u) : type(u.type), value(nullptr) {";
1528 code_ += " switch (type) {";
1529 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1531 const auto &ev = **it;
1532 if (ev.IsZero()) { continue; }
1533 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1534 code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
1535 code_ += " case {{LABEL}}: {";
1536 bool copyable = true;
1537 if (ev.union_type.base_type == BASE_TYPE_STRUCT &&
1538 !ev.union_type.struct_def->fixed) {
1539 // Don't generate code to copy if table is not copyable.
1540 // TODO(wvo): make tables copyable instead.
1541 for (auto fit = ev.union_type.struct_def->fields.vec.begin();
1542 fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
1543 const auto &field = **fit;
1544 if (!field.deprecated && field.value.type.struct_def &&
1545 !field.native_inline) {
1553 " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
1557 " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable.";
1562 code_ += " default:";
1568 // Union Reset() function.
1569 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1570 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1572 code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
1573 code_ += " switch (type) {";
1574 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1576 const auto &ev = **it;
1577 if (ev.IsZero()) { continue; }
1578 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1579 code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
1580 code_ += " case {{LABEL}}: {";
1581 code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
1582 code_ += " delete ptr;";
1586 code_ += " default: break;";
1588 code_ += " value = nullptr;";
1589 code_ += " type = {{NONE}};";
1595 // Generates a value with optionally a cast applied if the field has a
1596 // different underlying type from its interface type (currently only the
1597 // case for enums. "from" specify the direction, true meaning from the
1598 // underlying type to the interface type.
1599 std::string GenUnderlyingCast(const FieldDef &field, bool from,
1600 const std::string &val) {
1601 if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
1602 return val + " != 0";
1603 } else if ((field.value.type.enum_def &&
1604 IsScalar(field.value.type.base_type)) ||
1605 field.value.type.base_type == BASE_TYPE_BOOL) {
1606 return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
1613 std::string GenFieldOffsetName(const FieldDef &field) {
1614 std::string uname = Name(field);
1615 std::transform(uname.begin(), uname.end(), uname.begin(), CharToUpper);
1616 return "VT_" + uname;
1619 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1620 const std::string &name) {
1621 if (!opts_.generate_name_strings) { return; }
1622 auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
1623 code_.SetValue("NAME", fullname);
1624 code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
1625 code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
1626 code_ += " return \"{{NAME}}\";";
1630 std::string GenDefaultConstant(const FieldDef &field) {
1631 if (IsFloat(field.value.type.base_type))
1632 return float_const_gen_.GenFloatConstant(field);
1634 return NumToStringCpp(field.value.constant, field.value.type.base_type);
1637 std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
1638 const auto &type = field.value.type;
1639 if (field.IsScalarOptional()) {
1640 return GenOptionalNull();
1641 } else if (type.enum_def && IsScalar(type.base_type)) {
1642 auto ev = type.enum_def->FindByValue(field.value.constant);
1644 return WrapInNameSpace(type.enum_def->defined_namespace,
1645 GetEnumValUse(*type.enum_def, *ev));
1647 return GenUnderlyingCast(
1648 field, true, NumToStringCpp(field.value.constant, type.base_type));
1650 } else if (type.base_type == BASE_TYPE_BOOL) {
1651 return field.value.constant == "0" ? "false" : "true";
1652 } else if (field.attributes.Lookup("cpp_type")) {
1654 if (PtrType(&field) == "naked") {
1663 return GenDefaultConstant(field);
1667 void GenParam(const FieldDef &field, bool direct, const char *prefix) {
1668 code_.SetValue("PRE", prefix);
1669 code_.SetValue("PARAM_NAME", Name(field));
1670 if (direct && IsString(field.value.type)) {
1671 code_.SetValue("PARAM_TYPE", "const char *");
1672 code_.SetValue("PARAM_VALUE", "nullptr");
1673 } else if (direct && IsVector(field.value.type)) {
1674 const auto vtype = field.value.type.VectorType();
1676 if (IsStruct(vtype)) {
1677 type = WrapInNameSpace(*vtype.struct_def);
1679 type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
1681 if (TypeHasKey(vtype)) {
1682 code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
1684 code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
1686 code_.SetValue("PARAM_VALUE", "nullptr");
1688 const auto &type = field.value.type;
1689 code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
1690 if (field.IsScalarOptional())
1691 code_.SetValue("PARAM_TYPE", GenOptionalDecl(type) + " ");
1693 code_.SetValue("PARAM_TYPE", GenTypeWire(type, " ", true));
1695 code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
1698 // Generate a member, including a default value for scalars and raw pointers.
1699 void GenMember(const FieldDef &field) {
1700 if (!field.deprecated && // Deprecated fields won't be accessible.
1701 field.value.type.base_type != BASE_TYPE_UTYPE &&
1702 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1703 field.value.type.element != BASE_TYPE_UTYPE)) {
1704 auto type = GenTypeNative(field.value.type, false, field);
1705 auto cpp_type = field.attributes.Lookup("cpp_type");
1708 ? (IsVector(field.value.type)
1710 GenTypeNativePtr(cpp_type->constant, &field,
1713 : GenTypeNativePtr(cpp_type->constant, &field, false))
1715 // Generate default member initializers for >= C++11.
1716 std::string field_di = "";
1717 if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
1719 auto native_default = field.attributes.Lookup("native_default");
1720 // Scalar types get parsed defaults, raw pointers get nullptrs.
1721 if (IsScalar(field.value.type.base_type)) {
1723 " = " + (native_default ? std::string(native_default->constant)
1724 : GetDefaultScalarValue(field, true));
1725 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1726 if (IsStruct(field.value.type) && native_default) {
1727 field_di = " = " + native_default->constant;
1731 code_.SetValue("FIELD_TYPE", full_type);
1732 code_.SetValue("FIELD_NAME", Name(field));
1733 code_.SetValue("FIELD_DI", field_di);
1734 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}{{FIELD_DI}};";
1738 // Generate the default constructor for this struct. Properly initialize all
1739 // scalar members with default values.
1740 void GenDefaultConstructor(const StructDef &struct_def) {
1741 code_.SetValue("NATIVE_NAME",
1742 NativeName(Name(struct_def), &struct_def, opts_));
1743 // In >= C++11, default member initializers are generated.
1744 if (opts_.g_cpp_std >= cpp::CPP_STD_11) { return; }
1745 std::string initializer_list;
1746 for (auto it = struct_def.fields.vec.begin();
1747 it != struct_def.fields.vec.end(); ++it) {
1748 const auto &field = **it;
1749 if (!field.deprecated && // Deprecated fields won't be accessible.
1750 field.value.type.base_type != BASE_TYPE_UTYPE) {
1751 auto cpp_type = field.attributes.Lookup("cpp_type");
1752 auto native_default = field.attributes.Lookup("native_default");
1753 // Scalar types get parsed defaults, raw pointers get nullptrs.
1754 if (IsScalar(field.value.type.base_type)) {
1755 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1756 initializer_list += Name(field);
1759 (native_default ? std::string(native_default->constant)
1760 : GetDefaultScalarValue(field, true)) +
1762 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1763 if (IsStruct(field.value.type)) {
1764 if (native_default) {
1765 if (!initializer_list.empty()) {
1766 initializer_list += ",\n ";
1769 Name(field) + "(" + native_default->constant + ")";
1772 } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) {
1773 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1774 initializer_list += Name(field) + "(0)";
1778 if (!initializer_list.empty()) {
1779 initializer_list = "\n : " + initializer_list;
1782 code_.SetValue("INIT_LIST", initializer_list);
1784 code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
1788 void GenCompareOperator(const StructDef &struct_def,
1789 std::string accessSuffix = "") {
1790 std::string compare_op;
1791 for (auto it = struct_def.fields.vec.begin();
1792 it != struct_def.fields.vec.end(); ++it) {
1793 const auto &field = **it;
1794 if (!field.deprecated && // Deprecated fields won't be accessible.
1795 field.value.type.base_type != BASE_TYPE_UTYPE &&
1796 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1797 field.value.type.element != BASE_TYPE_UTYPE)) {
1798 if (!compare_op.empty()) { compare_op += " &&\n "; }
1799 auto accessor = Name(field) + accessSuffix;
1800 compare_op += "(lhs." + accessor + " == rhs." + accessor + ")";
1804 std::string cmp_lhs;
1805 std::string cmp_rhs;
1806 if (compare_op.empty()) {
1809 compare_op = " return true;";
1813 compare_op = " return\n " + compare_op + ";";
1816 code_.SetValue("CMP_OP", compare_op);
1817 code_.SetValue("CMP_LHS", cmp_lhs);
1818 code_.SetValue("CMP_RHS", cmp_rhs);
1821 "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
1822 "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
1823 code_ += "{{CMP_OP}}";
1828 "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
1829 "{{NATIVE_NAME}} &rhs) {";
1830 code_ += " return !(lhs == rhs);";
1835 void GenOperatorNewDelete(const StructDef &struct_def) {
1836 if (auto native_custom_alloc =
1837 struct_def.attributes.Lookup("native_custom_alloc")) {
1838 code_ += " inline void *operator new (std::size_t count) {";
1839 code_ += " return " + native_custom_alloc->constant +
1840 "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
1842 code_ += " inline void operator delete (void *ptr) {";
1843 code_ += " return " + native_custom_alloc->constant +
1844 "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
1850 void GenNativeTable(const StructDef &struct_def) {
1851 const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
1852 code_.SetValue("STRUCT_NAME", Name(struct_def));
1853 code_.SetValue("NATIVE_NAME", native_name);
1855 // Generate a C++ object that can hold an unpacked version of this table.
1856 code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
1857 code_ += " typedef {{STRUCT_NAME}} TableType;";
1858 GenFullyQualifiedNameGetter(struct_def, native_name);
1859 for (auto it = struct_def.fields.vec.begin();
1860 it != struct_def.fields.vec.end(); ++it) {
1863 GenOperatorNewDelete(struct_def);
1864 GenDefaultConstructor(struct_def);
1866 if (opts_.gen_compare) GenCompareOperator(struct_def);
1870 // Generate the code to call the appropriate Verify function(s) for a field.
1871 void GenVerifyCall(const FieldDef &field, const char *prefix) {
1872 code_.SetValue("PRE", prefix);
1873 code_.SetValue("NAME", Name(field));
1874 code_.SetValue("REQUIRED", field.IsRequired() ? "Required" : "");
1875 code_.SetValue("SIZE", GenTypeSize(field.value.type));
1876 code_.SetValue("OFFSET", GenFieldOffsetName(field));
1877 if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
1879 "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
1881 code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
1884 switch (field.value.type.base_type) {
1885 case BASE_TYPE_UNION: {
1886 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1887 code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
1889 "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
1890 "{{NAME}}{{SUFFIX}}())\\";
1893 case BASE_TYPE_STRUCT: {
1894 if (!field.value.type.struct_def->fixed) {
1895 code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
1899 case BASE_TYPE_STRING: {
1900 code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
1903 case BASE_TYPE_VECTOR: {
1904 code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
1906 switch (field.value.type.element) {
1907 case BASE_TYPE_STRING: {
1908 code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
1911 case BASE_TYPE_STRUCT: {
1912 if (!field.value.type.struct_def->fixed) {
1913 code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
1917 case BASE_TYPE_UNION: {
1918 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1920 "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
1921 "{{NAME}}_type())\\";
1934 // Generate CompareWithValue method for a key field.
1935 void GenKeyFieldMethods(const FieldDef &field) {
1936 FLATBUFFERS_ASSERT(field.key);
1937 const bool is_string = (IsString(field.value.type));
1939 code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
1941 // use operator< of flatbuffers::String
1942 code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
1944 code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
1949 code_ += " int KeyCompareWithValue(const char *val) const {";
1950 code_ += " return strcmp({{FIELD_NAME}}()->c_str(), val);";
1953 FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
1954 auto type = GenTypeBasic(field.value.type, false);
1955 if (opts_.scoped_enums && field.value.type.enum_def &&
1956 IsScalar(field.value.type.base_type)) {
1957 type = GenTypeGet(field.value.type, " ", "const ", " *", true);
1959 // Returns {field<val: -1, field==val: 0, field>val: +1}.
1960 code_.SetValue("KEY_TYPE", type);
1961 code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {";
1963 " return static_cast<int>({{FIELD_NAME}}() > val) - "
1964 "static_cast<int>({{FIELD_NAME}}() < val);";
1969 void GenTableUnionAsGetters(const FieldDef &field) {
1970 const auto &type = field.value.type;
1971 auto u = type.enum_def;
1973 if (!type.enum_def->uses_multiple_type_instances)
1975 " template<typename T> "
1976 "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
1978 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
1980 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1981 auto full_struct_name = GetUnionElement(ev, false, opts_);
1983 // @TODO: Mby make this decisions more universal? How?
1984 code_.SetValue("U_GET_TYPE",
1985 EscapeKeyword(field.name + UnionTypeFieldSuffix()));
1986 code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace,
1987 GetEnumValUse(*u, ev)));
1988 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
1989 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
1990 code_.SetValue("U_NULLABLE", NullableExtension());
1992 // `const Type *union_name_asType() const` accessor.
1993 code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
1995 " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
1996 "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
2002 void GenTableFieldGetter(const FieldDef &field) {
2003 const auto &type = field.value.type;
2004 const auto offset_str = GenFieldOffsetName(field);
2006 GenComment(field.doc_comment, " ");
2007 // Call a different accessor for pointers, that indirects.
2008 if (false == field.IsScalarOptional()) {
2009 const bool is_scalar = IsScalar(type.base_type);
2010 std::string accessor;
2012 accessor = "GetField<";
2013 else if (IsStruct(type))
2014 accessor = "GetStruct<";
2016 accessor = "GetPointer<";
2017 auto offset_type = GenTypeGet(type, "", "const ", " *", false);
2018 auto call = accessor + offset_type + ">(" + offset_str;
2019 // Default value as second arg for non-pointer types.
2020 if (is_scalar) { call += ", " + GenDefaultConstant(field); }
2023 std::string afterptr = " *" + NullableExtension();
2024 code_.SetValue("FIELD_TYPE",
2025 GenTypeGet(type, " ", "const ", afterptr.c_str(), true));
2026 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
2027 code_.SetValue("NULLABLE_EXT", NullableExtension());
2028 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
2029 code_ += " return {{FIELD_VALUE}};";
2032 auto wire_type = GenTypeBasic(type, false);
2033 auto face_type = GenTypeBasic(type, true);
2034 auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
2036 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2037 code_ += " {{FIELD_TYPE}} {{FIELD_NAME}}() const {";
2038 code_ += " return " + opt_value + ";";
2042 if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); }
2045 void GenTableFieldType(const FieldDef &field) {
2046 const auto &type = field.value.type;
2047 const auto offset_str = GenFieldOffsetName(field);
2048 if (!field.IsScalarOptional()) {
2049 std::string afterptr = " *" + NullableExtension();
2050 code_.SetValue("FIELD_TYPE",
2051 GenTypeGet(type, "", "const ", afterptr.c_str(), true));
2052 code_ += " {{FIELD_TYPE}}\\";
2054 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2055 code_ += " {{FIELD_TYPE}}\\";
2059 void GenStructFieldType(const FieldDef &field) {
2060 const auto is_array = IsArray(field.value.type);
2061 std::string field_type =
2062 GenTypeGet(field.value.type, "", is_array ? "" : "const ",
2063 is_array ? "" : " &", true);
2064 code_.SetValue("FIELD_TYPE", field_type);
2065 code_ += " {{FIELD_TYPE}}\\";
2068 void GenFieldTypeHelper(const StructDef &struct_def) {
2069 if (struct_def.fields.vec.empty()) { return; }
2070 code_ += " template<size_t Index>";
2071 code_ += " using FieldType = \\";
2072 code_ += "decltype(std::declval<type>().get_field<Index>());";
2075 void GenIndexBasedFieldGetter(const StructDef &struct_def) {
2076 if (struct_def.fields.vec.empty()) { return; }
2077 code_ += " template<size_t Index>";
2078 code_ += " auto get_field() const {";
2081 bool need_else = false;
2082 // Generate one index-based getter for each field.
2083 for (auto it = struct_def.fields.vec.begin();
2084 it != struct_def.fields.vec.end(); ++it) {
2085 const auto &field = **it;
2086 if (field.deprecated) {
2087 // Deprecated fields won't be accessible.
2090 code_.SetValue("FIELD_NAME", Name(field));
2091 code_.SetValue("FIELD_INDEX",
2092 std::to_string(static_cast<long long>(index++)));
2094 code_ += " else \\";
2099 code_ += "if constexpr (Index == {{FIELD_INDEX}}) \\";
2100 code_ += "return {{FIELD_NAME}}();";
2102 code_ += " else static_assert(Index != Index, \"Invalid Field Index\");";
2108 // static constexpr std::array<const char *, 3> field_names = {
2114 void GenFieldNames(const StructDef &struct_def) {
2115 auto non_deprecated_field_count = std::count_if(
2116 struct_def.fields.vec.begin(), struct_def.fields.vec.end(),
2117 [](const FieldDef *field) { return !field->deprecated; });
2118 code_ += " static constexpr std::array<\\";
2121 std::to_string(static_cast<long long>(non_deprecated_field_count)));
2122 code_ += "const char *, {{FIELD_COUNT}}> field_names = {\\";
2123 if (struct_def.fields.vec.empty()) {
2128 // Generate the field_names elements.
2129 for (auto it = struct_def.fields.vec.begin();
2130 it != struct_def.fields.vec.end(); ++it) {
2131 const auto &field = **it;
2132 if (field.deprecated) {
2133 // Deprecated fields won't be accessible.
2136 code_.SetValue("FIELD_NAME", Name(field));
2137 code_ += " \"{{FIELD_NAME}}\"\\";
2138 if (it + 1 != struct_def.fields.vec.end()) { code_ += ","; }
2143 void GenFieldsNumber(const StructDef &struct_def) {
2144 auto non_deprecated_field_count = std::count_if(
2145 struct_def.fields.vec.begin(), struct_def.fields.vec.end(),
2146 [](const FieldDef *field) { return !field->deprecated; });
2149 std::to_string(static_cast<long long>(non_deprecated_field_count)));
2150 code_ += " static constexpr size_t fields_number = {{FIELD_COUNT}};";
2153 void GenTraitsStruct(const StructDef &struct_def) {
2155 "FULLY_QUALIFIED_NAME",
2156 struct_def.defined_namespace->GetFullyQualifiedName(Name(struct_def)));
2157 code_ += "struct {{STRUCT_NAME}}::Traits {";
2158 code_ += " using type = {{STRUCT_NAME}};";
2159 if (!struct_def.fixed) {
2160 // We have a table and not a struct.
2161 code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
2163 if (opts_.cpp_static_reflection) {
2164 code_ += " static constexpr auto name = \"{{STRUCT_NAME}}\";";
2166 " static constexpr auto fully_qualified_name = "
2167 "\"{{FULLY_QUALIFIED_NAME}}\";";
2168 GenFieldNames(struct_def);
2169 GenFieldTypeHelper(struct_def);
2170 GenFieldsNumber(struct_def);
2176 void GenTableFieldSetter(const FieldDef &field) {
2177 const auto &type = field.value.type;
2178 const bool is_scalar = IsScalar(type.base_type);
2179 if (is_scalar && IsUnion(type))
2180 return; // changing of a union's type is forbidden
2182 auto offset_str = GenFieldOffsetName(field);
2184 const auto wire_type = GenTypeWire(type, "", false);
2185 code_.SetValue("SET_FN", "SetField<" + wire_type + ">");
2186 code_.SetValue("OFFSET_NAME", offset_str);
2187 code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true));
2188 code_.SetValue("FIELD_VALUE",
2189 GenUnderlyingCast(field, false, "_" + Name(field)));
2192 " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
2193 "_{{FIELD_NAME}}) {";
2194 if (false == field.IsScalarOptional()) {
2195 code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
2197 " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
2198 "{{DEFAULT_VALUE}});";
2200 code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
2204 auto postptr = " *" + NullableExtension();
2205 auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
2206 std::string accessor = IsStruct(type) ? "GetStruct<" : "GetPointer<";
2207 auto underlying = accessor + wire_type + ">(" + offset_str + ")";
2208 code_.SetValue("FIELD_TYPE", wire_type);
2209 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
2211 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
2212 code_ += " return {{FIELD_VALUE}};";
2217 // Generate an accessor struct, builder structs & function for a table.
2218 void GenTable(const StructDef &struct_def) {
2219 if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
2221 // Generate an accessor struct, with methods of the form:
2222 // type name() const { return GetField<type>(offset, defaultval); }
2223 GenComment(struct_def.doc_comment);
2225 code_.SetValue("STRUCT_NAME", Name(struct_def));
2227 "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
2228 " : private flatbuffers::Table {";
2229 if (opts_.generate_object_based_api) {
2230 code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
2232 code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
2233 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
2234 if (opts_.mini_reflect != IDLOptions::kNone) {
2236 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
2237 code_ += " return {{STRUCT_NAME}}TypeTable();";
2241 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
2243 // Generate field id constants.
2244 if (struct_def.fields.vec.size() > 0) {
2245 // We need to add a trailing comma to all elements except the last one as
2246 // older versions of gcc complain about this.
2247 code_.SetValue("SEP", "");
2249 " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
2250 for (auto it = struct_def.fields.vec.begin();
2251 it != struct_def.fields.vec.end(); ++it) {
2252 const auto &field = **it;
2253 if (field.deprecated) {
2254 // Deprecated fields won't be accessible.
2258 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2259 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
2260 code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
2261 code_.SetValue("SEP", ",\n");
2267 // Generate the accessors.
2268 for (auto it = struct_def.fields.vec.begin();
2269 it != struct_def.fields.vec.end(); ++it) {
2270 const auto &field = **it;
2271 if (field.deprecated) {
2272 // Deprecated fields won't be accessible.
2276 code_.SetValue("FIELD_NAME", Name(field));
2277 GenTableFieldGetter(field);
2278 if (opts_.mutable_buffer) { GenTableFieldSetter(field); }
2280 auto nested = field.attributes.Lookup("nested_flatbuffer");
2282 std::string qualified_name = nested->constant;
2283 auto nested_root = parser_.LookupStruct(nested->constant);
2284 if (nested_root == nullptr) {
2285 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
2287 nested_root = parser_.LookupStruct(qualified_name);
2289 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
2291 code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
2293 code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
2296 "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());";
2300 if (field.flexbuffer) {
2302 " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
2304 // Both Data() and size() are const-methods, therefore call order
2307 " return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), "
2308 "{{FIELD_NAME}}()->size());";
2312 // Generate a comparison function for this field if it is a key.
2313 if (field.key) { GenKeyFieldMethods(field); }
2316 if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
2318 // Generate a verifier function that can check a buffer from an untrusted
2319 // source will never cause reads outside the buffer.
2320 code_ += " bool Verify(flatbuffers::Verifier &verifier) const {";
2321 code_ += " return VerifyTableStart(verifier)\\";
2322 for (auto it = struct_def.fields.vec.begin();
2323 it != struct_def.fields.vec.end(); ++it) {
2324 const auto &field = **it;
2325 if (field.deprecated) { continue; }
2326 GenVerifyCall(field, " &&\n ");
2329 code_ += " &&\n verifier.EndTable();";
2332 if (opts_.generate_object_based_api) {
2333 // Generate the UnPack() pre declaration.
2334 code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";";
2335 code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";";
2336 code_ += " " + TablePackSignature(struct_def, true, opts_) + ";";
2339 code_ += "};"; // End of table.
2342 // Explicit specializations for union accessors
2343 for (auto it = struct_def.fields.vec.begin();
2344 it != struct_def.fields.vec.end(); ++it) {
2345 const auto &field = **it;
2346 if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
2350 auto u = field.value.type.enum_def;
2351 if (u->uses_multiple_type_instances) continue;
2353 code_.SetValue("FIELD_NAME", Name(field));
2355 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2357 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
2359 auto full_struct_name = GetUnionElement(ev, false, opts_);
2363 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
2364 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2365 code_.SetValue("U_ELEMENT_NAME", full_struct_name);
2366 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2368 // `template<> const T *union_name_as<T>() const` accessor.
2371 "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
2372 "<{{U_ELEMENT_NAME}}>() const {";
2373 code_ += " return {{U_FIELD_NAME}}();";
2379 GenBuilders(struct_def);
2381 if (opts_.generate_object_based_api) {
2382 // Generate a pre-declaration for a CreateX method that works with an
2383 // unpacked C++ object.
2384 code_ += TableCreateSignature(struct_def, true, opts_) + ";";
2389 // Generate code to force vector alignment. Return empty string for vector
2390 // that doesn't need alignment code.
2391 std::string GenVectorForceAlign(const FieldDef &field,
2392 const std::string &field_size) {
2393 FLATBUFFERS_ASSERT(IsVector(field.value.type));
2394 // Get the value of the force_align attribute.
2395 const auto *force_align = field.attributes.Lookup("force_align");
2396 const int align = force_align ? atoi(force_align->constant.c_str()) : 1;
2397 // Generate code to do force_align for the vector.
2399 const auto vtype = field.value.type.VectorType();
2400 const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def)
2401 : GenTypeWire(vtype, "", false);
2402 return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type +
2403 "), " + std::to_string(static_cast<long long>(align)) + ");";
2408 void GenBuilders(const StructDef &struct_def) {
2409 code_.SetValue("STRUCT_NAME", Name(struct_def));
2411 // Generate a builder struct:
2412 code_ += "struct {{STRUCT_NAME}}Builder {";
2413 code_ += " typedef {{STRUCT_NAME}} Table;";
2414 code_ += " flatbuffers::FlatBufferBuilder &fbb_;";
2415 code_ += " flatbuffers::uoffset_t start_;";
2417 bool has_string_or_vector_fields = false;
2418 for (auto it = struct_def.fields.vec.begin();
2419 it != struct_def.fields.vec.end(); ++it) {
2420 const auto &field = **it;
2421 if (field.deprecated) continue;
2422 const bool is_scalar = IsScalar(field.value.type.base_type);
2423 const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
2424 const bool is_string = IsString(field.value.type);
2425 const bool is_vector = IsVector(field.value.type);
2426 if (is_string || is_vector) { has_string_or_vector_fields = true; }
2428 std::string offset = GenFieldOffsetName(field);
2429 std::string name = GenUnderlyingCast(field, false, Name(field));
2430 std::string value = is_default_scalar ? GenDefaultConstant(field) : "";
2432 // Generate accessor functions of the form:
2433 // void add_name(type name) {
2434 // fbb_.AddElement<type>(offset, name, default);
2436 code_.SetValue("FIELD_NAME", Name(field));
2437 code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
2438 code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
2439 code_.SetValue("ADD_NAME", name);
2440 code_.SetValue("ADD_VALUE", value);
2442 const auto type = GenTypeWire(field.value.type, "", false);
2443 code_.SetValue("ADD_FN", "AddElement<" + type + ">");
2444 } else if (IsStruct(field.value.type)) {
2445 code_.SetValue("ADD_FN", "AddStruct");
2447 code_.SetValue("ADD_FN", "AddOffset");
2450 code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
2451 code_ += " fbb_.{{ADD_FN}}(\\";
2452 if (is_default_scalar) {
2453 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
2455 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
2460 // Builder constructor
2462 " explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder "
2464 code_ += " : fbb_(_fbb) {";
2465 code_ += " start_ = fbb_.StartTable();";
2468 // Finish() function.
2469 code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
2470 code_ += " const auto end = fbb_.EndTable(start_);";
2471 code_ += " auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
2473 for (auto it = struct_def.fields.vec.begin();
2474 it != struct_def.fields.vec.end(); ++it) {
2475 const auto &field = **it;
2476 if (!field.deprecated && field.IsRequired()) {
2477 code_.SetValue("FIELD_NAME", Name(field));
2478 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2479 code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
2482 code_ += " return o;";
2487 // Generate a convenient CreateX function that uses the above builder
2488 // to create a table in one go.
2490 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2491 "Create{{STRUCT_NAME}}(";
2492 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2493 for (auto it = struct_def.fields.vec.begin();
2494 it != struct_def.fields.vec.end(); ++it) {
2495 const auto &field = **it;
2496 if (!field.deprecated) { GenParam(field, false, ",\n "); }
2500 code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);";
2501 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
2503 for (auto it = struct_def.fields.vec.rbegin();
2504 it != struct_def.fields.vec.rend(); ++it) {
2505 const auto &field = **it;
2506 if (!field.deprecated && (!struct_def.sortbysize ||
2507 size == SizeOf(field.value.type.base_type))) {
2508 code_.SetValue("FIELD_NAME", Name(field));
2509 if (field.IsScalarOptional()) {
2511 " if({{FIELD_NAME}}) { "
2512 "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }";
2514 code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
2519 code_ += " return builder_.Finish();";
2523 // Definition for type traits for this table type. This allows querying var-
2524 // ious compile-time traits of the table.
2525 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
2527 // Generate a CreateXDirect function with vector types as parameters
2528 if (opts_.cpp_direct_copy && has_string_or_vector_fields) {
2530 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2531 "Create{{STRUCT_NAME}}Direct(";
2532 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2533 for (auto it = struct_def.fields.vec.begin();
2534 it != struct_def.fields.vec.end(); ++it) {
2535 const auto &field = **it;
2536 if (!field.deprecated) { GenParam(field, true, ",\n "); }
2538 // Need to call "Create" with the struct namespace.
2539 const auto qualified_create_name =
2540 struct_def.defined_namespace->GetFullyQualifiedName("Create");
2541 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2543 for (auto it = struct_def.fields.vec.begin();
2544 it != struct_def.fields.vec.end(); ++it) {
2545 const auto &field = **it;
2546 if (!field.deprecated) {
2547 code_.SetValue("FIELD_NAME", Name(field));
2548 if (IsString(field.value.type)) {
2549 if (!field.shared) {
2550 code_.SetValue("CREATE_STRING", "CreateString");
2552 code_.SetValue("CREATE_STRING", "CreateSharedString");
2555 " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
2556 "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
2557 } else if (IsVector(field.value.type)) {
2558 const std::string force_align_code =
2559 GenVectorForceAlign(field, Name(field) + "->size()");
2560 if (!force_align_code.empty()) {
2561 code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }";
2563 code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
2564 const auto vtype = field.value.type.VectorType();
2565 const auto has_key = TypeHasKey(vtype);
2566 if (IsStruct(vtype)) {
2567 const auto type = WrapInNameSpace(*vtype.struct_def);
2568 code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<"
2569 : "_fbb.CreateVectorOfStructs<") +
2571 } else if (has_key) {
2572 const auto type = WrapInNameSpace(*vtype.struct_def);
2573 code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\";
2576 GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
2577 code_ += "_fbb.CreateVector<" + type + ">\\";
2580 has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;";
2584 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2586 for (auto it = struct_def.fields.vec.begin();
2587 it != struct_def.fields.vec.end(); ++it) {
2588 const auto &field = **it;
2589 if (!field.deprecated) {
2590 code_.SetValue("FIELD_NAME", Name(field));
2591 code_ += ",\n {{FIELD_NAME}}\\";
2592 if (IsString(field.value.type) || IsVector(field.value.type)) {
2603 std::string GenUnionUnpackVal(const FieldDef &afield,
2604 const char *vec_elem_access,
2605 const char *vec_type_access) {
2606 auto type_name = WrapInNameSpace(*afield.value.type.enum_def);
2607 return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " +
2608 EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
2609 vec_type_access + ", _resolver)";
2612 std::string GenUnpackVal(const Type &type, const std::string &val,
2613 bool invector, const FieldDef &afield) {
2614 switch (type.base_type) {
2615 case BASE_TYPE_STRING: {
2616 if (FlexibleStringConstructor(&afield)) {
2617 return NativeString(&afield) + "(" + val + "->c_str(), " + val +
2620 return val + "->str()";
2623 case BASE_TYPE_STRUCT: {
2624 if (IsStruct(type)) {
2625 const auto &struct_attrs = type.struct_def->attributes;
2626 const auto native_type = struct_attrs.Lookup("native_type");
2628 std::string unpack_call = "flatbuffers::UnPack";
2629 const auto pack_name = struct_attrs.Lookup("native_type_pack_name");
2630 if (pack_name) { unpack_call += pack_name->constant; }
2631 unpack_call += "(*" + val + ")";
2633 } else if (invector || afield.native_inline) {
2636 const auto name = WrapInNameSpace(*type.struct_def);
2637 const auto ptype = GenTypeNativePtr(name, &afield, true);
2638 return ptype + "(new " + name + "(*" + val + "))";
2641 const auto ptype = GenTypeNativePtr(
2642 WrapNativeNameInNameSpace(*type.struct_def, opts_), &afield,
2644 return ptype + "(" + val + "->UnPack(_resolver))";
2647 case BASE_TYPE_UNION: {
2648 return GenUnionUnpackVal(
2649 afield, invector ? "->Get(_i)" : "",
2650 invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
2660 std::string GenUnpackFieldStatement(const FieldDef &field,
2661 const FieldDef *union_field) {
2663 switch (field.value.type.base_type) {
2664 case BASE_TYPE_VECTOR: {
2665 auto name = Name(field);
2666 if (field.value.type.element == BASE_TYPE_UTYPE) {
2667 name = StripUnionType(Name(field));
2669 code += "{ _o->" + name + ".resize(_e->size()); ";
2670 if (!field.value.type.enum_def && !IsBool(field.value.type.element) &&
2671 IsOneByte(field.value.type.element)) {
2672 // For vectors of bytes, std::copy is used to improve performance.
2673 // This doesn't work for:
2674 // - enum types because they have to be explicitly static_cast.
2675 // - vectors of bool, since they are a template specialization.
2676 // - multiple-byte types due to endianness.
2678 "std::copy(_e->begin(), _e->end(), _o->" + name + ".begin()); }";
2680 std::string indexing;
2681 if (field.value.type.enum_def) {
2682 indexing += "static_cast<" +
2683 WrapInNameSpace(*field.value.type.enum_def) + ">(";
2685 indexing += "_e->Get(_i)";
2686 if (field.value.type.enum_def) { indexing += ")"; }
2687 if (field.value.type.element == BASE_TYPE_BOOL) {
2688 indexing += " != 0";
2690 // Generate code that pushes data from _e to _o in the form:
2691 // for (uoffset_t i = 0; i < _e->size(); ++i) {
2692 // _o->field.push_back(_e->Get(_i));
2695 field.value.type.element == BASE_TYPE_UTYPE
2697 : (field.value.type.element == BASE_TYPE_UNION ? ".value"
2700 code += "for (flatbuffers::uoffset_t _i = 0;";
2701 code += " _i < _e->size(); _i++) { ";
2702 auto cpp_type = field.attributes.Lookup("cpp_type");
2704 // Generate code that resolves the cpp pointer type, of the form:
2706 // (*resolver)(&_o->field, (hash_value_t)(_e));
2708 // _o->field = nullptr;
2709 code += "//vector resolver, " + PtrType(&field) + "\n";
2710 code += "if (_resolver) ";
2711 code += "(*_resolver)";
2712 code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" +
2715 "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
2716 if (PtrType(&field) == "naked") {
2718 code += "_o->" + name + "[_i]" + access + " = nullptr";
2720 // code += " else ";
2721 // code += "_o->" + name + "[_i]" + access + " = " +
2722 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2723 code += "/* else do nothing */";
2726 code += "_o->" + name + "[_i]" + access + " = ";
2727 code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
2734 case BASE_TYPE_UTYPE: {
2735 FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
2737 // Generate code that sets the union type, of the form:
2738 // _o->field.type = _e;
2739 code += "_o->" + union_field->name + ".type = _e;";
2742 case BASE_TYPE_UNION: {
2743 // Generate code that sets the union value, of the form:
2744 // _o->field.value = Union::Unpack(_e, field_type(), resolver);
2745 code += "_o->" + Name(field) + ".value = ";
2746 code += GenUnionUnpackVal(field, "", "");
2751 auto cpp_type = field.attributes.Lookup("cpp_type");
2753 // Generate code that resolves the cpp pointer type, of the form:
2755 // (*resolver)(&_o->field, (hash_value_t)(_e));
2757 // _o->field = nullptr;
2758 code += "//scalar resolver, " + PtrType(&field) + " \n";
2759 code += "if (_resolver) ";
2760 code += "(*_resolver)";
2761 code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
2762 code += "static_cast<flatbuffers::hash_value_t>(_e));";
2763 if (PtrType(&field) == "naked") {
2765 code += "_o->" + Name(field) + " = nullptr;";
2767 // code += " else ";
2768 // code += "_o->" + Name(field) + " = " +
2769 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2770 code += "/* else do nothing */;";
2773 // Generate code for assigning the value, of the form:
2774 // _o->field = value;
2775 code += "_o->" + Name(field) + " = ";
2776 code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
2784 std::string GenCreateParam(const FieldDef &field) {
2785 std::string value = "_o->";
2786 if (field.value.type.base_type == BASE_TYPE_UTYPE) {
2787 value += StripUnionType(Name(field));
2790 value += Name(field);
2792 if (field.value.type.base_type != BASE_TYPE_VECTOR &&
2793 field.attributes.Lookup("cpp_type")) {
2794 auto type = GenTypeBasic(field.value.type, false);
2798 type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
2802 switch (field.value.type.base_type) {
2803 // String fields are of the form:
2804 // _fbb.CreateString(_o->field)
2806 // _fbb.CreateSharedString(_o->field)
2807 case BASE_TYPE_STRING: {
2808 if (!field.shared) {
2809 code += "_fbb.CreateString(";
2811 code += "_fbb.CreateSharedString(";
2814 code.push_back(')');
2816 // For optional fields, check to see if there actually is any data
2817 // in _o->field before attempting to access it. If there isn't,
2818 // depending on set_empty_strings_to_null either set it to 0 or an empty
2820 if (!field.IsRequired()) {
2821 auto empty_value = opts_.set_empty_strings_to_null
2823 : "_fbb.CreateSharedString(\"\")";
2824 code = value + ".empty() ? " + empty_value + " : " + code;
2828 // Vector fields come in several flavours, of the forms:
2829 // _fbb.CreateVector(_o->field);
2830 // _fbb.CreateVector((const utype*)_o->field.data(),
2831 // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field)
2832 // _fbb.CreateVectorOfStructs(_o->field)
2833 // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
2834 // return CreateT(_fbb, _o->Get(i), rehasher);
2836 case BASE_TYPE_VECTOR: {
2837 auto vector_type = field.value.type.VectorType();
2838 switch (vector_type.base_type) {
2839 case BASE_TYPE_STRING: {
2840 if (NativeString(&field) == "std::string") {
2841 code += "_fbb.CreateVectorOfStrings(" + value + ")";
2843 // Use by-function serialization to emulate
2844 // CreateVectorOfStrings(); this works also with non-std strings.
2846 "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>"
2848 code += "(" + value + ".size(), ";
2849 code += "[](size_t i, _VectorArgs *__va) { ";
2851 "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
2852 code += " }, &_va )";
2856 case BASE_TYPE_STRUCT: {
2857 if (IsStruct(vector_type)) {
2858 const auto &struct_attrs =
2859 field.value.type.struct_def->attributes;
2860 const auto native_type = struct_attrs.Lookup("native_type");
2862 code += "_fbb.CreateVectorOfNativeStructs<";
2863 code += WrapInNameSpace(*vector_type.struct_def) + ", " +
2864 native_type->constant + ">";
2865 code += "(" + value;
2866 const auto pack_name =
2867 struct_attrs.Lookup("native_type_pack_name");
2869 code += ", flatbuffers::Pack" + pack_name->constant;
2873 code += "_fbb.CreateVectorOfStructs";
2874 code += "(" + value + ")";
2877 code += "_fbb.CreateVector<flatbuffers::Offset<";
2878 code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
2879 code += "(" + value + ".size(), ";
2880 code += "[](size_t i, _VectorArgs *__va) { ";
2881 code += "return Create" + vector_type.struct_def->name;
2882 code += "(*__va->__fbb, __va->_" + value + "[i]" +
2883 GenPtrGet(field) + ", ";
2884 code += "__va->__rehasher); }, &_va )";
2888 case BASE_TYPE_BOOL: {
2889 code += "_fbb.CreateVector(" + value + ")";
2892 case BASE_TYPE_UNION: {
2894 "_fbb.CreateVector<flatbuffers::"
2897 ".size(), [](size_t i, _VectorArgs *__va) { "
2899 value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
2902 case BASE_TYPE_UTYPE: {
2903 value = StripUnionType(value);
2904 code += "_fbb.CreateVector<uint8_t>(" + value +
2905 ".size(), [](size_t i, _VectorArgs *__va) { "
2906 "return static_cast<uint8_t>(__va->_" +
2907 value + "[i].type); }, &_va)";
2911 if (field.value.type.enum_def &&
2912 !VectorElementUserFacing(vector_type)) {
2913 // For enumerations, we need to get access to the array data for
2914 // the underlying storage type (eg. uint8_t).
2915 const auto basetype = GenTypeBasic(
2916 field.value.type.enum_def->underlying_type, false);
2917 code += "_fbb.CreateVectorScalarCast<" + basetype +
2918 ">(flatbuffers::data(" + value + "), " + value +
2920 } else if (field.attributes.Lookup("cpp_type")) {
2921 auto type = GenTypeBasic(vector_type, false);
2922 code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
2923 code += "[](size_t i, _VectorArgs *__va) { ";
2924 code += "return __va->__rehasher ? ";
2925 code += "static_cast<" + type + ">((*__va->__rehasher)";
2926 code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
2927 code += "; }, &_va )";
2929 code += "_fbb.CreateVector(" + value + ")";
2935 // If set_empty_vectors_to_null option is enabled, for optional fields,
2936 // check to see if there actually is any data in _o->field before
2937 // attempting to access it.
2938 if (opts_.set_empty_vectors_to_null && !field.IsRequired()) {
2939 code = value + ".size() ? " + code + " : 0";
2943 case BASE_TYPE_UNION: {
2944 // _o->field.Pack(_fbb);
2945 code += value + ".Pack(_fbb)";
2948 case BASE_TYPE_STRUCT: {
2949 if (IsStruct(field.value.type)) {
2950 const auto &struct_attribs = field.value.type.struct_def->attributes;
2951 const auto native_type = struct_attribs.Lookup("native_type");
2953 code += "flatbuffers::Pack";
2954 const auto pack_name =
2955 struct_attribs.Lookup("native_type_pack_name");
2956 if (pack_name) { code += pack_name->constant; }
2957 code += "(" + value + ")";
2958 } else if (field.native_inline) {
2959 code += "&" + value;
2961 code += value + " ? " + value + GenPtrGet(field) + " : 0";
2964 // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
2965 const auto type = field.value.type.struct_def->name;
2966 code += value + " ? Create" + type;
2967 code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
2980 // Generate code for tables that needs to come after the regular definition.
2981 void GenTablePost(const StructDef &struct_def) {
2982 code_.SetValue("STRUCT_NAME", Name(struct_def));
2983 code_.SetValue("NATIVE_NAME",
2984 NativeName(Name(struct_def), &struct_def, opts_));
2986 if (opts_.generate_object_based_api) {
2987 // Generate the X::UnPack() method.
2989 "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
2991 if (opts_.g_cpp_std == cpp::CPP_STD_X0) {
2992 auto native_name = WrapNativeNameInNameSpace(struct_def, parser_.opts);
2993 code_.SetValue("POINTER_TYPE",
2994 GenTypeNativePtr(native_name, nullptr, false));
2996 " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
2997 } else if (opts_.g_cpp_std == cpp::CPP_STD_11) {
2999 " auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new "
3000 "{{NATIVE_NAME}}());";
3002 code_ += " auto _o = std::make_unique<{{NATIVE_NAME}}>();";
3004 code_ += " UnPackTo(_o.get(), _resolver);";
3005 code_ += " return _o.release();";
3009 "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
3010 code_ += " (void)_o;";
3011 code_ += " (void)_resolver;";
3013 for (auto it = struct_def.fields.vec.begin();
3014 it != struct_def.fields.vec.end(); ++it) {
3015 const auto &field = **it;
3016 if (field.deprecated) { continue; }
3018 // Assign a value from |this| to |_o|. Values from |this| are stored
3019 // in a variable |_e| by calling this->field_type(). The value is then
3020 // assigned to |_o| using the GenUnpackFieldStatement.
3021 const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
3022 const auto statement =
3023 GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
3025 code_.SetValue("FIELD_NAME", Name(field));
3026 auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
3027 auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
3028 auto postfix = " }";
3029 code_ += std::string(prefix) + check + statement + postfix;
3034 // Generate the X::Pack member function that simply calls the global
3035 // CreateX function.
3036 code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
3037 code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
3041 // Generate a CreateX method that works with an unpacked C++ object.
3043 "inline " + TableCreateSignature(struct_def, false, opts_) + " {";
3044 code_ += " (void)_rehasher;";
3045 code_ += " (void)_o;";
3048 " struct _VectorArgs "
3049 "{ flatbuffers::FlatBufferBuilder *__fbb; "
3051 NativeName(Name(struct_def), &struct_def, opts_) +
3053 "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
3054 "&_fbb, _o, _rehasher}; (void)_va;";
3056 for (auto it = struct_def.fields.vec.begin();
3057 it != struct_def.fields.vec.end(); ++it) {
3059 if (field.deprecated) { continue; }
3060 if (IsVector(field.value.type)) {
3061 const std::string force_align_code =
3062 GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
3063 if (!force_align_code.empty()) { code_ += " " + force_align_code; }
3065 code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
3067 // Need to call "Create" with the struct namespace.
3068 const auto qualified_create_name =
3069 struct_def.defined_namespace->GetFullyQualifiedName("Create");
3070 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
3072 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
3074 for (auto it = struct_def.fields.vec.begin();
3075 it != struct_def.fields.vec.end(); ++it) {
3077 if (field.deprecated) { continue; }
3079 bool pass_by_address = false;
3080 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
3081 if (IsStruct(field.value.type)) {
3083 field.value.type.struct_def->attributes.Lookup("native_type");
3084 if (native_type) { pass_by_address = true; }
3088 // Call the CreateX function using values from |_o|.
3089 if (pass_by_address) {
3090 code_ += ",\n &_" + Name(field) + "\\";
3092 code_ += ",\n _" + Name(field) + "\\";
3101 static void GenPadding(
3102 const FieldDef &field, std::string *code_ptr, int *id,
3103 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
3104 if (field.padding) {
3105 for (int i = 0; i < 4; i++) {
3106 if (static_cast<int>(field.padding) & (1 << i)) {
3107 f((1 << i) * 8, code_ptr, id);
3110 FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
3114 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
3115 *code_ptr += " int" + NumToString(bits) + "_t padding" +
3116 NumToString((*id)++) + "__;";
3119 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
3121 if (!code_ptr->empty()) *code_ptr += ",\n ";
3122 *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
3125 static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
3127 if (!code_ptr->empty()) *code_ptr += '\n';
3128 *code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
3131 void GenStructDefaultConstructor(const StructDef &struct_def) {
3132 std::string init_list;
3134 bool first_in_init_list = true;
3135 int padding_initializer_id = 0;
3136 int padding_body_id = 0;
3137 for (auto it = struct_def.fields.vec.begin();
3138 it != struct_def.fields.vec.end(); ++it) {
3139 const auto field = *it;
3140 const auto field_name = field->name + "_";
3142 if (first_in_init_list) {
3143 first_in_init_list = false;
3149 init_list += field_name;
3150 if (IsStruct(field->value.type) || IsArray(field->value.type)) {
3151 // this is either default initialization of struct
3153 // implicit initialization of array
3154 // for each object in array it:
3155 // * sets it as zeros for POD types (integral, floating point, etc)
3156 // * calls default constructor for classes/structs
3161 if (field->padding) {
3162 GenPadding(*field, &init_list, &padding_initializer_id,
3163 PaddingInitializer);
3164 GenPadding(*field, &body, &padding_body_id, PaddingNoop);
3168 if (init_list.empty()) {
3169 code_ += " {{STRUCT_NAME}}()";
3172 code_.SetValue("INIT_LIST", init_list);
3173 code_ += " {{STRUCT_NAME}}()";
3174 code_ += " : {{INIT_LIST}} {";
3175 if (!body.empty()) { code_ += body; }
3180 void GenStructConstructor(const StructDef &struct_def,
3181 GenArrayArgMode array_mode) {
3182 std::string arg_list;
3183 std::string init_list;
3185 auto first = struct_def.fields.vec.begin();
3186 // skip arrays if generate ctor without array assignment
3187 const auto init_arrays = (array_mode != kArrayArgModeNone);
3188 for (auto it = struct_def.fields.vec.begin();
3189 it != struct_def.fields.vec.end(); ++it) {
3190 const auto &field = **it;
3191 const auto &type = field.value.type;
3192 const auto is_array = IsArray(type);
3193 const auto arg_name = "_" + Name(field);
3194 if (!is_array || init_arrays) {
3195 if (it != first && !arg_list.empty()) { arg_list += ", "; }
3196 arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true)
3197 : GenTypeSpan(type, true, type.fixed_length);
3198 arg_list += arg_name;
3200 // skip an array with initialization from span
3201 if (false == (is_array && init_arrays)) {
3202 if (it != first && !init_list.empty()) { init_list += ",\n "; }
3203 init_list += Name(field) + "_";
3204 if (IsScalar(type.base_type)) {
3205 auto scalar_type = GenUnderlyingCast(field, false, arg_name);
3206 init_list += "(flatbuffers::EndianScalar(" + scalar_type + "))";
3208 FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type));
3210 init_list += "(" + arg_name + ")";
3216 GenPadding(field, &init_list, &padding_id, PaddingInitializer);
3219 if (!arg_list.empty()) {
3220 code_.SetValue("ARG_LIST", arg_list);
3221 code_.SetValue("INIT_LIST", init_list);
3222 if (!init_list.empty()) {
3223 code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
3224 code_ += " : {{INIT_LIST}} {";
3226 code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
3229 for (auto it = struct_def.fields.vec.begin();
3230 it != struct_def.fields.vec.end(); ++it) {
3231 const auto &field = **it;
3232 const auto &type = field.value.type;
3233 if (IsArray(type) && init_arrays) {
3234 const auto &element_type = type.VectorType();
3235 const auto is_enum = IsEnum(element_type);
3237 (IsScalar(element_type.base_type) || IsStruct(element_type)) &&
3238 "invalid declaration");
3239 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3240 std::string get_array =
3241 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3242 const auto field_name = Name(field) + "_";
3243 const auto arg_name = "_" + Name(field);
3244 code_ += " flatbuffers::" + get_array + "(" + field_name +
3245 ").CopyFromSpan(" + arg_name + ");";
3247 if (field.padding) {
3248 std::string padding;
3249 GenPadding(field, &padding, &padding_id, PaddingNoop);
3257 void GenArrayAccessor(const Type &type, bool mutable_accessor) {
3258 FLATBUFFERS_ASSERT(IsArray(type));
3259 const auto is_enum = IsEnum(type.VectorType());
3260 // The Array<bool,N> is a tricky case, like std::vector<bool>.
3261 // It requires a specialization of Array class.
3262 // Generate Array<uint8_t> for Array<bool>.
3263 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3264 std::string ret_type = "flatbuffers::Array<" + face_type + ", " +
3265 NumToString(type.fixed_length) + ">";
3266 if (mutable_accessor)
3267 code_ += " " + ret_type + " *mutable_{{FIELD_NAME}}() {";
3269 code_ += " const " + ret_type + " *{{FIELD_NAME}}() const {";
3271 std::string get_array =
3272 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3273 code_ += " return &flatbuffers::" + get_array + "({{FIELD_VALUE}});";
3277 // Generate an accessor struct with constructor for a flatbuffers struct.
3278 void GenStruct(const StructDef &struct_def) {
3279 // Generate an accessor struct, with private variables of the form:
3281 // Generates manual padding and alignment.
3282 // Variables are private because they contain little endian data on all
3284 GenComment(struct_def.doc_comment);
3285 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
3286 code_.SetValue("STRUCT_NAME", Name(struct_def));
3289 "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
3290 "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
3291 code_ += " private:";
3294 for (auto it = struct_def.fields.vec.begin();
3295 it != struct_def.fields.vec.end(); ++it) {
3296 const auto &field = **it;
3297 const auto &field_type = field.value.type;
3298 code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
3299 code_.SetValue("FIELD_NAME", Name(field));
3300 code_.SetValue("ARRAY",
3302 ? "[" + NumToString(field_type.fixed_length) + "]"
3304 code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
3306 if (field.padding) {
3307 std::string padding;
3308 GenPadding(field, &padding, &padding_id, PaddingDefinition);
3313 // Generate GetFullyQualifiedName
3315 code_ += " public:";
3317 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
3319 // Make TypeTable accessible via the generated struct.
3320 if (opts_.mini_reflect != IDLOptions::kNone) {
3322 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
3323 code_ += " return {{STRUCT_NAME}}TypeTable();";
3327 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
3329 // Generate a default constructor.
3330 GenStructDefaultConstructor(struct_def);
3332 // Generate a constructor that takes all fields as arguments,
3333 // excluding arrays.
3334 GenStructConstructor(struct_def, kArrayArgModeNone);
3336 auto arrays_num = std::count_if(struct_def.fields.vec.begin(),
3337 struct_def.fields.vec.end(),
3338 [](const flatbuffers::FieldDef *fd) {
3339 return IsArray(fd->value.type);
3341 if (arrays_num > 0) {
3342 GenStructConstructor(struct_def, kArrayArgModeSpanStatic);
3345 // Generate accessor methods of the form:
3346 // type name() const { return flatbuffers::EndianScalar(name_); }
3347 for (auto it = struct_def.fields.vec.begin();
3348 it != struct_def.fields.vec.end(); ++it) {
3349 const auto &field = **it;
3350 const auto &type = field.value.type;
3351 const auto is_scalar = IsScalar(type.base_type);
3352 const auto is_array = IsArray(type);
3354 const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ",
3355 is_array ? "" : " &", true);
3356 auto member = Name(field) + "_";
3358 is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
3360 code_.SetValue("FIELD_NAME", Name(field));
3361 code_.SetValue("FIELD_TYPE", field_type);
3362 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
3364 GenComment(field.doc_comment, " ");
3366 // Generate a const accessor function.
3368 GenArrayAccessor(type, false);
3370 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
3371 code_ += " return {{FIELD_VALUE}};";
3375 // Generate a mutable accessor function.
3376 if (opts_.mutable_buffer) {
3377 auto mut_field_type =
3378 GenTypeGet(type, " ", "", is_array ? "" : " &", true);
3379 code_.SetValue("FIELD_TYPE", mut_field_type);
3381 code_.SetValue("ARG", GenTypeBasic(type, true));
3382 code_.SetValue("FIELD_VALUE",
3383 GenUnderlyingCast(field, false, "_" + Name(field)));
3385 code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
3387 " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
3388 "{{FIELD_VALUE}});";
3390 } else if (is_array) {
3391 GenArrayAccessor(type, true);
3393 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
3394 code_ += " return {{FIELD_VALUE}};";
3399 // Generate a comparison function for this field if it is a key.
3400 if (field.key) { GenKeyFieldMethods(field); }
3402 code_.SetValue("NATIVE_NAME", Name(struct_def));
3403 GenOperatorNewDelete(struct_def);
3405 if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
3409 code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
3410 code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
3411 if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
3414 // Definition for type traits for this table type. This allows querying var-
3415 // ious compile-time traits of the table.
3416 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
3419 // Set up the correct namespace. Only open a namespace if the existing one is
3420 // different (closing/opening only what is necessary).
3422 // The file must start and end with an empty (or null) namespace so that
3423 // namespaces are properly opened and closed.
3424 void SetNameSpace(const Namespace *ns) {
3425 if (cur_name_space_ == ns) { return; }
3427 // Compute the size of the longest common namespace prefix.
3428 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
3429 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
3430 // and common_prefix_size = 2
3431 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
3432 size_t new_size = ns ? ns->components.size() : 0;
3434 size_t common_prefix_size = 0;
3435 while (common_prefix_size < old_size && common_prefix_size < new_size &&
3436 ns->components[common_prefix_size] ==
3437 cur_name_space_->components[common_prefix_size]) {
3438 common_prefix_size++;
3441 // Close cur_name_space in reverse order to reach the common prefix.
3442 // In the previous example, D then C are closed.
3443 for (size_t j = old_size; j > common_prefix_size; --j) {
3444 code_ += "} // namespace " + cur_name_space_->components[j - 1];
3446 if (old_size != common_prefix_size) { code_ += ""; }
3448 // open namespace parts to reach the ns namespace
3449 // in the previous example, E, then F, then G are opened
3450 for (auto j = common_prefix_size; j != new_size; ++j) {
3451 code_ += "namespace " + ns->components[j] + " {";
3453 if (new_size != common_prefix_size) { code_ += ""; }
3455 cur_name_space_ = ns;
3461 bool GenerateCPP(const Parser &parser, const std::string &path,
3462 const std::string &file_name) {
3463 cpp::IDLOptionsCpp opts(parser.opts);
3464 // The '--cpp_std' argument could be extended (like ASAN):
3465 // Example: "flatc --cpp_std c++17:option1:option2".
3466 auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++11";
3467 std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), CharToUpper);
3468 if (cpp_std == "C++0X") {
3469 opts.g_cpp_std = cpp::CPP_STD_X0;
3470 opts.g_only_fixed_enums = false;
3471 } else if (cpp_std == "C++11") {
3472 // Use the standard C++11 code generator.
3473 opts.g_cpp_std = cpp::CPP_STD_11;
3474 opts.g_only_fixed_enums = true;
3475 } else if (cpp_std == "C++17") {
3476 opts.g_cpp_std = cpp::CPP_STD_17;
3477 // With c++17 generate strong enums only.
3478 opts.scoped_enums = true;
3479 // By default, prefixed_enums==true, reset it.
3480 opts.prefixed_enums = false;
3482 LogCompilerError("Unknown value of the '--cpp-std' switch: " +
3486 // The opts.scoped_enums has priority.
3487 opts.g_only_fixed_enums |= opts.scoped_enums;
3489 if (opts.cpp_static_reflection && opts.g_cpp_std < cpp::CPP_STD_17) {
3491 "--cpp-static-reflection requires using --cpp-std at \"C++17\" or "
3496 cpp::CppGenerator generator(parser, path, file_name, opts);
3497 return generator.generate();
3500 std::string CPPMakeRule(const Parser &parser, const std::string &path,
3501 const std::string &file_name) {
3502 const auto filebase =
3503 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
3504 cpp::CppGenerator geneartor(parser, path, file_name, parser.opts);
3505 const auto included_files = parser.GetIncludedFilesRecursive(file_name);
3506 std::string make_rule =
3507 geneartor.GeneratedFileName(path, filebase, parser.opts) + ": ";
3508 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
3509 make_rule += " " + *it;
3514 } // namespace flatbuffers