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 // Don't generate code to copy if table is not copyable.
1539 // TODO(wvo): make tables copyable instead.
1540 for (auto fit = ev.union_type.struct_def->fields.vec.begin();
1541 fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
1542 const auto &field = **fit;
1543 if (!field.deprecated && field.value.type.struct_def &&
1544 !field.native_inline) {
1552 " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
1556 " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable.";
1561 code_ += " default:";
1567 // Union Reset() function.
1568 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1569 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1571 code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
1572 code_ += " switch (type) {";
1573 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1575 const auto &ev = **it;
1576 if (ev.IsZero()) { continue; }
1577 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1578 code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
1579 code_ += " case {{LABEL}}: {";
1580 code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
1581 code_ += " delete ptr;";
1585 code_ += " default: break;";
1587 code_ += " value = nullptr;";
1588 code_ += " type = {{NONE}};";
1594 // Generates a value with optionally a cast applied if the field has a
1595 // different underlying type from its interface type (currently only the
1596 // case for enums. "from" specify the direction, true meaning from the
1597 // underlying type to the interface type.
1598 std::string GenUnderlyingCast(const FieldDef &field, bool from,
1599 const std::string &val) {
1600 if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
1601 return val + " != 0";
1602 } else if ((field.value.type.enum_def &&
1603 IsScalar(field.value.type.base_type)) ||
1604 field.value.type.base_type == BASE_TYPE_BOOL) {
1605 return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
1612 std::string GenFieldOffsetName(const FieldDef &field) {
1613 std::string uname = Name(field);
1614 std::transform(uname.begin(), uname.end(), uname.begin(), CharToUpper);
1615 return "VT_" + uname;
1618 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1619 const std::string &name) {
1620 if (!opts_.generate_name_strings) { return; }
1621 auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
1622 code_.SetValue("NAME", fullname);
1623 code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
1624 code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
1625 code_ += " return \"{{NAME}}\";";
1629 std::string GenDefaultConstant(const FieldDef &field) {
1630 if (IsFloat(field.value.type.base_type))
1631 return float_const_gen_.GenFloatConstant(field);
1633 return NumToStringCpp(field.value.constant, field.value.type.base_type);
1636 std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
1637 const auto &type = field.value.type;
1638 if (field.IsScalarOptional()) {
1639 return GenOptionalNull();
1640 } else if (type.enum_def && IsScalar(type.base_type)) {
1641 auto ev = type.enum_def->FindByValue(field.value.constant);
1643 return WrapInNameSpace(type.enum_def->defined_namespace,
1644 GetEnumValUse(*type.enum_def, *ev));
1646 return GenUnderlyingCast(
1647 field, true, NumToStringCpp(field.value.constant, type.base_type));
1649 } else if (type.base_type == BASE_TYPE_BOOL) {
1650 return field.value.constant == "0" ? "false" : "true";
1651 } else if (field.attributes.Lookup("cpp_type")) {
1653 if (PtrType(&field) == "naked") {
1662 return GenDefaultConstant(field);
1666 void GenParam(const FieldDef &field, bool direct, const char *prefix) {
1667 code_.SetValue("PRE", prefix);
1668 code_.SetValue("PARAM_NAME", Name(field));
1669 if (direct && IsString(field.value.type)) {
1670 code_.SetValue("PARAM_TYPE", "const char *");
1671 code_.SetValue("PARAM_VALUE", "nullptr");
1672 } else if (direct && IsVector(field.value.type)) {
1673 const auto vtype = field.value.type.VectorType();
1675 if (IsStruct(vtype)) {
1676 type = WrapInNameSpace(*vtype.struct_def);
1678 type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
1680 if (TypeHasKey(vtype)) {
1681 code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
1683 code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
1685 code_.SetValue("PARAM_VALUE", "nullptr");
1687 const auto &type = field.value.type;
1688 code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
1689 if (field.IsScalarOptional())
1690 code_.SetValue("PARAM_TYPE", GenOptionalDecl(type) + " ");
1692 code_.SetValue("PARAM_TYPE", GenTypeWire(type, " ", true));
1694 code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
1697 // Generate a member, including a default value for scalars and raw pointers.
1698 void GenMember(const FieldDef &field) {
1699 if (!field.deprecated && // Deprecated fields won't be accessible.
1700 field.value.type.base_type != BASE_TYPE_UTYPE &&
1701 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1702 field.value.type.element != BASE_TYPE_UTYPE)) {
1703 auto type = GenTypeNative(field.value.type, false, field);
1704 auto cpp_type = field.attributes.Lookup("cpp_type");
1707 ? (IsVector(field.value.type)
1709 GenTypeNativePtr(cpp_type->constant, &field,
1712 : GenTypeNativePtr(cpp_type->constant, &field, false))
1714 // Generate default member initializers for >= C++11.
1715 std::string field_di = "";
1716 if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
1718 auto native_default = field.attributes.Lookup("native_default");
1719 // Scalar types get parsed defaults, raw pointers get nullptrs.
1720 if (IsScalar(field.value.type.base_type)) {
1722 " = " + (native_default ? std::string(native_default->constant)
1723 : GetDefaultScalarValue(field, true));
1724 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1725 if (IsStruct(field.value.type) && native_default) {
1726 field_di = " = " + native_default->constant;
1730 code_.SetValue("FIELD_TYPE", full_type);
1731 code_.SetValue("FIELD_NAME", Name(field));
1732 code_.SetValue("FIELD_DI", field_di);
1733 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}{{FIELD_DI}};";
1737 // Generate the default constructor for this struct. Properly initialize all
1738 // scalar members with default values.
1739 void GenDefaultConstructor(const StructDef &struct_def) {
1740 code_.SetValue("NATIVE_NAME",
1741 NativeName(Name(struct_def), &struct_def, opts_));
1742 // In >= C++11, default member initializers are generated.
1743 if (opts_.g_cpp_std >= cpp::CPP_STD_11) { return; }
1744 std::string initializer_list;
1745 for (auto it = struct_def.fields.vec.begin();
1746 it != struct_def.fields.vec.end(); ++it) {
1747 const auto &field = **it;
1748 if (!field.deprecated && // Deprecated fields won't be accessible.
1749 field.value.type.base_type != BASE_TYPE_UTYPE) {
1750 auto cpp_type = field.attributes.Lookup("cpp_type");
1751 auto native_default = field.attributes.Lookup("native_default");
1752 // Scalar types get parsed defaults, raw pointers get nullptrs.
1753 if (IsScalar(field.value.type.base_type)) {
1754 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1755 initializer_list += Name(field);
1758 (native_default ? std::string(native_default->constant)
1759 : GetDefaultScalarValue(field, true)) +
1761 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1762 if (IsStruct(field.value.type)) {
1763 if (native_default) {
1764 if (!initializer_list.empty()) {
1765 initializer_list += ",\n ";
1768 Name(field) + "(" + native_default->constant + ")";
1771 } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) {
1772 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1773 initializer_list += Name(field) + "(0)";
1777 if (!initializer_list.empty()) {
1778 initializer_list = "\n : " + initializer_list;
1781 code_.SetValue("INIT_LIST", initializer_list);
1783 code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
1787 void GenCompareOperator(const StructDef &struct_def,
1788 std::string accessSuffix = "") {
1789 std::string compare_op;
1790 for (auto it = struct_def.fields.vec.begin();
1791 it != struct_def.fields.vec.end(); ++it) {
1792 const auto &field = **it;
1793 if (!field.deprecated && // Deprecated fields won't be accessible.
1794 field.value.type.base_type != BASE_TYPE_UTYPE &&
1795 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1796 field.value.type.element != BASE_TYPE_UTYPE)) {
1797 if (!compare_op.empty()) { compare_op += " &&\n "; }
1798 auto accessor = Name(field) + accessSuffix;
1799 compare_op += "(lhs." + accessor + " == rhs." + accessor + ")";
1803 std::string cmp_lhs;
1804 std::string cmp_rhs;
1805 if (compare_op.empty()) {
1808 compare_op = " return true;";
1812 compare_op = " return\n " + compare_op + ";";
1815 code_.SetValue("CMP_OP", compare_op);
1816 code_.SetValue("CMP_LHS", cmp_lhs);
1817 code_.SetValue("CMP_RHS", cmp_rhs);
1820 "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
1821 "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
1822 code_ += "{{CMP_OP}}";
1827 "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
1828 "{{NATIVE_NAME}} &rhs) {";
1829 code_ += " return !(lhs == rhs);";
1834 void GenOperatorNewDelete(const StructDef &struct_def) {
1835 if (auto native_custom_alloc =
1836 struct_def.attributes.Lookup("native_custom_alloc")) {
1837 code_ += " inline void *operator new (std::size_t count) {";
1838 code_ += " return " + native_custom_alloc->constant +
1839 "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
1841 code_ += " inline void operator delete (void *ptr) {";
1842 code_ += " return " + native_custom_alloc->constant +
1843 "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
1849 void GenNativeTable(const StructDef &struct_def) {
1850 const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
1851 code_.SetValue("STRUCT_NAME", Name(struct_def));
1852 code_.SetValue("NATIVE_NAME", native_name);
1854 // Generate a C++ object that can hold an unpacked version of this table.
1855 code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
1856 code_ += " typedef {{STRUCT_NAME}} TableType;";
1857 GenFullyQualifiedNameGetter(struct_def, native_name);
1858 for (auto it = struct_def.fields.vec.begin();
1859 it != struct_def.fields.vec.end(); ++it) {
1862 GenOperatorNewDelete(struct_def);
1863 GenDefaultConstructor(struct_def);
1865 if (opts_.gen_compare) GenCompareOperator(struct_def);
1869 // Generate the code to call the appropriate Verify function(s) for a field.
1870 void GenVerifyCall(const FieldDef &field, const char *prefix) {
1871 code_.SetValue("PRE", prefix);
1872 code_.SetValue("NAME", Name(field));
1873 code_.SetValue("REQUIRED", field.IsRequired() ? "Required" : "");
1874 code_.SetValue("SIZE", GenTypeSize(field.value.type));
1875 code_.SetValue("OFFSET", GenFieldOffsetName(field));
1876 if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
1878 "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
1880 code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
1883 switch (field.value.type.base_type) {
1884 case BASE_TYPE_UNION: {
1885 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1886 code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
1888 "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
1889 "{{NAME}}{{SUFFIX}}())\\";
1892 case BASE_TYPE_STRUCT: {
1893 if (!field.value.type.struct_def->fixed) {
1894 code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
1898 case BASE_TYPE_STRING: {
1899 code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
1902 case BASE_TYPE_VECTOR: {
1903 code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
1905 switch (field.value.type.element) {
1906 case BASE_TYPE_STRING: {
1907 code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
1910 case BASE_TYPE_STRUCT: {
1911 if (!field.value.type.struct_def->fixed) {
1912 code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
1916 case BASE_TYPE_UNION: {
1917 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1919 "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
1920 "{{NAME}}_type())\\";
1933 // Generate CompareWithValue method for a key field.
1934 void GenKeyFieldMethods(const FieldDef &field) {
1935 FLATBUFFERS_ASSERT(field.key);
1936 const bool is_string = (IsString(field.value.type));
1938 code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
1940 // use operator< of flatbuffers::String
1941 code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
1943 code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
1948 code_ += " int KeyCompareWithValue(const char *val) const {";
1949 code_ += " return strcmp({{FIELD_NAME}}()->c_str(), val);";
1952 FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
1953 auto type = GenTypeBasic(field.value.type, false);
1954 if (opts_.scoped_enums && field.value.type.enum_def &&
1955 IsScalar(field.value.type.base_type)) {
1956 type = GenTypeGet(field.value.type, " ", "const ", " *", true);
1958 // Returns {field<val: -1, field==val: 0, field>val: +1}.
1959 code_.SetValue("KEY_TYPE", type);
1960 code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {";
1962 " return static_cast<int>({{FIELD_NAME}}() > val) - "
1963 "static_cast<int>({{FIELD_NAME}}() < val);";
1968 void GenTableUnionAsGetters(const FieldDef &field) {
1969 const auto &type = field.value.type;
1970 auto u = type.enum_def;
1972 if (!type.enum_def->uses_multiple_type_instances)
1974 " template<typename T> "
1975 "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
1977 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
1979 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1980 auto full_struct_name = GetUnionElement(ev, false, opts_);
1982 // @TODO: Mby make this decisions more universal? How?
1983 code_.SetValue("U_GET_TYPE",
1984 EscapeKeyword(field.name + UnionTypeFieldSuffix()));
1985 code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace,
1986 GetEnumValUse(*u, ev)));
1987 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
1988 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
1989 code_.SetValue("U_NULLABLE", NullableExtension());
1991 // `const Type *union_name_asType() const` accessor.
1992 code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
1994 " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
1995 "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
2001 void GenTableFieldGetter(const FieldDef &field) {
2002 const auto &type = field.value.type;
2003 const auto offset_str = GenFieldOffsetName(field);
2005 GenComment(field.doc_comment, " ");
2006 // Call a different accessor for pointers, that indirects.
2007 if (false == field.IsScalarOptional()) {
2008 const bool is_scalar = IsScalar(type.base_type);
2009 std::string accessor;
2011 accessor = "GetField<";
2012 else if (IsStruct(type))
2013 accessor = "GetStruct<";
2015 accessor = "GetPointer<";
2016 auto offset_type = GenTypeGet(type, "", "const ", " *", false);
2017 auto call = accessor + offset_type + ">(" + offset_str;
2018 // Default value as second arg for non-pointer types.
2019 if (is_scalar) { call += ", " + GenDefaultConstant(field); }
2022 std::string afterptr = " *" + NullableExtension();
2023 code_.SetValue("FIELD_TYPE",
2024 GenTypeGet(type, " ", "const ", afterptr.c_str(), true));
2025 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
2026 code_.SetValue("NULLABLE_EXT", NullableExtension());
2027 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
2028 code_ += " return {{FIELD_VALUE}};";
2031 auto wire_type = GenTypeBasic(type, false);
2032 auto face_type = GenTypeBasic(type, true);
2033 auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
2035 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2036 code_ += " {{FIELD_TYPE}} {{FIELD_NAME}}() const {";
2037 code_ += " return " + opt_value + ";";
2041 if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); }
2044 void GenTableFieldType(const FieldDef &field) {
2045 const auto &type = field.value.type;
2046 const auto offset_str = GenFieldOffsetName(field);
2047 if (!field.IsScalarOptional()) {
2048 std::string afterptr = " *" + NullableExtension();
2049 code_.SetValue("FIELD_TYPE",
2050 GenTypeGet(type, "", "const ", afterptr.c_str(), true));
2051 code_ += " {{FIELD_TYPE}}\\";
2053 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2054 code_ += " {{FIELD_TYPE}}\\";
2058 void GenStructFieldType(const FieldDef &field) {
2059 const auto is_array = IsArray(field.value.type);
2060 std::string field_type =
2061 GenTypeGet(field.value.type, "", is_array ? "" : "const ",
2062 is_array ? "" : " &", true);
2063 code_.SetValue("FIELD_TYPE", field_type);
2064 code_ += " {{FIELD_TYPE}}\\";
2067 void GenFieldTypeHelper(const StructDef &struct_def) {
2068 if (struct_def.fields.vec.empty()) { return; }
2069 code_ += " template<size_t Index>";
2070 code_ += " using FieldType = \\";
2071 code_ += "decltype(std::declval<type>().get_field<Index>());";
2074 void GenIndexBasedFieldGetter(const StructDef &struct_def) {
2075 if (struct_def.fields.vec.empty()) { return; }
2076 code_ += " template<size_t Index>";
2077 code_ += " auto get_field() const {";
2080 bool need_else = false;
2081 // Generate one index-based getter for each field.
2082 for (auto it = struct_def.fields.vec.begin();
2083 it != struct_def.fields.vec.end(); ++it) {
2084 const auto &field = **it;
2085 if (field.deprecated) {
2086 // Deprecated fields won't be accessible.
2089 code_.SetValue("FIELD_NAME", Name(field));
2090 code_.SetValue("FIELD_INDEX",
2091 std::to_string(static_cast<long long>(index++)));
2093 code_ += " else \\";
2098 code_ += "if constexpr (Index == {{FIELD_INDEX}}) \\";
2099 code_ += "return {{FIELD_NAME}}();";
2101 code_ += " else static_assert(Index != Index, \"Invalid Field Index\");";
2107 // static constexpr std::array<const char *, 3> field_names = {
2113 void GenFieldNames(const StructDef &struct_def) {
2114 auto non_deprecated_field_count = std::count_if(
2115 struct_def.fields.vec.begin(), struct_def.fields.vec.end(),
2116 [](const FieldDef *field) { return !field->deprecated; });
2117 code_ += " static constexpr std::array<\\";
2120 std::to_string(static_cast<long long>(non_deprecated_field_count)));
2121 code_ += "const char *, {{FIELD_COUNT}}> field_names = {\\";
2122 if (struct_def.fields.vec.empty()) {
2127 // Generate the field_names elements.
2128 for (auto it = struct_def.fields.vec.begin();
2129 it != struct_def.fields.vec.end(); ++it) {
2130 const auto &field = **it;
2131 if (field.deprecated) {
2132 // Deprecated fields won't be accessible.
2135 code_.SetValue("FIELD_NAME", Name(field));
2136 code_ += " \"{{FIELD_NAME}}\"\\";
2137 if (it + 1 != struct_def.fields.vec.end()) { code_ += ","; }
2142 void GenFieldsNumber(const StructDef &struct_def) {
2143 auto non_deprecated_field_count = std::count_if(
2144 struct_def.fields.vec.begin(), struct_def.fields.vec.end(),
2145 [](const FieldDef *field) { return !field->deprecated; });
2148 std::to_string(static_cast<long long>(non_deprecated_field_count)));
2149 code_ += " static constexpr size_t fields_number = {{FIELD_COUNT}};";
2152 void GenTraitsStruct(const StructDef &struct_def) {
2154 "FULLY_QUALIFIED_NAME",
2155 struct_def.defined_namespace->GetFullyQualifiedName(Name(struct_def)));
2156 code_ += "struct {{STRUCT_NAME}}::Traits {";
2157 code_ += " using type = {{STRUCT_NAME}};";
2158 if (!struct_def.fixed) {
2159 // We have a table and not a struct.
2160 code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
2162 if (opts_.cpp_static_reflection) {
2163 code_ += " static constexpr auto name = \"{{STRUCT_NAME}}\";";
2165 " static constexpr auto fully_qualified_name = "
2166 "\"{{FULLY_QUALIFIED_NAME}}\";";
2167 GenFieldNames(struct_def);
2168 GenFieldTypeHelper(struct_def);
2169 GenFieldsNumber(struct_def);
2175 void GenTableFieldSetter(const FieldDef &field) {
2176 const auto &type = field.value.type;
2177 const bool is_scalar = IsScalar(type.base_type);
2178 if (is_scalar && IsUnion(type))
2179 return; // changing of a union's type is forbidden
2181 auto offset_str = GenFieldOffsetName(field);
2183 const auto wire_type = GenTypeWire(type, "", false);
2184 code_.SetValue("SET_FN", "SetField<" + wire_type + ">");
2185 code_.SetValue("OFFSET_NAME", offset_str);
2186 code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true));
2187 code_.SetValue("FIELD_VALUE",
2188 GenUnderlyingCast(field, false, "_" + Name(field)));
2191 " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
2192 "_{{FIELD_NAME}}) {";
2193 if (false == field.IsScalarOptional()) {
2194 code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
2196 " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
2197 "{{DEFAULT_VALUE}});";
2199 code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
2203 auto postptr = " *" + NullableExtension();
2204 auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
2205 std::string accessor = IsStruct(type) ? "GetStruct<" : "GetPointer<";
2206 auto underlying = accessor + wire_type + ">(" + offset_str + ")";
2207 code_.SetValue("FIELD_TYPE", wire_type);
2208 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
2210 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
2211 code_ += " return {{FIELD_VALUE}};";
2216 // Generate an accessor struct, builder structs & function for a table.
2217 void GenTable(const StructDef &struct_def) {
2218 if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
2220 // Generate an accessor struct, with methods of the form:
2221 // type name() const { return GetField<type>(offset, defaultval); }
2222 GenComment(struct_def.doc_comment);
2224 code_.SetValue("STRUCT_NAME", Name(struct_def));
2226 "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
2227 " : private flatbuffers::Table {";
2228 if (opts_.generate_object_based_api) {
2229 code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
2231 code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
2232 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
2233 if (opts_.mini_reflect != IDLOptions::kNone) {
2235 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
2236 code_ += " return {{STRUCT_NAME}}TypeTable();";
2240 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
2242 // Generate field id constants.
2243 if (struct_def.fields.vec.size() > 0) {
2244 // We need to add a trailing comma to all elements except the last one as
2245 // older versions of gcc complain about this.
2246 code_.SetValue("SEP", "");
2248 " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
2249 for (auto it = struct_def.fields.vec.begin();
2250 it != struct_def.fields.vec.end(); ++it) {
2251 const auto &field = **it;
2252 if (field.deprecated) {
2253 // Deprecated fields won't be accessible.
2257 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2258 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
2259 code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
2260 code_.SetValue("SEP", ",\n");
2266 // Generate the accessors.
2267 for (auto it = struct_def.fields.vec.begin();
2268 it != struct_def.fields.vec.end(); ++it) {
2269 const auto &field = **it;
2270 if (field.deprecated) {
2271 // Deprecated fields won't be accessible.
2275 code_.SetValue("FIELD_NAME", Name(field));
2276 GenTableFieldGetter(field);
2277 if (opts_.mutable_buffer) { GenTableFieldSetter(field); }
2279 auto nested = field.attributes.Lookup("nested_flatbuffer");
2281 std::string qualified_name = nested->constant;
2282 auto nested_root = parser_.LookupStruct(nested->constant);
2283 if (nested_root == nullptr) {
2284 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
2286 nested_root = parser_.LookupStruct(qualified_name);
2288 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
2290 code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
2292 code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
2295 "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());";
2299 if (field.flexbuffer) {
2301 " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
2303 // Both Data() and size() are const-methods, therefore call order
2306 " return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), "
2307 "{{FIELD_NAME}}()->size());";
2311 // Generate a comparison function for this field if it is a key.
2312 if (field.key) { GenKeyFieldMethods(field); }
2315 if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
2317 // Generate a verifier function that can check a buffer from an untrusted
2318 // source will never cause reads outside the buffer.
2319 code_ += " bool Verify(flatbuffers::Verifier &verifier) const {";
2320 code_ += " return VerifyTableStart(verifier)\\";
2321 for (auto it = struct_def.fields.vec.begin();
2322 it != struct_def.fields.vec.end(); ++it) {
2323 const auto &field = **it;
2324 if (field.deprecated) { continue; }
2325 GenVerifyCall(field, " &&\n ");
2328 code_ += " &&\n verifier.EndTable();";
2331 if (opts_.generate_object_based_api) {
2332 // Generate the UnPack() pre declaration.
2333 code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";";
2334 code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";";
2335 code_ += " " + TablePackSignature(struct_def, true, opts_) + ";";
2338 code_ += "};"; // End of table.
2341 // Explicit specializations for union accessors
2342 for (auto it = struct_def.fields.vec.begin();
2343 it != struct_def.fields.vec.end(); ++it) {
2344 const auto &field = **it;
2345 if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
2349 auto u = field.value.type.enum_def;
2350 if (u->uses_multiple_type_instances) continue;
2352 code_.SetValue("FIELD_NAME", Name(field));
2354 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2356 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
2358 auto full_struct_name = GetUnionElement(ev, false, opts_);
2362 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
2363 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2364 code_.SetValue("U_ELEMENT_NAME", full_struct_name);
2365 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2367 // `template<> const T *union_name_as<T>() const` accessor.
2370 "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
2371 "<{{U_ELEMENT_NAME}}>() const {";
2372 code_ += " return {{U_FIELD_NAME}}();";
2378 GenBuilders(struct_def);
2380 if (opts_.generate_object_based_api) {
2381 // Generate a pre-declaration for a CreateX method that works with an
2382 // unpacked C++ object.
2383 code_ += TableCreateSignature(struct_def, true, opts_) + ";";
2388 // Generate code to force vector alignment. Return empty string for vector
2389 // that doesn't need alignment code.
2390 std::string GenVectorForceAlign(const FieldDef &field,
2391 const std::string &field_size) {
2392 FLATBUFFERS_ASSERT(IsVector(field.value.type));
2393 // Get the value of the force_align attribute.
2394 const auto *force_align = field.attributes.Lookup("force_align");
2395 const int align = force_align ? atoi(force_align->constant.c_str()) : 1;
2396 // Generate code to do force_align for the vector.
2398 const auto vtype = field.value.type.VectorType();
2399 const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def)
2400 : GenTypeWire(vtype, "", false);
2401 return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type +
2402 "), " + std::to_string(static_cast<long long>(align)) + ");";
2407 void GenBuilders(const StructDef &struct_def) {
2408 code_.SetValue("STRUCT_NAME", Name(struct_def));
2410 // Generate a builder struct:
2411 code_ += "struct {{STRUCT_NAME}}Builder {";
2412 code_ += " typedef {{STRUCT_NAME}} Table;";
2413 code_ += " flatbuffers::FlatBufferBuilder &fbb_;";
2414 code_ += " flatbuffers::uoffset_t start_;";
2416 bool has_string_or_vector_fields = false;
2417 for (auto it = struct_def.fields.vec.begin();
2418 it != struct_def.fields.vec.end(); ++it) {
2419 const auto &field = **it;
2420 if (field.deprecated) continue;
2421 const bool is_scalar = IsScalar(field.value.type.base_type);
2422 const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
2423 const bool is_string = IsString(field.value.type);
2424 const bool is_vector = IsVector(field.value.type);
2425 if (is_string || is_vector) { has_string_or_vector_fields = true; }
2427 std::string offset = GenFieldOffsetName(field);
2428 std::string name = GenUnderlyingCast(field, false, Name(field));
2429 std::string value = is_default_scalar ? GenDefaultConstant(field) : "";
2431 // Generate accessor functions of the form:
2432 // void add_name(type name) {
2433 // fbb_.AddElement<type>(offset, name, default);
2435 code_.SetValue("FIELD_NAME", Name(field));
2436 code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
2437 code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
2438 code_.SetValue("ADD_NAME", name);
2439 code_.SetValue("ADD_VALUE", value);
2441 const auto type = GenTypeWire(field.value.type, "", false);
2442 code_.SetValue("ADD_FN", "AddElement<" + type + ">");
2443 } else if (IsStruct(field.value.type)) {
2444 code_.SetValue("ADD_FN", "AddStruct");
2446 code_.SetValue("ADD_FN", "AddOffset");
2449 code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
2450 code_ += " fbb_.{{ADD_FN}}(\\";
2451 if (is_default_scalar) {
2452 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
2454 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
2459 // Builder constructor
2461 " explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder "
2463 code_ += " : fbb_(_fbb) {";
2464 code_ += " start_ = fbb_.StartTable();";
2467 // Finish() function.
2468 code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
2469 code_ += " const auto end = fbb_.EndTable(start_);";
2470 code_ += " auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
2472 for (auto it = struct_def.fields.vec.begin();
2473 it != struct_def.fields.vec.end(); ++it) {
2474 const auto &field = **it;
2475 if (!field.deprecated && field.IsRequired()) {
2476 code_.SetValue("FIELD_NAME", Name(field));
2477 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2478 code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
2481 code_ += " return o;";
2486 // Generate a convenient CreateX function that uses the above builder
2487 // to create a table in one go.
2489 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2490 "Create{{STRUCT_NAME}}(";
2491 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2492 for (auto it = struct_def.fields.vec.begin();
2493 it != struct_def.fields.vec.end(); ++it) {
2494 const auto &field = **it;
2495 if (!field.deprecated) { GenParam(field, false, ",\n "); }
2499 code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);";
2500 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
2502 for (auto it = struct_def.fields.vec.rbegin();
2503 it != struct_def.fields.vec.rend(); ++it) {
2504 const auto &field = **it;
2505 if (!field.deprecated && (!struct_def.sortbysize ||
2506 size == SizeOf(field.value.type.base_type))) {
2507 code_.SetValue("FIELD_NAME", Name(field));
2508 if (field.IsScalarOptional()) {
2510 " if({{FIELD_NAME}}) { "
2511 "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }";
2513 code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
2518 code_ += " return builder_.Finish();";
2522 // Definition for type traits for this table type. This allows querying var-
2523 // ious compile-time traits of the table.
2524 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
2526 // Generate a CreateXDirect function with vector types as parameters
2527 if (opts_.cpp_direct_copy && has_string_or_vector_fields) {
2529 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2530 "Create{{STRUCT_NAME}}Direct(";
2531 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2532 for (auto it = struct_def.fields.vec.begin();
2533 it != struct_def.fields.vec.end(); ++it) {
2534 const auto &field = **it;
2535 if (!field.deprecated) { GenParam(field, true, ",\n "); }
2537 // Need to call "Create" with the struct namespace.
2538 const auto qualified_create_name =
2539 struct_def.defined_namespace->GetFullyQualifiedName("Create");
2540 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2542 for (auto it = struct_def.fields.vec.begin();
2543 it != struct_def.fields.vec.end(); ++it) {
2544 const auto &field = **it;
2545 if (!field.deprecated) {
2546 code_.SetValue("FIELD_NAME", Name(field));
2547 if (IsString(field.value.type)) {
2548 if (!field.shared) {
2549 code_.SetValue("CREATE_STRING", "CreateString");
2551 code_.SetValue("CREATE_STRING", "CreateSharedString");
2554 " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
2555 "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
2556 } else if (IsVector(field.value.type)) {
2557 const std::string force_align_code =
2558 GenVectorForceAlign(field, Name(field) + "->size()");
2559 if (!force_align_code.empty()) {
2560 code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }";
2562 code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
2563 const auto vtype = field.value.type.VectorType();
2564 const auto has_key = TypeHasKey(vtype);
2565 if (IsStruct(vtype)) {
2566 const auto type = WrapInNameSpace(*vtype.struct_def);
2567 code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<"
2568 : "_fbb.CreateVectorOfStructs<") +
2570 } else if (has_key) {
2571 const auto type = WrapInNameSpace(*vtype.struct_def);
2572 code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\";
2575 GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
2576 code_ += "_fbb.CreateVector<" + type + ">\\";
2579 has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;";
2583 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2585 for (auto it = struct_def.fields.vec.begin();
2586 it != struct_def.fields.vec.end(); ++it) {
2587 const auto &field = **it;
2588 if (!field.deprecated) {
2589 code_.SetValue("FIELD_NAME", Name(field));
2590 code_ += ",\n {{FIELD_NAME}}\\";
2591 if (IsString(field.value.type) || IsVector(field.value.type)) {
2602 std::string GenUnionUnpackVal(const FieldDef &afield,
2603 const char *vec_elem_access,
2604 const char *vec_type_access) {
2605 auto type_name = WrapInNameSpace(*afield.value.type.enum_def);
2606 return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " +
2607 EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
2608 vec_type_access + ", _resolver)";
2611 std::string GenUnpackVal(const Type &type, const std::string &val,
2612 bool invector, const FieldDef &afield) {
2613 switch (type.base_type) {
2614 case BASE_TYPE_STRING: {
2615 if (FlexibleStringConstructor(&afield)) {
2616 return NativeString(&afield) + "(" + val + "->c_str(), " + val +
2619 return val + "->str()";
2622 case BASE_TYPE_STRUCT: {
2623 if (IsStruct(type)) {
2624 const auto &struct_attrs = type.struct_def->attributes;
2625 const auto native_type = struct_attrs.Lookup("native_type");
2627 std::string unpack_call = "flatbuffers::UnPack";
2628 const auto pack_name = struct_attrs.Lookup("native_type_pack_name");
2629 if (pack_name) { unpack_call += pack_name->constant; }
2630 unpack_call += "(*" + val + ")";
2632 } else if (invector || afield.native_inline) {
2635 const auto name = WrapInNameSpace(*type.struct_def);
2636 const auto ptype = GenTypeNativePtr(name, &afield, true);
2637 return ptype + "(new " + name + "(*" + val + "))";
2640 const auto ptype = GenTypeNativePtr(
2641 WrapNativeNameInNameSpace(*type.struct_def, opts_), &afield,
2643 return ptype + "(" + val + "->UnPack(_resolver))";
2646 case BASE_TYPE_UNION: {
2647 return GenUnionUnpackVal(
2648 afield, invector ? "->Get(_i)" : "",
2649 invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
2659 std::string GenUnpackFieldStatement(const FieldDef &field,
2660 const FieldDef *union_field) {
2662 switch (field.value.type.base_type) {
2663 case BASE_TYPE_VECTOR: {
2664 auto name = Name(field);
2665 if (field.value.type.element == BASE_TYPE_UTYPE) {
2666 name = StripUnionType(Name(field));
2668 code += "{ _o->" + name + ".resize(_e->size()); ";
2669 if (!field.value.type.enum_def && !IsBool(field.value.type.element) &&
2670 IsOneByte(field.value.type.element)) {
2671 // For vectors of bytes, std::copy is used to improve performance.
2672 // This doesn't work for:
2673 // - enum types because they have to be explicitly static_cast.
2674 // - vectors of bool, since they are a template specialization.
2675 // - multiple-byte types due to endianness.
2677 "std::copy(_e->begin(), _e->end(), _o->" + name + ".begin()); }";
2679 std::string indexing;
2680 if (field.value.type.enum_def) {
2681 indexing += "static_cast<" +
2682 WrapInNameSpace(*field.value.type.enum_def) + ">(";
2684 indexing += "_e->Get(_i)";
2685 if (field.value.type.enum_def) { indexing += ")"; }
2686 if (field.value.type.element == BASE_TYPE_BOOL) {
2687 indexing += " != 0";
2689 // Generate code that pushes data from _e to _o in the form:
2690 // for (uoffset_t i = 0; i < _e->size(); ++i) {
2691 // _o->field.push_back(_e->Get(_i));
2694 field.value.type.element == BASE_TYPE_UTYPE
2696 : (field.value.type.element == BASE_TYPE_UNION ? ".value"
2699 code += "for (flatbuffers::uoffset_t _i = 0;";
2700 code += " _i < _e->size(); _i++) { ";
2701 auto cpp_type = field.attributes.Lookup("cpp_type");
2703 // Generate code that resolves the cpp pointer type, of the form:
2705 // (*resolver)(&_o->field, (hash_value_t)(_e));
2707 // _o->field = nullptr;
2708 code += "//vector resolver, " + PtrType(&field) + "\n";
2709 code += "if (_resolver) ";
2710 code += "(*_resolver)";
2711 code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" +
2714 "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
2715 if (PtrType(&field) == "naked") {
2717 code += "_o->" + name + "[_i]" + access + " = nullptr";
2719 // code += " else ";
2720 // code += "_o->" + name + "[_i]" + access + " = " +
2721 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2722 code += "/* else do nothing */";
2725 code += "_o->" + name + "[_i]" + access + " = ";
2726 code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
2733 case BASE_TYPE_UTYPE: {
2734 FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
2736 // Generate code that sets the union type, of the form:
2737 // _o->field.type = _e;
2738 code += "_o->" + union_field->name + ".type = _e;";
2741 case BASE_TYPE_UNION: {
2742 // Generate code that sets the union value, of the form:
2743 // _o->field.value = Union::Unpack(_e, field_type(), resolver);
2744 code += "_o->" + Name(field) + ".value = ";
2745 code += GenUnionUnpackVal(field, "", "");
2750 auto cpp_type = field.attributes.Lookup("cpp_type");
2752 // Generate code that resolves the cpp pointer type, of the form:
2754 // (*resolver)(&_o->field, (hash_value_t)(_e));
2756 // _o->field = nullptr;
2757 code += "//scalar resolver, " + PtrType(&field) + " \n";
2758 code += "if (_resolver) ";
2759 code += "(*_resolver)";
2760 code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
2761 code += "static_cast<flatbuffers::hash_value_t>(_e));";
2762 if (PtrType(&field) == "naked") {
2764 code += "_o->" + Name(field) + " = nullptr;";
2766 // code += " else ";
2767 // code += "_o->" + Name(field) + " = " +
2768 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2769 code += "/* else do nothing */;";
2772 // Generate code for assigning the value, of the form:
2773 // _o->field = value;
2774 code += "_o->" + Name(field) + " = ";
2775 code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
2783 std::string GenCreateParam(const FieldDef &field) {
2784 std::string value = "_o->";
2785 if (field.value.type.base_type == BASE_TYPE_UTYPE) {
2786 value += StripUnionType(Name(field));
2789 value += Name(field);
2791 if (field.value.type.base_type != BASE_TYPE_VECTOR &&
2792 field.attributes.Lookup("cpp_type")) {
2793 auto type = GenTypeBasic(field.value.type, false);
2797 type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
2801 switch (field.value.type.base_type) {
2802 // String fields are of the form:
2803 // _fbb.CreateString(_o->field)
2805 // _fbb.CreateSharedString(_o->field)
2806 case BASE_TYPE_STRING: {
2807 if (!field.shared) {
2808 code += "_fbb.CreateString(";
2810 code += "_fbb.CreateSharedString(";
2813 code.push_back(')');
2815 // For optional fields, check to see if there actually is any data
2816 // in _o->field before attempting to access it. If there isn't,
2817 // depending on set_empty_strings_to_null either set it to 0 or an empty
2819 if (!field.IsRequired()) {
2820 auto empty_value = opts_.set_empty_strings_to_null
2822 : "_fbb.CreateSharedString(\"\")";
2823 code = value + ".empty() ? " + empty_value + " : " + code;
2827 // Vector fields come in several flavours, of the forms:
2828 // _fbb.CreateVector(_o->field);
2829 // _fbb.CreateVector((const utype*)_o->field.data(),
2830 // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field)
2831 // _fbb.CreateVectorOfStructs(_o->field)
2832 // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
2833 // return CreateT(_fbb, _o->Get(i), rehasher);
2835 case BASE_TYPE_VECTOR: {
2836 auto vector_type = field.value.type.VectorType();
2837 switch (vector_type.base_type) {
2838 case BASE_TYPE_STRING: {
2839 if (NativeString(&field) == "std::string") {
2840 code += "_fbb.CreateVectorOfStrings(" + value + ")";
2842 // Use by-function serialization to emulate
2843 // CreateVectorOfStrings(); this works also with non-std strings.
2845 "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>"
2847 code += "(" + value + ".size(), ";
2848 code += "[](size_t i, _VectorArgs *__va) { ";
2850 "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
2851 code += " }, &_va )";
2855 case BASE_TYPE_STRUCT: {
2856 if (IsStruct(vector_type)) {
2857 const auto &struct_attrs =
2858 field.value.type.struct_def->attributes;
2859 const auto native_type = struct_attrs.Lookup("native_type");
2861 code += "_fbb.CreateVectorOfNativeStructs<";
2862 code += WrapInNameSpace(*vector_type.struct_def) + ", " +
2863 native_type->constant + ">";
2864 code += "(" + value;
2865 const auto pack_name =
2866 struct_attrs.Lookup("native_type_pack_name");
2868 code += ", flatbuffers::Pack" + pack_name->constant;
2872 code += "_fbb.CreateVectorOfStructs";
2873 code += "(" + value + ")";
2876 code += "_fbb.CreateVector<flatbuffers::Offset<";
2877 code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
2878 code += "(" + value + ".size(), ";
2879 code += "[](size_t i, _VectorArgs *__va) { ";
2880 code += "return Create" + vector_type.struct_def->name;
2881 code += "(*__va->__fbb, __va->_" + value + "[i]" +
2882 GenPtrGet(field) + ", ";
2883 code += "__va->__rehasher); }, &_va )";
2887 case BASE_TYPE_BOOL: {
2888 code += "_fbb.CreateVector(" + value + ")";
2891 case BASE_TYPE_UNION: {
2893 "_fbb.CreateVector<flatbuffers::"
2896 ".size(), [](size_t i, _VectorArgs *__va) { "
2898 value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
2901 case BASE_TYPE_UTYPE: {
2902 value = StripUnionType(value);
2903 code += "_fbb.CreateVector<uint8_t>(" + value +
2904 ".size(), [](size_t i, _VectorArgs *__va) { "
2905 "return static_cast<uint8_t>(__va->_" +
2906 value + "[i].type); }, &_va)";
2910 if (field.value.type.enum_def &&
2911 !VectorElementUserFacing(vector_type)) {
2912 // For enumerations, we need to get access to the array data for
2913 // the underlying storage type (eg. uint8_t).
2914 const auto basetype = GenTypeBasic(
2915 field.value.type.enum_def->underlying_type, false);
2916 code += "_fbb.CreateVectorScalarCast<" + basetype +
2917 ">(flatbuffers::data(" + value + "), " + value +
2919 } else if (field.attributes.Lookup("cpp_type")) {
2920 auto type = GenTypeBasic(vector_type, false);
2921 code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
2922 code += "[](size_t i, _VectorArgs *__va) { ";
2923 code += "return __va->__rehasher ? ";
2924 code += "static_cast<" + type + ">((*__va->__rehasher)";
2925 code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
2926 code += "; }, &_va )";
2928 code += "_fbb.CreateVector(" + value + ")";
2934 // If set_empty_vectors_to_null option is enabled, for optional fields,
2935 // check to see if there actually is any data in _o->field before
2936 // attempting to access it.
2937 if (opts_.set_empty_vectors_to_null && !field.IsRequired()) {
2938 code = value + ".size() ? " + code + " : 0";
2942 case BASE_TYPE_UNION: {
2943 // _o->field.Pack(_fbb);
2944 code += value + ".Pack(_fbb)";
2947 case BASE_TYPE_STRUCT: {
2948 if (IsStruct(field.value.type)) {
2949 const auto &struct_attribs = field.value.type.struct_def->attributes;
2950 const auto native_type = struct_attribs.Lookup("native_type");
2952 code += "flatbuffers::Pack";
2953 const auto pack_name =
2954 struct_attribs.Lookup("native_type_pack_name");
2955 if (pack_name) { code += pack_name->constant; }
2956 code += "(" + value + ")";
2957 } else if (field.native_inline) {
2958 code += "&" + value;
2960 code += value + " ? " + value + GenPtrGet(field) + " : 0";
2963 // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
2964 const auto type = field.value.type.struct_def->name;
2965 code += value + " ? Create" + type;
2966 code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
2979 // Generate code for tables that needs to come after the regular definition.
2980 void GenTablePost(const StructDef &struct_def) {
2981 code_.SetValue("STRUCT_NAME", Name(struct_def));
2982 code_.SetValue("NATIVE_NAME",
2983 NativeName(Name(struct_def), &struct_def, opts_));
2985 if (opts_.generate_object_based_api) {
2986 // Generate the X::UnPack() method.
2988 "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
2990 if (opts_.g_cpp_std == cpp::CPP_STD_X0) {
2991 auto native_name = WrapNativeNameInNameSpace(struct_def, parser_.opts);
2992 code_.SetValue("POINTER_TYPE",
2993 GenTypeNativePtr(native_name, nullptr, false));
2995 " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
2996 } else if (opts_.g_cpp_std == cpp::CPP_STD_11) {
2998 " auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new "
2999 "{{NATIVE_NAME}}());";
3001 code_ += " auto _o = std::make_unique<{{NATIVE_NAME}}>();";
3003 code_ += " UnPackTo(_o.get(), _resolver);";
3004 code_ += " return _o.release();";
3008 "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
3009 code_ += " (void)_o;";
3010 code_ += " (void)_resolver;";
3012 for (auto it = struct_def.fields.vec.begin();
3013 it != struct_def.fields.vec.end(); ++it) {
3014 const auto &field = **it;
3015 if (field.deprecated) { continue; }
3017 // Assign a value from |this| to |_o|. Values from |this| are stored
3018 // in a variable |_e| by calling this->field_type(). The value is then
3019 // assigned to |_o| using the GenUnpackFieldStatement.
3020 const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
3021 const auto statement =
3022 GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
3024 code_.SetValue("FIELD_NAME", Name(field));
3025 auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
3026 auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
3027 auto postfix = " }";
3028 code_ += std::string(prefix) + check + statement + postfix;
3033 // Generate the X::Pack member function that simply calls the global
3034 // CreateX function.
3035 code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
3036 code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
3040 // Generate a CreateX method that works with an unpacked C++ object.
3042 "inline " + TableCreateSignature(struct_def, false, opts_) + " {";
3043 code_ += " (void)_rehasher;";
3044 code_ += " (void)_o;";
3047 " struct _VectorArgs "
3048 "{ flatbuffers::FlatBufferBuilder *__fbb; "
3050 NativeName(Name(struct_def), &struct_def, opts_) +
3052 "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
3053 "&_fbb, _o, _rehasher}; (void)_va;";
3055 for (auto it = struct_def.fields.vec.begin();
3056 it != struct_def.fields.vec.end(); ++it) {
3058 if (field.deprecated) { continue; }
3059 if (IsVector(field.value.type)) {
3060 const std::string force_align_code =
3061 GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
3062 if (!force_align_code.empty()) { code_ += " " + force_align_code; }
3064 code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
3066 // Need to call "Create" with the struct namespace.
3067 const auto qualified_create_name =
3068 struct_def.defined_namespace->GetFullyQualifiedName("Create");
3069 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
3071 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
3073 for (auto it = struct_def.fields.vec.begin();
3074 it != struct_def.fields.vec.end(); ++it) {
3076 if (field.deprecated) { continue; }
3078 bool pass_by_address = false;
3079 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
3080 if (IsStruct(field.value.type)) {
3082 field.value.type.struct_def->attributes.Lookup("native_type");
3083 if (native_type) { pass_by_address = true; }
3087 // Call the CreateX function using values from |_o|.
3088 if (pass_by_address) {
3089 code_ += ",\n &_" + Name(field) + "\\";
3091 code_ += ",\n _" + Name(field) + "\\";
3100 static void GenPadding(
3101 const FieldDef &field, std::string *code_ptr, int *id,
3102 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
3103 if (field.padding) {
3104 for (int i = 0; i < 4; i++) {
3105 if (static_cast<int>(field.padding) & (1 << i)) {
3106 f((1 << i) * 8, code_ptr, id);
3109 FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
3113 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
3114 *code_ptr += " int" + NumToString(bits) + "_t padding" +
3115 NumToString((*id)++) + "__;";
3118 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
3120 if (!code_ptr->empty()) *code_ptr += ",\n ";
3121 *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
3124 static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
3126 if (!code_ptr->empty()) *code_ptr += '\n';
3127 *code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
3130 void GenStructDefaultConstructor(const StructDef &struct_def) {
3131 std::string init_list;
3133 bool first_in_init_list = true;
3134 int padding_initializer_id = 0;
3135 int padding_body_id = 0;
3136 for (auto it = struct_def.fields.vec.begin();
3137 it != struct_def.fields.vec.end(); ++it) {
3138 const auto field = *it;
3139 const auto field_name = field->name + "_";
3141 if (first_in_init_list) {
3142 first_in_init_list = false;
3148 init_list += field_name;
3149 if (IsStruct(field->value.type) || IsArray(field->value.type)) {
3150 // this is either default initialization of struct
3152 // implicit initialization of array
3153 // for each object in array it:
3154 // * sets it as zeros for POD types (integral, floating point, etc)
3155 // * calls default constructor for classes/structs
3160 if (field->padding) {
3161 GenPadding(*field, &init_list, &padding_initializer_id,
3162 PaddingInitializer);
3163 GenPadding(*field, &body, &padding_body_id, PaddingNoop);
3167 if (init_list.empty()) {
3168 code_ += " {{STRUCT_NAME}}()";
3171 code_.SetValue("INIT_LIST", init_list);
3172 code_ += " {{STRUCT_NAME}}()";
3173 code_ += " : {{INIT_LIST}} {";
3174 if (!body.empty()) { code_ += body; }
3179 void GenStructConstructor(const StructDef &struct_def,
3180 GenArrayArgMode array_mode) {
3181 std::string arg_list;
3182 std::string init_list;
3184 auto first = struct_def.fields.vec.begin();
3185 // skip arrays if generate ctor without array assignment
3186 const auto init_arrays = (array_mode != kArrayArgModeNone);
3187 for (auto it = struct_def.fields.vec.begin();
3188 it != struct_def.fields.vec.end(); ++it) {
3189 const auto &field = **it;
3190 const auto &type = field.value.type;
3191 const auto is_array = IsArray(type);
3192 const auto arg_name = "_" + Name(field);
3193 if (!is_array || init_arrays) {
3194 if (it != first && !arg_list.empty()) { arg_list += ", "; }
3195 arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true)
3196 : GenTypeSpan(type, true, type.fixed_length);
3197 arg_list += arg_name;
3199 // skip an array with initialization from span
3200 if (false == (is_array && init_arrays)) {
3201 if (it != first && !init_list.empty()) { init_list += ",\n "; }
3202 init_list += Name(field) + "_";
3203 if (IsScalar(type.base_type)) {
3204 auto scalar_type = GenUnderlyingCast(field, false, arg_name);
3205 init_list += "(flatbuffers::EndianScalar(" + scalar_type + "))";
3207 FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type));
3209 init_list += "(" + arg_name + ")";
3215 GenPadding(field, &init_list, &padding_id, PaddingInitializer);
3218 if (!arg_list.empty()) {
3219 code_.SetValue("ARG_LIST", arg_list);
3220 code_.SetValue("INIT_LIST", init_list);
3221 if (!init_list.empty()) {
3222 code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
3223 code_ += " : {{INIT_LIST}} {";
3225 code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
3228 for (auto it = struct_def.fields.vec.begin();
3229 it != struct_def.fields.vec.end(); ++it) {
3230 const auto &field = **it;
3231 const auto &type = field.value.type;
3232 if (IsArray(type) && init_arrays) {
3233 const auto &element_type = type.VectorType();
3234 const auto is_enum = IsEnum(element_type);
3236 (IsScalar(element_type.base_type) || IsStruct(element_type)) &&
3237 "invalid declaration");
3238 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3239 std::string get_array =
3240 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3241 const auto field_name = Name(field) + "_";
3242 const auto arg_name = "_" + Name(field);
3243 code_ += " flatbuffers::" + get_array + "(" + field_name +
3244 ").CopyFromSpan(" + arg_name + ");";
3246 if (field.padding) {
3247 std::string padding;
3248 GenPadding(field, &padding, &padding_id, PaddingNoop);
3256 void GenArrayAccessor(const Type &type, bool mutable_accessor) {
3257 FLATBUFFERS_ASSERT(IsArray(type));
3258 const auto is_enum = IsEnum(type.VectorType());
3259 // The Array<bool,N> is a tricky case, like std::vector<bool>.
3260 // It requires a specialization of Array class.
3261 // Generate Array<uint8_t> for Array<bool>.
3262 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3263 std::string ret_type = "flatbuffers::Array<" + face_type + ", " +
3264 NumToString(type.fixed_length) + ">";
3265 if (mutable_accessor)
3266 code_ += " " + ret_type + " *mutable_{{FIELD_NAME}}() {";
3268 code_ += " const " + ret_type + " *{{FIELD_NAME}}() const {";
3270 std::string get_array =
3271 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3272 code_ += " return &flatbuffers::" + get_array + "({{FIELD_VALUE}});";
3276 // Generate an accessor struct with constructor for a flatbuffers struct.
3277 void GenStruct(const StructDef &struct_def) {
3278 // Generate an accessor struct, with private variables of the form:
3280 // Generates manual padding and alignment.
3281 // Variables are private because they contain little endian data on all
3283 GenComment(struct_def.doc_comment);
3284 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
3285 code_.SetValue("STRUCT_NAME", Name(struct_def));
3288 "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
3289 "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
3290 code_ += " private:";
3293 for (auto it = struct_def.fields.vec.begin();
3294 it != struct_def.fields.vec.end(); ++it) {
3295 const auto &field = **it;
3296 const auto &field_type = field.value.type;
3297 code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
3298 code_.SetValue("FIELD_NAME", Name(field));
3299 code_.SetValue("ARRAY",
3301 ? "[" + NumToString(field_type.fixed_length) + "]"
3303 code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
3305 if (field.padding) {
3306 std::string padding;
3307 GenPadding(field, &padding, &padding_id, PaddingDefinition);
3312 // Generate GetFullyQualifiedName
3314 code_ += " public:";
3316 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
3318 // Make TypeTable accessible via the generated struct.
3319 if (opts_.mini_reflect != IDLOptions::kNone) {
3321 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
3322 code_ += " return {{STRUCT_NAME}}TypeTable();";
3326 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
3328 // Generate a default constructor.
3329 GenStructDefaultConstructor(struct_def);
3331 // Generate a constructor that takes all fields as arguments,
3332 // excluding arrays.
3333 GenStructConstructor(struct_def, kArrayArgModeNone);
3335 auto arrays_num = std::count_if(struct_def.fields.vec.begin(),
3336 struct_def.fields.vec.end(),
3337 [](const flatbuffers::FieldDef *fd) {
3338 return IsArray(fd->value.type);
3340 if (arrays_num > 0) {
3341 GenStructConstructor(struct_def, kArrayArgModeSpanStatic);
3344 // Generate accessor methods of the form:
3345 // type name() const { return flatbuffers::EndianScalar(name_); }
3346 for (auto it = struct_def.fields.vec.begin();
3347 it != struct_def.fields.vec.end(); ++it) {
3348 const auto &field = **it;
3349 const auto &type = field.value.type;
3350 const auto is_scalar = IsScalar(type.base_type);
3351 const auto is_array = IsArray(type);
3353 const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ",
3354 is_array ? "" : " &", true);
3355 auto member = Name(field) + "_";
3357 is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
3359 code_.SetValue("FIELD_NAME", Name(field));
3360 code_.SetValue("FIELD_TYPE", field_type);
3361 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
3363 GenComment(field.doc_comment, " ");
3365 // Generate a const accessor function.
3367 GenArrayAccessor(type, false);
3369 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
3370 code_ += " return {{FIELD_VALUE}};";
3374 // Generate a mutable accessor function.
3375 if (opts_.mutable_buffer) {
3376 auto mut_field_type =
3377 GenTypeGet(type, " ", "", is_array ? "" : " &", true);
3378 code_.SetValue("FIELD_TYPE", mut_field_type);
3380 code_.SetValue("ARG", GenTypeBasic(type, true));
3381 code_.SetValue("FIELD_VALUE",
3382 GenUnderlyingCast(field, false, "_" + Name(field)));
3384 code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
3386 " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
3387 "{{FIELD_VALUE}});";
3389 } else if (is_array) {
3390 GenArrayAccessor(type, true);
3392 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
3393 code_ += " return {{FIELD_VALUE}};";
3398 // Generate a comparison function for this field if it is a key.
3399 if (field.key) { GenKeyFieldMethods(field); }
3401 code_.SetValue("NATIVE_NAME", Name(struct_def));
3402 GenOperatorNewDelete(struct_def);
3404 if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
3408 code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
3409 code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
3410 if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
3413 // Definition for type traits for this table type. This allows querying var-
3414 // ious compile-time traits of the table.
3415 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
3418 // Set up the correct namespace. Only open a namespace if the existing one is
3419 // different (closing/opening only what is necessary).
3421 // The file must start and end with an empty (or null) namespace so that
3422 // namespaces are properly opened and closed.
3423 void SetNameSpace(const Namespace *ns) {
3424 if (cur_name_space_ == ns) { return; }
3426 // Compute the size of the longest common namespace prefix.
3427 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
3428 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
3429 // and common_prefix_size = 2
3430 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
3431 size_t new_size = ns ? ns->components.size() : 0;
3433 size_t common_prefix_size = 0;
3434 while (common_prefix_size < old_size && common_prefix_size < new_size &&
3435 ns->components[common_prefix_size] ==
3436 cur_name_space_->components[common_prefix_size]) {
3437 common_prefix_size++;
3440 // Close cur_name_space in reverse order to reach the common prefix.
3441 // In the previous example, D then C are closed.
3442 for (size_t j = old_size; j > common_prefix_size; --j) {
3443 code_ += "} // namespace " + cur_name_space_->components[j - 1];
3445 if (old_size != common_prefix_size) { code_ += ""; }
3447 // open namespace parts to reach the ns namespace
3448 // in the previous example, E, then F, then G are opened
3449 for (auto j = common_prefix_size; j != new_size; ++j) {
3450 code_ += "namespace " + ns->components[j] + " {";
3452 if (new_size != common_prefix_size) { code_ += ""; }
3454 cur_name_space_ = ns;
3460 bool GenerateCPP(const Parser &parser, const std::string &path,
3461 const std::string &file_name) {
3462 cpp::IDLOptionsCpp opts(parser.opts);
3463 // The '--cpp_std' argument could be extended (like ASAN):
3464 // Example: "flatc --cpp_std c++17:option1:option2".
3465 auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++11";
3466 std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), CharToUpper);
3467 if (cpp_std == "C++0X") {
3468 opts.g_cpp_std = cpp::CPP_STD_X0;
3469 opts.g_only_fixed_enums = false;
3470 } else if (cpp_std == "C++11") {
3471 // Use the standard C++11 code generator.
3472 opts.g_cpp_std = cpp::CPP_STD_11;
3473 opts.g_only_fixed_enums = true;
3474 } else if (cpp_std == "C++17") {
3475 opts.g_cpp_std = cpp::CPP_STD_17;
3476 // With c++17 generate strong enums only.
3477 opts.scoped_enums = true;
3478 // By default, prefixed_enums==true, reset it.
3479 opts.prefixed_enums = false;
3481 LogCompilerError("Unknown value of the '--cpp-std' switch: " +
3485 // The opts.scoped_enums has priority.
3486 opts.g_only_fixed_enums |= opts.scoped_enums;
3488 if (opts.cpp_static_reflection && opts.g_cpp_std < cpp::CPP_STD_17) {
3490 "--cpp-static-reflection requires using --cpp-std at \"C++17\" or "
3495 cpp::CppGenerator generator(parser, path, file_name, opts);
3496 return generator.generate();
3499 std::string CPPMakeRule(const Parser &parser, const std::string &path,
3500 const std::string &file_name) {
3501 const auto filebase =
3502 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
3503 cpp::CppGenerator geneartor(parser, path, file_name, parser.opts);
3504 const auto included_files = parser.GetIncludedFilesRecursive(file_name);
3505 std::string make_rule =
3506 geneartor.GeneratedFileName(path, filebase, parser.opts) + ": ";
3507 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
3508 make_rule += " " + *it;
3513 } // namespace flatbuffers