diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md index 0e226fc75..cff3071bd 100755 --- a/docs/source/CppUsage.md +++ b/docs/source/CppUsage.md @@ -411,4 +411,22 @@ manually wrap it in synchronisation primites. There's no automatic way to accomplish this, by design, as we feel multithreaded construction of a single buffer will be rare, and synchronisation overhead would be costly. +## Advanced union features + +The C++ implementation currently supports vectors of unions (i.e. you can +declare a field as `[T]` where `T` is a union type instead of a table type). It +also supports structs and strings in unions, besides tables. + +For an example of these features, see `tests/union_vector`, and +`UnionVectorTest` in `test.cpp`. + +Since these features haven't been ported to other languages yet, if you +choose to use them, you won't be able to use these buffers in other languages +(`flatc` will refuse to compile a schema that uses these features). + +These features reduce the amount of "table wrapping" that was previously +needed to use unions. + +To use scalars, simply wrap them in a struct. +
diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 664be4ca4..0a553a0c0 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -360,6 +360,8 @@ private: const uint8_t *data_; }; +struct String; + // This is used as a helper type for accessing vectors. // Vector::data() assumes the vector elements start after the length field. template class Vector { @@ -391,6 +393,18 @@ public: return static_cast(Get(i)); } + // If this a vector of unions, this does the cast for you. There's no check + // to make sure this is the right type! + template const U *GetAs(uoffset_t i) const { + return reinterpret_cast(Get(i)); + } + + // If this a vector of unions, this does the cast for you. There's no check + // to make sure this is actually a string! + const String *GetAsString(uoffset_t i) const { + return reinterpret_cast(Get(i)); + } + const void *GetStructFromOffset(size_t o) const { return reinterpret_cast(Data() + o); } @@ -1327,6 +1341,13 @@ FLATBUFFERS_FINAL_CLASS reinterpret_cast(buf)); } + /// @brief Write a struct by itself, typically to be part of a union. + template Offset CreateStruct(const T &structobj) { + Align(AlignOf()); + buf_.push_small(structobj); + return Offset(GetSize()); + } + /// @brief The length of a FlatBuffer file header. static const size_t kFileIdentifierLength = 4; diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 9978d34ec..e81b2fcb9 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -283,18 +283,18 @@ inline size_t InlineAlignment(const Type &type) { struct EnumVal { EnumVal(const std::string &_name, int64_t _val) - : name(_name), value(_val), struct_def(nullptr) {} + : name(_name), value(_val) {} Offset Serialize(FlatBufferBuilder *builder) const; std::string name; std::vector doc_comment; int64_t value; - StructDef *struct_def; // only set if this is a union + Type union_type; }; struct EnumDef : public Definition { - EnumDef() : is_union(false) {} + EnumDef() : is_union(false), uses_type_aliases(false) {} EnumVal *ReverseLookup(int enum_idx, bool skip_union_default = true) { for (auto it = vals.vec.begin() + static_cast(is_union && @@ -312,6 +312,7 @@ struct EnumDef : public Definition { SymbolTable vals; bool is_union; + bool uses_type_aliases; Type underlying_type; }; @@ -548,6 +549,7 @@ private: const std::string &name, const Type &type, FieldDef **dest); FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def); + FLATBUFFERS_CHECKED_ERROR ParseString(Value &val); FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field, size_t parent_fieldn, const StructDef *parent_struct_def); diff --git a/include/flatbuffers/reflection_generated.h b/include/flatbuffers/reflection_generated.h index 8379dcf52..b76814e47 100644 --- a/include/flatbuffers/reflection_generated.h +++ b/include/flatbuffers/reflection_generated.h @@ -204,7 +204,8 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { enum { VT_NAME = 4, VT_VALUE = 6, - VT_OBJECT = 8 + VT_OBJECT = 8, + VT_UNION_TYPE = 10 }; const flatbuffers::String *name() const { return GetPointer(VT_NAME); @@ -228,6 +229,9 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const Object *object() const { return GetPointer(VT_OBJECT); } + const Type *union_type() const { + return GetPointer(VT_UNION_TYPE); + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyFieldRequired(verifier, VT_NAME) && @@ -235,6 +239,8 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyField(verifier, VT_VALUE) && VerifyField(verifier, VT_OBJECT) && verifier.VerifyTable(object()) && + VerifyField(verifier, VT_UNION_TYPE) && + verifier.VerifyTable(union_type()) && verifier.EndTable(); } }; @@ -251,13 +257,16 @@ struct EnumValBuilder { void add_object(flatbuffers::Offset object) { fbb_.AddOffset(EnumVal::VT_OBJECT, object); } + void add_union_type(flatbuffers::Offset union_type) { + fbb_.AddOffset(EnumVal::VT_UNION_TYPE, union_type); + } EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } EnumValBuilder &operator=(const EnumValBuilder &); flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_, 3); + const auto end = fbb_.EndTable(start_, 4); auto o = flatbuffers::Offset(end); fbb_.Required(o, EnumVal::VT_NAME); return o; @@ -268,9 +277,11 @@ inline flatbuffers::Offset CreateEnumVal( flatbuffers::FlatBufferBuilder &_fbb, flatbuffers::Offset name = 0, int64_t value = 0, - flatbuffers::Offset object = 0) { + flatbuffers::Offset object = 0, + flatbuffers::Offset union_type = 0) { EnumValBuilder builder_(_fbb); builder_.add_value(value); + builder_.add_union_type(union_type); builder_.add_object(object); builder_.add_name(name); return builder_.Finish(); @@ -280,12 +291,14 @@ inline flatbuffers::Offset CreateEnumValDirect( flatbuffers::FlatBufferBuilder &_fbb, const char *name = nullptr, int64_t value = 0, - flatbuffers::Offset object = 0) { + flatbuffers::Offset object = 0, + flatbuffers::Offset union_type = 0) { return reflection::CreateEnumVal( _fbb, name ? _fbb.CreateString(name) : 0, value, - object); + object, + union_type); } struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { diff --git a/reflection/reflection.fbs b/reflection/reflection.fbs index 76ccf85cc..ea41891c3 100644 --- a/reflection/reflection.fbs +++ b/reflection/reflection.fbs @@ -42,7 +42,8 @@ table KeyValue { table EnumVal { name:string (required); value:long (key); - object:Object; // Only if part of a union. + object:Object; // Will be deprecated in favor of union_type in the future. + union_type:Type; } table Enum { diff --git a/samples/monster_generated.h b/samples/monster_generated.h index 05633d96e..fdbac0fcc 100644 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -71,35 +71,35 @@ template<> struct EquipmentTraits { struct EquipmentUnion { Equipment type; - flatbuffers::NativeTable *table; + void *value; - EquipmentUnion() : type(Equipment_NONE), table(nullptr) {} + EquipmentUnion() : type(Equipment_NONE), value(nullptr) {} EquipmentUnion(EquipmentUnion&& u) FLATBUFFERS_NOEXCEPT : - type(Equipment_NONE), table(nullptr) - { std::swap(type, u.type); std::swap(table, u.table); } + type(Equipment_NONE), value(nullptr) + { std::swap(type, u.type); std::swap(value, u.value); } EquipmentUnion(const EquipmentUnion &); EquipmentUnion &operator=(const EquipmentUnion &); EquipmentUnion &operator=(EquipmentUnion &&u) FLATBUFFERS_NOEXCEPT - { std::swap(type, u.type); std::swap(table, u.table); return *this; } + { std::swap(type, u.type); std::swap(value, u.value); return *this; } ~EquipmentUnion() { Reset(); } void Reset(); template - void Set(T&& value) { + void Set(T&& val) { Reset(); type = EquipmentTraits::enum_value; if (type != Equipment_NONE) { - table = new T(std::forward(value)); + value = new T(std::forward(val)); } } - static flatbuffers::NativeTable *UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver); + static void *UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver); flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const; WeaponT *AsWeapon() { return type == Equipment_Weapon ? - reinterpret_cast(table) : nullptr; + reinterpret_cast(value) : nullptr; } }; @@ -228,7 +228,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { } template const T *equipped_as() const; const Weapon *equipped_as_Weapon() const { - return (equipped_type() == Equipment_Weapon)? static_cast(equipped()) : nullptr; + return equipped_type() == Equipment_Weapon ? static_cast(equipped()) : nullptr; } void *mutable_equipped() { return GetPointer(VT_EQUIPPED); @@ -451,7 +451,7 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function { auto _e = color(); _o->color = _e; }; { auto _e = weapons(); if (_e) { _o->weapons.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); } } }; { auto _e = equipped_type(); _o->equipped.type = _e; }; - { auto _e = equipped(); if (_e) _o->equipped.table = EquipmentUnion::UnPack(_e, equipped_type(),_resolver); }; + { auto _e = equipped(); if (_e) _o->equipped.value = EquipmentUnion::UnPack(_e, equipped_type(), _resolver); }; } inline flatbuffers::Offset Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) { @@ -535,7 +535,7 @@ inline bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuf return true; } -inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) { +inline void *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) { switch (type) { case Equipment_Weapon: { auto ptr = reinterpret_cast(obj); @@ -548,7 +548,7 @@ inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *obj, Equipme inline flatbuffers::Offset EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const { switch (type) { case Equipment_Weapon: { - auto ptr = reinterpret_cast(table); + auto ptr = reinterpret_cast(value); return CreateWeapon(_fbb, ptr, _rehasher).Union(); } default: return 0; @@ -558,13 +558,13 @@ inline flatbuffers::Offset EquipmentUnion::Pack(flatbuffers::FlatBufferBui inline void EquipmentUnion::Reset() { switch (type) { case Equipment_Weapon: { - auto ptr = reinterpret_cast(table); + auto ptr = reinterpret_cast(value); delete ptr; break; } default: break; } - table = nullptr; + value = nullptr; type = Equipment_NONE; } diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 95c5d71ab..b5a6c59ac 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -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 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 "; - code_ += " void Set(T&& value) {"; - code_ += " Reset();"; - code_ += " type = {{NAME}}Traits::enum_value;"; - code_ += " if (type != {{NONE}}) {"; - code_ += " table = new T(std::forward(value));"; - code_ += " }"; - code_ += " }"; - code_ += ""; + if (!enum_def.uses_type_aliases) { + code_ += " template "; + code_ += " void Set(T&& val) {"; + code_ += " Reset();"; + code_ += " type = {{NAME}}Traits::enum_value;"; + code_ += " if (type != {{NONE}}) {"; + code_ += " value = new T(std::forward(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(obj);"; - code_ += " return verifier.VerifyTable(ptr);"; + auto getptr = + " auto ptr = reinterpret_cast(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(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(table);"; - code_ += " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();"; + code_ += " auto ptr = reinterpret_cast(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() 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>(" + value + + ".size(), [&](size_t i) { return " + value + + "[i].Pack(_fbb, _rehasher); })"; + break; + } + case BASE_TYPE_UTYPE: { + value = StripUnionType(value); + code += "_fbb.CreateVector(" + value + + ".size(), [&](size_t i) { return static_cast(" + 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. diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp index e39387e66..b2839e130 100644 --- a/src/idl_gen_js.cpp +++ b/src/idl_gen_js.cpp @@ -71,7 +71,8 @@ namespace js { class JsGenerator : public BaseGenerator { public: typedef std::unordered_set imported_fileset; - typedef std::unordered_multimap reexport_map; + typedef std::unordered_multimap + reexport_map; JsGenerator(const Parser &parser, const std::string &path, const std::string &file_name) @@ -104,19 +105,22 @@ class JsGenerator : public BaseGenerator { code += enum_code; code += struct_code; - if (lang_.language == IDLOptions::kJs && !exports_code.empty() && !parser_.opts.skip_js_exports) { + if (lang_.language == IDLOptions::kJs && !exports_code.empty() && + !parser_.opts.skip_js_exports) { code += "// Exports for Node.js and RequireJS\n"; code += exports_code; } - return SaveFile(GeneratedFileName(path_, file_name_, lang_).c_str(), code, false); + return SaveFile(GeneratedFileName(path_, file_name_, lang_).c_str(), code, + false); } private: JsLanguageParameters lang_; // Generate code for imports - void generateImportDependencies(std::string *code_ptr, const imported_fileset &imported_files) { + void generateImportDependencies(std::string *code_ptr, + const imported_fileset &imported_files) { std::string &code = *code_ptr; for (auto it = imported_files.begin(); it != imported_files.end(); ++it) { const auto &file = *it; @@ -129,11 +133,13 @@ class JsGenerator : public BaseGenerator { } } - // Generate reexports, which might not have been explicitly imported using the "export import" trick + // Generate reexports, which might not have been explicitly imported using the + // "export import" trick void generateReexports(std::string *code_ptr, const reexport_map &reexports, imported_fileset imported_files) { - if (!parser_.opts.reexport_ts_modules || lang_.language != IDLOptions::kTs) { + if (!parser_.opts.reexport_ts_modules || + lang_.language != IDLOptions::kTs) { return; } @@ -152,7 +158,9 @@ class JsGenerator : public BaseGenerator { code += "export namespace " + file.second.target_namespace + " { \n"; code += "export import " + file.second.symbol + " = "; - code += GenFileNamespacePrefix(file.first) + "." + file.second.source_namespace + "." + file.second.symbol + "; }\n"; + code += GenFileNamespacePrefix(file.first) + "." + + file.second.source_namespace + "." + file.second.symbol + + "; }\n"; } } } @@ -175,11 +183,13 @@ class JsGenerator : public BaseGenerator { for (auto it = parser_.structs_.vec.begin(); it != parser_.structs_.vec.end(); ++it) { auto &struct_def = **it; - GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr, imported_files); + GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr, + imported_files); } } void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) { - if (lang_.language == IDLOptions::kTs && parser_.opts.skip_flatbuffers_import) { + if (lang_.language == IDLOptions::kTs && + parser_.opts.skip_flatbuffers_import) { return; } @@ -282,13 +292,14 @@ void GenEnum(EnumDef &enum_def, std::string *code_ptr, std::string &exports = *exports_ptr; GenDocComment(enum_def.doc_comment, code_ptr, "@enum"); if (lang_.language == IDLOptions::kTs) { - code += "export namespace " + GetNameSpace(enum_def) + "{\n" + "export enum " + enum_def.name + "{\n"; + code += "export namespace " + GetNameSpace(enum_def) + "{\n" + + "export enum " + enum_def.name + "{\n"; } else { if (enum_def.defined_namespace->components.empty()) { code += "var "; if(parser_.opts.use_goog_js_export_format) { - exports += "goog.exportSymbol('" + enum_def.name + "', " + enum_def.name + - ");\n"; + exports += "goog.exportSymbol('" + enum_def.name + "', " + + enum_def.name + ");\n"; } else { exports += "this." + enum_def.name + " = " + enum_def.name + ";\n"; } @@ -304,12 +315,19 @@ void GenEnum(EnumDef &enum_def, std::string *code_ptr, } GenDocComment(ev.doc_comment, code_ptr, "", " "); } - code += " " + ev.name + ((lang_.language == IDLOptions::kTs) ? ("= ") : (": ")) + NumToString(ev.value); + code += " " + ev.name; + code += lang_.language == IDLOptions::kTs ? "= " : ": "; + code += NumToString(ev.value); code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n"; - if (ev.struct_def) { - ReexportDescription desc = { ev.name, GetNameSpace(*ev.struct_def), GetNameSpace(enum_def) }; - reexports.insert(std::make_pair(ev.struct_def->file, std::move(desc))); + if (ev.union_type.struct_def) { + ReexportDescription desc = { + ev.name, + GetNameSpace(*ev.union_type.struct_def), + GetNameSpace(enum_def) + }; + reexports.insert(std::make_pair(ev.union_type.struct_def->file, + std::move(desc))); } } @@ -366,7 +384,8 @@ std::string GenDefaultValue(const Value &value, const std::string &context) { if (auto val = value.type.enum_def->ReverseLookup( atoi(value.constant.c_str()), false)) { if (lang_.language == IDLOptions::kTs) { - return GenPrefixedTypeName(WrapInNameSpace(*value.type.enum_def), value.type.enum_def->file) + "." + val->name; + return GenPrefixedTypeName(WrapInNameSpace(*value.type.enum_def), + value.type.enum_def->file) + "." + val->name; } else { return WrapInNameSpace(*value.type.enum_def) + "." + val->name; } @@ -448,17 +467,21 @@ static std::string MaybeScale(T value) { } static std::string GenFileNamespacePrefix(const std::string &file) { - return "NS" + std::to_string(static_cast(std::hash()(file))); + return "NS" + std::to_string( + static_cast(std::hash()(file))); } static std::string GenPrefixedImport(const std::string &full_file_name, const std::string &base_file_name) { - return "import * as "+ GenFileNamespacePrefix(full_file_name) + " from \"./" + base_file_name + "\";\n"; + return "import * as "+ GenFileNamespacePrefix(full_file_name) + + " from \"./" + base_file_name + "\";\n"; } // Adds a source-dependent prefix, for of import * statements. -std::string GenPrefixedTypeName(const std::string &typeName, const std::string &file) { - const auto basename = flatbuffers::StripPath(flatbuffers::StripExtension(file)); +std::string GenPrefixedTypeName(const std::string &typeName, + const std::string &file) { + const auto basename = + flatbuffers::StripPath(flatbuffers::StripExtension(file)); if (basename == file_name_) { return typeName; } @@ -483,7 +506,8 @@ void GenStructArgs(const StructDef &struct_def, *annotations += "} " + nameprefix + field.name + "\n"; if (lang_.language == IDLOptions::kTs) { - *arguments += ", " + nameprefix + field.name + ": " + GenTypeName(field.value.type, true); + *arguments += ", " + nameprefix + field.name + ": " + + GenTypeName(field.value.type, true); } else { *arguments += ", " + nameprefix + field.name; } @@ -521,7 +545,8 @@ static void GenStructBody(const StructDef &struct_def, } // Generate an accessor struct with constructor for a flatbuffers struct. -void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_ptr, std::string *exports_ptr, +void GenStruct(const Parser &parser, StructDef &struct_def, + std::string *code_ptr, std::string *exports_ptr, imported_fileset &imported_files) { if (struct_def.generated) return; std::string &code = *code_ptr; @@ -583,7 +608,8 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt code += " */\n"; if (lang_.language == IDLOptions::kTs) { - code += "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name + " {\n"; + code += "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name + + " {\n"; } else { code += object_name + ".prototype.__init = function(i, bb) {\n"; } @@ -602,7 +628,8 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt "@returns {" + object_name + "}"); if (lang_.language == IDLOptions::kTs) { code += "static getRootAs" + struct_def.name; - code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name + "):" + object_name + " {\n"; + code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name + "):" + + object_name + " {\n"; } else { code += object_name + ".getRootAs" + struct_def.name; code += " = function(bb, obj) {\n"; @@ -618,7 +645,8 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt "@param {flatbuffers.ByteBuffer} bb\n" "@returns {boolean}"); if (lang_.language == IDLOptions::kTs) { - code += "static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {\n"; + code += + "static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {\n"; } else { code += object_name + ".bufferHasIdentifier = function(bb) {\n"; } @@ -647,13 +675,16 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt std::string prefix = MakeCamel(field.name, false) + "("; if (field.value.type.base_type == BASE_TYPE_STRING) { code += prefix + "):string\n"; - code += prefix + "optionalEncoding:flatbuffers.Encoding"+"):" + GenTypeName(field.value.type, false)+"\n"; + code += prefix + "optionalEncoding:flatbuffers.Encoding"+"):" + + GenTypeName(field.value.type, false)+"\n"; code += prefix + "optionalEncoding?:any"; } else { code += prefix; } if (field.value.type.enum_def) { - code += "):" + GenPrefixedTypeName(GenTypeName(field.value.type, false), field.value.type.enum_def->file) + " {\n"; + code += "):" + + GenPrefixedTypeName(GenTypeName(field.value.type, false), + field.value.type.enum_def->file) + " {\n"; } else { code += "):" + GenTypeName(field.value.type, false) + " {\n"; } @@ -733,12 +764,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt std::string prefix = MakeCamel(field.name, false); prefix += "(index: number"; if (vectortype.base_type == BASE_TYPE_STRUCT) { - vectortypename = GenPrefixedTypeName(vectortypename, vectortype.struct_def->file); + vectortypename = GenPrefixedTypeName(vectortypename, + vectortype.struct_def->file); code += prefix + ", obj?:" + vectortypename; imported_files.insert(vectortype.struct_def->file); } else if (vectortype.base_type == BASE_TYPE_STRING) { code += prefix + "):string\n"; - code += prefix + ",optionalEncoding:flatbuffers.Encoding" + "):" + vectortypename + "\n"; + code += prefix + ",optionalEncoding:flatbuffers.Encoding" + "):" + + vectortypename + "\n"; code += prefix + ",optionalEncoding?:any"; } else { code += prefix; @@ -819,31 +852,37 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt // Adds the mutable scalar value to the output if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer) { - std::string annotations = "@param {" + GenTypeName(field.value.type, true) + "} value\n"; + std::string annotations = + "@param {" + GenTypeName(field.value.type, true) + "} value\n"; GenDocComment(code_ptr, annotations + "@returns {boolean}"); if (lang_.language == IDLOptions::kTs) { std::string type; if (field.value.type.enum_def) { - type = GenPrefixedTypeName(GenTypeName(field.value.type, true), field.value.type.enum_def->file); + type = GenPrefixedTypeName(GenTypeName(field.value.type, true), + field.value.type.enum_def->file); } else { type = GenTypeName(field.value.type, true); } code += "mutate_" + field.name + "(value:" + type + "):boolean {\n"; } else { - code += object_name + ".prototype.mutate_" + field.name + " = function(value) {\n"; + code += object_name + ".prototype.mutate_" + field.name + + " = function(value) {\n"; } - code += " var offset = this.bb.__offset(this.bb_pos, " + NumToString(field.value.offset) + ");\n\n"; + code += " var offset = this.bb.__offset(this.bb_pos, " + + NumToString(field.value.offset) + ");\n\n"; code += " if (offset === 0) {\n"; code += " return false;\n"; code += " }\n\n"; // special case for bools, which are treated as uint8 - code += " this.bb.write" + MakeCamel(GenType(field.value.type)) + "(this.bb_pos + offset, "; - if (field.value.type.base_type == BASE_TYPE_BOOL && lang_.language == IDLOptions::kTs) { + code += " this.bb.write" + MakeCamel(GenType(field.value.type)) + + "(this.bb_pos + offset, "; + if (field.value.type.base_type == BASE_TYPE_BOOL && + lang_.language == IDLOptions::kTs) { code += "+"; } @@ -885,7 +924,8 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt if (lang_.language == IDLOptions::kTs) { code += MakeCamel(field.name, false); - code += "Array():" + GenType(vectorType) + "Array {\n" + offset_prefix; + code += "Array():" + GenType(vectorType) + "Array {\n" + + offset_prefix; } else { code += object_name + ".prototype." + MakeCamel(field.name, false); code += "Array = function() {\n" + offset_prefix; @@ -958,13 +998,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt if (lang_.language == IDLOptions::kTs) { std::string argType; if (field.value.type.enum_def) { - argType = GenPrefixedTypeName(GenTypeName(field.value.type, true), field.value.type.enum_def->file); + argType = GenPrefixedTypeName(GenTypeName(field.value.type, true), + field.value.type.enum_def->file); } else { argType = GenTypeName(field.value.type, true); } code += "static add" + MakeCamel(field.name); - code += "(builder:flatbuffers.Builder, " + argname + ":" + argType + ") {\n"; + code += "(builder:flatbuffers.Builder, " + argname + ":" + argType + + ") {\n"; } else { code += object_name + ".add" + MakeCamel(field.name); code += " = function(builder, " + argname + ") {\n"; @@ -1005,7 +1047,8 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt if (type == "number[]") { type += " | Uint8Array"; } - code += "Vector(builder:flatbuffers.Builder, data:" + type+"):flatbuffers.Offset {\n"; + code += "Vector(builder:flatbuffers.Builder, data:" + type + + "):flatbuffers.Offset {\n"; code += "if(!data){\n return null\n}\n"; } else { code += object_name + ".create" + MakeCamel(field.name); diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp index 17cd987dd..cff1b322d 100644 --- a/src/idl_gen_text.cpp +++ b/src/idl_gen_text.cpp @@ -49,7 +49,7 @@ void OutputIdentifier(const std::string &name, const IDLOptions &opts, // for a single FlatBuffer value into JSON format. // The general case for scalars: template bool Print(T val, Type type, int /*indent*/, - StructDef * /*union_sd*/, + Type */*union_type*/, const IDLOptions &opts, std::string *_text) { std::string &text = *_text; @@ -169,22 +169,16 @@ static bool EscapeString(const String &s, std::string *_text, const IDLOptions& // Specialization of Print above for pointer types. template<> bool Print(const void *val, Type type, int indent, - StructDef *union_sd, + Type *union_type, const IDLOptions &opts, std::string *_text) { switch (type.base_type) { case BASE_TYPE_UNION: // If this assert hits, you have an corrupt buffer, a union type field // was not present or was out of range. - assert(union_sd); - if (!GenStruct(*union_sd, - reinterpret_cast(val), - indent, - opts, - _text)) { - return false; - } - break; + assert(union_type); + return Print(val, *union_type, indent, nullptr, opts, + _text); case BASE_TYPE_STRUCT: if (!GenStruct(*type.struct_def, reinterpret_cast(val), @@ -236,7 +230,7 @@ template static bool GenField(const FieldDef &fd, // Generate text for non-scalar field. static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed, - int indent, StructDef *union_sd, + int indent, Type *union_type, const IDLOptions &opts, std::string *_text) { const void *val = nullptr; if (fixed) { @@ -249,7 +243,7 @@ static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed, ? table->GetStruct(fd.value.offset) : table->GetPointer(fd.value.offset); } - return Print(val, fd.value.type, indent, union_sd, opts, _text); + return Print(val, fd.value.type, indent, union_type, opts, _text); } // Generate text for a struct or table, values separated by commas, indented, @@ -260,7 +254,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table, std::string &text = *_text; text += "{"; int fieldout = 0; - StructDef *union_sd = nullptr; + Type *union_type = nullptr; for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { @@ -296,7 +290,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table, FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD) #undef FLATBUFFERS_TD if (!GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts), - union_sd, opts, _text)) { + union_type, opts, _text)) { return false; } break; @@ -305,7 +299,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table, auto enum_val = fd.value.type.enum_def->ReverseLookup( table->GetField(fd.value.offset, 0)); assert(enum_val); - union_sd = enum_val->struct_def; + union_type = &enum_val->union_type; } } else diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 0d689da3c..3076f7188 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -735,6 +735,13 @@ CheckedError Parser::ParseField(StructDef &struct_def) { return NoError(); } +CheckedError Parser::ParseString(Value &val) { + auto s = attribute_; + EXPECT(kTokenStringConstant); + val.constant = NumToString(builder_.CreateString(s).o); + return NoError(); +} + CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field, size_t parent_fieldn, const StructDef *parent_struct_def) { @@ -784,16 +791,27 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field, ECHECK(atot(constant.c_str(), *this, &enum_idx)); auto enum_val = val.type.enum_def->ReverseLookup(enum_idx); if (!enum_val) return Error("illegal type id for: " + field->name); - ECHECK(ParseTable(*enum_val->struct_def, &val.constant, nullptr)); + if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) { + ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant, + nullptr)); + if (enum_val->union_type.struct_def->fixed) { + // All BASE_TYPE_UNION values are offsets, so turn this into one. + SerializeStruct(*enum_val->union_type.struct_def, val); + builder_.ClearOffsets(); + val.constant = NumToString(builder_.GetSize()); + } + } else if (enum_val->union_type.base_type == BASE_TYPE_STRING) { + ECHECK(ParseString(val)); + } else { + assert(false); + } break; } case BASE_TYPE_STRUCT: ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr)); break; case BASE_TYPE_STRING: { - auto s = attribute_; - EXPECT(kTokenStringConstant); - val.constant = NumToString(builder_.CreateString(s).o); + ECHECK(ParseString(val)); break; } case BASE_TYPE_VECTOR: { @@ -1290,7 +1308,16 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) { return Error("enum value already exists: " + value_name); ev.doc_comment = value_comment; if (is_union) { - ev.struct_def = LookupCreateStruct(full_name); + if (Is(':')) { + NEXT(); + ECHECK(ParseType(ev.union_type)); + if (ev.union_type.base_type != BASE_TYPE_STRUCT && + ev.union_type.base_type != BASE_TYPE_STRING) + return Error("union value type may only be table/struct/string"); + enum_def.uses_type_aliases = true; + } else { + ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name)); + } } if (Is('=')) { NEXT(); @@ -1994,6 +2021,8 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths, return Error("type referenced but not defined: " + (*it)->name); } } + // This check has to happen here and not earlier, because only now do we + // know for sure what the type of these are. for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { auto &enum_def = **it; if (enum_def.is_union) { @@ -2001,8 +2030,11 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths, val_it != enum_def.vals.vec.end(); ++val_it) { auto &val = **val_it; - if (val.struct_def && val.struct_def->fixed) - return Error("only tables can be union elements: " + val.name); + if (opts.lang_to_generate != IDLOptions::kCpp && + val.union_type.struct_def && val.union_type.struct_def->fixed) + return Error( + "only tables can be union elements in the generated language: " + + val.name); } } } @@ -2145,9 +2177,11 @@ Offset EnumVal::Serialize(FlatBufferBuilder *builder) const return reflection::CreateEnumVal(*builder, builder->CreateString(name), value, - struct_def - ? struct_def->serialized_location - : 0); + union_type.struct_def + ? union_type.struct_def-> + serialized_location + : 0, + union_type.Serialize(builder)); } Offset Type::Serialize(FlatBufferBuilder *builder) const { diff --git a/tests/generate_code.sh b/tests/generate_code.sh index 00d87f7c7..b12e78a76 100755 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -16,7 +16,7 @@ ../flatc --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json ../flatc --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs -../flatc --cpp -o union_vector ./union_vector/union_vector.fbs +../flatc --cpp --gen-mutable --gen-object-api -o union_vector ./union_vector/union_vector.fbs ../flatc -b --schema --bfbs-comments monster_test.fbs cd ../samples ../flatc --cpp --gen-mutable --gen-object-api monster.fbs diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs index d5a1aadaa..78871d504 100644 Binary files a/tests/monster_test.bfbs and b/tests/monster_test.bfbs differ diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 9fca310b8..08970f942 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -102,43 +102,43 @@ template<> struct AnyTraits { struct AnyUnion { Any type; - flatbuffers::NativeTable *table; + void *value; - AnyUnion() : type(Any_NONE), table(nullptr) {} + AnyUnion() : type(Any_NONE), value(nullptr) {} AnyUnion(AnyUnion&& u) FLATBUFFERS_NOEXCEPT : - type(Any_NONE), table(nullptr) - { std::swap(type, u.type); std::swap(table, u.table); } + type(Any_NONE), value(nullptr) + { std::swap(type, u.type); std::swap(value, u.value); } AnyUnion(const AnyUnion &); AnyUnion &operator=(const AnyUnion &); AnyUnion &operator=(AnyUnion &&u) FLATBUFFERS_NOEXCEPT - { std::swap(type, u.type); std::swap(table, u.table); return *this; } + { std::swap(type, u.type); std::swap(value, u.value); return *this; } ~AnyUnion() { Reset(); } void Reset(); template - void Set(T&& value) { + void Set(T&& val) { Reset(); type = AnyTraits::enum_value; if (type != Any_NONE) { - table = new T(std::forward(value)); + value = new T(std::forward(val)); } } - static flatbuffers::NativeTable *UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver); + static void *UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver); flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const; MonsterT *AsMonster() { return type == Any_Monster ? - reinterpret_cast(table) : nullptr; + reinterpret_cast(value) : nullptr; } TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() { return type == Any_TestSimpleTableWithEnum ? - reinterpret_cast(table) : nullptr; + reinterpret_cast(value) : nullptr; } MyGame::Example2::MonsterT *AsMyGame_Example2_Monster() { return type == Any_MyGame_Example2_Monster ? - reinterpret_cast(table) : nullptr; + reinterpret_cast(value) : nullptr; } }; @@ -629,13 +629,13 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { } template const T *test_as() const; const Monster *test_as_Monster() const { - return (test_type() == Any_Monster)? static_cast(test()) : nullptr; + return test_type() == Any_Monster ? static_cast(test()) : nullptr; } const TestSimpleTableWithEnum *test_as_TestSimpleTableWithEnum() const { - return (test_type() == Any_TestSimpleTableWithEnum)? static_cast(test()) : nullptr; + return test_type() == Any_TestSimpleTableWithEnum ? static_cast(test()) : nullptr; } const MyGame::Example2::Monster *test_as_MyGame_Example2_Monster() const { - return (test_type() == Any_MyGame_Example2_Monster)? static_cast(test()) : nullptr; + return test_type() == Any_MyGame_Example2_Monster ? static_cast(test()) : nullptr; } void *mutable_test() { return GetPointer(VT_TEST); @@ -1172,7 +1172,7 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function { auto _e = inventory(); if (_e) { _o->inventory.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory[_i] = _e->Get(_i); } } }; { auto _e = color(); _o->color = _e; }; { auto _e = test_type(); _o->test.type = _e; }; - { auto _e = test(); if (_e) _o->test.table = AnyUnion::UnPack(_e, test_type(),_resolver); }; + { auto _e = test(); if (_e) _o->test.value = AnyUnion::UnPack(_e, test_type(), _resolver); }; { auto _e = test4(); if (_e) { _o->test4.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test4[_i] = *_e->Get(_i); } } }; { auto _e = testarrayofstring(); if (_e) { _o->testarrayofstring.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring[_i] = _e->Get(_i)->str(); } } }; { auto _e = testarrayoftables(); if (_e) { _o->testarrayoftables.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); } } }; @@ -1297,7 +1297,7 @@ inline bool VerifyAnyVector(flatbuffers::Verifier &verifier, const flatbuffers:: return true; } -inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver) { +inline void *AnyUnion::UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver) { switch (type) { case Any_Monster: { auto ptr = reinterpret_cast(obj); @@ -1318,15 +1318,15 @@ inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *obj, Any type, con inline flatbuffers::Offset AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const { switch (type) { case Any_Monster: { - auto ptr = reinterpret_cast(table); + auto ptr = reinterpret_cast(value); return CreateMonster(_fbb, ptr, _rehasher).Union(); } case Any_TestSimpleTableWithEnum: { - auto ptr = reinterpret_cast(table); + auto ptr = reinterpret_cast(value); return CreateTestSimpleTableWithEnum(_fbb, ptr, _rehasher).Union(); } case Any_MyGame_Example2_Monster: { - auto ptr = reinterpret_cast(table); + auto ptr = reinterpret_cast(value); return CreateMonster(_fbb, ptr, _rehasher).Union(); } default: return 0; @@ -1336,23 +1336,23 @@ inline flatbuffers::Offset AnyUnion::Pack(flatbuffers::FlatBufferBuilder & inline void AnyUnion::Reset() { switch (type) { case Any_Monster: { - auto ptr = reinterpret_cast(table); + auto ptr = reinterpret_cast(value); delete ptr; break; } case Any_TestSimpleTableWithEnum: { - auto ptr = reinterpret_cast(table); + auto ptr = reinterpret_cast(value); delete ptr; break; } case Any_MyGame_Example2_Monster: { - auto ptr = reinterpret_cast(table); + auto ptr = reinterpret_cast(value); delete ptr; break; } default: break; } - table = nullptr; + value = nullptr; type = Any_NONE; } diff --git a/tests/test.cpp b/tests/test.cpp index 262562a60..53b2fe710 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1334,46 +1334,78 @@ void UnionVectorTest() { // union types. std::vector types; types.push_back(static_cast(Character_Belle)); - types.push_back(static_cast(Character_Rapunzel)); types.push_back(static_cast(Character_MuLan)); + types.push_back(static_cast(Character_BookFan)); + types.push_back(static_cast(Character_Other)); + types.push_back(static_cast(Character_Unused)); // union values. std::vector> characters; - characters.push_back(CreateBelle(fbb, /*books_read=*/7).Union()); - characters.push_back(CreateRapunzel(fbb, /*hair_length=*/6).Union()); - characters.push_back(CreateMuLan(fbb, /*sword_attack_damage=*/5).Union()); + characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union()); + characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union()); + characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union()); + characters.push_back(fbb.CreateString("Other").Union()); + characters.push_back(fbb.CreateString("Unused").Union()); // create Movie. const auto movie_offset = - CreateMovie(fbb, fbb.CreateVector(types), fbb.CreateVector(characters)); + CreateMovie(fbb, + Character_Rapunzel, + fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(), + fbb.CreateVector(types), + fbb.CreateVector(characters)); FinishMovieBuffer(fbb, movie_offset); - uint8_t *buf = fbb.GetBufferPointer(); + auto buf = fbb.GetBufferPointer(); flatbuffers::Verifier verifier(buf, fbb.GetSize()); TEST_EQ(VerifyMovieBuffer(verifier), true); - const Movie *movie = GetMovie(buf); - TEST_EQ(movie->characters_type()->size(), 3); - TEST_EQ( - movie->characters_type()->GetEnum(0) == Character_Belle, - true); - TEST_EQ( - movie->characters_type()->GetEnum(1) == Character_Rapunzel, - true); - TEST_EQ( - movie->characters_type()->GetEnum(2) == Character_MuLan, - true); + auto flat_movie = GetMovie(buf); - TEST_EQ(movie->characters()->size(), 3); - const Belle *belle = - reinterpret_cast(movie->characters()->Get(0)); - TEST_EQ(belle->books_read(), 7); - const Rapunzel *rapunzel = - reinterpret_cast(movie->characters()->Get(1)); - TEST_EQ(rapunzel->hair_length(), 6); - const MuLan *mu_lan = - reinterpret_cast(movie->characters()->Get(2)); - TEST_EQ(mu_lan->sword_attack_damage(), 5); + auto TestMovie = [](const Movie *movie) { + TEST_EQ(movie->main_character_type() == Character_Rapunzel, true); + + auto cts = movie->characters_type(); + TEST_EQ(movie->characters_type()->size(), 5); + TEST_EQ(cts->GetEnum(0) == Character_Belle, true); + TEST_EQ(cts->GetEnum(1) == Character_MuLan, true); + TEST_EQ(cts->GetEnum(2) == Character_BookFan, true); + TEST_EQ(cts->GetEnum(3) == Character_Other, true); + TEST_EQ(cts->GetEnum(4) == Character_Unused, true); + + auto rapunzel = movie->main_character_as_Rapunzel(); + TEST_EQ(rapunzel->hair_length(), 6); + + auto cs = movie->characters(); + TEST_EQ(cs->size(), 5); + auto belle = cs->GetAs(0); + TEST_EQ(belle->books_read(), 7); + auto mu_lan = cs->GetAs(1); + TEST_EQ(mu_lan->sword_attack_damage(), 5); + auto book_fan = cs->GetAs(2); + TEST_EQ(book_fan->books_read(), 2); + auto other = cs->GetAsString(3); + TEST_EQ_STR(other->c_str(), "Other"); + auto unused = cs->GetAsString(4); + TEST_EQ_STR(unused->c_str(), "Unused"); + }; + + TestMovie(flat_movie); + + auto movie_object = flat_movie->UnPack(); + TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6); + TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7); + TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5); + TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2); + TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other"); + TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused"); + + fbb.Clear(); + fbb.Finish(Movie::Pack(fbb, movie_object)); + + auto repacked_movie = GetMovie(fbb.GetBufferPointer()); + + TestMovie(repacked_movie); } void ConformTest() { diff --git a/tests/union_vector/union_vector.fbs b/tests/union_vector/union_vector.fbs index 4957cd862..495076f52 100644 --- a/tests/union_vector/union_vector.fbs +++ b/tests/union_vector/union_vector.fbs @@ -1,22 +1,29 @@ -table MuLan { +// Demonstrates the ability to have vectors of unions, and also to +// store structs and strings in unions. + +table Attacker { sword_attack_damage: int; } -table Rapunzel { +struct Rapunzel { hair_length: int; } -table Belle { +struct BookReader { books_read: int; } union Character { - MuLan, - Rapunzel, - Belle, + MuLan: Attacker, // Can have name be different from type. + Rapunzel, // Or just both the same, as before. + Belle: BookReader, + BookFan: BookReader, + Other: string, + Unused: string } table Movie { + main_character: Character; characters: [Character]; } diff --git a/tests/union_vector/union_vector_generated.h b/tests/union_vector/union_vector_generated.h index 560860c62..24046bc5d 100644 --- a/tests/union_vector/union_vector_generated.h +++ b/tests/union_vector/union_vector_generated.h @@ -6,21 +6,26 @@ #include "flatbuffers/flatbuffers.h" -struct MuLan; +struct Attacker; +struct AttackerT; struct Rapunzel; -struct Belle; +struct BookReader; struct Movie; +struct MovieT; enum Character { Character_NONE = 0, Character_MuLan = 1, Character_Rapunzel = 2, Character_Belle = 3, + Character_BookFan = 4, + Character_Other = 5, + Character_Unused = 6, Character_MIN = Character_NONE, - Character_MAX = Character_Belle + Character_MAX = Character_Unused }; inline const char **EnumNamesCharacter() { @@ -29,6 +34,9 @@ inline const char **EnumNamesCharacter() { "MuLan", "Rapunzel", "Belle", + "BookFan", + "Other", + "Unused", nullptr }; return names; @@ -39,158 +47,221 @@ inline const char *EnumNameCharacter(Character e) { return EnumNamesCharacter()[index]; } -template struct CharacterTraits { - static const Character enum_value = Character_NONE; -}; +struct CharacterUnion { + Character type; + void *value; -template<> struct CharacterTraits { - static const Character enum_value = Character_MuLan; -}; + CharacterUnion() : type(Character_NONE), value(nullptr) {} + CharacterUnion(CharacterUnion&& u) FLATBUFFERS_NOEXCEPT : + type(Character_NONE), value(nullptr) + { std::swap(type, u.type); std::swap(value, u.value); } + CharacterUnion(const CharacterUnion &); + CharacterUnion &operator=(const CharacterUnion &); + CharacterUnion &operator=(CharacterUnion &&u) FLATBUFFERS_NOEXCEPT + { std::swap(type, u.type); std::swap(value, u.value); return *this; } + ~CharacterUnion() { Reset(); } -template<> struct CharacterTraits { - static const Character enum_value = Character_Rapunzel; -}; + void Reset(); -template<> struct CharacterTraits { - static const Character enum_value = Character_Belle; + static void *UnPack(const void *obj, Character type, const flatbuffers::resolver_function_t *resolver); + flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const; + + AttackerT *AsMuLan() { + return type == Character_MuLan ? + reinterpret_cast(value) : nullptr; + } + Rapunzel *AsRapunzel() { + return type == Character_Rapunzel ? + reinterpret_cast(value) : nullptr; + } + BookReader *AsBelle() { + return type == Character_Belle ? + reinterpret_cast(value) : nullptr; + } + BookReader *AsBookFan() { + return type == Character_BookFan ? + reinterpret_cast(value) : nullptr; + } + std::string *AsOther() { + return type == Character_Other ? + reinterpret_cast(value) : nullptr; + } + std::string *AsUnused() { + return type == Character_Unused ? + reinterpret_cast(value) : nullptr; + } }; bool VerifyCharacter(flatbuffers::Verifier &verifier, const void *obj, Character type); bool VerifyCharacterVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types); -struct MuLan FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { +MANUALLY_ALIGNED_STRUCT(4) Rapunzel FLATBUFFERS_FINAL_CLASS { + private: + int32_t hair_length_; + + public: + Rapunzel() { + memset(this, 0, sizeof(Rapunzel)); + } + Rapunzel(const Rapunzel &_o) { + memcpy(this, &_o, sizeof(Rapunzel)); + } + Rapunzel(int32_t _hair_length) + : hair_length_(flatbuffers::EndianScalar(_hair_length)) { + } + int32_t hair_length() const { + return flatbuffers::EndianScalar(hair_length_); + } + void mutate_hair_length(int32_t _hair_length) { + flatbuffers::WriteScalar(&hair_length_, _hair_length); + } +}; +STRUCT_END(Rapunzel, 4); + +MANUALLY_ALIGNED_STRUCT(4) BookReader FLATBUFFERS_FINAL_CLASS { + private: + int32_t books_read_; + + public: + BookReader() { + memset(this, 0, sizeof(BookReader)); + } + BookReader(const BookReader &_o) { + memcpy(this, &_o, sizeof(BookReader)); + } + BookReader(int32_t _books_read) + : books_read_(flatbuffers::EndianScalar(_books_read)) { + } + int32_t books_read() const { + return flatbuffers::EndianScalar(books_read_); + } + void mutate_books_read(int32_t _books_read) { + flatbuffers::WriteScalar(&books_read_, _books_read); + } +}; +STRUCT_END(BookReader, 4); + +struct AttackerT : public flatbuffers::NativeTable { + typedef Attacker TableType; + int32_t sword_attack_damage; + AttackerT() + : sword_attack_damage(0) { + } +}; + +struct Attacker FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef AttackerT NativeTableType; enum { VT_SWORD_ATTACK_DAMAGE = 4 }; int32_t sword_attack_damage() const { return GetField(VT_SWORD_ATTACK_DAMAGE, 0); } + bool mutate_sword_attack_damage(int32_t _sword_attack_damage) { + return SetField(VT_SWORD_ATTACK_DAMAGE, _sword_attack_damage, 0); + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, VT_SWORD_ATTACK_DAMAGE) && verifier.EndTable(); } + AttackerT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AttackerT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); }; -struct MuLanBuilder { +struct AttackerBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; void add_sword_attack_damage(int32_t sword_attack_damage) { - fbb_.AddElement(MuLan::VT_SWORD_ATTACK_DAMAGE, sword_attack_damage, 0); + fbb_.AddElement(Attacker::VT_SWORD_ATTACK_DAMAGE, sword_attack_damage, 0); } - MuLanBuilder(flatbuffers::FlatBufferBuilder &_fbb) + AttackerBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } - MuLanBuilder &operator=(const MuLanBuilder &); - flatbuffers::Offset Finish() { + AttackerBuilder &operator=(const AttackerBuilder &); + flatbuffers::Offset Finish() { const auto end = fbb_.EndTable(start_, 1); - auto o = flatbuffers::Offset(end); + auto o = flatbuffers::Offset(end); return o; } }; -inline flatbuffers::Offset CreateMuLan( +inline flatbuffers::Offset CreateAttacker( flatbuffers::FlatBufferBuilder &_fbb, int32_t sword_attack_damage = 0) { - MuLanBuilder builder_(_fbb); + AttackerBuilder builder_(_fbb); builder_.add_sword_attack_damage(sword_attack_damage); return builder_.Finish(); } -struct Rapunzel FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - enum { - VT_HAIR_LENGTH = 4 - }; - int32_t hair_length() const { - return GetField(VT_HAIR_LENGTH, 0); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField(verifier, VT_HAIR_LENGTH) && - verifier.EndTable(); +flatbuffers::Offset CreateAttacker(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct MovieT : public flatbuffers::NativeTable { + typedef Movie TableType; + CharacterUnion main_character; + std::vector characters; + MovieT() { } }; -struct RapunzelBuilder { - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_hair_length(int32_t hair_length) { - fbb_.AddElement(Rapunzel::VT_HAIR_LENGTH, hair_length, 0); - } - RapunzelBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - RapunzelBuilder &operator=(const RapunzelBuilder &); - flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_, 1); - auto o = flatbuffers::Offset(end); - return o; - } -}; - -inline flatbuffers::Offset CreateRapunzel( - flatbuffers::FlatBufferBuilder &_fbb, - int32_t hair_length = 0) { - RapunzelBuilder builder_(_fbb); - builder_.add_hair_length(hair_length); - return builder_.Finish(); -} - -struct Belle FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - enum { - VT_BOOKS_READ = 4 - }; - int32_t books_read() const { - return GetField(VT_BOOKS_READ, 0); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField(verifier, VT_BOOKS_READ) && - verifier.EndTable(); - } -}; - -struct BelleBuilder { - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_books_read(int32_t books_read) { - fbb_.AddElement(Belle::VT_BOOKS_READ, books_read, 0); - } - BelleBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - BelleBuilder &operator=(const BelleBuilder &); - flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_, 1); - auto o = flatbuffers::Offset(end); - return o; - } -}; - -inline flatbuffers::Offset CreateBelle( - flatbuffers::FlatBufferBuilder &_fbb, - int32_t books_read = 0) { - BelleBuilder builder_(_fbb); - builder_.add_books_read(books_read); - return builder_.Finish(); -} - struct Movie FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef MovieT NativeTableType; enum { - VT_CHARACTERS_TYPE = 4, - VT_CHARACTERS = 6 + VT_MAIN_CHARACTER_TYPE = 4, + VT_MAIN_CHARACTER = 6, + VT_CHARACTERS_TYPE = 8, + VT_CHARACTERS = 10 }; + Character main_character_type() const { + return static_cast(GetField(VT_MAIN_CHARACTER_TYPE, 0)); + } + bool mutate_main_character_type(Character _main_character_type) { + return SetField(VT_MAIN_CHARACTER_TYPE, static_cast(_main_character_type), 0); + } + const void *main_character() const { + return GetPointer(VT_MAIN_CHARACTER); + } + template const T *main_character_as() const; + const Attacker *main_character_as_MuLan() const { + return main_character_type() == Character_MuLan ? static_cast(main_character()) : nullptr; + } + const Rapunzel *main_character_as_Rapunzel() const { + return main_character_type() == Character_Rapunzel ? static_cast(main_character()) : nullptr; + } + const BookReader *main_character_as_Belle() const { + return main_character_type() == Character_Belle ? static_cast(main_character()) : nullptr; + } + const BookReader *main_character_as_BookFan() const { + return main_character_type() == Character_BookFan ? static_cast(main_character()) : nullptr; + } + const flatbuffers::String *main_character_as_Other() const { + return main_character_type() == Character_Other ? static_cast(main_character()) : nullptr; + } + const flatbuffers::String *main_character_as_Unused() const { + return main_character_type() == Character_Unused ? static_cast(main_character()) : nullptr; + } + void *mutable_main_character() { + return GetPointer(VT_MAIN_CHARACTER); + } const flatbuffers::Vector *characters_type() const { return GetPointer *>(VT_CHARACTERS_TYPE); } + flatbuffers::Vector *mutable_characters_type() { + return GetPointer *>(VT_CHARACTERS_TYPE); + } const flatbuffers::Vector> *characters() const { return GetPointer> *>(VT_CHARACTERS); } + flatbuffers::Vector> *mutable_characters() { + return GetPointer> *>(VT_CHARACTERS); + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && + VerifyField(verifier, VT_MAIN_CHARACTER_TYPE) && + VerifyField(verifier, VT_MAIN_CHARACTER) && + VerifyCharacter(verifier, main_character(), main_character_type()) && VerifyField(verifier, VT_CHARACTERS_TYPE) && verifier.Verify(characters_type()) && VerifyField(verifier, VT_CHARACTERS) && @@ -198,11 +269,20 @@ struct Movie FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyCharacterVector(verifier, characters(), characters_type()) && verifier.EndTable(); } + MovieT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(MovieT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const MovieT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); }; struct MovieBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; + void add_main_character_type(Character main_character_type) { + fbb_.AddElement(Movie::VT_MAIN_CHARACTER_TYPE, static_cast(main_character_type), 0); + } + void add_main_character(flatbuffers::Offset main_character) { + fbb_.AddOffset(Movie::VT_MAIN_CHARACTER, main_character); + } void add_characters_type(flatbuffers::Offset> characters_type) { fbb_.AddOffset(Movie::VT_CHARACTERS_TYPE, characters_type); } @@ -215,7 +295,7 @@ struct MovieBuilder { } MovieBuilder &operator=(const MovieBuilder &); flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_, 2); + const auto end = fbb_.EndTable(start_, 4); auto o = flatbuffers::Offset(end); return o; } @@ -223,40 +303,118 @@ struct MovieBuilder { inline flatbuffers::Offset CreateMovie( flatbuffers::FlatBufferBuilder &_fbb, + Character main_character_type = Character_NONE, + flatbuffers::Offset main_character = 0, flatbuffers::Offset> characters_type = 0, flatbuffers::Offset>> characters = 0) { MovieBuilder builder_(_fbb); builder_.add_characters(characters); builder_.add_characters_type(characters_type); + builder_.add_main_character(main_character); + builder_.add_main_character_type(main_character_type); return builder_.Finish(); } inline flatbuffers::Offset CreateMovieDirect( flatbuffers::FlatBufferBuilder &_fbb, + Character main_character_type = Character_NONE, + flatbuffers::Offset main_character = 0, const std::vector *characters_type = nullptr, const std::vector> *characters = nullptr) { return CreateMovie( _fbb, + main_character_type, + main_character, characters_type ? _fbb.CreateVector(*characters_type) : 0, characters ? _fbb.CreateVector>(*characters) : 0); } +flatbuffers::Offset CreateMovie(flatbuffers::FlatBufferBuilder &_fbb, const MovieT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +inline AttackerT *Attacker::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new AttackerT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void Attacker::UnPackTo(AttackerT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = sword_attack_damage(); _o->sword_attack_damage = _e; }; +} + +inline flatbuffers::Offset Attacker::Pack(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateAttacker(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateAttacker(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + auto _sword_attack_damage = _o->sword_attack_damage; + return CreateAttacker( + _fbb, + _sword_attack_damage); +} + +inline MovieT *Movie::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new MovieT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void Movie::UnPackTo(MovieT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = main_character_type(); _o->main_character.type = _e; }; + { auto _e = main_character(); if (_e) _o->main_character.value = CharacterUnion::UnPack(_e, main_character_type(), _resolver); }; + { auto _e = characters_type(); if (_e) { _o->characters.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->characters[_i].type = (Character)_e->Get(_i); } } }; + { auto _e = characters(); if (_e) { _o->characters.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->characters[_i].value = CharacterUnion::UnPack(_e->Get(_i), characters_type()->GetEnum(_i), _resolver); } } }; +} + +inline flatbuffers::Offset Movie::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MovieT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateMovie(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateMovie(flatbuffers::FlatBufferBuilder &_fbb, const MovieT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + auto _main_character_type = _o->main_character.type; + auto _main_character = _o->main_character.Pack(_fbb); + auto _characters_type = _o->characters.size() ? _fbb.CreateVector(_o->characters.size(), [&](size_t i) { return static_cast(_o->characters[i].type); }) : 0; + auto _characters = _o->characters.size() ? _fbb.CreateVector>(_o->characters.size(), [&](size_t i) { return _o->characters[i].Pack(_fbb, _rehasher); }) : 0; + return CreateMovie( + _fbb, + _main_character_type, + _main_character, + _characters_type, + _characters); +} + inline bool VerifyCharacter(flatbuffers::Verifier &verifier, const void *obj, Character type) { switch (type) { case Character_NONE: { return true; } case Character_MuLan: { - auto ptr = reinterpret_cast(obj); + auto ptr = reinterpret_cast(obj); return verifier.VerifyTable(ptr); } case Character_Rapunzel: { - auto ptr = reinterpret_cast(obj); - return verifier.VerifyTable(ptr); + return true; } case Character_Belle: { - auto ptr = reinterpret_cast(obj); - return verifier.VerifyTable(ptr); + return true; + } + case Character_BookFan: { + return true; + } + case Character_Other: { + auto ptr = reinterpret_cast(obj); + return verifier.Verify(ptr); + } + case Character_Unused: { + auto ptr = reinterpret_cast(obj); + return verifier.Verify(ptr); } default: return false; } @@ -273,10 +431,112 @@ inline bool VerifyCharacterVector(flatbuffers::Verifier &verifier, const flatbuf return true; } +inline void *CharacterUnion::UnPack(const void *obj, Character type, const flatbuffers::resolver_function_t *resolver) { + switch (type) { + case Character_MuLan: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case Character_Rapunzel: { + auto ptr = reinterpret_cast(obj); + return new Rapunzel(*ptr); + } + case Character_Belle: { + auto ptr = reinterpret_cast(obj); + return new BookReader(*ptr); + } + case Character_BookFan: { + auto ptr = reinterpret_cast(obj); + return new BookReader(*ptr); + } + case Character_Other: { + auto ptr = reinterpret_cast(obj); + return new std::string(ptr->c_str(), ptr->size()); + } + case Character_Unused: { + auto ptr = reinterpret_cast(obj); + return new std::string(ptr->c_str(), ptr->size()); + } + default: return nullptr; + } +} + +inline flatbuffers::Offset CharacterUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const { + switch (type) { + case Character_MuLan: { + auto ptr = reinterpret_cast(value); + return CreateAttacker(_fbb, ptr, _rehasher).Union(); + } + case Character_Rapunzel: { + auto ptr = reinterpret_cast(value); + return _fbb.CreateStruct(*ptr).Union(); + } + case Character_Belle: { + auto ptr = reinterpret_cast(value); + return _fbb.CreateStruct(*ptr).Union(); + } + case Character_BookFan: { + auto ptr = reinterpret_cast(value); + return _fbb.CreateStruct(*ptr).Union(); + } + case Character_Other: { + auto ptr = reinterpret_cast(value); + return _fbb.CreateString(*ptr).Union(); + } + case Character_Unused: { + auto ptr = reinterpret_cast(value); + return _fbb.CreateString(*ptr).Union(); + } + default: return 0; + } +} + +inline void CharacterUnion::Reset() { + switch (type) { + case Character_MuLan: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case Character_Rapunzel: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case Character_Belle: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case Character_BookFan: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case Character_Other: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case Character_Unused: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + default: break; + } + value = nullptr; + type = Character_NONE; +} + inline const Movie *GetMovie(const void *buf) { return flatbuffers::GetRoot(buf); } +inline Movie *GetMutableMovie(void *buf) { + return flatbuffers::GetMutableRoot(buf); +} + inline const char *MovieIdentifier() { return "MOVI"; } @@ -297,4 +557,10 @@ inline void FinishMovieBuffer( fbb.Finish(root, MovieIdentifier()); } +inline std::unique_ptr UnPackMovie( + const void *buf, + const flatbuffers::resolver_function_t *res = nullptr) { + return std::unique_ptr(GetMovie(buf)->UnPack(res)); +} + #endif // FLATBUFFERS_GENERATED_UNIONVECTOR_H_