diff --git a/samples/monster_generated.h b/samples/monster_generated.h index cdde13c4a..e1a1e7e1c 100644 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -77,8 +77,9 @@ struct EquipmentUnion { EquipmentUnion(EquipmentUnion&& u) FLATBUFFERS_NOEXCEPT : type(Equipment_NONE), value(nullptr) { std::swap(type, u.type); std::swap(value, u.value); } - EquipmentUnion(const EquipmentUnion &) { assert(false); } - EquipmentUnion &operator=(const EquipmentUnion &) { assert(false); return *this; } + EquipmentUnion(const EquipmentUnion &) FLATBUFFERS_NOEXCEPT; + EquipmentUnion &operator=(EquipmentUnion u) FLATBUFFERS_NOEXCEPT + { std::swap(type, u.type); std::swap(value, u.value); return *this; } EquipmentUnion &operator=(EquipmentUnion &&u) FLATBUFFERS_NOEXCEPT { std::swap(type, u.type); std::swap(value, u.value); return *this; } ~EquipmentUnion() { Reset(); } @@ -555,6 +556,17 @@ inline flatbuffers::Offset EquipmentUnion::Pack(flatbuffers::FlatBufferBui } } +inline EquipmentUnion::EquipmentUnion(const EquipmentUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) { + switch (type) { + case Equipment_Weapon: { + value = new WeaponT(*reinterpret_cast(u.value)); + break; + } + default: + break; + } +} + inline void EquipmentUnion::Reset() { switch (type) { case Equipment_Weapon: { diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 1bfadf21a..983e01628 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -687,8 +687,9 @@ 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 &) { assert(false); }"; - code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &) { assert(false); return *this; }"; + code_ += " {{NAME}}Union(const {{NAME}}Union &) FLATBUFFERS_NOEXCEPT;"; + code_ += " {{NAME}}Union &operator=({{NAME}}Union u) FLATBUFFERS_NOEXCEPT"; + code_ += " { std::swap(type, u.type); std::swap(value, u.value); return *this; }"; code_ += " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT"; code_ += " { std::swap(type, u.type); std::swap(value, u.value); return *this; }"; code_ += " ~{{NAME}}Union() { Reset(); }"; @@ -865,6 +866,49 @@ class CppGenerator : public BaseGenerator { code_ += "}"; code_ += ""; + // Union copy constructor + code_ += "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const " + "{{ENUM_NAME}}Union &u) FLATBUFFERS_NOEXCEPT : type(u.type), " + "value(nullptr) {"; + code_ += " switch (type) {"; + for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); + ++it) { + const auto &ev = **it; + if (!ev.value) { + continue; + } + code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); + code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true), + ev.union_type.struct_def)); + code_ += " case {{LABEL}}: {"; + bool copyable = true; + if (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(); + fit != ev.union_type.struct_def->fields.vec.end(); ++fit) { + const auto &field = **fit; + if (!field.deprecated && field.value.type.struct_def) { + copyable = false; + break; + } + } + } + if (copyable) { + code_ += " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>" + "(u.value));"; + } else { + code_ += " assert(false); // {{TYPE}} not copyable."; + } + code_ += " break;"; + code_ += " }"; + } + code_ += " default:"; + code_ += " break;"; + code_ += " }"; + code_ += "}"; + code_ += ""; + // Union Reset() function. code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE"))); @@ -877,11 +921,9 @@ class CppGenerator : public BaseGenerator { if (!ev.value) { continue; } - code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true), ev.union_type.struct_def)); - code_ += " case {{LABEL}}: {"; code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);"; code_ += " delete ptr;"; diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 647367a96..1974a84ab 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -108,8 +108,9 @@ struct AnyUnion { AnyUnion(AnyUnion&& u) FLATBUFFERS_NOEXCEPT : type(Any_NONE), value(nullptr) { std::swap(type, u.type); std::swap(value, u.value); } - AnyUnion(const AnyUnion &) { assert(false); } - AnyUnion &operator=(const AnyUnion &) { assert(false); return *this; } + AnyUnion(const AnyUnion &) FLATBUFFERS_NOEXCEPT; + AnyUnion &operator=(AnyUnion u) FLATBUFFERS_NOEXCEPT + { std::swap(type, u.type); std::swap(value, u.value); return *this; } AnyUnion &operator=(AnyUnion &&u) FLATBUFFERS_NOEXCEPT { std::swap(type, u.type); std::swap(value, u.value); return *this; } ~AnyUnion() { Reset(); } @@ -1333,6 +1334,25 @@ inline flatbuffers::Offset AnyUnion::Pack(flatbuffers::FlatBufferBuilder & } } +inline AnyUnion::AnyUnion(const AnyUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) { + switch (type) { + case Any_Monster: { + assert(false); // MonsterT not copyable. + break; + } + case Any_TestSimpleTableWithEnum: { + value = new TestSimpleTableWithEnumT(*reinterpret_cast(u.value)); + break; + } + case Any_MyGame_Example2_Monster: { + value = new MyGame::Example2::MonsterT(*reinterpret_cast(u.value)); + break; + } + default: + break; + } +} + inline void AnyUnion::Reset() { switch (type) { case Any_Monster: { diff --git a/tests/union_vector/union_vector_generated.h b/tests/union_vector/union_vector_generated.h index 88f4f368d..7eaa0fb07 100644 --- a/tests/union_vector/union_vector_generated.h +++ b/tests/union_vector/union_vector_generated.h @@ -55,8 +55,9 @@ struct CharacterUnion { CharacterUnion(CharacterUnion&& u) FLATBUFFERS_NOEXCEPT : type(Character_NONE), value(nullptr) { std::swap(type, u.type); std::swap(value, u.value); } - CharacterUnion(const CharacterUnion &) { assert(false); } - CharacterUnion &operator=(const CharacterUnion &) { assert(false); return *this; } + CharacterUnion(const CharacterUnion &) FLATBUFFERS_NOEXCEPT; + CharacterUnion &operator=(CharacterUnion u) FLATBUFFERS_NOEXCEPT + { std::swap(type, u.type); std::swap(value, u.value); return *this; } CharacterUnion &operator=(CharacterUnion &&u) FLATBUFFERS_NOEXCEPT { std::swap(type, u.type); std::swap(value, u.value); return *this; } ~CharacterUnion() { Reset(); } @@ -491,6 +492,37 @@ inline flatbuffers::Offset CharacterUnion::Pack(flatbuffers::FlatBufferBui } } +inline CharacterUnion::CharacterUnion(const CharacterUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) { + switch (type) { + case Character_MuLan: { + value = new AttackerT(*reinterpret_cast(u.value)); + break; + } + case Character_Rapunzel: { + value = new Rapunzel(*reinterpret_cast(u.value)); + break; + } + case Character_Belle: { + value = new BookReader(*reinterpret_cast(u.value)); + break; + } + case Character_BookFan: { + value = new BookReader(*reinterpret_cast(u.value)); + break; + } + case Character_Other: { + value = new std::string(*reinterpret_cast(u.value)); + break; + } + case Character_Unused: { + value = new std::string(*reinterpret_cast(u.value)); + break; + } + default: + break; + } +} + inline void CharacterUnion::Reset() { switch (type) { case Character_MuLan: {