diff options
author | Tony Mak <tonymak@google.com> | 2021-01-08 15:36:41 +0000 |
---|---|---|
committer | Tony Mak <tonymak@google.com> | 2021-01-08 15:54:47 +0000 |
commit | 4ae7c6ee6aa6ded74f79633e3de2577e3f913ee7 (patch) | |
tree | 31e2d4ecf7e1a9f628b4c06a9636f55b8b489e5b /src/idl_gen_cpp.cpp | |
parent | 912d7566fbedac9941027018108144b9de12c2b3 (diff) | |
parent | efda179c1b15756a641f24129d0aaaa856bd1079 (diff) | |
download | flatbuffers-4ae7c6ee6aa6ded74f79633e3de2577e3f913ee7.tar.gz |
Merge remote-tracking branch 'goog/stage-aosp-master' into mainline-prod
The current one in the mainline-prod branch is not able to compile our
libtextclassifier anymore.
Change-Id: I7282aa04e1bc861822b70c7b9c9c510605141b10
Diffstat (limited to 'src/idl_gen_cpp.cpp')
-rw-r--r-- | src/idl_gen_cpp.cpp | 772 |
1 files changed, 527 insertions, 245 deletions
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 268c436e..f78ee268 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -16,30 +16,84 @@ // independent from idl_parser, since this code is not needed for most clients +#include <unordered_set> + #include "flatbuffers/code_generators.h" #include "flatbuffers/flatbuffers.h" +#include "flatbuffers/flatc.h" #include "flatbuffers/idl.h" #include "flatbuffers/util.h" -#include <unordered_set> - namespace flatbuffers { // Pedantic warning free version of toupper(). -inline char ToUpper(char c) { return static_cast<char>(::toupper(c)); } +inline char ToUpper(char c) { + return static_cast<char>(::toupper(static_cast<unsigned char>(c))); +} + +// Make numerical literal with type-suffix. +// This function is only needed for C++! Other languages do not need it. +static inline std::string NumToStringCpp(std::string val, BaseType type) { + // Avoid issues with -2147483648, -9223372036854775808. + switch (type) { + case BASE_TYPE_INT: + return (val != "-2147483648") ? val : ("(-2147483647 - 1)"); + case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL"); + case BASE_TYPE_LONG: + if (val == "-9223372036854775808") + return "(-9223372036854775807LL - 1LL)"; + else + return (val == "0") ? val : (val + "LL"); + default: return val; + } +} -static std::string GeneratedFileName(const std::string &path, - const std::string &file_name) { - return path + file_name + "_generated.h"; +static std::string GenIncludeGuard(const std::string &file_name, + const Namespace &name_space, + const std::string &postfix = "") { + // Generate include guard. + std::string guard = file_name; + // Remove any non-alpha-numeric characters that may appear in a filename. + struct IsAlnum { + bool operator()(char c) const { return !is_alnum(c); } + }; + guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()), + guard.end()); + guard = "FLATBUFFERS_GENERATED_" + guard; + guard += "_"; + // For further uniqueness, also add the namespace. + for (auto it = name_space.components.begin(); + it != name_space.components.end(); ++it) { + guard += *it + "_"; + } + // Anything extra to add to the guard? + if (!postfix.empty()) { guard += postfix + "_"; } + guard += "H_"; + std::transform(guard.begin(), guard.end(), guard.begin(), ToUpper); + return guard; } namespace cpp { + +enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 }; + +// Extension of IDLOptions for cpp-generator. +struct IDLOptionsCpp : public IDLOptions { + // All fields start with 'g_' prefix to distinguish from the base IDLOptions. + CppStandard g_cpp_std; // Base version of C++ standard. + bool g_only_fixed_enums; // Generate underlaying type for all enums. + + IDLOptionsCpp(const IDLOptions &opts) + : IDLOptions(opts), g_cpp_std(CPP_STD_11), g_only_fixed_enums(true) {} +}; + class CppGenerator : public BaseGenerator { public: CppGenerator(const Parser &parser, const std::string &path, - const std::string &file_name) - : BaseGenerator(parser, path, file_name, "", "::"), + const std::string &file_name, IDLOptionsCpp opts) + : BaseGenerator(parser, path, file_name, "", "::", "h"), cur_name_space_(nullptr), + opts_(opts), float_const_gen_("std::numeric_limits<double>::", "std::numeric_limits<float>::", "quiet_NaN()", "infinity()") { @@ -144,28 +198,6 @@ class CppGenerator : public BaseGenerator { for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw); } - std::string GenIncludeGuard() const { - // Generate include guard. - std::string guard = file_name_; - // Remove any non-alpha-numeric characters that may appear in a filename. - struct IsAlnum { - bool operator()(char c) const { return !is_alnum(c); } - }; - guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()), - guard.end()); - guard = "FLATBUFFERS_GENERATED_" + guard; - guard += "_"; - // For further uniqueness, also add the namespace. - auto name_space = parser_.current_namespace_; - for (auto it = name_space->components.begin(); - it != name_space->components.end(); ++it) { - guard += *it + "_"; - } - guard += "H_"; - std::transform(guard.begin(), guard.end(), guard.begin(), ToUpper); - return guard; - } - void GenIncludeDependencies() { int num_includes = 0; for (auto it = parser_.native_included_files_.begin(); @@ -178,15 +210,22 @@ class CppGenerator : public BaseGenerator { if (it->second.empty()) continue; auto noext = flatbuffers::StripExtension(it->second); auto basename = flatbuffers::StripPath(noext); - - code_ += "#include \"" + parser_.opts.include_prefix + - (parser_.opts.keep_include_path ? noext : basename) + - "_generated.h\""; + auto includeName = + GeneratedFileName(opts_.include_prefix, + opts_.keep_include_path ? noext : basename, opts_); + code_ += "#include \"" + includeName + "\""; num_includes++; } if (num_includes) code_ += ""; } + void GenExtraIncludes() { + for (std::size_t i = 0; i < opts_.cpp_includes.size(); ++i) { + code_ += "#include \"" + opts_.cpp_includes[i] + "\""; + } + if (!opts_.cpp_includes.empty()) { code_ += ""; } + } + std::string EscapeKeyword(const std::string &name) const { return keywords_.find(name) == keywords_.end() ? name : name + "_"; } @@ -197,20 +236,83 @@ class CppGenerator : public BaseGenerator { std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); } + bool generate_bfbs_embed() { + code_.Clear(); + code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n"; + + // If we don't have a root struct definition, + if (!parser_.root_struct_def_) { + // put a comment in the output why there is no code generated. + code_ += "// Binary schema not generated, no root struct found"; + } else { + auto &struct_def = *parser_.root_struct_def_; + const auto include_guard = + GenIncludeGuard(file_name_, *struct_def.defined_namespace, "bfbs"); + + code_ += "#ifndef " + include_guard; + code_ += "#define " + include_guard; + code_ += ""; + if (parser_.opts.gen_nullable) { + code_ += "#pragma clang system_header\n\n"; + } + + SetNameSpace(struct_def.defined_namespace); + auto name = Name(struct_def); + code_.SetValue("STRUCT_NAME", name); + + // Create code to return the binary schema data. + auto binary_schema_hex_text = + BufferToHexText(parser_.builder_.GetBufferPointer(), + parser_.builder_.GetSize(), 105, " ", ""); + + code_ += "struct {{STRUCT_NAME}}BinarySchema {"; + code_ += " static const uint8_t *data() {"; + code_ += " // Buffer containing the binary schema."; + code_ += " static const uint8_t bfbsData[" + + NumToString(parser_.builder_.GetSize()) + "] = {"; + code_ += binary_schema_hex_text; + code_ += " };"; + code_ += " return bfbsData;"; + code_ += " }"; + code_ += " static size_t size() {"; + code_ += " return " + NumToString(parser_.builder_.GetSize()) + ";"; + code_ += " }"; + code_ += " const uint8_t *begin() {"; + code_ += " return data();"; + code_ += " }"; + code_ += " const uint8_t *end() {"; + code_ += " return data() + size();"; + code_ += " }"; + code_ += "};"; + code_ += ""; + + if (cur_name_space_) SetNameSpace(nullptr); + + // Close the include guard. + code_ += "#endif // " + include_guard; + } + + // We are just adding "_bfbs" to the generated filename. + const auto file_path = + GeneratedFileName(path_, file_name_ + "_bfbs", opts_); + const auto final_code = code_.ToString(); + + return SaveFile(file_path.c_str(), final_code, false); + } + // Iterate through all definitions we haven't generate code for (enums, // structs, and tables) and output them to a single file. bool generate() { code_.Clear(); code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n"; - const auto include_guard = GenIncludeGuard(); + const auto include_guard = + GenIncludeGuard(file_name_, *parser_.current_namespace_); code_ += "#ifndef " + include_guard; code_ += "#define " + include_guard; code_ += ""; - if (parser_.opts.gen_nullable) { - code_ += "#pragma clang system_header\n\n"; - } + if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; } code_ += "#include \"flatbuffers/flatbuffers.h\""; if (parser_.uses_flexbuffers_) { @@ -218,7 +320,8 @@ class CppGenerator : public BaseGenerator { } code_ += ""; - if (parser_.opts.include_dependence_headers) { GenIncludeDependencies(); } + if (opts_.include_dependence_headers) { GenIncludeDependencies(); } + GenExtraIncludes(); FLATBUFFERS_ASSERT(!cur_name_space_); @@ -230,9 +333,11 @@ class CppGenerator : public BaseGenerator { if (!struct_def.generated) { SetNameSpace(struct_def.defined_namespace); code_ += "struct " + Name(struct_def) + ";"; - if (parser_.opts.generate_object_based_api) { - auto nativeName = - NativeName(Name(struct_def), &struct_def, parser_.opts); + if (!struct_def.fixed) { + code_ += "struct " + Name(struct_def) + "Builder;"; + } + if (opts_.generate_object_based_api) { + auto nativeName = NativeName(Name(struct_def), &struct_def, opts_); if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; } } code_ += ""; @@ -240,25 +345,24 @@ class CppGenerator : public BaseGenerator { } // Generate forward declarations for all equal operators - if (parser_.opts.generate_object_based_api && parser_.opts.gen_compare) { + if (opts_.generate_object_based_api && opts_.gen_compare) { for (auto it = parser_.structs_.vec.begin(); it != parser_.structs_.vec.end(); ++it) { const auto &struct_def = **it; if (!struct_def.generated) { SetNameSpace(struct_def.defined_namespace); - auto nativeName = - NativeName(Name(struct_def), &struct_def, parser_.opts); + auto nativeName = NativeName(Name(struct_def), &struct_def, opts_); code_ += "bool operator==(const " + nativeName + " &lhs, const " + nativeName + " &rhs);"; code_ += "bool operator!=(const " + nativeName + " &lhs, const " + - nativeName + " &rhs);"; + nativeName + " &rhs);"; } } code_ += ""; } // Generate preablmle code for mini reflection. - if (parser_.opts.mini_reflect != IDLOptions::kNone) { + if (opts_.mini_reflect != IDLOptions::kNone) { // To break cyclic dependencies, first pre-declare all tables/structs. for (auto it = parser_.structs_.vec.begin(); it != parser_.structs_.vec.end(); ++it) { @@ -317,7 +421,7 @@ class CppGenerator : public BaseGenerator { } // Generate code for mini reflection. - if (parser_.opts.mini_reflect != IDLOptions::kNone) { + if (opts_.mini_reflect != IDLOptions::kNone) { // Then the unions/enums that may refer to them. for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); ++it) { @@ -368,7 +472,7 @@ class CppGenerator : public BaseGenerator { code_ += "}"; code_ += ""; - if (parser_.opts.mutable_buffer) { + if (opts_.mutable_buffer) { code_ += "inline \\"; code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {"; code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);"; @@ -441,10 +545,10 @@ class CppGenerator : public BaseGenerator { code_ += "}"; code_ += ""; - if (parser_.opts.generate_object_based_api) { + if (opts_.generate_object_based_api) { // A convenient root unpack function. auto native_name = - NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts); + NativeName(WrapInNameSpace(struct_def), &struct_def, opts_); code_.SetValue("UNPACK_RETURN", GenTypeNativePtr(native_name, nullptr, false)); code_.SetValue("UNPACK_TYPE", @@ -457,6 +561,14 @@ class CppGenerator : public BaseGenerator { code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));"; code_ += "}"; code_ += ""; + + code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}("; + code_ += " const void *buf,"; + code_ += " const flatbuffers::resolver_function_t *res = nullptr) {"; + code_ += " return {{UNPACK_TYPE}}\\"; + code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));"; + code_ += "}"; + code_ += ""; } } @@ -465,9 +577,12 @@ class CppGenerator : public BaseGenerator { // Close the include guard. code_ += "#endif // " + include_guard; - const auto file_path = GeneratedFileName(path_, file_name_); + const auto file_path = GeneratedFileName(path_, file_name_, opts_); const auto final_code = code_.ToString(); - return SaveFile(file_path.c_str(), final_code, false); + + // Save the file and optionally generate the binary schema code. + return SaveFile(file_path.c_str(), final_code, false) && + (!parser_.opts.binary_schema_gen_embed || generate_bfbs_embed()); } private: @@ -478,6 +593,9 @@ class CppGenerator : public BaseGenerator { // This tracks the current namespace so we can insert namespace declarations. const Namespace *cur_name_space_; + const IDLOptionsCpp opts_; + const TypedFloatConstantGenerator float_const_gen_; + const Namespace *CurrentNameSpace() const { return cur_name_space_; } // Translates a qualified name in flatbuffer text format to the same name in @@ -485,13 +603,28 @@ class CppGenerator : public BaseGenerator { static std::string TranslateNameSpace(const std::string &qualified_name) { std::string cpp_qualified_name = qualified_name; size_t start_pos = 0; - while ((start_pos = cpp_qualified_name.find(".", start_pos)) != + while ((start_pos = cpp_qualified_name.find('.', start_pos)) != std::string::npos) { cpp_qualified_name.replace(start_pos, 1, "::"); } return cpp_qualified_name; } + bool TypeHasKey(const Type &type) { + if (type.base_type != BASE_TYPE_STRUCT) { return false; } + for (auto it = type.struct_def->fields.vec.begin(); + it != type.struct_def->fields.vec.end(); ++it) { + const auto &field = **it; + if (field.key) { return true; } + } + return false; + } + + bool VectorElementUserFacing(const Type &type) const { + return opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums && + IsEnum(type); + } + void GenComment(const std::vector<std::string> &dc, const char *prefix = "") { std::string text; ::flatbuffers::GenComment(dc, &text, nullptr, prefix); @@ -502,11 +635,10 @@ class CppGenerator : public BaseGenerator { std::string GenTypeBasic(const Type &type, bool user_facing_type) const { // clang-format off static const char *const ctypename[] = { - #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ - RTYPE) \ - #CTYPE, + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + #CTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) - #undef FLATBUFFERS_TD + #undef FLATBUFFERS_TD }; // clang-format on if (user_facing_type) { @@ -524,15 +656,18 @@ class CppGenerator : public BaseGenerator { return "flatbuffers::String"; } case BASE_TYPE_VECTOR: { - const auto type_name = GenTypeWire(type.VectorType(), "", false); + const auto type_name = GenTypeWire( + type.VectorType(), "", VectorElementUserFacing(type.VectorType())); return "flatbuffers::Vector<" + type_name + ">"; } case BASE_TYPE_STRUCT: { return WrapInNameSpace(*type.struct_def); } case BASE_TYPE_UNION: - // fall through - default: { return "void"; } + // fall through + default: { + return "void"; + } } } @@ -562,7 +697,7 @@ class CppGenerator : public BaseGenerator { } std::string NullableExtension() { - return parser_.opts.gen_nullable ? " _Nullable " : ""; + return opts_.gen_nullable ? " _Nullable " : ""; } static std::string NativeName(const std::string &name, const StructDef *sd, @@ -573,12 +708,12 @@ class CppGenerator : public BaseGenerator { const std::string &PtrType(const FieldDef *field) { auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr; - return attr ? attr->constant : parser_.opts.cpp_object_api_pointer_type; + return attr ? attr->constant : opts_.cpp_object_api_pointer_type; } const std::string NativeString(const FieldDef *field) { auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr; - auto &ret = attr ? attr->constant : parser_.opts.cpp_object_api_string_type; + auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type; if (ret.empty()) { return "std::string"; } return ret; } @@ -587,8 +722,7 @@ class CppGenerator : public BaseGenerator { auto attr = field ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr) : false; - auto ret = - attr ? attr : parser_.opts.cpp_object_api_string_flexible_constructor; + auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor; return ret && NativeString(field) != "std::string"; // Only for custom string types. } @@ -599,7 +733,7 @@ class CppGenerator : public BaseGenerator { if (ptr_type != "naked") { return (ptr_type != "default_ptr_type" ? ptr_type - : parser_.opts.cpp_object_api_pointer_type) + + : opts_.cpp_object_api_pointer_type) + "<" + type + ">"; } else if (is_constructor) { return ""; @@ -643,15 +777,17 @@ class CppGenerator : public BaseGenerator { return GenTypeNativePtr(type_name, &field, false); } } else { - return GenTypeNativePtr( - NativeName(type_name, type.struct_def, parser_.opts), &field, - false); + return GenTypeNativePtr(NativeName(type_name, type.struct_def, opts_), + &field, false); } } case BASE_TYPE_UNION: { - return type.enum_def->name + "Union"; + auto type_name = WrapInNameSpace(*type.enum_def); + return type_name + "Union"; + } + default: { + return GenTypeBasic(type, true); } - default: { return GenTypeBasic(type, true); } } } @@ -662,28 +798,34 @@ class CppGenerator : public BaseGenerator { bool user_facing_type) { if (IsScalar(type.base_type)) { return GenTypeBasic(type, user_facing_type) + afterbasic; + } else if (IsArray(type)) { + auto element_type = type.VectorType(); + // Check if enum arrays are used in C++ without specifying --scoped-enums + if (IsEnum(element_type) && !opts_.g_only_fixed_enums) { + LogCompilerError( + "--scoped-enums must be enabled to use enum arrays in C++"); + FLATBUFFERS_ASSERT(true); + } + return beforeptr + + (IsScalar(element_type.base_type) + ? GenTypeBasic(element_type, user_facing_type) + : GenTypePointer(element_type)) + + afterptr; } else { return beforeptr + GenTypePointer(type) + afterptr; } } - std::string GenEnumDecl(const EnumDef &enum_def) const { - const IDLOptions &opts = parser_.opts; - return (opts.scoped_enums ? "enum class " : "enum ") + Name(enum_def); - } - std::string GenEnumValDecl(const EnumDef &enum_def, const std::string &enum_val) const { - const IDLOptions &opts = parser_.opts; - return opts.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val; + return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val; } std::string GetEnumValUse(const EnumDef &enum_def, const EnumVal &enum_val) const { - const IDLOptions &opts = parser_.opts; - if (opts.scoped_enums) { + if (opts_.scoped_enums) { return Name(enum_def) + "::" + Name(enum_val); - } else if (opts.prefixed_enums) { + } else if (opts_.prefixed_enums) { return Name(enum_def) + "_" + Name(enum_val); } else { return Name(enum_val); @@ -789,7 +931,7 @@ class CppGenerator : public BaseGenerator { code_.SetValue("NUM_FIELDS", NumToString(num_fields)); std::vector<std::string> names; std::vector<Type> types; - bool consecutive_enum_from_zero = true; + if (struct_def) { for (auto it = struct_def->fields.vec.begin(); it != struct_def->fields.vec.end(); ++it) { @@ -804,9 +946,6 @@ class CppGenerator : public BaseGenerator { names.push_back(Name(ev)); types.push_back(enum_def->is_union ? ev.union_type : Type(enum_def->underlying_type)); - if (static_cast<int64_t>(it - enum_def->Vals().begin()) != ev.value) { - consecutive_enum_from_zero = false; - } } } std::string ts; @@ -851,12 +990,16 @@ class CppGenerator : public BaseGenerator { ns += "\"" + *it + "\""; } std::string vs; + const auto consecutive_enum_from_zero = + enum_def && enum_def->MinValue()->IsZero() && + ((enum_def->size() - 1) == enum_def->Distance()); if (enum_def && !consecutive_enum_from_zero) { for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end(); ++it) { const auto &ev = **it; if (!vs.empty()) vs += ", "; - vs += NumToString(ev.value); + vs += NumToStringCpp(enum_def->ToString(ev), + enum_def->underlying_type.base_type); } } else if (struct_def && struct_def->fixed) { for (auto it = struct_def->fields.vec.begin(); @@ -883,10 +1026,11 @@ class CppGenerator : public BaseGenerator { code_ += " };"; } if (!vs.empty()) { + // Problem with uint64_t values greater than 9223372036854775807ULL. code_ += " static const int64_t values[] = { {{VALUES}} };"; } auto has_names = - num_fields && parser_.opts.mini_reflect == IDLOptions::kTypesAndNames; + num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames; if (has_names) { code_ += " static const char * const names[] = {"; code_ += " {{NAMES}}"; @@ -907,33 +1051,34 @@ class CppGenerator : public BaseGenerator { // Generate an enum declaration, // an enum string lookup table, // and an enum array of values + void GenEnum(const EnumDef &enum_def) { code_.SetValue("ENUM_NAME", Name(enum_def)); code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false)); - code_.SetValue("SEP", ""); GenComment(enum_def.doc_comment); - code_ += GenEnumDecl(enum_def) + "\\"; - if (parser_.opts.scoped_enums) code_ += " : {{BASE_TYPE}}\\"; + code_ += + (opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\"; + if (opts_.g_only_fixed_enums) { code_ += " : {{BASE_TYPE}}\\"; } code_ += " {"; - int64_t anyv = 0; - const EnumVal *minv = nullptr, *maxv = nullptr; + code_.SetValue("SEP", ","); + auto add_sep = false; for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { const auto &ev = **it; - + if (add_sep) code_ += "{{SEP}}"; GenComment(ev.doc_comment, " "); code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev))); - code_.SetValue("VALUE", NumToString(ev.value)); - code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\"; - code_.SetValue("SEP", ",\n"); - - minv = !minv || minv->value > ev.value ? &ev : minv; - maxv = !maxv || maxv->value < ev.value ? &ev : maxv; - anyv |= ev.value; + code_.SetValue("VALUE", + NumToStringCpp(enum_def.ToString(ev), + enum_def.underlying_type.base_type)); + code_ += " {{KEY}} = {{VALUE}}\\"; + add_sep = true; } + const EnumVal *minv = enum_def.MinValue(); + const EnumVal *maxv = enum_def.MaxValue(); - if (parser_.opts.scoped_enums || parser_.opts.prefixed_enums) { + if (opts_.scoped_enums || opts_.prefixed_enums) { FLATBUFFERS_ASSERT(minv && maxv); code_.SetValue("SEP", ",\n"); @@ -943,22 +1088,24 @@ class CppGenerator : public BaseGenerator { code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\"; code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY")); - code_.SetValue("VALUE", NumToString(anyv)); + code_.SetValue("VALUE", + NumToStringCpp(enum_def.AllFlags(), + enum_def.underlying_type.base_type)); code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\"; } else { // MIN & MAX are useless for bit_flags code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN")); - code_.SetValue("VALUE", GenEnumValDecl(enum_def, minv->name)); + code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*minv))); code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\"; code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX")); - code_.SetValue("VALUE", GenEnumValDecl(enum_def, maxv->name)); + code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*maxv))); code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\"; } } code_ += ""; code_ += "};"; - if (parser_.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags")) { + if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) { code_ += "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})"; } @@ -984,22 +1131,24 @@ class CppGenerator : public BaseGenerator { // Problem is, if values are very sparse that could generate really big // tables. Ideally in that case we generate a map lookup instead, but for // the moment we simply don't output a table at all. - auto range = - enum_def.vals.vec.back()->value - enum_def.vals.vec.front()->value + 1; + auto range = enum_def.Distance(); // Average distance between values above which we consider a table // "too sparse". Change at will. - static const int kMaxSparseness = 5; - if (range / static_cast<int64_t>(enum_def.vals.vec.size()) < - kMaxSparseness) { + static const uint64_t kMaxSparseness = 5; + if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) { code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {"; - code_ += " static const char * const names[] = {"; + code_ += " static const char * const names[" + + NumToString(range + 1 + 1) + "] = {"; - auto val = enum_def.Vals().front()->value; + auto val = enum_def.Vals().front(); for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { - const auto &ev = **it; - while (val++ != ev.value) { code_ += " \"\","; } - code_ += " \"" + Name(ev) + "\","; + auto ev = *it; + for (auto k = enum_def.Distance(val, ev); k > 1; --k) { + code_ += " \"\","; + } + val = ev; + code_ += " \"" + Name(*ev) + "\","; } code_ += " nullptr"; code_ += " };"; @@ -1010,14 +1159,14 @@ class CppGenerator : public BaseGenerator { code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {"; - code_ += " if (e < " + - GetEnumValUse(enum_def, *enum_def.vals.vec.front()) + - " || e > " + GetEnumValUse(enum_def, *enum_def.vals.vec.back()) + - ") return \"\";"; + code_ += " if (flatbuffers::IsOutRange(e, " + + GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " + + GetEnumValUse(enum_def, *enum_def.MaxValue()) + + ")) return \"\";"; code_ += " const size_t index = static_cast<size_t>(e)\\"; - if (enum_def.vals.vec.front()->value) { - auto vals = GetEnumValUse(enum_def, *enum_def.vals.vec.front()); + if (enum_def.MinValue()->IsNonZero()) { + auto vals = GetEnumValUse(enum_def, *enum_def.MinValue()); code_ += " - static_cast<size_t>(" + vals + ")\\"; } code_ += ";"; @@ -1064,11 +1213,11 @@ class CppGenerator : public BaseGenerator { } } - if (parser_.opts.generate_object_based_api && enum_def.is_union) { + if (opts_.generate_object_based_api && enum_def.is_union) { // Generate a union type code_.SetValue("NAME", Name(enum_def)); - code_.SetValue("NONE", - GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE"))); + FLATBUFFERS_ASSERT(enum_def.Lookup("NONE")); + code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE"))); code_ += "struct {{NAME}}Union {"; code_ += " {{NAME}} type;"; @@ -1078,10 +1227,8 @@ class CppGenerator : public BaseGenerator { code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :"; code_ += " type({{NONE}}), value(nullptr)"; code_ += " { std::swap(type, u.type); std::swap(value, u.value); }"; - code_ += " {{NAME}}Union(const {{NAME}}Union &) FLATBUFFERS_NOEXCEPT;"; - code_ += - " {{NAME}}Union &operator=(const {{NAME}}Union &u) " - "FLATBUFFERS_NOEXCEPT"; + code_ += " {{NAME}}Union(const {{NAME}}Union &);"; + code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)"; code_ += " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, " "t.value); return *this; }"; @@ -1100,7 +1247,8 @@ class CppGenerator : public BaseGenerator { code_ += " void Set(T&& val) {"; code_ += " using RT = typename std::remove_reference<T>::type;"; code_ += " Reset();"; - code_ += " type = {{NAME}}Traits<typename RT::TableType>::enum_value;"; + code_ += + " type = {{NAME}}Traits<typename RT::TableType>::enum_value;"; code_ += " if (type != {{NONE}}) {"; code_ += " value = new RT(std::forward<T>(val));"; code_ += " }"; @@ -1119,7 +1267,7 @@ class CppGenerator : public BaseGenerator { const auto native_type = NativeName(GetUnionElement(ev, true, true, true), - ev.union_type.struct_def, parser_.opts); + ev.union_type.struct_def, opts_); code_.SetValue("NATIVE_TYPE", native_type); code_.SetValue("NATIVE_NAME", Name(ev)); code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev)); @@ -1138,7 +1286,7 @@ class CppGenerator : public BaseGenerator { code_ += "};"; code_ += ""; - if (parser_.opts.gen_compare) { + if (opts_.gen_compare) { code_ += ""; code_ += "inline bool operator==(const {{NAME}}Union &lhs, const " @@ -1153,7 +1301,7 @@ class CppGenerator : public BaseGenerator { if (ev.IsNonZero()) { const auto native_type = NativeName(GetUnionElement(ev, true, true, true), - ev.union_type.struct_def, parser_.opts); + ev.union_type.struct_def, opts_); code_.SetValue("NATIVE_TYPE", native_type); code_ += " case {{NATIVE_ID}}: {"; code_ += @@ -1213,8 +1361,9 @@ class CppGenerator : public BaseGenerator { " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);"; if (ev.union_type.base_type == BASE_TYPE_STRUCT) { if (ev.union_type.struct_def->fixed) { - code_ += " return verifier.Verify<{{TYPE}}>(static_cast<const " - "uint8_t *>(obj), 0);"; + code_ += + " return verifier.Verify<{{TYPE}}>(static_cast<const " + "uint8_t *>(obj), 0);"; } else { code_ += getptr; code_ += " return verifier.VerifyTable(ptr);"; @@ -1232,7 +1381,7 @@ class CppGenerator : public BaseGenerator { code_ += " }"; } } - code_ += " default: return false;"; + code_ += " default: return true;"; // unknown values are OK. code_ += " }"; code_ += "}"; code_ += ""; @@ -1251,7 +1400,7 @@ class CppGenerator : public BaseGenerator { code_ += "}"; code_ += ""; - if (parser_.opts.generate_object_based_api) { + if (opts_.generate_object_based_api) { // Generate union Unpack() and Pack() functions. code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {"; code_ += " switch (type) {"; @@ -1291,9 +1440,8 @@ class CppGenerator : public BaseGenerator { if (ev.IsZero()) { continue; } code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); - code_.SetValue("TYPE", - NativeName(GetUnionElement(ev, true, true, true), - ev.union_type.struct_def, parser_.opts)); + code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true), + ev.union_type.struct_def, opts_)); code_.SetValue("NAME", GetUnionElement(ev, false, true)); code_ += " case {{LABEL}}: {"; code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);"; @@ -1319,17 +1467,15 @@ class CppGenerator : public BaseGenerator { // Union copy constructor code_ += "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const " - "{{ENUM_NAME}}Union &u) FLATBUFFERS_NOEXCEPT : type(u.type), " - "value(nullptr) {"; + "{{ENUM_NAME}}Union &u) : type(u.type), value(nullptr) {"; code_ += " switch (type) {"; for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { const auto &ev = **it; if (ev.IsZero()) { continue; } code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); - code_.SetValue("TYPE", - NativeName(GetUnionElement(ev, true, true, true), - ev.union_type.struct_def, parser_.opts)); + code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true), + ev.union_type.struct_def, opts_)); code_ += " case {{LABEL}}: {"; bool copyable = true; if (ev.union_type.base_type == BASE_TYPE_STRUCT) { @@ -1363,8 +1509,8 @@ class CppGenerator : public BaseGenerator { code_ += ""; // Union Reset() function. - code_.SetValue("NONE", - GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE"))); + FLATBUFFERS_ASSERT(enum_def.Lookup("NONE")); + code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE"))); code_ += "inline void {{ENUM_NAME}}Union::Reset() {"; code_ += " switch (type) {"; @@ -1373,9 +1519,8 @@ class CppGenerator : public BaseGenerator { const auto &ev = **it; if (ev.IsZero()) { continue; } code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); - code_.SetValue("TYPE", - NativeName(GetUnionElement(ev, true, true, true), - ev.union_type.struct_def, parser_.opts)); + code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true), + ev.union_type.struct_def, opts_)); code_ += " case {{LABEL}}: {"; code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);"; code_ += " delete ptr;"; @@ -1417,7 +1562,7 @@ class CppGenerator : public BaseGenerator { void GenFullyQualifiedNameGetter(const StructDef &struct_def, const std::string &name) { - if (!parser_.opts.generate_name_strings) { return; } + if (!opts_.generate_name_strings) { return; } auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name); code_.SetValue("NAME", fullname); code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR"); @@ -1430,18 +1575,19 @@ class CppGenerator : public BaseGenerator { if (IsFloat(field.value.type.base_type)) return float_const_gen_.GenFloatConstant(field); else - return field.value.constant; + return NumToStringCpp(field.value.constant, field.value.type.base_type); } std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) { if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) { - auto ev = field.value.type.enum_def->ReverseLookup( - StringToInt(field.value.constant.c_str()), false); + auto ev = field.value.type.enum_def->FindByValue(field.value.constant); if (ev) { return WrapInNameSpace(field.value.type.enum_def->defined_namespace, GetEnumValUse(*field.value.type.enum_def, *ev)); } else { - return GenUnderlyingCast(field, true, field.value.constant); + return GenUnderlyingCast( + field, true, + NumToStringCpp(field.value.constant, field.value.type.base_type)); } } else if (field.value.type.base_type == BASE_TYPE_BOOL) { return field.value.constant == "0" ? "false" : "true"; @@ -1472,9 +1618,13 @@ class CppGenerator : public BaseGenerator { if (IsStruct(vtype)) { type = WrapInNameSpace(*vtype.struct_def); } else { - type = GenTypeWire(vtype, "", false); + type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype)); + } + if (TypeHasKey(vtype)) { + code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *"); + } else { + code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *"); } - code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *"); code_.SetValue("PARAM_VALUE", "nullptr"); } else { code_.SetValue("PARAM_TYPE", GenTypeWire(field.value.type, " ", true)); @@ -1547,7 +1697,7 @@ class CppGenerator : public BaseGenerator { } code_.SetValue("NATIVE_NAME", - NativeName(Name(struct_def), &struct_def, parser_.opts)); + NativeName(Name(struct_def), &struct_def, opts_)); code_.SetValue("INIT_LIST", initializer_list); code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {"; @@ -1617,8 +1767,7 @@ class CppGenerator : public BaseGenerator { } void GenNativeTable(const StructDef &struct_def) { - const auto native_name = - NativeName(Name(struct_def), &struct_def, parser_.opts); + const auto native_name = NativeName(Name(struct_def), &struct_def, opts_); code_.SetValue("STRUCT_NAME", Name(struct_def)); code_.SetValue("NATIVE_NAME", native_name); @@ -1633,7 +1782,7 @@ class CppGenerator : public BaseGenerator { GenOperatorNewDelete(struct_def); GenDefaultConstructor(struct_def); code_ += "};"; - if (parser_.opts.gen_compare) GenCompareOperator(struct_def); + if (opts_.gen_compare) GenCompareOperator(struct_def); code_ += ""; } @@ -1695,7 +1844,9 @@ class CppGenerator : public BaseGenerator { } break; } - default: { break; } + default: { + break; + } } } @@ -1720,7 +1871,7 @@ class CppGenerator : public BaseGenerator { } else { FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type)); auto type = GenTypeBasic(field.value.type, false); - if (parser_.opts.scoped_enums && field.value.type.enum_def && + if (opts_.scoped_enums && field.value.type.enum_def && IsScalar(field.value.type.base_type)) { type = GenTypeGet(field.value.type, " ", "const ", " *", true); } @@ -1736,7 +1887,7 @@ class CppGenerator : public BaseGenerator { // Generate an accessor struct, builder structs & function for a table. void GenTable(const StructDef &struct_def) { - if (parser_.opts.generate_object_based_api) { GenNativeTable(struct_def); } + if (opts_.generate_object_based_api) { GenNativeTable(struct_def); } // Generate an accessor struct, with methods of the form: // type name() const { return GetField<type>(offset, defaultval); } @@ -1746,10 +1897,12 @@ class CppGenerator : public BaseGenerator { code_ += "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS" " : private flatbuffers::Table {"; - if (parser_.opts.generate_object_based_api) { + if (opts_.generate_object_based_api) { code_ += " typedef {{NATIVE_NAME}} NativeTableType;"; } - if (parser_.opts.mini_reflect != IDLOptions::kNone) { + code_ += " typedef {{STRUCT_NAME}}Builder Builder;"; + if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; } + if (opts_.mini_reflect != IDLOptions::kNone) { code_ += " static const flatbuffers::TypeTable *MiniReflectTypeTable() {"; code_ += " return {{STRUCT_NAME}}TypeTable();"; @@ -1857,7 +2010,7 @@ class CppGenerator : public BaseGenerator { } } - if (parser_.opts.mutable_buffer) { + if (opts_.mutable_buffer && !(is_scalar && IsUnion(field.value.type))) { if (is_scalar) { const auto type = GenTypeWire(field.value.type, "", false); code_.SetValue("SET_FN", "SetField<" + type + ">"); @@ -1939,13 +2092,11 @@ class CppGenerator : public BaseGenerator { code_ += " &&\n verifier.EndTable();"; code_ += " }"; - if (parser_.opts.generate_object_based_api) { + if (opts_.generate_object_based_api) { // Generate the UnPack() pre declaration. - code_ += - " " + TableUnPackSignature(struct_def, true, parser_.opts) + ";"; - code_ += - " " + TableUnPackToSignature(struct_def, true, parser_.opts) + ";"; - code_ += " " + TablePackSignature(struct_def, true, parser_.opts) + ";"; + code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";"; + code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";"; + code_ += " " + TablePackSignature(struct_def, true, opts_) + ";"; } code_ += "};"; // End of table. @@ -1990,19 +2141,39 @@ class CppGenerator : public BaseGenerator { GenBuilders(struct_def); - if (parser_.opts.generate_object_based_api) { + if (opts_.generate_object_based_api) { // Generate a pre-declaration for a CreateX method that works with an // unpacked C++ object. - code_ += TableCreateSignature(struct_def, true, parser_.opts) + ";"; + code_ += TableCreateSignature(struct_def, true, opts_) + ";"; code_ += ""; } } + // Generate code to force vector alignment. Return empty string for vector + // that doesn't need alignment code. + std::string GenVectorForceAlign(const FieldDef &field, + const std::string &field_size) { + FLATBUFFERS_ASSERT(field.value.type.base_type == BASE_TYPE_VECTOR); + // Get the value of the force_align attribute. + const auto *force_align = field.attributes.Lookup("force_align"); + const int align = force_align ? atoi(force_align->constant.c_str()) : 1; + // Generate code to do force_align for the vector. + if (align > 1) { + const auto vtype = field.value.type.VectorType(); + const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def) + : GenTypeWire(vtype, "", false); + return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type + + "), " + std::to_string(static_cast<long long>(align)) + ");"; + } + return ""; + } + void GenBuilders(const StructDef &struct_def) { code_.SetValue("STRUCT_NAME", Name(struct_def)); // Generate a builder struct: code_ += "struct {{STRUCT_NAME}}Builder {"; + code_ += " typedef {{STRUCT_NAME}} Table;"; code_ += " flatbuffers::FlatBufferBuilder &fbb_;"; code_ += " flatbuffers::uoffset_t start_;"; @@ -2111,6 +2282,16 @@ class CppGenerator : public BaseGenerator { code_ += "}"; code_ += ""; + // Definition for type traits for this table type. This allows querying var- + // ious compile-time traits of the table. + if (opts_.g_cpp_std >= cpp::CPP_STD_17) { + code_ += "struct {{STRUCT_NAME}}::Traits {"; + code_ += " using type = {{STRUCT_NAME}};"; + code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};"; + code_ += "};"; + code_ += ""; + } + // Generate a CreateXDirect function with vector types as parameters if (has_string_or_vector_fields) { code_ += @@ -2142,16 +2323,29 @@ class CppGenerator : public BaseGenerator { " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? " "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;"; } else if (field.value.type.base_type == BASE_TYPE_VECTOR) { + const std::string force_align_code = + GenVectorForceAlign(field, Name(field) + "->size()"); + if (!force_align_code.empty()) { + code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }"; + } code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\"; const auto vtype = field.value.type.VectorType(); + const auto has_key = TypeHasKey(vtype); if (IsStruct(vtype)) { const auto type = WrapInNameSpace(*vtype.struct_def); - code_ += "_fbb.CreateVectorOfStructs<" + type + ">\\"; + code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<" + : "_fbb.CreateVectorOfStructs<") + + type + ">\\"; + } else if (has_key) { + const auto type = WrapInNameSpace(*vtype.struct_def); + code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\"; } else { - const auto type = GenTypeWire(vtype, "", false); + const auto type = + GenTypeWire(vtype, "", VectorElementUserFacing(vtype)); code_ += "_fbb.CreateVector<" + type + ">\\"; } - code_ += "(*{{FIELD_NAME}}) : 0;"; + code_ += + has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;"; } } } @@ -2178,8 +2372,8 @@ class CppGenerator : public BaseGenerator { std::string GenUnionUnpackVal(const FieldDef &afield, const char *vec_elem_access, const char *vec_type_access) { - return afield.value.type.enum_def->name + "Union::UnPack(" + "_e" + - vec_elem_access + ", " + + auto type_name = WrapInNameSpace(*afield.value.type.enum_def); + return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " + EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" + vec_type_access + ", _resolver)"; } @@ -2209,7 +2403,7 @@ class CppGenerator : public BaseGenerator { } } else { const auto ptype = GenTypeNativePtr( - NativeName(name, type.struct_def, parser_.opts), &afield, true); + NativeName(name, type.struct_def, opts_), &afield, true); return ptype + "(" + val + "->UnPack(_resolver))"; } } @@ -2336,8 +2530,6 @@ class CppGenerator : public BaseGenerator { } std::string GenCreateParam(const FieldDef &field) { - const IDLOptions &opts = parser_.opts; - std::string value = "_o->"; if (field.value.type.base_type == BASE_TYPE_UTYPE) { value += StripUnionType(Name(field)); @@ -2371,22 +2563,24 @@ class CppGenerator : public BaseGenerator { // For optional fields, check to see if there actually is any data // in _o->field before attempting to access it. If there isn't, - // depending on set_empty_to_null either set it to 0 or an empty string. + // depending on set_empty_strings_to_null either set it to 0 or an empty + // string. if (!field.required) { - auto empty_value = - opts.set_empty_to_null ? "0" : "_fbb.CreateSharedString(\"\")"; + auto empty_value = opts_.set_empty_strings_to_null + ? "0" + : "_fbb.CreateSharedString(\"\")"; code = value + ".empty() ? " + empty_value + " : " + code; } break; } - // Vector fields come in several flavours, of the forms: - // _fbb.CreateVector(_o->field); - // _fbb.CreateVector((const utype*)_o->field.data(), _o->field.size()); - // _fbb.CreateVectorOfStrings(_o->field) - // _fbb.CreateVectorOfStructs(_o->field) - // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) { - // return CreateT(_fbb, _o->Get(i), rehasher); - // }); + // Vector fields come in several flavours, of the forms: + // _fbb.CreateVector(_o->field); + // _fbb.CreateVector((const utype*)_o->field.data(), + // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field) + // _fbb.CreateVectorOfStructs(_o->field) + // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) { + // return CreateT(_fbb, _o->Get(i), rehasher); + // }); case BASE_TYPE_VECTOR: { auto vector_type = field.value.type.VectorType(); switch (vector_type.base_type) { @@ -2453,7 +2647,8 @@ class CppGenerator : public BaseGenerator { break; } default: { - if (field.value.type.enum_def) { + if (field.value.type.enum_def && + !VectorElementUserFacing(vector_type)) { // For enumerations, we need to get access to the array data for // the underlying storage type (eg. uint8_t). const auto basetype = GenTypeBasic( @@ -2476,10 +2671,10 @@ class CppGenerator : public BaseGenerator { } } - // If set_empty_to_null option is enabled, for optional fields, check to - // see if there actually is any data in _o->field before attempting to - // access it. - if (opts.set_empty_to_null && !field.required) { + // If set_empty_vectors_to_null option is enabled, for optional fields, + // check to see if there actually is any data in _o->field before + // attempting to access it. + if (opts_.set_empty_vectors_to_null && !field.required) { code = value + ".size() ? " + code + " : 0"; } break; @@ -2521,20 +2716,27 @@ class CppGenerator : public BaseGenerator { void GenTablePost(const StructDef &struct_def) { code_.SetValue("STRUCT_NAME", Name(struct_def)); code_.SetValue("NATIVE_NAME", - NativeName(Name(struct_def), &struct_def, parser_.opts)); + NativeName(Name(struct_def), &struct_def, opts_)); + auto native_name = + NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts); + code_.SetValue("POINTER_TYPE", + GenTypeNativePtr(native_name, nullptr, false)); - if (parser_.opts.generate_object_based_api) { + if (opts_.generate_object_based_api) { // Generate the X::UnPack() method. - code_ += "inline " + - TableUnPackSignature(struct_def, false, parser_.opts) + " {"; - code_ += " auto _o = new {{NATIVE_NAME}}();"; - code_ += " UnPackTo(_o, _resolver);"; - code_ += " return _o;"; + code_ += + "inline " + TableUnPackSignature(struct_def, false, opts_) + " {"; + + code_ += + " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());"; + code_ += " UnPackTo(_o.get(), _resolver);"; + code_ += " return _o.release();"; + code_ += "}"; code_ += ""; - code_ += "inline " + - TableUnPackToSignature(struct_def, false, parser_.opts) + " {"; + code_ += + "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {"; code_ += " (void)_o;"; code_ += " (void)_resolver;"; @@ -2553,7 +2755,7 @@ class CppGenerator : public BaseGenerator { code_.SetValue("FIELD_NAME", Name(field)); auto prefix = " { auto _e = {{FIELD_NAME}}(); "; auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) "; - auto postfix = " };"; + auto postfix = " }"; code_ += std::string(prefix) + check + statement + postfix; } code_ += "}"; @@ -2561,15 +2763,14 @@ class CppGenerator : public BaseGenerator { // Generate the X::Pack member function that simply calls the global // CreateX function. - code_ += "inline " + TablePackSignature(struct_def, false, parser_.opts) + - " {"; + code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {"; code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);"; code_ += "}"; code_ += ""; // Generate a CreateX method that works with an unpacked C++ object. - code_ += "inline " + - TableCreateSignature(struct_def, false, parser_.opts) + " {"; + code_ += + "inline " + TableCreateSignature(struct_def, false, opts_) + " {"; code_ += " (void)_rehasher;"; code_ += " (void)_o;"; @@ -2577,7 +2778,7 @@ class CppGenerator : public BaseGenerator { " struct _VectorArgs " "{ flatbuffers::FlatBufferBuilder *__fbb; " "const " + - NativeName(Name(struct_def), &struct_def, parser_.opts) + + NativeName(Name(struct_def), &struct_def, opts_) + "* __o; " "const flatbuffers::rehasher_function_t *__rehasher; } _va = { " "&_fbb, _o, _rehasher}; (void)_va;"; @@ -2586,6 +2787,11 @@ class CppGenerator : public BaseGenerator { it != struct_def.fields.vec.end(); ++it) { auto &field = **it; if (field.deprecated) { continue; } + if (field.value.type.base_type == BASE_TYPE_VECTOR) { + const std::string force_align_code = + GenVectorForceAlign(field, "_o->" + Name(field) + ".size()"); + if (!force_align_code.empty()) { code_ += " " + force_align_code; } + } code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";"; } // Need to call "Create" with the struct namespace. @@ -2642,7 +2848,8 @@ class CppGenerator : public BaseGenerator { static void PaddingInitializer(int bits, std::string *code_ptr, int *id) { (void)bits; - *code_ptr += ",\n padding" + NumToString((*id)++) + "__(0)"; + if (*code_ptr != "") *code_ptr += ",\n "; + *code_ptr += "padding" + NumToString((*id)++) + "__(0)"; } static void PaddingNoop(int bits, std::string *code_ptr, int *id) { @@ -2670,10 +2877,14 @@ class CppGenerator : public BaseGenerator { for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { const auto &field = **it; - code_.SetValue("FIELD_TYPE", - GenTypeGet(field.value.type, " ", "", " ", false)); + const auto &field_type = field.value.type; + code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false)); code_.SetValue("FIELD_NAME", Name(field)); - code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}_;"; + code_.SetValue("ARRAY", + IsArray(field_type) + ? "[" + NumToString(field_type.fixed_length) + "]" + : ""); + code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};"); if (field.padding) { std::string padding; @@ -2687,7 +2898,7 @@ class CppGenerator : public BaseGenerator { code_ += " public:"; // Make TypeTable accessible via the generated struct. - if (parser_.opts.mini_reflect != IDLOptions::kNone) { + if (opts_.mini_reflect != IDLOptions::kNone) { code_ += " static const flatbuffers::TypeTable *MiniReflectTypeTable() {"; code_ += " return {{STRUCT_NAME}}TypeTable();"; @@ -2698,33 +2909,40 @@ class CppGenerator : public BaseGenerator { // Generate a default constructor. code_ += " {{STRUCT_NAME}}() {"; - code_ += " memset(static_cast<void *>(this), 0, sizeof({{STRUCT_NAME}}));"; + code_ += + " memset(static_cast<void *>(this), 0, sizeof({{STRUCT_NAME}}));"; code_ += " }"; - // Generate a constructor that takes all fields as arguments. + // Generate a constructor that takes all fields as arguments, + // excluding arrays std::string arg_list; std::string init_list; padding_id = 0; + auto first = struct_def.fields.vec.begin(); for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { const auto &field = **it; + if (IsArray(field.value.type)) { + first++; + continue; + } const auto member_name = Name(field) + "_"; const auto arg_name = "_" + Name(field); const auto arg_type = GenTypeGet(field.value.type, " ", "const ", " &", true); - if (it != struct_def.fields.vec.begin()) { - arg_list += ", "; - init_list += ",\n "; - } + if (it != first) { arg_list += ", "; } arg_list += arg_type; arg_list += arg_name; - init_list += member_name; - if (IsScalar(field.value.type.base_type)) { - auto type = GenUnderlyingCast(field, false, arg_name); - init_list += "(flatbuffers::EndianScalar(" + type + "))"; - } else { - init_list += "(" + arg_name + ")"; + if (!IsArray(field.value.type)) { + if (it != first && init_list != "") { init_list += ",\n "; } + init_list += member_name; + if (IsScalar(field.value.type.base_type)) { + auto type = GenUnderlyingCast(field, false, arg_name); + init_list += "(flatbuffers::EndianScalar(" + type + "))"; + } else { + init_list += "(" + arg_name + ")"; + } } if (field.padding) { GenPadding(field, &init_list, &padding_id, PaddingInitializer); @@ -2734,12 +2952,21 @@ class CppGenerator : public BaseGenerator { if (!arg_list.empty()) { code_.SetValue("ARG_LIST", arg_list); code_.SetValue("INIT_LIST", init_list); - code_ += " {{STRUCT_NAME}}({{ARG_LIST}})"; - code_ += " : {{INIT_LIST}} {"; + if (!init_list.empty()) { + code_ += " {{STRUCT_NAME}}({{ARG_LIST}})"; + code_ += " : {{INIT_LIST}} {"; + } else { + code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {"; + } padding_id = 0; for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { const auto &field = **it; + if (IsArray(field.value.type)) { + const auto &member = Name(field) + "_"; + code_ += + " std::memset(" + member + ", 0, sizeof(" + member + "));"; + } if (field.padding) { std::string padding; GenPadding(field, &padding, &padding_id, PaddingNoop); @@ -2755,7 +2982,9 @@ class CppGenerator : public BaseGenerator { it != struct_def.fields.vec.end(); ++it) { const auto &field = **it; - auto field_type = GenTypeGet(field.value.type, " ", "const ", " &", true); + auto field_type = GenTypeGet(field.value.type, " ", + IsArray(field.value.type) ? "" : "const ", + IsArray(field.value.type) ? "" : " &", true); auto is_scalar = IsScalar(field.value.type.base_type); auto member = Name(field) + "_"; auto value = @@ -2766,12 +2995,29 @@ class CppGenerator : public BaseGenerator { code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value)); GenComment(field.doc_comment, " "); - code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {"; - code_ += " return {{FIELD_VALUE}};"; - code_ += " }"; - if (parser_.opts.mutable_buffer) { - auto mut_field_type = GenTypeGet(field.value.type, " ", "", " &", true); + // Generate a const accessor function. + if (IsArray(field.value.type)) { + auto underlying = GenTypeGet(field.value.type, "", "", "", false); + code_ += " const flatbuffers::Array<" + field_type + ", " + + NumToString(field.value.type.fixed_length) + "> *" + + "{{FIELD_NAME}}() const {"; + code_ += " return reinterpret_cast<const flatbuffers::Array<" + + field_type + ", " + + NumToString(field.value.type.fixed_length) + + "> *>({{FIELD_VALUE}});"; + code_ += " }"; + } else { + code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {"; + code_ += " return {{FIELD_VALUE}};"; + code_ += " }"; + } + + // Generate a mutable accessor function. + if (opts_.mutable_buffer) { + auto mut_field_type = + GenTypeGet(field.value.type, " ", "", + IsArray(field.value.type) ? "" : " &", true); code_.SetValue("FIELD_TYPE", mut_field_type); if (is_scalar) { code_.SetValue("ARG", GenTypeBasic(field.value.type, true)); @@ -2783,9 +3029,19 @@ class CppGenerator : public BaseGenerator { " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, " "{{FIELD_VALUE}});"; code_ += " }"; + } else if (IsArray(field.value.type)) { + auto underlying = GenTypeGet(field.value.type, "", "", "", false); + code_ += " flatbuffers::Array<" + mut_field_type + ", " + + NumToString(field.value.type.fixed_length) + "> *" + + "mutable_{{FIELD_NAME}}() {"; + code_ += " return reinterpret_cast<flatbuffers::Array<" + + mut_field_type + ", " + + NumToString(field.value.type.fixed_length) + + "> *>({{FIELD_VALUE}});"; + code_ += " }"; } else { code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {"; - code_ += " return {{FIELD_NAME}}_;"; + code_ += " return {{FIELD_VALUE}};"; code_ += " }"; } } @@ -2799,7 +3055,7 @@ class CppGenerator : public BaseGenerator { code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize)); code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});"; - if (parser_.opts.gen_compare) GenCompareOperator(struct_def, "()"); + if (opts_.gen_compare) GenCompareOperator(struct_def, "()"); code_ += ""; } @@ -2841,15 +3097,39 @@ class CppGenerator : public BaseGenerator { cur_name_space_ = ns; } - - const TypedFloatConstantGenerator float_const_gen_; }; } // namespace cpp bool GenerateCPP(const Parser &parser, const std::string &path, const std::string &file_name) { - cpp::CppGenerator generator(parser, path, file_name); + cpp::IDLOptionsCpp opts(parser.opts); + // The '--cpp_std' argument could be extended (like ASAN): + // Example: "flatc --cpp_std c++17:option1:option2". + auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++0X"; + std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), ToUpper); + if (cpp_std == "C++0X") { + opts.g_cpp_std = cpp::CPP_STD_X0; + opts.g_only_fixed_enums = false; + } else if (cpp_std == "C++11") { + // Use the standard C++11 code generator. + opts.g_cpp_std = cpp::CPP_STD_11; + opts.g_only_fixed_enums = true; + } else if (cpp_std == "C++17") { + opts.g_cpp_std = cpp::CPP_STD_17; + // With c++17 generate strong enums only. + opts.scoped_enums = true; + // By default, prefixed_enums==true, reset it. + opts.prefixed_enums = false; + } else { + LogCompilerError("Unknown value of the '--cpp-std' switch: " + + opts.cpp_std); + return false; + } + // The opts.scoped_enums has priority. + opts.g_only_fixed_enums |= opts.scoped_enums; + + cpp::CppGenerator generator(parser, path, file_name, opts); return generator.generate(); } @@ -2857,8 +3137,10 @@ std::string CPPMakeRule(const Parser &parser, const std::string &path, const std::string &file_name) { const auto filebase = flatbuffers::StripPath(flatbuffers::StripExtension(file_name)); + cpp::CppGenerator geneartor(parser, path, file_name, parser.opts); const auto included_files = parser.GetIncludedFilesRecursive(file_name); - std::string make_rule = GeneratedFileName(path, filebase) + ": "; + std::string make_rule = + geneartor.GeneratedFileName(path, filebase, parser.opts) + ": "; for (auto it = included_files.begin(); it != included_files.end(); ++it) { make_rule += " " + *it; } |