Added support for structs and strings in unions.

(C++ only for now).
Also fixed vector of union support in the object API.

Bug: 36902939
Change-Id: I935f4cc2c303a4728e26c7916a8ec0adcd6f84cb
Tested: on Linux.
This commit is contained in:
Wouter van Oortmerssen
2017-04-10 15:56:51 -07:00
parent 1fc12e0e5b
commit b0752e179b
16 changed files with 856 additions and 322 deletions

View File

@@ -109,7 +109,7 @@ class CppGenerator : public BaseGenerator {
SetNameSpace(struct_def.defined_namespace);
code_ += "struct " + struct_def.name + ";";
if (parser_.opts.generate_object_based_api && !struct_def.fixed) {
code_ += "struct " + NativeName(struct_def.name) + ";";
code_ += "struct " + NativeName(struct_def.name, &struct_def) + ";";
}
code_ += "";
}
@@ -239,7 +239,7 @@ class CppGenerator : public BaseGenerator {
if (parser_.opts.generate_object_based_api) {
// A convenient root unpack function.
auto native_name =
NativeName(WrapInNameSpace(struct_def));
NativeName(WrapInNameSpace(struct_def), &struct_def);
code_.SetValue("UNPACK_RETURN",
GenTypeNativePtr(native_name, nullptr, false));
code_.SetValue("UNPACK_TYPE",
@@ -355,7 +355,9 @@ class CppGenerator : public BaseGenerator {
}
// TODO(wvo): make this configurable.
static std::string NativeName(const std::string &name) { return name + "T"; }
static std::string NativeName(const std::string &name, const StructDef *sd) {
return sd && !sd->fixed ? name + "T" : name;
}
const std::string &PtrType(const FieldDef *field) {
auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
@@ -411,7 +413,8 @@ class CppGenerator : public BaseGenerator {
return GenTypeNativePtr(type_name, &field, false);
}
} else {
return GenTypeNativePtr(NativeName(type_name), &field, false);
return GenTypeNativePtr(NativeName(type_name, type.struct_def),
&field, false);
}
}
case BASE_TYPE_UNION: {
@@ -458,6 +461,26 @@ class CppGenerator : public BaseGenerator {
}
}
std::string StripUnionType(const std::string &name) {
return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
}
std::string GetUnionElement(const EnumVal &ev, bool wrap, bool actual_type,
bool native_type = false) {
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
auto name = actual_type ? ev.union_type.struct_def->name : ev.name;
return wrap
? WrapInNameSpace(ev.union_type.struct_def->defined_namespace, name)
: name;
} else if (ev.union_type.base_type == BASE_TYPE_STRING) {
return actual_type
? (native_type ? "std::string" : "flatbuffers::String")
: ev.name;
} else {
assert(false);
}
}
static std::string UnionVerifySignature(const EnumDef &enum_def) {
return "bool Verify" + enum_def.name +
"(flatbuffers::Verifier &verifier, const void *obj, " +
@@ -474,7 +497,7 @@ class CppGenerator : public BaseGenerator {
static std::string UnionUnPackSignature(const EnumDef &enum_def,
bool inclass) {
return (inclass ? "static " : "") +
std::string("flatbuffers::NativeTable *") +
std::string("void *") +
(inclass ? "" : enum_def.name + "Union::") +
"UnPack(const void *obj, " + enum_def.name +
" type, const flatbuffers::resolver_function_t *resolver)";
@@ -493,7 +516,7 @@ class CppGenerator : public BaseGenerator {
return "flatbuffers::Offset<" + struct_def.name + "> Create" +
struct_def.name +
"(flatbuffers::FlatBufferBuilder &_fbb, const " +
NativeName(struct_def.name) +
NativeName(struct_def.name, &struct_def) +
" *_o, const flatbuffers::rehasher_function_t *_rehasher" +
(predecl ? " = nullptr" : "") + ")";
}
@@ -504,14 +527,14 @@ class CppGenerator : public BaseGenerator {
"flatbuffers::Offset<" + struct_def.name + "> " +
(inclass ? "" : struct_def.name + "::") +
"Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
"const " + NativeName(struct_def.name) + "* _o, " +
"const " + NativeName(struct_def.name, &struct_def) + "* _o, " +
"const flatbuffers::rehasher_function_t *_rehasher" +
(inclass ? " = nullptr" : "") + ")";
}
static std::string TableUnPackSignature(const StructDef &struct_def,
bool inclass) {
return NativeName(struct_def.name) + " *" +
return NativeName(struct_def.name, &struct_def) + " *" +
(inclass ? "" : struct_def.name + "::") +
"UnPack(const flatbuffers::resolver_function_t *_resolver" +
(inclass ? " = nullptr" : "") + ") const";
@@ -520,8 +543,8 @@ class CppGenerator : public BaseGenerator {
static std::string TableUnPackToSignature(const StructDef &struct_def,
bool inclass) {
return "void " + (inclass ? "" : struct_def.name + "::") +
"UnPackTo(" + NativeName(struct_def.name) + " *" + "_o, " +
"const flatbuffers::resolver_function_t *_resolver" +
"UnPackTo(" + NativeName(struct_def.name, &struct_def) + " *" +
"_o, const flatbuffers::resolver_function_t *_resolver" +
(inclass ? " = nullptr" : "") + ") const";
}
@@ -629,7 +652,7 @@ class CppGenerator : public BaseGenerator {
}
// Generate type traits for unions to map from a type to union enum value.
if (enum_def.is_union) {
if (enum_def.is_union && !enum_def.uses_type_aliases) {
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
const auto &ev = **it;
@@ -638,7 +661,7 @@ class CppGenerator : public BaseGenerator {
code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
}
else {
auto name = WrapInNameSpace(*ev.struct_def);
auto name = GetUnionElement(ev, true, true);
code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
}
@@ -657,29 +680,31 @@ class CppGenerator : public BaseGenerator {
code_ += "struct {{NAME}}Union {";
code_ += " {{NAME}} type;";
code_ += " flatbuffers::NativeTable *table;";
code_ += " void *value;";
code_ += "";
code_ += " {{NAME}}Union() : type({{NONE}}), table(nullptr) {}";
code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
code_ += " type({{NONE}}), table(nullptr)";
code_ += " { std::swap(type, u.type); std::swap(table, u.table); }";
code_ += " type({{NONE}}), value(nullptr)";
code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
code_ += " {{NAME}}Union(const {{NAME}}Union &);";
code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &);";
code_ += " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
code_ += " { std::swap(type, u.type); std::swap(table, u.table); return *this; }";
code_ += " { std::swap(type, u.type); std::swap(value, u.value); return *this; }";
code_ += " ~{{NAME}}Union() { Reset(); }";
code_ += "";
code_ += " void Reset();";
code_ += "";
code_ += " template <typename T>";
code_ += " void Set(T&& value) {";
code_ += " Reset();";
code_ += " type = {{NAME}}Traits<typename T::TableType>::enum_value;";
code_ += " if (type != {{NONE}}) {";
code_ += " table = new T(std::forward<T>(value));";
code_ += " }";
code_ += " }";
code_ += "";
if (!enum_def.uses_type_aliases) {
code_ += " template <typename T>";
code_ += " void Set(T&& val) {";
code_ += " Reset();";
code_ += " type = {{NAME}}Traits<typename T::TableType>::enum_value;";
code_ += " if (type != {{NONE}}) {";
code_ += " value = new T(std::forward<T>(val));";
code_ += " }";
code_ += " }";
code_ += "";
}
code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
code_ += " " + UnionPackSignature(enum_def, true) + ";";
code_ += "";
@@ -691,14 +716,16 @@ class CppGenerator : public BaseGenerator {
continue;
}
const auto native_type = NativeName(WrapInNameSpace(*ev.struct_def));
const auto native_type =
NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def);
code_.SetValue("NATIVE_TYPE", native_type);
code_.SetValue("NATIVE_NAME", ev.name);
code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
code_ += " return type == {{NATIVE_ID}} ?";
code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(table) : nullptr;";
code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
code_ += " }";
}
code_ += "};";
@@ -728,10 +755,23 @@ class CppGenerator : public BaseGenerator {
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
if (ev.value) {
code_.SetValue("TYPE", WrapInNameSpace(*ev.struct_def));
code_.SetValue("TYPE", GetUnionElement(ev, true, true));
code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
code_ += " return verifier.VerifyTable(ptr);";
auto getptr =
" 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 true;";
} else {
code_ += getptr;
code_ += " return verifier.VerifyTable(ptr);";
}
} else if (ev.union_type.base_type == BASE_TYPE_STRING) {
code_ += getptr;
code_ += " return verifier.Verify(ptr);";
} else {
assert(false);
}
code_ += " }";
} else {
code_ += " case {{LABEL}}: {";
@@ -768,10 +808,21 @@ class CppGenerator : public BaseGenerator {
}
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
code_.SetValue("TYPE", WrapInNameSpace(*ev.struct_def));
code_.SetValue("TYPE", GetUnionElement(ev, true, true));
code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
code_ += " return ptr->UnPack(resolver);";
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
if (ev.union_type.struct_def->fixed) {
code_ += " return new " +
WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
} else {
code_ += " return ptr->UnPack(resolver);";
}
} else if (ev.union_type.base_type == BASE_TYPE_STRING) {
code_ += " return new std::string(ptr->c_str(), ptr->size());";
} else {
assert(false);
}
code_ += " }";
}
code_ += " default: return nullptr;";
@@ -789,11 +840,23 @@ class CppGenerator : public BaseGenerator {
}
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
code_.SetValue("TYPE", NativeName(WrapInNameSpace(*ev.struct_def)));
code_.SetValue("NAME", ev.struct_def->name);
code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def));
code_.SetValue("NAME", GetUnionElement(ev, false, true));
code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(table);";
code_ += " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
if (ev.union_type.struct_def->fixed) {
code_ += " return _fbb.CreateStruct(*ptr).Union();";
} else {
code_ +=
" return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
}
} else if (ev.union_type.base_type == BASE_TYPE_STRING) {
code_ += " return _fbb.CreateString(*ptr).Union();";
} else {
assert(false);
}
code_ += " }";
}
code_ += " default: return 0;";
@@ -815,17 +878,18 @@ class CppGenerator : public BaseGenerator {
}
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
code_.SetValue("TYPE", NativeName(WrapInNameSpace(*ev.struct_def)));
code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def));
code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(table);";
code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
code_ += " delete ptr;";
code_ += " break;";
code_ += " }";
}
code_ += " default: break;";
code_ += " }";
code_ += " table = nullptr;";
code_ += " value = nullptr;";
code_ += " type = {{NONE}};";
code_ += "}";
code_ += "";
@@ -914,7 +978,9 @@ class CppGenerator : public BaseGenerator {
// Generate a member, including a default value for scalars and raw pointers.
void GenMember(const FieldDef &field) {
if (!field.deprecated && // Deprecated fields won't be accessible.
field.value.type.base_type != BASE_TYPE_UTYPE) {
field.value.type.base_type != BASE_TYPE_UTYPE &&
(field.value.type.base_type != BASE_TYPE_VECTOR ||
field.value.type.element != BASE_TYPE_UTYPE)) {
auto type = GenTypeNative(field.value.type, false, field);
auto cpp_type = field.attributes.Lookup("cpp_type");
auto full_type = (cpp_type ? cpp_type->constant + " *" : type + " ");
@@ -964,7 +1030,7 @@ class CppGenerator : public BaseGenerator {
initializer_list = "\n : " + initializer_list;
}
code_.SetValue("NATIVE_NAME", NativeName(struct_def.name));
code_.SetValue("NATIVE_NAME", NativeName(struct_def.name, &struct_def));
code_.SetValue("INIT_LIST", initializer_list);
code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
@@ -972,7 +1038,7 @@ class CppGenerator : public BaseGenerator {
}
void GenNativeTable(const StructDef &struct_def) {
const auto native_name = NativeName(struct_def.name);
const auto native_name = NativeName(struct_def.name, &struct_def);
code_.SetValue("STRUCT_NAME", struct_def.name);
code_.SetValue("NATIVE_NAME", native_name);
@@ -1138,24 +1204,23 @@ class CppGenerator : public BaseGenerator {
for (auto u_it = u->vals.vec.begin();
u_it != u->vals.vec.end(); ++u_it) {
if (!(*u_it)->struct_def) {
auto &ev = **u_it;
if (ev.union_type.base_type == BASE_TYPE_NONE) {
continue;
}
auto arg_struct_def = (*u_it)->struct_def;
auto full_struct_name = WrapInNameSpace(*arg_struct_def);
auto full_struct_name = GetUnionElement(ev, true, true);
// @TODO: Mby make this decisions more universal? How?
code_.SetValue("U_GET_TYPE", field.name + UnionTypeFieldSuffix());
code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(
u->defined_namespace, GetEnumValUse(*u, **u_it)));
u->defined_namespace, GetEnumValUse(*u, ev)));
code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
code_.SetValue("U_ELEMENT_NAME", full_struct_name);
code_.SetValue("U_FIELD_NAME",
field.name + "_as_" + (*u_it)->name);
field.name + "_as_" + ev.name);
// `const Type *union_name_asType() const` accessor.
code_ += " {{U_FIELD_TYPE}}{{U_FIELD_NAME}}() const {";
code_ += " return ({{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}})? "
code_ += " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
"static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
": nullptr;";
code_ += " }";
@@ -1279,23 +1344,25 @@ class CppGenerator : public BaseGenerator {
}
auto u = field.value.type.enum_def;
if (u->uses_type_aliases) continue;
code_.SetValue("FIELD_NAME", field.name);
for (auto u_it = u->vals.vec.begin();
u_it != u->vals.vec.end(); ++u_it) {
if (!(*u_it)->struct_def) {
auto &ev = **u_it;
if (ev.union_type.base_type == BASE_TYPE_NONE) {
continue;
}
auto arg_struct_def = (*u_it)->struct_def;
auto full_struct_name = WrapInNameSpace(*arg_struct_def);
auto full_struct_name = GetUnionElement(ev, true, true);
code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(
u->defined_namespace, GetEnumValUse(*u, **u_it)));
u->defined_namespace, GetEnumValUse(*u, ev)));
code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
code_.SetValue("U_ELEMENT_NAME", full_struct_name);
code_.SetValue("U_FIELD_NAME",
field.name + "_as_" + (*u_it)->name);
field.name + "_as_" + ev.name);
// `template<> const T *union_name_as<T>() const` accessor.
code_ += "template<> "
@@ -1475,6 +1542,14 @@ 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 + ", " + 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) {
@@ -1494,10 +1569,18 @@ class CppGenerator : public BaseGenerator {
return ptype + "(new " + name + "(*" + val + "))";
}
} else {
const auto ptype = GenTypeNativePtr(NativeName(name), &afield, true);
const auto ptype = GenTypeNativePtr(NativeName(name, type.struct_def),
&afield, true);
return ptype + "(" + val + "->UnPack(_resolver))";
}
}
case BASE_TYPE_UNION: {
return GenUnionUnpackVal(afield,
invector ? "->Get(_i)" : "",
invector ? ("->GetEnum<" +
type.enum_def->name +
">(_i)").c_str() : "");
}
default: {
return val;
break;
@@ -1523,10 +1606,19 @@ class CppGenerator : public BaseGenerator {
// for (uoffset_t i = 0; i < _e->size(); ++i) {
// _o->field.push_back(_e->Get(_i));
// }
code += "{ _o->" + field.name + ".resize(_e->size()); ";
auto name = field.name;
if (field.value.type.element == BASE_TYPE_UTYPE) {
name = StripUnionType(field.name);
}
auto access = field.value.type.element == BASE_TYPE_UTYPE
? ".type"
: (field.value.type.element == BASE_TYPE_UNION
? ".value"
: "");
code += "{ _o->" + name + ".resize(_e->size()); ";
code += "for (flatbuffers::uoffset_t _i = 0;";
code += " _i < _e->size(); _i++) { ";
code += "_o->" + field.name + "[_i] = ";
code += "_o->" + name + "[_i]" + access + " = ";
code += GenUnpackVal(field.value.type.VectorType(),
indexing, true, field);
code += "; } }";
@@ -1540,12 +1632,11 @@ class CppGenerator : public BaseGenerator {
break;
}
case BASE_TYPE_UNION: {
// Generate code that sets the union table, of the form:
// _o->field.table = Union::Unpack(_e, field_type(), resolver);
code += "_o->" + field.name + ".table = ";
code += field.value.type.enum_def->name + "Union::UnPack(";
code += "_e, " + field.name + UnionTypeFieldSuffix() + "(),";
code += "_resolver);";
// Generate code that sets the union value, of the form:
// _o->field.value = Union::Unpack(_e, field_type(), resolver);
code += "_o->" + field.name + ".value = ";
code += GenUnionUnpackVal(field, "", "");
code += ";";
break;
}
default: {
@@ -1577,8 +1668,7 @@ class CppGenerator : public BaseGenerator {
std::string GenCreateParam(const FieldDef &field) {
std::string value = "_o->";
if (field.value.type.base_type == BASE_TYPE_UTYPE) {
value += field.name.substr(0, field.name.size() -
strlen(UnionTypeFieldSuffix()));
value += StripUnionType(field.name);
value += ".type";
} else {
value += field.name;
@@ -1635,6 +1725,19 @@ class CppGenerator : public BaseGenerator {
code += "_fbb.CreateVector(" + value + ")";
break;
}
case BASE_TYPE_UNION: {
code += "_fbb.CreateVector<flatbuffers::Offset<void>>(" + value +
".size(), [&](size_t i) { return " + value +
"[i].Pack(_fbb, _rehasher); })";
break;
}
case BASE_TYPE_UTYPE: {
value = StripUnionType(value);
code += "_fbb.CreateVector<uint8_t>(" + value +
".size(), [&](size_t i) { return static_cast<uint8_t>(" + value +
"[i].type); })";
break;
}
default: {
if (field.value.type.enum_def) {
// For enumerations, we need to get access to the array data for
@@ -1693,7 +1796,7 @@ class CppGenerator : public BaseGenerator {
// Generate code for tables that needs to come after the regular definition.
void GenTablePost(const StructDef &struct_def) {
code_.SetValue("STRUCT_NAME", struct_def.name);
code_.SetValue("NATIVE_NAME", NativeName(struct_def.name));
code_.SetValue("NATIVE_NAME", NativeName(struct_def.name, &struct_def));
if (parser_.opts.generate_object_based_api) {
// Generate the X::UnPack() method.