Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merging https://github.com/google/flatbuffers/pull/5988 #1

Merged
merged 1 commit into from
Jan 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 177 additions & 7 deletions src/idl_gen_cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@ class CppGenerator : public BaseGenerator {
}

std::string GenTypeNative(const Type &type, bool invector,
const FieldDef &field) {
const FieldDef &field, bool forcopy = false) {
switch (type.base_type) {
case BASE_TYPE_STRING: {
return NativeString(&field);
Expand All @@ -780,14 +780,14 @@ class CppGenerator : public BaseGenerator {
if (IsStruct(type)) {
auto native_type = type.struct_def->attributes.Lookup("native_type");
if (native_type) { type_name = native_type->constant; }
if (invector || field.native_inline) {
if (invector || field.native_inline || forcopy) {
return type_name;
} else {
return GenTypeNativePtr(type_name, &field, false);
}
} else {
return GenTypeNativePtr(NativeName(type_name, type.struct_def, opts_),
&field, false);
const auto nn = NativeName(type_name, type.struct_def, opts_);
return forcopy ? nn : GenTypeNativePtr(nn, &field, false);
}
}
case BASE_TYPE_UNION: {
Expand Down Expand Up @@ -1534,7 +1534,8 @@ class CppGenerator : public BaseGenerator {
ev.union_type.struct_def, opts_));
code_ += " case {{LABEL}}: {";
bool copyable = true;
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
if (opts_.g_cpp_std < cpp::CPP_STD_11 &&
ev.union_type.base_type == BASE_TYPE_STRUCT) {
// Don't generate code to copy if table is not copyable.
// TODO(wvo): make tables copyable instead.
for (auto fit = ev.union_type.struct_def->fields.vec.begin();
Expand Down Expand Up @@ -1735,13 +1736,54 @@ class CppGenerator : public BaseGenerator {
}
}

// Returns true if `struct_def` needs a copy constructor and assignment
// operator because it has one or more table members, struct members with a
// custom cpp_type and non-naked pointer type, or vector members of those.
bool NeedsCopyCtorAssignOp(const StructDef &struct_def) {
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
const auto &type = field.value.type;
if (field.deprecated) continue;
if (type.base_type == BASE_TYPE_STRUCT) {
const auto cpp_type = field.attributes.Lookup("cpp_type");
const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
const bool is_ptr = !(IsStruct(type) && field.native_inline) ||
(cpp_type && cpp_ptr_type->constant != "naked");
if (is_ptr) {
return true;
}
} else if (IsVector(type)) {
const auto vec_type = type.VectorType();
if (vec_type.base_type == BASE_TYPE_UTYPE) continue;
const auto cpp_type = field.attributes.Lookup("cpp_type");
const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
const bool is_ptr =
(vec_type.base_type == BASE_TYPE_STRUCT && !IsStruct(vec_type)) ||
(cpp_type && cpp_ptr_type->constant != "naked");
if (is_ptr) {
return true;
}
}
}
return false;
}

// Generate the default constructor for this struct. Properly initialize all
// scalar members with default values.
void GenDefaultConstructor(const StructDef &struct_def) {
code_.SetValue("NATIVE_NAME",
NativeName(Name(struct_def), &struct_def, opts_));
// In >= C++11, default member initializers are generated.
if (opts_.g_cpp_std >= cpp::CPP_STD_11) { return; }
// In >= C++11, default member initializers are generated. To allow for
// aggregate initialization, do not emit a default constructor at all, with
// the exception of types that need a copy/move ctors and assignment
// operators.
if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
if (NeedsCopyCtorAssignOp(struct_def)) {
code_ += " {{NATIVE_NAME}}() = default;";
}
return;
}
std::string initializer_list;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
Expand Down Expand Up @@ -1785,6 +1827,130 @@ class CppGenerator : public BaseGenerator {
code_ += " }";
}

// Generate the >= C++11 copy/move constructor and assignment operator
// declarations if required. Tables that are default-copyable do not get
// user-provided copy/move constructors and assignment operators so they
// remain aggregates.
void GenCopyMoveCtorAndAssigOpDecls(const StructDef &struct_def) {
if (opts_.g_cpp_std < cpp::CPP_STD_11) return;
if (!NeedsCopyCtorAssignOp(struct_def)) return;
code_.SetValue("NATIVE_NAME",
NativeName(Name(struct_def), &struct_def, opts_));
code_ += " {{NATIVE_NAME}}(const {{NATIVE_NAME}} &o);";
code_ +=
" {{NATIVE_NAME}}({{NATIVE_NAME}}&&) FLATBUFFERS_NOEXCEPT = "
"default;";
code_ += " {{NATIVE_NAME}} &operator=(const {{NATIVE_NAME}} &o);";
code_ +=
" {{NATIVE_NAME}} &operator=({{NATIVE_NAME}}&&) FLATBUFFERS_NOEXCEPT "
"= default;";
}

// Generate the >= C++11 copy constructor and assignment operator definitions.
void GenCopyCtorAssignOpDefs(const StructDef &struct_def) {
if (opts_.g_cpp_std < cpp::CPP_STD_11) return;
if (!NeedsCopyCtorAssignOp(struct_def)) return;
std::string initializer_list;
std::string vector_copies;
std::string assignments;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
const auto &type = field.value.type;
if (field.deprecated || type.base_type == BASE_TYPE_UTYPE) continue;
if (type.base_type == BASE_TYPE_STRUCT) {
if (!initializer_list.empty()) { initializer_list += ",\n "; }
if (!assignments.empty()) { assignments += "\n "; }
const auto cpp_type = field.attributes.Lookup("cpp_type");
const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
auto type_name = (cpp_type) ? cpp_type->constant
: GenTypeNative(type, /*invector*/ false,
field, /*forcopy*/ true);
const bool is_ptr = !(IsStruct(type) && field.native_inline) ||
(cpp_type && cpp_ptr_type->constant != "naked");
const std::string o_dot_field = "o." + Name(field);
CodeWriter cw;
cw.SetValue("FIELD", Name(field));
cw.SetValue("TYPE", type_name);
if (is_ptr) {
cw +=
"{{FIELD}}((o.{{FIELD}}) ? new {{TYPE}}(*o.{{FIELD}}) : "
"nullptr)\\";
initializer_list += cw.ToString();
cw.Clear();
cw +=
"{{FIELD}}.reset((o.{{FIELD}}) ? new {{TYPE}}(*o.{{FIELD}}) : "
"nullptr);\\";
assignments += cw.ToString();
} else {
cw += "{{FIELD}}(o.{{FIELD}})\\";
initializer_list += cw.ToString();
cw.Clear();
cw += "{{FIELD}} = o.{{FIELD}};\\";
assignments += cw.ToString();
}
} else if (IsVector(type)) {
const auto vec_type = type.VectorType();
if (vec_type.base_type == BASE_TYPE_UTYPE) continue;
const auto cpp_type = field.attributes.Lookup("cpp_type");
const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
const auto type_name = (cpp_type)
? cpp_type->constant
: GenTypeNative(vec_type, /*invector*/ true,
field, /*forcopy*/ true);
const bool is_ptr =
(vec_type.base_type == BASE_TYPE_STRUCT && !IsStruct(vec_type)) ||
(cpp_type && cpp_ptr_type->constant != "naked");
CodeWriter cw(" ");
cw.SetValue("FIELD", Name(field));
cw.SetValue("TYPE", type_name);
cw.IncrementIdentLevel();
cw += "{{FIELD}}.clear();";
cw += "{{FIELD}}.reserve(o.{{FIELD}}.size());";
if (is_ptr) {
cw +=
"for (const auto &v : o.{{FIELD}}) { "
"{{FIELD}}.emplace_back((v) ? new {{TYPE}}(*v) : nullptr); }";
} else {
cw +=
"for (const auto &v : o.{{FIELD}}) { {{FIELD}}.emplace_back(v); "
"}";
}
vector_copies += cw.ToString();
} else {
if (!initializer_list.empty()) { initializer_list += ",\n "; }
if (!assignments.empty()) { assignments += "\n "; }
CodeWriter cw;
cw.SetValue("FIELD", Name(field));
cw += "{{FIELD}}(o.{{FIELD}})\\";
initializer_list += cw.ToString();
cw.Clear();
cw += "{{FIELD}} = o.{{FIELD}};\\";
assignments += cw.ToString();
}
}
if (!initializer_list.empty()) {
initializer_list = "\n : " + initializer_list;
}
if (!assignments.empty()) { assignments = " " + assignments; }

code_.SetValue("NATIVE_NAME",
NativeName(Name(struct_def), &struct_def, opts_));
code_.SetValue("INIT_LIST", initializer_list);
code_.SetValue("ASSIGN", assignments);
code_.SetValue("VEC_COPY", vector_copies);

code_ +=
"inline {{NATIVE_NAME}}::{{NATIVE_NAME}}(const {{NATIVE_NAME}} &o)"
"{{INIT_LIST}} {";
code_ += "{{VEC_COPY}}}\n";
code_ +=
"inline {{NATIVE_NAME}} &{{NATIVE_NAME}}::operator="
"(const {{NATIVE_NAME}} &o) {";
code_ += "{{ASSIGN}}\n{{VEC_COPY}}";
code_ += " return *this;\n}\n";
}

void GenCompareOperator(const StructDef &struct_def,
std::string accessSuffix = "") {
std::string compare_op;
Expand Down Expand Up @@ -1862,6 +2028,7 @@ class CppGenerator : public BaseGenerator {
}
GenOperatorNewDelete(struct_def);
GenDefaultConstructor(struct_def);
GenCopyMoveCtorAndAssigOpDecls(struct_def);
code_ += "};";
if (opts_.gen_compare) GenCompareOperator(struct_def);
code_ += "";
Expand Down Expand Up @@ -2841,6 +3008,9 @@ class CppGenerator : public BaseGenerator {
NativeName(Name(struct_def), &struct_def, opts_));

if (opts_.generate_object_based_api) {
// Generate the >= C++11 copy ctor and assignment operator definitions.
GenCopyCtorAssignOpDefs(struct_def);

// Generate the X::UnPack() method.
code_ +=
"inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
Expand Down
Loading