diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md index d7b44c874..90f8d8b41 100644 --- a/docs/source/Compiler.md +++ b/docs/source/Compiler.md @@ -75,7 +75,7 @@ Additional options: - `--allow-non-utf8` : Pass non-UTF-8 input through parser and emit nonstandard \x escapes in JSON. (Default is to raise parse error on non-UTF-8 input.) -- `--natural-utf8` : Output strings with UTF-8 as human-readable strings. +- `--natural-utf8` : Output strings with UTF-8 as human-readable strings. By default, UTF-8 characters are printed as \uXXXX escapes." - `--defaults-json` : Output fields whose value is equal to the default value @@ -120,7 +120,13 @@ Additional options: - `--cpp-ptr-type T` : Set object API pointer type (default std::unique_ptr) - `--cpp-str-type T` : Set object API string type (default std::string) -- T::c_str() and T::length() must be supported. + T::c_str(), T::length() and T::empty() must be supported. + The custom type also needs to be constructible from std::string (see the + --cpp-str-flex-ctor option to change this behavior). + +- `--cpp-str-flex-ctor` : Don't construct custom string types by passing + std::string from Flatbuffers, but (char* + length). This allows efficient + construction of custom string types, including zero-copy construction. - `--object-prefix` : Customise class prefix for C++ object-based API. @@ -168,7 +174,7 @@ Additional options: an evolution of. Gives errors if not. Useful to check if schema modifications don't break schema evolution rules. -- `--conform-includes PATH` : Include path for the schema given with +- `--conform-includes PATH` : Include path for the schema given with `--conform PATH`. - `--include-prefix PATH` : Prefix this path to any generated include diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md index 2808c49c6..6cf36d1fa 100644 --- a/docs/source/CppUsage.md +++ b/docs/source/CppUsage.md @@ -255,14 +255,24 @@ you, so you'll have to manage their lifecycles manually. To reference the pointer type specified by the `--cpp-ptr-type` argument to `flatc` from a flatbuffer field set the `cpp_ptr_type` attribute to `default_ptr_type`. - # Using different string type. By default the object tree is built out of `std::string`, but you can influence this either globally (using the `--cpp-str-type` argument to `flatc`) or per field using the `cpp_str_type` attribute. -The type must support T::c_str() and T::length() as member functions. +The type must support T::c_str(), T::length() and T::empty() as member functions. + +Further, the type must be constructible from std::string, as by default a +std::string instance is constructed and then used to initialize the custom +string type. This behavior impedes efficient and zero-copy construction of +custom string types; the `--cpp-str-flex-ctor` argument to `flatc` or the +per field attribute `cpp_str_flex_ctor` can be used to change this behavior, +so that the custom string type is constructed by passing the pointer and +length of the FlatBuffers String. The custom string class will require a +constructor in the following format: custom_str_class(const char *, size_t). +Please note that the character array is not guaranteed to be NULL terminated, +you should always use the provided size to determine end of string. ## Reflection (& Resizing) diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 62b3396e0..05d666cbc 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -410,6 +410,7 @@ struct IDLOptions { bool gen_compare; std::string cpp_object_api_pointer_type; std::string cpp_object_api_string_type; + bool cpp_object_api_string_flexible_constructor; bool gen_nullable; bool gen_generated; std::string object_prefix; @@ -486,6 +487,7 @@ struct IDLOptions { generate_object_based_api(false), gen_compare(false), cpp_object_api_pointer_type("std::unique_ptr"), + cpp_object_api_string_flexible_constructor(false), gen_nullable(false), gen_generated(false), object_suffix("T"), @@ -627,6 +629,7 @@ class Parser : public ParserState { known_attributes_["cpp_ptr_type"] = true; known_attributes_["cpp_ptr_type_get"] = true; known_attributes_["cpp_str_type"] = true; + known_attributes_["cpp_str_flex_ctor"] = true; known_attributes_["native_inline"] = true; known_attributes_["native_custom_alloc"] = true; known_attributes_["native_type"] = true; diff --git a/src/flatc.cpp b/src/flatc.cpp index c5ec70ecf..3833f3dec 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -100,14 +100,18 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const { " --gen-compare Generate operator== for object-based API types.\n" " --gen-nullable Add Clang _Nullable for C++ pointer. or @Nullable for Java\n" " --gen-generated Add @Generated annotation for Java\n" - " --gen-all Generate not just code for the current schema files,\n" + " --gen-all Generate not just code for the current schema files,\n" " but for all files it includes as well.\n" " If the language uses a single file for output (by default\n" " the case for C++ and JS), all code will end up in this one\n" " file.\n" " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr).\n" " --cpp-str-type T Set object API string type (default std::string).\n" - " T::c_str() and T::length() must be supported.\n" + " T::c_str(), T::length() and T::empty() must be supported.\n" + " The custom type also needs to be constructible from std::string\n" + " (see the --cpp-str-flex-ctor option to change this behavior).\n" + " --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n" + " from Flatbuffers, but (char* + length).\n" " --object-prefix Customise class prefix for C++ object-based API.\n" " --object-suffix Customise class suffix for C++ object-based API.\n" " Default value is \"T\".\n" @@ -247,6 +251,8 @@ int FlatCompiler::Compile(int argc, const char **argv) { } else if (arg == "--cpp-str-type") { if (++argi >= argc) Error("missing type following" + arg, true); opts.cpp_object_api_string_type = argv[argi]; + } else if (arg == "--cpp-str-flex-ctor") { + opts.cpp_object_api_string_flexible_constructor = true; } else if (arg == "--gen-nullable") { opts.gen_nullable = true; } else if (arg == "--gen-generated") { diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index efbfe07c6..90f747aa2 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -43,103 +43,104 @@ class CppGenerator : public BaseGenerator { float_const_gen_("std::numeric_limits::", "std::numeric_limits::", "quiet_NaN()", "infinity()") { - static const char * const keywords[] = { - "alignas", - "alignof", - "and", - "and_eq", - "asm", - "atomic_cancel", - "atomic_commit", - "atomic_noexcept", - "auto", - "bitand", - "bitor", - "bool", - "break", - "case", - "catch", - "char", - "char16_t", - "char32_t", - "class", - "compl", - "concept", - "const", - "constexpr", - "const_cast", - "continue", - "co_await", - "co_return", - "co_yield", - "decltype", - "default", - "delete", - "do", - "double", - "dynamic_cast", - "else", - "enum", - "explicit", - "export", - "extern", - "false", - "float", - "for", - "friend", - "goto", - "if", - "import", - "inline", - "int", - "long", - "module", - "mutable", - "namespace", - "new", - "noexcept", - "not", - "not_eq", - "nullptr", - "operator", - "or", - "or_eq", - "private", - "protected", - "public", - "register", - "reinterpret_cast", - "requires", - "return", - "short", - "signed", - "sizeof", - "static", - "static_assert", - "static_cast", - "struct", - "switch", - "synchronized", - "template", - "this", - "thread_local", - "throw", - "true", - "try", - "typedef", - "typeid", - "typename", - "union", - "unsigned", - "using", - "virtual", - "void", - "volatile", - "wchar_t", - "while", - "xor", - "xor_eq", - nullptr }; + static const char *const keywords[] = { + "alignas", + "alignof", + "and", + "and_eq", + "asm", + "atomic_cancel", + "atomic_commit", + "atomic_noexcept", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char16_t", + "char32_t", + "class", + "compl", + "concept", + "const", + "constexpr", + "const_cast", + "continue", + "co_await", + "co_return", + "co_yield", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "import", + "inline", + "int", + "long", + "module", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "requires", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "synchronized", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq", + nullptr, + }; for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw); } @@ -230,10 +231,9 @@ class CppGenerator : public BaseGenerator { 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 " + nativeName + ";"; - } + auto nativeName = + NativeName(Name(struct_def), &struct_def, parser_.opts); + if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; } } code_ += ""; } @@ -242,12 +242,14 @@ class CppGenerator : public BaseGenerator { // Generate forward declarations for all equal operators if (parser_.opts.generate_object_based_api && parser_.opts.gen_compare) { for (auto it = parser_.structs_.vec.begin(); - it != parser_.structs_.vec.end(); ++it) { + 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); - code_ += "bool operator==(const " + nativeName + " &lhs, const " + nativeName + " &rhs);"; + auto nativeName = + NativeName(Name(struct_def), &struct_def, parser_.opts); + code_ += "bool operator==(const " + nativeName + " &lhs, const " + + nativeName + " &rhs);"; } } code_ += ""; @@ -357,7 +359,8 @@ class CppGenerator : public BaseGenerator { code_ += "inline \\"; code_ += - "const {{CPP_NAME}} *{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void " + "const {{CPP_NAME}} " + "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void " "*buf) {"; code_ += " return flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}>(buf);"; code_ += "}"; @@ -402,7 +405,8 @@ class CppGenerator : public BaseGenerator { code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer("; code_ += " flatbuffers::Verifier &verifier) {"; - code_ += " return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});"; + code_ += + " return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});"; code_ += "}"; code_ += ""; @@ -494,15 +498,15 @@ class CppGenerator : public BaseGenerator { // Return a C++ type from the table in idl.h std::string GenTypeBasic(const Type &type, bool user_facing_type) const { - static const char * const ctypename[] = { // clang-format off + static const char *const ctypename[] = { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ RTYPE) \ #CTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD - // clang-format on }; + // clang-format on if (user_facing_type) { if (type.enum_def) return WrapInNameSpace(*type.enum_def); if (type.base_type == BASE_TYPE_BOOL) return "bool"; @@ -577,12 +581,24 @@ class CppGenerator : public BaseGenerator { return ret; } + bool FlexibleStringConstructor(const FieldDef *field) { + auto attr = field + ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr) + : false; + auto ret = + attr ? attr : parser_.opts.cpp_object_api_string_flexible_constructor; + return ret && NativeString(field) != + "std::string"; // Only for custom string types. + } + std::string GenTypeNativePtr(const std::string &type, const FieldDef *field, bool is_constructor) { auto &ptr_type = PtrType(field); if (ptr_type != "naked") { - return (ptr_type != "default_ptr_type" ? ptr_type : - parser_.opts.cpp_object_api_pointer_type) + "<" + type + ">"; + return (ptr_type != "default_ptr_type" + ? ptr_type + : parser_.opts.cpp_object_api_pointer_type) + + "<" + type + ">"; } else if (is_constructor) { return ""; } else { @@ -592,8 +608,7 @@ class CppGenerator : public BaseGenerator { std::string GenPtrGet(const FieldDef &field) { auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get"); - if (cpp_ptr_type_get) - return cpp_ptr_type_get->constant; + if (cpp_ptr_type_get) return cpp_ptr_type_get->constant; auto &ptr_type = PtrType(&field); return ptr_type == "naked" ? "" : ".get()"; } @@ -943,14 +958,15 @@ class CppGenerator : public BaseGenerator { code_ += "};"; if (parser_.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags")) { - code_ += "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})"; + code_ += + "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})"; } code_ += ""; // Generate an array of all enumeration values auto num_fields = NumToString(enum_def.vals.vec.size()); - code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" + num_fields + - "] {"; + code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" + + num_fields + "] {"; code_ += " static const {{ENUM_NAME}} values[] = {"; for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); ++it) { @@ -994,7 +1010,8 @@ 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()) + + code_ += " if (e < " + + GetEnumValUse(enum_def, *enum_def.vals.vec.front()) + " || e > " + GetEnumValUse(enum_def, *enum_def.vals.vec.back()) + ") return \"\";"; @@ -1123,22 +1140,28 @@ class CppGenerator : public BaseGenerator { if (parser_.opts.gen_compare) { code_ += ""; - code_ += "inline bool operator==(const {{NAME}}Union &lhs, const {{NAME}}Union &rhs) {"; + code_ += + "inline bool operator==(const {{NAME}}Union &lhs, const " + "{{NAME}}Union &rhs) {"; code_ += " if (lhs.type != rhs.type) return false;"; code_ += " switch (lhs.type) {"; for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); - ++it) { + ++it) { const auto &ev = **it; code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev)); if (ev.value) { const auto native_type = NativeName(GetUnionElement(ev, true, true, true), - ev.union_type.struct_def, parser_.opts); + ev.union_type.struct_def, parser_.opts); code_.SetValue("NATIVE_TYPE", native_type); code_ += " case {{NATIVE_ID}}: {"; - code_ += " return *(reinterpret_cast(lhs.value)) =="; - code_ += " *(reinterpret_cast(rhs.value));"; + code_ += + " return *(reinterpret_cast(lhs.value)) =="; + code_ += + " *(reinterpret_cast(rhs.value));"; code_ += " }"; } else { code_ += " case {{NATIVE_ID}}: {"; @@ -1319,7 +1342,8 @@ class CppGenerator : public BaseGenerator { " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>" "(u.value));"; } else { - code_ += " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable."; + code_ += + " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable."; } code_ += " break;"; code_ += " }"; @@ -1395,7 +1419,7 @@ class CppGenerator : public BaseGenerator { } std::string GenDefaultConstant(const FieldDef &field) { - if(IsFloat(field.value.type.base_type)) + if (IsFloat(field.value.type.base_type)) return float_const_gen_.GenFloatConstant(field); else return field.value.constant; @@ -1460,10 +1484,14 @@ class CppGenerator : public BaseGenerator { auto type = GenTypeNative(field.value.type, false, field); auto cpp_type = field.attributes.Lookup("cpp_type"); auto full_type = - (cpp_type ? (field.value.type.base_type == BASE_TYPE_VECTOR - ? "std::vector<" + GenTypeNativePtr(cpp_type->constant, &field, false) + "> " + (cpp_type + ? (field.value.type.base_type == BASE_TYPE_VECTOR + ? "std::vector<" + + GenTypeNativePtr(cpp_type->constant, &field, + false) + + "> " : GenTypeNativePtr(cpp_type->constant, &field, false)) - : type + " "); + : type + " "); code_.SetValue("FIELD_TYPE", full_type); code_.SetValue("FIELD_NAME", Name(field)); code_ += " {{FIELD_TYPE}}{{FIELD_NAME}};"; @@ -1485,7 +1513,11 @@ class CppGenerator : public BaseGenerator { if (IsScalar(field.value.type.base_type)) { if (!initializer_list.empty()) { initializer_list += ",\n "; } initializer_list += Name(field); - initializer_list += "(" + (native_default ? std::string(native_default->constant) : GetDefaultScalarValue(field, true)) + ")"; + initializer_list += + "(" + + (native_default ? std::string(native_default->constant) + : GetDefaultScalarValue(field, true)) + + ")"; } else if (field.value.type.base_type == BASE_TYPE_STRUCT) { if (IsStruct(field.value.type)) { if (native_default) { @@ -1514,18 +1546,17 @@ class CppGenerator : public BaseGenerator { code_ += " }"; } - void GenCompareOperator(const StructDef &struct_def, std::string accessSuffix = "") { + void GenCompareOperator(const StructDef &struct_def, + std::string accessSuffix = "") { std::string compare_op; for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { const auto &field = **it; if (!field.deprecated && // Deprecated fields won't be accessible. - field.value.type.base_type != BASE_TYPE_UTYPE && - (field.value.type.base_type != BASE_TYPE_VECTOR || - field.value.type.element != BASE_TYPE_UTYPE)) { - if (!compare_op.empty()) { - compare_op += " &&\n "; - } + field.value.type.base_type != BASE_TYPE_UTYPE && + (field.value.type.base_type != BASE_TYPE_VECTOR || + field.value.type.element != BASE_TYPE_UTYPE)) { + if (!compare_op.empty()) { compare_op += " &&\n "; } auto accessor = Name(field) + accessSuffix; compare_op += "(lhs." + accessor + " == rhs." + accessor + ")"; } @@ -1547,7 +1578,9 @@ class CppGenerator : public BaseGenerator { code_.SetValue("CMP_LHS", cmp_lhs); code_.SetValue("CMP_RHS", cmp_rhs); code_ += ""; - code_ += "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const {{NATIVE_NAME}} &{{CMP_RHS}}) {"; + code_ += + "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const " + "{{NATIVE_NAME}} &{{CMP_RHS}}) {"; code_ += "{{CMP_OP}}"; code_ += "}"; } @@ -1701,12 +1734,12 @@ class CppGenerator : public BaseGenerator { code_ += " typedef {{NATIVE_NAME}} NativeTableType;"; } if (parser_.opts.mini_reflect != IDLOptions::kNone) { - code_ += " static const flatbuffers::TypeTable *MiniReflectTypeTable() {"; + code_ += + " static const flatbuffers::TypeTable *MiniReflectTypeTable() {"; code_ += " return {{STRUCT_NAME}}TypeTable();"; code_ += " }"; } - GenFullyQualifiedNameGetter(struct_def, Name(struct_def)); // Generate field id constants. @@ -1714,7 +1747,8 @@ class CppGenerator : public BaseGenerator { // We need to add a trailing comma to all elements except the last one as // older versions of gcc complain about this. code_.SetValue("SEP", ""); - code_ += " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {"; + code_ += + " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {"; for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { const auto &field = **it; @@ -1789,9 +1823,8 @@ class CppGenerator : public BaseGenerator { auto full_struct_name = GetUnionElement(ev, true, true); // @TODO: Mby make this decisions more universal? How? - code_.SetValue( - "U_GET_TYPE", - EscapeKeyword(field.name + UnionTypeFieldSuffix())); + code_.SetValue("U_GET_TYPE", + EscapeKeyword(field.name + UnionTypeFieldSuffix())); code_.SetValue( "U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev))); @@ -1855,7 +1888,9 @@ class CppGenerator : public BaseGenerator { code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name)); code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {"; - code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());"; + code_ += + " return " + "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());"; code_ += " }"; } @@ -1863,7 +1898,8 @@ class CppGenerator : public BaseGenerator { code_ += " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()" " const {"; - // Both Data() and size() are const-methods, therefore call order doesn't matter. + // Both Data() and size() are const-methods, therefore call order + // doesn't matter. code_ += " return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), " "{{FIELD_NAME}}()->size());"; @@ -1871,9 +1907,7 @@ class CppGenerator : public BaseGenerator { } // Generate a comparison function for this field if it is a key. - if (field.key) { - GenKeyFieldMethods(field); - } + if (field.key) { GenKeyFieldMethods(field); } } // Generate a verifier function that can check a buffer from an untrusted @@ -2064,8 +2098,9 @@ class CppGenerator : public BaseGenerator { // Generate a CreateXDirect function with vector types as parameters if (has_string_or_vector_fields) { - code_ += "inline flatbuffers::Offset<{{STRUCT_NAME}}> " - "Create{{STRUCT_NAME}}Direct("; + code_ += + "inline flatbuffers::Offset<{{STRUCT_NAME}}> " + "Create{{STRUCT_NAME}}Direct("; code_ += " flatbuffers::FlatBufferBuilder &_fbb\\"; for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { @@ -2128,17 +2163,22 @@ 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 + ", " + - EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + - "()" + vec_type_access + ", _resolver)"; + return afield.value.type.enum_def->name + "Union::UnPack(" + "_e" + + vec_elem_access + ", " + + EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" + + vec_type_access + ", _resolver)"; } std::string GenUnpackVal(const Type &type, const std::string &val, bool invector, const FieldDef &afield) { switch (type.base_type) { case BASE_TYPE_STRING: { - return val + "->str()"; + if (FlexibleStringConstructor(&afield)) { + return NativeString(&afield) + "(" + val + "->c_str(), " + val + + "->size())"; + } else { + return val + "->str()"; + } } case BASE_TYPE_STRUCT: { const auto name = WrapInNameSpace(*type.struct_def); @@ -2210,26 +2250,29 @@ class CppGenerator : public BaseGenerator { code += "//vector resolver, " + PtrType(&field) + "\n"; code += "if (_resolver) "; code += "(*_resolver)"; - code += "(reinterpret_cast(&_o->" + name + "[_i]" + access + "), "; + code += "(reinterpret_cast(&_o->" + name + "[_i]" + access + + "), "; code += "static_cast(" + indexing + "));"; if (PtrType(&field) == "naked") { code += " else "; code += "_o->" + name + "[_i]" + access + " = nullptr"; } else { - //code += " else "; - //code += "_o->" + name + "[_i]" + access + " = " + GenTypeNativePtr(cpp_type->constant, &field, true) + "();"; + // code += " else "; + // code += "_o->" + name + "[_i]" + access + " = " + + // GenTypeNativePtr(cpp_type->constant, &field, true) + "();"; code += "/* else do nothing */"; } } else { code += "_o->" + name + "[_i]" + access + " = "; - code += - GenUnpackVal(field.value.type.VectorType(), indexing, true, field); + code += GenUnpackVal(field.value.type.VectorType(), indexing, true, + field); } code += "; } }"; break; } case BASE_TYPE_UTYPE: { - FLATBUFFERS_ASSERT(union_field->value.type.base_type == BASE_TYPE_UNION); + FLATBUFFERS_ASSERT(union_field->value.type.base_type == + BASE_TYPE_UNION); // Generate code that sets the union type, of the form: // _o->field.type = _e; code += "_o->" + union_field->name + ".type = _e;"; @@ -2260,8 +2303,9 @@ class CppGenerator : public BaseGenerator { code += " else "; code += "_o->" + Name(field) + " = nullptr;"; } else { - //code += " else "; - //code += "_o->" + Name(field) + " = " + GenTypeNativePtr(cpp_type->constant, &field, true) + "();"; + // code += " else "; + // code += "_o->" + Name(field) + " = " + + // GenTypeNativePtr(cpp_type->constant, &field, true) + "();"; code += "/* else do nothing */;"; } } else { @@ -2286,7 +2330,8 @@ class CppGenerator : public BaseGenerator { } else { value += Name(field); } - if (field.value.type.base_type != BASE_TYPE_VECTOR && field.attributes.Lookup("cpp_type")) { + if (field.value.type.base_type != BASE_TYPE_VECTOR && + field.attributes.Lookup("cpp_type")) { auto type = GenTypeBasic(field.value.type, false); value = "_rehasher ? " @@ -2294,7 +2339,6 @@ class CppGenerator : public BaseGenerator { type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0"; } - std::string code; switch (field.value.type.base_type) { // String fields are of the form: @@ -2332,7 +2376,20 @@ class CppGenerator : public BaseGenerator { auto vector_type = field.value.type.VectorType(); switch (vector_type.base_type) { case BASE_TYPE_STRING: { - code += "_fbb.CreateVectorOfStrings(" + value + ")"; + if (NativeString(&field) == "std::string") { + code += "_fbb.CreateVectorOfStrings(" + value + ")"; + } else { + // Use by-function serialization to emulate + // CreateVectorOfStrings(); this works also with non-std strings. + code += + "_fbb.CreateVector>" + " "; + code += "(" + value + ".size(), "; + code += "[](size_t i, _VectorArgs *__va) { "; + code += + "return __va->__fbb->CreateString(__va->_" + value + "[i]);"; + code += " }, &_va )"; + } break; } case BASE_TYPE_STRUCT: { @@ -2710,9 +2767,7 @@ class CppGenerator : public BaseGenerator { } // Generate a comparison function for this field if it is a key. - if (field.key) { - GenKeyFieldMethods(field); - } + if (field.key) { GenKeyFieldMethods(field); } } code_.SetValue("NATIVE_NAME", Name(struct_def)); GenOperatorNewDelete(struct_def);