[C++] Object API: document custom string type requirements,

implement better custom string type constructor alternative
for Unpack() and fix bug with vector of custom string types
in Pack().

Squashed commit of the following:

commit e9519c647ef949b22756ed660839dd3af854881c
Author: Luca Longinotti <luca.longinotti@inivation.com>
Date:   Tue Mar 5 18:24:49 2019 +0100

    tests: regenerate code, reverts change to CreateVectorOfStrings().

commit 117e3b0679209f2aa55cbee18c4036e7da4bd4b3
Author: Luca Longinotti <luca.longinotti@inivation.com>
Date:   Tue Mar 5 18:15:05 2019 +0100

    idl_gen_cpp.cpp: move clang-format on/off outside of declaration, so they are kept properly aligned automatically.

commit 4791923806965637d5b13f7003329bfbb2fdf18b
Author: Luca Longinotti <luca.longinotti@inivation.com>
Date:   Tue Mar 5 18:11:40 2019 +0100

    idl_gen_cpp.cpp: full clang-format run with provided Google format file, enforce 80 lines width.

commit 2f0402f9ff43b1af0a29806932e08e6d64373345
Author: Luca Longinotti <luca.longinotti@inivation.com>
Date:   Tue Mar 5 18:09:32 2019 +0100

    CppUsage: address requested changes.
    idl_gen_cpp.cpp: fix formatting, keep CreateVectorOfStrings for normal string cases.

commit 371d4e0b7972a59e5cff418c44e4043c016ce56a
Author: Luca Longinotti <luca.longinotti@inivation.com>
Date:   Fri Mar 1 16:35:29 2019 +0100

    Fix compile error with a vector of non-std::strings. CreateVectorOfStrings() expects a vector of std::string types, but that's not always the case.

commit 92b90d7f0fbcfc837a94aa06bedccec0f7b4bb62
Author: Luca Longinotti <luca.longinotti@inivation.com>
Date:   Fri Mar 1 16:15:36 2019 +0100

    Document requirement for custom string types to implement empty() and be constructible from std::string.
    Add new option --cpp-str-flex-ctor to construct custom string types not via std::string, but (char * + length).

commit 28cb2e92d5b7684b5df5184da3a3fad2d0cda733
Author: Luca Longinotti <luca.longinotti@inivation.com>
Date:   Fri Mar 1 14:31:17 2019 +0100

    idl_gen_cpp.cpp: clang-format run, to better separate changes in content from formatting.

Change-Id: I4887ba2f2c632b9e7a8c938659b088cd95690870
parent 3968d005
......@@ -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.
......
......@@ -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)
......
......@@ -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;
......
......@@ -107,7 +107,11 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const {
" 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") {
......
......@@ -43,7 +43,7 @@ class CppGenerator : public BaseGenerator {
float_const_gen_("std::numeric_limits<double>::",
"std::numeric_limits<float>::", "quiet_NaN()",
"infinity()") {
static const char * const keywords[] = {
static const char *const keywords[] = {
"alignas",
"alignof",
"and",
......@@ -139,7 +139,8 @@ class CppGenerator : public BaseGenerator {
"while",
"xor",
"xor_eq",
nullptr };
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_ += "";
}
......@@ -246,8 +246,10 @@ class CppGenerator : public BaseGenerator {
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,7 +1140,9 @@ 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) {";
......@@ -1137,8 +1156,12 @@ class CppGenerator : public BaseGenerator {
ev.union_type.struct_def, parser_.opts);
code_.SetValue("NATIVE_TYPE", native_type);
code_ += " case {{NATIVE_ID}}: {";
code_ += " return *(reinterpret_cast<const {{NATIVE_TYPE}} *>(lhs.value)) ==";
code_ += " *(reinterpret_cast<const {{NATIVE_TYPE}} *>(rhs.value));";
code_ +=
" return *(reinterpret_cast<const {{NATIVE_TYPE}} "
"*>(lhs.value)) ==";
code_ +=
" *(reinterpret_cast<const {{NATIVE_TYPE}} "
"*>(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,8 +1484,12 @@ 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 + " ");
code_.SetValue("FIELD_TYPE", full_type);
......@@ -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,7 +1546,8 @@ 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) {
......@@ -1523,9 +1556,7 @@ class CppGenerator : public BaseGenerator {
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 ";
}
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,8 +1823,7 @@ 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",
code_.SetValue("U_GET_TYPE",
EscapeKeyword(field.name + UnionTypeFieldSuffix()));
code_.SetValue(
"U_ELEMENT_TYPE",
......@@ -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,7 +2098,8 @@ 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}}> "
code_ +=
"inline flatbuffers::Offset<{{STRUCT_NAME}}> "
"Create{{STRUCT_NAME}}Direct(";
code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
for (auto it = struct_def.fields.vec.begin();
......@@ -2128,18 +2163,23 @@ 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: {
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);
if (IsStruct(type)) {
......@@ -2210,26 +2250,29 @@ class CppGenerator : public BaseGenerator {
code += "//vector resolver, " + PtrType(&field) + "\n";
code += "if (_resolver) ";
code += "(*_resolver)";
code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" + access + "), ";
code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" + access +
"), ";
code += "static_cast<flatbuffers::hash_value_t>(" + 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: {
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<flatbuffers::Offset<flatbuffers::String>>"
" ";
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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment