diff --git a/CMakeLists.txt b/CMakeLists.txt index 51b2c9541..a895a340e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -540,6 +540,7 @@ if(FLATBUFFERS_BUILD_TESTS) compile_schema_for_test(tests/64bit/test_64bit.fbs "${FLATC_OPT_COMP};--bfbs-gen-embed") compile_schema_for_test(tests/64bit/evolution/v1.fbs "${FLATC_OPT_COMP}") compile_schema_for_test(tests/64bit/evolution/v2.fbs "${FLATC_OPT_COMP}") + compile_schema_for_test(tests/union_underlying_type_test.fbs "${FLATC_OPT_COMP}") if(FLATBUFFERS_CODE_SANITIZE) add_fsanitize_to_target(flattests ${FLATBUFFERS_CODE_SANITIZE}) diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index e1008a73c..ad45d3115 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -1151,6 +1151,7 @@ class Parser : public ParserState { bool SupportsOptionalScalars() const; bool SupportsDefaultVectorsAndStrings() const; bool Supports64BitOffsets() const; + bool SupportsUnionUnderlyingType() const; Namespace *UniqueNamespace(Namespace *ns); FLATBUFFERS_CHECKED_ERROR RecurseError(); diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 39ab826eb..ff8382bea 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -779,7 +779,12 @@ class CppGenerator : public BaseGenerator { if (type.enum_def) return WrapInNameSpace(*type.enum_def); if (type.base_type == BASE_TYPE_BOOL) return "bool"; } - return StringOf(type.base_type); + // Get real underlying type for union type + auto base_type = type.base_type; + if (type.base_type == BASE_TYPE_UTYPE && type.enum_def != nullptr) { + base_type = type.enum_def->underlying_type.base_type; + } + return StringOf(base_type); } // Return a C++ pointer type, specialized to the actual struct/table types, @@ -1048,7 +1053,7 @@ class CppGenerator : public BaseGenerator { std::string UnionVectorVerifySignature(const EnumDef &enum_def) { const std::string name = Name(enum_def); - const std::string &type = opts_.scoped_enums ? name : "uint8_t"; + const std::string &type = opts_.scoped_enums ? name : GenTypeBasic(enum_def.underlying_type, false); return "bool Verify" + name + "Vector" + "(::flatbuffers::Verifier &verifier, " + "const ::flatbuffers::Vector<::flatbuffers::Offset> " @@ -3496,12 +3501,13 @@ class CppGenerator : public BaseGenerator { } case BASE_TYPE_UTYPE: { value = StripUnionType(value); + auto underlying_type = GenTypeBasic(vector_type, false); const std::string &type = opts_.scoped_enums ? Name(*field.value.type.enum_def) - : "uint8_t"; + : underlying_type; auto enum_value = "__va->_" + value + "[i].type"; if (!opts_.scoped_enums) - enum_value = "static_cast(" + enum_value + ")"; + enum_value = "static_cast<" + underlying_type + ">(" + enum_value + ")"; code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), [](size_t i, _VectorArgs *__va) { return " + diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index fe1d63986..4df4558ce 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -947,8 +947,12 @@ CheckedError Parser::ParseField(StructDef &struct_def) { if (type.base_type == BASE_TYPE_UNION) { // For union fields, add a second auto-generated field to hold the type, // with a special suffix. - ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), - type.enum_def->underlying_type, &typefield)); + + // To ensure compatibility with many codes that rely on the BASE_TYPE_UTYPE value to identify union type fields. + Type union_type(type.enum_def->underlying_type); + union_type.base_type = BASE_TYPE_UTYPE; + ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),union_type, &typefield)); + } else if (IsVector(type) && type.element == BASE_TYPE_UNION) { advanced_features_ |= reflection::AdvancedUnionFeatures; // Only cpp, js and ts supports the union vector feature so far. @@ -2482,23 +2486,39 @@ CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest, &GetPooledString(RelativeToRootPath(opts.project_root, filename)); } enum_def->doc_comment = enum_comment; - if (!is_union && !opts.proto_mode) { + if (!opts.proto_mode) { // Give specialized error message, since this type spec used to // be optional in the first FlatBuffers release. + bool explicit_underlying_type = false; if (!Is(':')) { - return Error( - "must specify the underlying integer type for this" - " enum (e.g. \': short\', which was the default)."); + // Enum is forced to have an explicit underlying type in declaration. + if (!is_union) { + return Error( + "must specify the underlying integer type for this" + " enum (e.g. \': short\', which was the default)."); + } } else { + // Union underlying type is only supported for cpp + if (is_union && !SupportsUnionUnderlyingType()) { + return Error( + "Underlying type for union is not yet supported in at least one of " + "the specified programming languages."); + } NEXT(); + explicit_underlying_type = true; } - // Specify the integer type underlying this enum. - ECHECK(ParseType(enum_def->underlying_type)); - if (!IsInteger(enum_def->underlying_type.base_type) || - IsBool(enum_def->underlying_type.base_type)) - return Error("underlying enum type must be integral"); - // Make this type refer back to the enum it was derived from. - enum_def->underlying_type.enum_def = enum_def; + + if (explicit_underlying_type) { + // Specify the integer type underlying this enum. + ECHECK(ParseType(enum_def->underlying_type)); + if (!IsInteger(enum_def->underlying_type.base_type) || IsBool(enum_def->underlying_type.base_type)) { + return Error("underlying " + std::string(is_union ? "union" : "enum") + "type must be integral"); + } + + // Make this type refer back to the enum it was derived from. + enum_def->underlying_type.enum_def = enum_def; + } + } ECHECK(ParseMetaData(&enum_def->attributes)); const auto underlying_type = enum_def->underlying_type.base_type; @@ -2697,6 +2717,10 @@ bool Parser::Supports64BitOffsets() const { ~(IDLOptions::kCpp | IDLOptions::kJson | IDLOptions::kBinary)) == 0; } +bool Parser::SupportsUnionUnderlyingType() const { + return (opts.lang_to_generate & ~IDLOptions::kCpp) == 0; +} + Namespace *Parser::UniqueNamespace(Namespace *ns) { for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) { if (ns->components == (*it)->components) { @@ -4428,6 +4452,10 @@ std::string Parser::ConformTo(const Parser &base) { return "values differ for enum: " + enum_val.name; } } + // Check underlying type changes + if (enum_def_base->underlying_type.base_type != enum_def.underlying_type.base_type) { + return "underlying type differ for " + std::string(enum_def.is_union ? "union: " : "enum: ") + qualified_name; + } } return ""; } diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index c723eb81b..f306f7ec8 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -65,6 +65,7 @@ cc_test( "test_assert.h", "test_builder.cpp", "test_builder.h", + "union_underlying_type_test_generated.h", "union_vector/union_vector_generated.h", "util_test.cpp", "util_test.h", diff --git a/tests/evolution_test.cpp b/tests/evolution_test.cpp index 6ed2f5745..51c2e8131 100644 --- a/tests/evolution_test.cpp +++ b/tests/evolution_test.cpp @@ -111,6 +111,13 @@ void ConformTest() { test_conform(ref2, "enum E:int32 { A } table T2 { df:byte; f:E; }", "field renamed to different type: T2.df (renamed from T2.f)"); + // Check enum underlying type changes. + test_conform("enum E:int32 {A}", "enum E: byte {A}", "underlying type differ for enum: E"); + + // Check union underlying type changes. + const char ref3[] = "table A {} table B {} union C {A, B}"; + test_conform(ref3, "table A {} table B {} union C:int32 {A, B}", "underlying type differ for union: C"); + // Check conformity for Offset64-related changes. { const char ref[] = "table T { a:[uint8]; b:string; }"; diff --git a/tests/parser_test.cpp b/tests/parser_test.cpp index 085c2fe08..d63c0b180 100644 --- a/tests/parser_test.cpp +++ b/tests/parser_test.cpp @@ -841,6 +841,15 @@ void ParseUnionTest() { "table B { e:U; } root_type B;" "{ e_type: N_A, e: {} }"), true); + + // Test union underlying type + const char *source = "table A {} table B {} union U : int {A, B} table C {test_union: U; test_vector_of_union: [U];}"; + flatbuffers::Parser parser3; + parser3.opts.lang_to_generate = flatbuffers::IDLOptions::kCpp; + TEST_EQ(parser3.Parse(source), true); + + parser3.opts.lang_to_generate &= flatbuffers::IDLOptions::kJava; + TEST_EQ(parser3.Parse(source), false); } void ValidSameNameDifferentNamespaceTest() { diff --git a/tests/test.cpp b/tests/test.cpp index 5d4838939..f26b1adf2 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -39,6 +39,7 @@ #include "proto_test.h" #include "reflection_test.h" #include "union_vector/union_vector_generated.h" +#include "union_underlying_type_test_generated.h" #if !defined(_MSC_VER) || _MSC_VER >= 1700 # include "arrays_test_generated.h" #endif @@ -1540,6 +1541,41 @@ void DoNotRequireEofTest(const std::string &tests_data_path) { } #endif +void UnionUnderlyingTypeTest() { + using namespace UnionUnderlyingType; + TEST_ASSERT(sizeof(ABC) == sizeof(uint32_t)); + TEST_ASSERT(ABC::ABC_A == 555); + TEST_ASSERT(ABC::ABC_B == 666); + TEST_ASSERT(ABC::ABC_C == 777); + + DT buffer; + AT a; + a.a = 42; + BT b; + b.b = "foo"; + CT c; + c.c = true; + buffer.test_union = ABCUnion(); + buffer.test_union.Set(a); + buffer.test_vector_of_union.resize(3); + buffer.test_vector_of_union[0].Set(a); + buffer.test_vector_of_union[1].Set(b); + buffer.test_vector_of_union[2].Set(c); + + flatbuffers::FlatBufferBuilder fbb; + auto offset = D::Pack(fbb, &buffer); + fbb.Finish(offset); + + auto *root = + flatbuffers::GetRoot(fbb.GetBufferPointer()); + DT unpacked; + root->UnPackTo(&unpacked); + + TEST_ASSERT(unpacked.test_union == buffer.test_union); + TEST_ASSERT(unpacked.test_vector_of_union == buffer.test_vector_of_union); + +} + static void Offset64Tests() { Offset64Test(); Offset64SerializedFirst(); @@ -1663,6 +1699,7 @@ int FlatBufferTests(const std::string &tests_data_path) { FixedSizedStructArrayKeyInStructTest(); EmbeddedSchemaAccess(); Offset64Tests(); + UnionUnderlyingTypeTest(); return 0; } } // namespace diff --git a/tests/union_underlying_type_test.fbs b/tests/union_underlying_type_test.fbs new file mode 100644 index 000000000..2f4ed12e2 --- /dev/null +++ b/tests/union_underlying_type_test.fbs @@ -0,0 +1,17 @@ + +namespace UnionUnderlyingType; + +table A { + a: int; +} +table B { + b: string; +} +table C { + c: bool; +} +union ABC: int { A = 555, B = 666, C = 777} +table D { + test_union: ABC; + test_vector_of_union: [ABC]; +} diff --git a/tests/union_underlying_type_test_generated.h b/tests/union_underlying_type_test_generated.h new file mode 100644 index 000000000..f70af50a4 --- /dev/null +++ b/tests/union_underlying_type_test_generated.h @@ -0,0 +1,880 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_UNIONUNDERLYINGTYPETEST_UNIONUNDERLYINGTYPE_H_ +#define FLATBUFFERS_GENERATED_UNIONUNDERLYINGTYPETEST_UNIONUNDERLYINGTYPE_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 23 && + FLATBUFFERS_VERSION_MINOR == 5 && + FLATBUFFERS_VERSION_REVISION == 9, + "Non-compatible flatbuffers version included"); + +namespace UnionUnderlyingType { + +struct A; +struct ABuilder; +struct AT; + +struct B; +struct BBuilder; +struct BT; + +struct C; +struct CBuilder; +struct CT; + +struct D; +struct DBuilder; +struct DT; + +bool operator==(const AT &lhs, const AT &rhs); +bool operator!=(const AT &lhs, const AT &rhs); +bool operator==(const BT &lhs, const BT &rhs); +bool operator!=(const BT &lhs, const BT &rhs); +bool operator==(const CT &lhs, const CT &rhs); +bool operator!=(const CT &lhs, const CT &rhs); +bool operator==(const DT &lhs, const DT &rhs); +bool operator!=(const DT &lhs, const DT &rhs); + +inline const ::flatbuffers::TypeTable *ATypeTable(); + +inline const ::flatbuffers::TypeTable *BTypeTable(); + +inline const ::flatbuffers::TypeTable *CTypeTable(); + +inline const ::flatbuffers::TypeTable *DTypeTable(); + +enum ABC : int32_t { + ABC_NONE = 0, + ABC_A = 555, + ABC_B = 666, + ABC_C = 777, + ABC_MIN = ABC_NONE, + ABC_MAX = ABC_C +}; + +inline const ABC (&EnumValuesABC())[4] { + static const ABC values[] = { + ABC_NONE, + ABC_A, + ABC_B, + ABC_C + }; + return values; +} + +inline const char *EnumNameABC(ABC e) { + switch (e) { + case ABC_NONE: return "NONE"; + case ABC_A: return "A"; + case ABC_B: return "B"; + case ABC_C: return "C"; + default: return ""; + } +} + +template struct ABCTraits { + static const ABC enum_value = ABC_NONE; +}; + +template<> struct ABCTraits { + static const ABC enum_value = ABC_A; +}; + +template<> struct ABCTraits { + static const ABC enum_value = ABC_B; +}; + +template<> struct ABCTraits { + static const ABC enum_value = ABC_C; +}; + +template struct ABCUnionTraits { + static const ABC enum_value = ABC_NONE; +}; + +template<> struct ABCUnionTraits { + static const ABC enum_value = ABC_A; +}; + +template<> struct ABCUnionTraits { + static const ABC enum_value = ABC_B; +}; + +template<> struct ABCUnionTraits { + static const ABC enum_value = ABC_C; +}; + +struct ABCUnion { + ABC type; + void *value; + + ABCUnion() : type(ABC_NONE), value(nullptr) {} + ABCUnion(ABCUnion&& u) FLATBUFFERS_NOEXCEPT : + type(ABC_NONE), value(nullptr) + { std::swap(type, u.type); std::swap(value, u.value); } + ABCUnion(const ABCUnion &); + ABCUnion &operator=(const ABCUnion &u) + { ABCUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; } + ABCUnion &operator=(ABCUnion &&u) FLATBUFFERS_NOEXCEPT + { std::swap(type, u.type); std::swap(value, u.value); return *this; } + ~ABCUnion() { Reset(); } + + void Reset(); + + template + void Set(T&& val) { + typedef typename std::remove_reference::type RT; + Reset(); + type = ABCUnionTraits::enum_value; + if (type != ABC_NONE) { + value = new RT(std::forward(val)); + } + } + + static void *UnPack(const void *obj, ABC type, const ::flatbuffers::resolver_function_t *resolver); + ::flatbuffers::Offset Pack(::flatbuffers::FlatBufferBuilder &_fbb, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr) const; + + UnionUnderlyingType::AT *AsA() { + return type == ABC_A ? + reinterpret_cast(value) : nullptr; + } + const UnionUnderlyingType::AT *AsA() const { + return type == ABC_A ? + reinterpret_cast(value) : nullptr; + } + UnionUnderlyingType::BT *AsB() { + return type == ABC_B ? + reinterpret_cast(value) : nullptr; + } + const UnionUnderlyingType::BT *AsB() const { + return type == ABC_B ? + reinterpret_cast(value) : nullptr; + } + UnionUnderlyingType::CT *AsC() { + return type == ABC_C ? + reinterpret_cast(value) : nullptr; + } + const UnionUnderlyingType::CT *AsC() const { + return type == ABC_C ? + reinterpret_cast(value) : nullptr; + } +}; + + +inline bool operator==(const ABCUnion &lhs, const ABCUnion &rhs) { + if (lhs.type != rhs.type) return false; + switch (lhs.type) { + case ABC_NONE: { + return true; + } + case ABC_A: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + case ABC_B: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + case ABC_C: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + default: { + return false; + } + } +} + +inline bool operator!=(const ABCUnion &lhs, const ABCUnion &rhs) { + return !(lhs == rhs); +} + +bool VerifyABC(::flatbuffers::Verifier &verifier, const void *obj, ABC type); +bool VerifyABCVector(::flatbuffers::Verifier &verifier, const ::flatbuffers::Vector<::flatbuffers::Offset> *values, const ::flatbuffers::Vector *types); + +struct AT : public ::flatbuffers::NativeTable { + typedef A TableType; + int32_t a = 0; +}; + +struct A FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef AT NativeTableType; + typedef ABuilder Builder; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return ATypeTable(); + } + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_A = 4 + }; + int32_t a() const { + return GetField(VT_A, 0); + } + bool mutate_a(int32_t _a = 0) { + return SetField(VT_A, _a, 0); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_A, 4) && + verifier.EndTable(); + } + AT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + static ::flatbuffers::Offset Pack(::flatbuffers::FlatBufferBuilder &_fbb, const AT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ABuilder { + typedef A Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_a(int32_t a) { + fbb_.AddElement(A::VT_A, a, 0); + } + explicit ABuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateA( + ::flatbuffers::FlatBufferBuilder &_fbb, + int32_t a = 0) { + ABuilder builder_(_fbb); + builder_.add_a(a); + return builder_.Finish(); +} + +::flatbuffers::Offset CreateA(::flatbuffers::FlatBufferBuilder &_fbb, const AT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct BT : public ::flatbuffers::NativeTable { + typedef B TableType; + std::string b{}; +}; + +struct B FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef BT NativeTableType; + typedef BBuilder Builder; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return BTypeTable(); + } + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_B = 4 + }; + const ::flatbuffers::String *b() const { + return GetPointer(VT_B); + } + ::flatbuffers::String *mutable_b() { + return GetPointer<::flatbuffers::String *>(VT_B); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_B) && + verifier.VerifyString(b()) && + verifier.EndTable(); + } + BT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(BT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + static ::flatbuffers::Offset Pack(::flatbuffers::FlatBufferBuilder &_fbb, const BT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct BBuilder { + typedef B Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_b(::flatbuffers::Offset<::flatbuffers::String> b) { + fbb_.AddOffset(B::VT_B, b); + } + explicit BBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateB( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset<::flatbuffers::String> b = 0) { + BBuilder builder_(_fbb); + builder_.add_b(b); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateBDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + const char *b = nullptr) { + auto b__ = b ? _fbb.CreateString(b) : 0; + return UnionUnderlyingType::CreateB( + _fbb, + b__); +} + +::flatbuffers::Offset CreateB(::flatbuffers::FlatBufferBuilder &_fbb, const BT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct CT : public ::flatbuffers::NativeTable { + typedef C TableType; + bool c = false; +}; + +struct C FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef CT NativeTableType; + typedef CBuilder Builder; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return CTypeTable(); + } + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_C = 4 + }; + bool c() const { + return GetField(VT_C, 0) != 0; + } + bool mutate_c(bool _c = 0) { + return SetField(VT_C, static_cast(_c), 0); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_C, 1) && + verifier.EndTable(); + } + CT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(CT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + static ::flatbuffers::Offset Pack(::flatbuffers::FlatBufferBuilder &_fbb, const CT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct CBuilder { + typedef C Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_c(bool c) { + fbb_.AddElement(C::VT_C, static_cast(c), 0); + } + explicit CBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateC( + ::flatbuffers::FlatBufferBuilder &_fbb, + bool c = false) { + CBuilder builder_(_fbb); + builder_.add_c(c); + return builder_.Finish(); +} + +::flatbuffers::Offset CreateC(::flatbuffers::FlatBufferBuilder &_fbb, const CT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct DT : public ::flatbuffers::NativeTable { + typedef D TableType; + UnionUnderlyingType::ABCUnion test_union{}; + std::vector test_vector_of_union{}; +}; + +struct D FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef DT NativeTableType; + typedef DBuilder Builder; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return DTypeTable(); + } + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_TEST_UNION_TYPE = 4, + VT_TEST_UNION = 6, + VT_TEST_VECTOR_OF_UNION_TYPE = 8, + VT_TEST_VECTOR_OF_UNION = 10 + }; + UnionUnderlyingType::ABC test_union_type() const { + return static_cast(GetField(VT_TEST_UNION_TYPE, 0)); + } + const void *test_union() const { + return GetPointer(VT_TEST_UNION); + } + template const T *test_union_as() const; + const UnionUnderlyingType::A *test_union_as_A() const { + return test_union_type() == UnionUnderlyingType::ABC_A ? static_cast(test_union()) : nullptr; + } + const UnionUnderlyingType::B *test_union_as_B() const { + return test_union_type() == UnionUnderlyingType::ABC_B ? static_cast(test_union()) : nullptr; + } + const UnionUnderlyingType::C *test_union_as_C() const { + return test_union_type() == UnionUnderlyingType::ABC_C ? static_cast(test_union()) : nullptr; + } + void *mutable_test_union() { + return GetPointer(VT_TEST_UNION); + } + const ::flatbuffers::Vector *test_vector_of_union_type() const { + return GetPointer *>(VT_TEST_VECTOR_OF_UNION_TYPE); + } + ::flatbuffers::Vector *mutable_test_vector_of_union_type() { + return GetPointer<::flatbuffers::Vector *>(VT_TEST_VECTOR_OF_UNION_TYPE); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *test_vector_of_union() const { + return GetPointer> *>(VT_TEST_VECTOR_OF_UNION); + } + ::flatbuffers::Vector<::flatbuffers::Offset> *mutable_test_vector_of_union() { + return GetPointer<::flatbuffers::Vector<::flatbuffers::Offset> *>(VT_TEST_VECTOR_OF_UNION); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_TEST_UNION_TYPE, 1) && + VerifyOffset(verifier, VT_TEST_UNION) && + VerifyABC(verifier, test_union(), test_union_type()) && + VerifyOffset(verifier, VT_TEST_VECTOR_OF_UNION_TYPE) && + verifier.VerifyVector(test_vector_of_union_type()) && + VerifyOffset(verifier, VT_TEST_VECTOR_OF_UNION) && + verifier.VerifyVector(test_vector_of_union()) && + VerifyABCVector(verifier, test_vector_of_union(), test_vector_of_union_type()) && + verifier.EndTable(); + } + DT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(DT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + static ::flatbuffers::Offset Pack(::flatbuffers::FlatBufferBuilder &_fbb, const DT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +template<> inline const UnionUnderlyingType::A *D::test_union_as() const { + return test_union_as_A(); +} + +template<> inline const UnionUnderlyingType::B *D::test_union_as() const { + return test_union_as_B(); +} + +template<> inline const UnionUnderlyingType::C *D::test_union_as() const { + return test_union_as_C(); +} + +struct DBuilder { + typedef D Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_test_union_type(UnionUnderlyingType::ABC test_union_type) { + fbb_.AddElement(D::VT_TEST_UNION_TYPE, static_cast(test_union_type), 0); + } + void add_test_union(::flatbuffers::Offset test_union) { + fbb_.AddOffset(D::VT_TEST_UNION, test_union); + } + void add_test_vector_of_union_type(::flatbuffers::Offset<::flatbuffers::Vector> test_vector_of_union_type) { + fbb_.AddOffset(D::VT_TEST_VECTOR_OF_UNION_TYPE, test_vector_of_union_type); + } + void add_test_vector_of_union(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> test_vector_of_union) { + fbb_.AddOffset(D::VT_TEST_VECTOR_OF_UNION, test_vector_of_union); + } + explicit DBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateD( + ::flatbuffers::FlatBufferBuilder &_fbb, + UnionUnderlyingType::ABC test_union_type = UnionUnderlyingType::ABC_NONE, + ::flatbuffers::Offset test_union = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> test_vector_of_union_type = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> test_vector_of_union = 0) { + DBuilder builder_(_fbb); + builder_.add_test_vector_of_union(test_vector_of_union); + builder_.add_test_vector_of_union_type(test_vector_of_union_type); + builder_.add_test_union(test_union); + builder_.add_test_union_type(test_union_type); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateDDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + UnionUnderlyingType::ABC test_union_type = UnionUnderlyingType::ABC_NONE, + ::flatbuffers::Offset test_union = 0, + const std::vector *test_vector_of_union_type = nullptr, + const std::vector<::flatbuffers::Offset> *test_vector_of_union = nullptr) { + auto test_vector_of_union_type__ = test_vector_of_union_type ? _fbb.CreateVector(*test_vector_of_union_type) : 0; + auto test_vector_of_union__ = test_vector_of_union ? _fbb.CreateVector<::flatbuffers::Offset>(*test_vector_of_union) : 0; + return UnionUnderlyingType::CreateD( + _fbb, + test_union_type, + test_union, + test_vector_of_union_type__, + test_vector_of_union__); +} + +::flatbuffers::Offset CreateD(::flatbuffers::FlatBufferBuilder &_fbb, const DT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); + + +inline bool operator==(const AT &lhs, const AT &rhs) { + return + (lhs.a == rhs.a); +} + +inline bool operator!=(const AT &lhs, const AT &rhs) { + return !(lhs == rhs); +} + + +inline AT *A::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new AT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void A::UnPackTo(AT *_o, const ::flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = a(); _o->a = _e; } +} + +inline ::flatbuffers::Offset A::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const AT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) { + return CreateA(_fbb, _o, _rehasher); +} + +inline ::flatbuffers::Offset CreateA(::flatbuffers::FlatBufferBuilder &_fbb, const AT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const AT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _a = _o->a; + return UnionUnderlyingType::CreateA( + _fbb, + _a); +} + + +inline bool operator==(const BT &lhs, const BT &rhs) { + return + (lhs.b == rhs.b); +} + +inline bool operator!=(const BT &lhs, const BT &rhs) { + return !(lhs == rhs); +} + + +inline BT *B::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new BT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void B::UnPackTo(BT *_o, const ::flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = b(); if (_e) _o->b = _e->str(); } +} + +inline ::flatbuffers::Offset B::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const BT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) { + return CreateB(_fbb, _o, _rehasher); +} + +inline ::flatbuffers::Offset CreateB(::flatbuffers::FlatBufferBuilder &_fbb, const BT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const BT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _b = _o->b.empty() ? 0 : _fbb.CreateString(_o->b); + return UnionUnderlyingType::CreateB( + _fbb, + _b); +} + + +inline bool operator==(const CT &lhs, const CT &rhs) { + return + (lhs.c == rhs.c); +} + +inline bool operator!=(const CT &lhs, const CT &rhs) { + return !(lhs == rhs); +} + + +inline CT *C::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new CT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void C::UnPackTo(CT *_o, const ::flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = c(); _o->c = _e; } +} + +inline ::flatbuffers::Offset C::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const CT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) { + return CreateC(_fbb, _o, _rehasher); +} + +inline ::flatbuffers::Offset CreateC(::flatbuffers::FlatBufferBuilder &_fbb, const CT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const CT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _c = _o->c; + return UnionUnderlyingType::CreateC( + _fbb, + _c); +} + + +inline bool operator==(const DT &lhs, const DT &rhs) { + return + (lhs.test_union == rhs.test_union) && + (lhs.test_vector_of_union == rhs.test_vector_of_union); +} + +inline bool operator!=(const DT &lhs, const DT &rhs) { + return !(lhs == rhs); +} + + +inline DT *D::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr
(new DT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void D::UnPackTo(DT *_o, const ::flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = test_union_type(); _o->test_union.type = _e; } + { auto _e = test_union(); if (_e) _o->test_union.value = UnionUnderlyingType::ABCUnion::UnPack(_e, test_union_type(), _resolver); } + { auto _e = test_vector_of_union_type(); if (_e) { _o->test_vector_of_union.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test_vector_of_union[_i].type = static_cast(_e->Get(_i)); } } else { _o->test_vector_of_union.resize(0); } } + { auto _e = test_vector_of_union(); if (_e) { _o->test_vector_of_union.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test_vector_of_union[_i].value = UnionUnderlyingType::ABCUnion::UnPack(_e->Get(_i), test_vector_of_union_type()->GetEnum(_i), _resolver); } } else { _o->test_vector_of_union.resize(0); } } +} + +inline ::flatbuffers::Offset D::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const DT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) { + return CreateD(_fbb, _o, _rehasher); +} + +inline ::flatbuffers::Offset CreateD(::flatbuffers::FlatBufferBuilder &_fbb, const DT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const DT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _test_union_type = _o->test_union.type; + auto _test_union = _o->test_union.Pack(_fbb); + auto _test_vector_of_union_type = _o->test_vector_of_union.size() ? _fbb.CreateVector(_o->test_vector_of_union.size(), [](size_t i, _VectorArgs *__va) { return static_cast(__va->__o->test_vector_of_union[i].type); }, &_va) : 0; + auto _test_vector_of_union = _o->test_vector_of_union.size() ? _fbb.CreateVector<::flatbuffers::Offset>(_o->test_vector_of_union.size(), [](size_t i, _VectorArgs *__va) { return __va->__o->test_vector_of_union[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va) : 0; + return UnionUnderlyingType::CreateD( + _fbb, + _test_union_type, + _test_union, + _test_vector_of_union_type, + _test_vector_of_union); +} + +inline bool VerifyABC(::flatbuffers::Verifier &verifier, const void *obj, ABC type) { + switch (type) { + case ABC_NONE: { + return true; + } + case ABC_A: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case ABC_B: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case ABC_C: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + default: return true; + } +} + +inline bool VerifyABCVector(::flatbuffers::Verifier &verifier, const ::flatbuffers::Vector<::flatbuffers::Offset> *values, const ::flatbuffers::Vector *types) { + if (!values || !types) return !values && !types; + if (values->size() != types->size()) return false; + for (::flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { + if (!VerifyABC( + verifier, values->Get(i), types->GetEnum(i))) { + return false; + } + } + return true; +} + +inline void *ABCUnion::UnPack(const void *obj, ABC type, const ::flatbuffers::resolver_function_t *resolver) { + (void)resolver; + switch (type) { + case ABC_A: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case ABC_B: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case ABC_C: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + default: return nullptr; + } +} + +inline ::flatbuffers::Offset ABCUnion::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const ::flatbuffers::rehasher_function_t *_rehasher) const { + (void)_rehasher; + switch (type) { + case ABC_A: { + auto ptr = reinterpret_cast(value); + return CreateA(_fbb, ptr, _rehasher).Union(); + } + case ABC_B: { + auto ptr = reinterpret_cast(value); + return CreateB(_fbb, ptr, _rehasher).Union(); + } + case ABC_C: { + auto ptr = reinterpret_cast(value); + return CreateC(_fbb, ptr, _rehasher).Union(); + } + default: return 0; + } +} + +inline ABCUnion::ABCUnion(const ABCUnion &u) : type(u.type), value(nullptr) { + switch (type) { + case ABC_A: { + value = new UnionUnderlyingType::AT(*reinterpret_cast(u.value)); + break; + } + case ABC_B: { + value = new UnionUnderlyingType::BT(*reinterpret_cast(u.value)); + break; + } + case ABC_C: { + value = new UnionUnderlyingType::CT(*reinterpret_cast(u.value)); + break; + } + default: + break; + } +} + +inline void ABCUnion::Reset() { + switch (type) { + case ABC_A: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case ABC_B: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case ABC_C: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + default: break; + } + value = nullptr; + type = ABC_NONE; +} + +inline const ::flatbuffers::TypeTable *ABCTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_SEQUENCE, 0, -1 }, + { ::flatbuffers::ET_SEQUENCE, 0, 0 }, + { ::flatbuffers::ET_SEQUENCE, 0, 1 }, + { ::flatbuffers::ET_SEQUENCE, 0, 2 } + }; + static const ::flatbuffers::TypeFunction type_refs[] = { + UnionUnderlyingType::ATypeTable, + UnionUnderlyingType::BTypeTable, + UnionUnderlyingType::CTypeTable + }; + static const int64_t values[] = { 0, 555, 666, 777 }; + static const char * const names[] = { + "NONE", + "A", + "B", + "C" + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_UNION, 4, type_codes, type_refs, nullptr, values, names + }; + return &tt; +} + +inline const ::flatbuffers::TypeTable *ATypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_INT, 0, -1 } + }; + static const char * const names[] = { + "a" + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, nullptr, names + }; + return &tt; +} + +inline const ::flatbuffers::TypeTable *BTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_STRING, 0, -1 } + }; + static const char * const names[] = { + "b" + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, nullptr, names + }; + return &tt; +} + +inline const ::flatbuffers::TypeTable *CTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_BOOL, 0, -1 } + }; + static const char * const names[] = { + "c" + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, nullptr, names + }; + return &tt; +} + +inline const ::flatbuffers::TypeTable *DTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_UTYPE, 0, 0 }, + { ::flatbuffers::ET_SEQUENCE, 0, 0 }, + { ::flatbuffers::ET_UTYPE, 1, 0 }, + { ::flatbuffers::ET_SEQUENCE, 1, 0 } + }; + static const ::flatbuffers::TypeFunction type_refs[] = { + UnionUnderlyingType::ABCTypeTable + }; + static const char * const names[] = { + "test_union_type", + "test_union", + "test_vector_of_union_type", + "test_vector_of_union" + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_TABLE, 4, type_codes, type_refs, nullptr, nullptr, names + }; + return &tt; +} + +} // namespace UnionUnderlyingType + +#endif // FLATBUFFERS_GENERATED_UNIONUNDERLYINGTYPETEST_UNIONUNDERLYINGTYPE_H_